28 #include <QTextStream>
31 #include <QFormLayout>
32 #include <QGridLayout>
36 #include <QPushButton>
37 #include <QScrollArea>
40 #include <QMessageBox>
42 int QgsAttributeForm::sFormCounter = 0;
48 , mButtonBox( nullptr )
49 , mFormNr( sFormCounter++ )
51 , mIsAddDialog( false )
52 , mPreventFeatureRefresh( false )
53 , mEditCommandMessage(
tr(
"Attributes changed" ) )
62 connect( vl, SIGNAL( attributeAdded(
int ) ),
this, SLOT( onAttributeAdded(
int ) ) );
63 connect( vl, SIGNAL( attributeDeleted(
int ) ),
this, SLOT( onAttributeDeleted(
int ) ) );
65 connect( vl, SIGNAL( updatedFields() ),
this, SLOT( onUpdatedFields() ) );
66 connect( vl, SIGNAL( beforeAddingExpressionField(
QString ) ),
this, SLOT( preventFeatureRefresh() ) );
67 connect( vl, SIGNAL( beforeRemovingExpressionField(
int ) ),
this, SLOT( preventFeatureRefresh() ) );
73 qDeleteAll( mInterfaces );
82 connect( mLayer, SIGNAL( beforeModifiedCheck() ),
this, SLOT(
save() ) );
89 disconnect( mLayer, SIGNAL( beforeModifiedCheck() ),
this, SLOT(
save() ) );
100 mInterfaces.
append( iface );
110 mIsAddDialog = isAddDialog;
112 synchronizeEnabledState();
120 if ( eww && eww->
field().
name() == field )
133 synchronizeEnabledState();
148 bool changedLayer =
false;
160 if ( mFeature.
isValid() || mIsAddDialog )
162 bool doUpdate =
false;
183 bool changed = ( dstVar != srcVar && !dstVar.
isNull() && !srcVar.
isNull() )
185 if ( changed && srcVar.
isValid()
211 bool res = mLayer->
addFeature( updatedFeature );
216 mIsAddDialog =
false;
227 for (
int i = 0; i < dst.
count(); ++i )
229 if (( dst.
at( i ) == src.
at( i ) && dst.
at( i ).isNull() == src.
at( i ).isNull() )
230 || !dst.
at( i ).isValid()
238 .arg( dst.
at( i ).toString(), dst.
at( i ).typeName() ).arg( dst.
at( i ).isNull() ).arg( dst.
at( i ).isValid() ) );
240 .arg( src.
at( i ).toString(), src.
at( i ).typeName() ).arg( src.
at( i ).isNull() ).arg( src.
at( i ).isValid() ) );
246 if ( success && n > 0 )
283 void QgsAttributeForm::onAttributeChanged(
const QVariant& value )
292 void QgsAttributeForm::onAttributeAdded(
int idx )
294 mPreventFeatureRefresh =
false;
306 void QgsAttributeForm::onAttributeDeleted(
int idx )
308 mPreventFeatureRefresh =
false;
320 void QgsAttributeForm::onUpdatedFields()
322 mPreventFeatureRefresh =
false;
334 attrs[i].convert(
layer()->fields().at( i ).type() );
349 void QgsAttributeForm::preventFeatureRefresh()
351 mPreventFeatureRefresh =
true;
368 void QgsAttributeForm::synchronizeEnabledState()
370 bool isEditable = ( mFeature.
isValid() || mIsAddDialog ) && mLayer->
isEditable();
374 bool fieldEditable =
true;
382 ww->
setEnabled( isEditable && fieldEditable );
390 void QgsAttributeForm::init()
397 bool buttonBoxVisible =
true;
401 buttonBoxVisible = mButtonBox->
isVisible();
403 mButtonBox =
nullptr;
406 qDeleteAll( mWidgets );
409 while (
QWidget* w = this->findChild<QWidget*>() )
423 if ( file.open( QFile::ReadOnly ) )
429 formWidget = loader.
load( &file,
this );
434 mButtonBox = findChild<QDialogButtonBox*>();
451 tabWidget->
addTab( tabPage, widgDef->
name() );
464 tabPageLayout->
addWidget( createWidgetFromDef( widgDef, tabPage, mLayer, mContext, dummy1, dummy2 ) );
468 QgsDebugMsg(
"No support for fields in attribute editor on top level" );
471 formWidget = tabWidget;
478 formWidget =
new QWidget(
this );
504 if ( widgetType ==
"Hidden" )
513 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 ) );
519 addWidgetWrapper( eww );
523 gridLayout->
addWidget( l, row++, 0, 1, 2 );
524 gridLayout->
addWidget( w, row++, 0, 1, 2 );
546 gridLayout->
addItem( spacerItem, row++, 0 );
552 mButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
561 connect( mButtonBox, SIGNAL( accepted() ),
this, SLOT(
accept() ) );
564 connect( mLayer, SIGNAL( editingStarted() ),
this, SLOT( synchronizeEnabledState() ) );
565 connect( mLayer, SIGNAL( editingStopped() ),
this, SLOT( synchronizeEnabledState() ) );
574 void QgsAttributeForm::cleanPython()
576 if ( !mPyFormVarName.
isNull() )
578 QString expr =
QString(
"if locals().has_key('%1'): del %1\n" ).
arg( mPyFormVarName );
583 void QgsAttributeForm::initPython()
600 if ( ! initFilePath.
isEmpty() )
602 QFile inputFile( initFilePath );
604 if ( inputFile.open( QFile::ReadOnly ) )
608 initCode = inf.readAll();
649 static int sFormId = 0;
650 mPyFormVarName =
QString(
"_qgis_featureform_%1_%2" ).
arg( mFormNr ).
arg( sFormId++ );
652 QString form =
QString(
"%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
653 .
arg( mPyFormVarName )
654 .
arg((
unsigned long )
this );
661 if ( numArgs ==
"3" )
669 msgBox.
setText(
tr(
"The python init function (<code>%1</code>) does not accept three arguments as expected!<br>Please check the function name in the <b>Fields</b> tab of the layer properties." ).arg( initFunction ) );
674 .arg( mPyFormVarName );
675 QgsAttributeFormInterface* iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface*>( expr,
"QgsAttributeFormInterface" );
685 msgBox.
setText(
tr(
"The python init function (<code>%1</code>) could not be found!<br>Please check the function name in the <b>Fields</b> tab of the layer properties." ).arg( initFunction ) );
695 switch ( widgetDef->
type() )
704 if ( fldIdx < vl->fields().count() && fldIdx >= 0 )
710 newWidget = eww->
widget();
711 addWidgetWrapper( eww );
730 newWidget = rww->
widget();
732 labelText = QString::null;
748 myContainer = groupBox;
749 newWidget = myContainer;
755 myContainer =
new QWidget( scrollArea );
761 newWidget = scrollArea;
775 QWidget* editor = createWidgetFromDef( childDef, myContainer, vl, context, labelText, labelOnTop );
779 gbLayout->
addWidget( editor, index, 0, 1, 2 );
786 gbLayout->
addWidget( mypLabel, index, 0, 1, 2 );
788 gbLayout->
addWidget( editor, index, 0, 1, 2 );
792 gbLayout->
addWidget( mypLabel, index, 0 );
800 spacer->
setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
803 labelText = QString::null;
809 QgsDebugMsg(
"Unknown attribute editor widget type encountered..." );
835 void QgsAttributeForm::createWrappers()
840 Q_FOREACH (
QWidget* myWidget, myWidgets )
859 Q_FOREACH (
const QgsField& field, fields )
868 addWidgetWrapper( eww );
875 void QgsAttributeForm::connectWrappers()
877 bool isFirstEww =
true;
891 connect( eww, SIGNAL( valueChanged(
const QVariant& ) ),
this, SLOT( onAttributeChanged(
const QVariant& ) ) );
901 if ( e->
type() == QEvent::KeyPress )
904 if ( keyEvent && keyEvent->
key() == Qt::Key_Escape )
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
QgsFeatureId id() const
Get the feature ID for this feature.
bool isValid() const
Returns the validity of this relation.
Allows modification of attribute values.
This is an abstract base class for any elements of a drag and drop form.
virtual bool isGroupBox() const
Returns if this container is going to be rendered as a group box.
bool isValid() const
Returns the validity of this feature.
void beginEditCommand(const QString &text)
Create edit command for undo/redo operations.
QgsFields fields() const
Returns the list of fields of this layer.
void setFrameShape(Shape)
This class contains context information for attribute editor widgets.
static void warning(const QString &msg)
Goes to qWarning.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
const QObjectList & children() const
void insert(int i, const T &value)
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
This element will load a field's widget onto the form.
This element will load a relation editor onto the form.
bool addFeature(QgsFeature &f, bool alsoUpdateExtent=true)
Adds a feature.
const QgsRelation & relation() const
Get the id of the relation which shall be embedded.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
QgsEditFormConfig * editFormConfig() const
Get the configuration of the form used to represent this vector layer.
void setWorkingDirectory(const QDir &dir)
QString id() const
A (project-wide) unique id for this relation.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
virtual bool isEditable() const override
Returns true if the provider is in editing mode.
QString tr(const char *sourceText, const char *disambiguation, int n)
int idx() const
Return the index of the field.
QString name() const
Return the name of this element.
const char * name() const
void append(const T &value)
QVariant property(const char *name) const
void installEventFilter(QObject *filterObj)
QString attributeDisplayName(int attributeIndex) const
Convenience function that returns the attribute alias if defined or the field name else...
QgsRelation relation(const QString &id) const
Get access to a relation by its id.
QgsAttributes attributes() const
Returns the feature's attributes.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities Note, some capabilities may change depending ...
QString name() const
Gets the name of the field.
const QgsFields * fields() const
Returns the field map associated with the feature.
void setObjectName(const QString &name)
void setText(const QString &text)
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)...
void setOverrideCursor(const QCursor &cursor)
AttributeEditorType type() const
The type of this element.
void destroyEditCommand()
Destroy active command and reverts all changes in it.
void restoreOverrideCursor()
Encapsulate a field in an attribute table or data source.
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Q_DECL_DEPRECATED void setFields(const QgsFields *fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Q_DECL_DEPRECATED bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &value, bool emitSignal)
Changes an attribute value (but does not commit it)
void endEditCommand()
Finish edit command and add it to undo/redo stack.
int indexFromName(const QString &name) const
Look up field's index from name. Returns -1 on error.
QList< QgsAttributeEditorElement * > children() const
Get a list of the children elements of this container.
static bool eval(const QString &command, QString &result)
Eval a python statement.
void setFrameShadow(Shadow)
void setValid(bool validity)
Sets the validity of the feature.
const T & at(int i) const
static bool run(const QString &command, const QString &messageOnError=QString())
Execute a python statement.
Q_DECL_DEPRECATED QString editFormInit() const
Get python function for edit form initialization.
void setTitle(const QString &title)
virtual void setIsGroupBox(bool isGroupBox)
Determines if this container is rendered as collapsible group box or tab in a tabwidget.
This class manages a set of relations between layers.
void addItem(QLayoutItem *item, int row, int column, int rowSpan, int columnSpan, QFlags< Qt::AlignmentFlag > alignment)
static QgsProject * instance()
access to canonical QgsProject instance
int count(const T &value) const
int size() const
Return number of items.
This is a container for attribute editors, used to group them visually in the attribute form if it is...
QWidget * load(QIODevice *device, QWidget *parentWidget)
QgsVectorDataProvider * dataProvider()
Returns the data provider.
bool nextFeature(QgsFeature &f)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
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
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.