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;
206 bool res = mLayer->
addFeature( updatedFeature );
211 mIsAddDialog =
false;
222 for (
int i = 0; i < dst.
count(); ++i )
224 if (( dst.
at( i ) == src.
at( i ) && dst.
at( i ).isNull() == src.
at( i ).isNull() )
225 || !dst.
at( i ).isValid()
233 .arg( dst.
at( i ).toString(), dst.
at( i ).typeName() ).arg( dst.
at( i ).isNull() ).arg( dst.
at( i ).isValid() ) );
235 .arg( src.
at( i ).toString(), src.
at( i ).typeName() ).arg( src.
at( i ).isNull() ).arg( src.
at( i ).isValid() ) );
241 if ( success && n > 0 )
278 void QgsAttributeForm::onAttributeChanged(
const QVariant& value )
287 void QgsAttributeForm::onAttributeAdded(
int idx )
289 mPreventFeatureRefresh =
false;
301 void QgsAttributeForm::onAttributeDeleted(
int idx )
303 mPreventFeatureRefresh =
false;
315 void QgsAttributeForm::onUpdatedFields()
317 mPreventFeatureRefresh =
false;
329 attrs[i].convert(
layer()->fields().at( i ).type() );
344 void QgsAttributeForm::preventFeatureRefresh()
346 mPreventFeatureRefresh =
true;
363 void QgsAttributeForm::synchronizeEnabledState()
365 bool isEditable = ( mFeature.
isValid() || mIsAddDialog ) && mLayer->
isEditable();
369 bool fieldEditable =
true;
377 ww->
setEnabled( isEditable && fieldEditable );
385 void QgsAttributeForm::init()
392 bool buttonBoxVisible =
true;
396 buttonBoxVisible = mButtonBox->
isVisible();
398 mButtonBox =
nullptr;
401 qDeleteAll( mWidgets );
404 while (
QWidget* w = this->findChild<QWidget*>() )
418 if ( file.open( QFile::ReadOnly ) )
424 formWidget = loader.
load( &file,
this );
429 mButtonBox = findChild<QDialogButtonBox*>();
446 tabWidget->
addTab( tabPage, widgDef->
name() );
459 tabPageLayout->
addWidget( createWidgetFromDef( widgDef, tabPage, mLayer, mContext, dummy1, dummy2 ) );
463 QgsDebugMsg(
"No support for fields in attribute editor on top level" );
466 formWidget = tabWidget;
473 formWidget =
new QWidget(
this );
499 if ( widgetType ==
"Hidden" )
508 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 ) );
514 addWidgetWrapper( eww );
518 gridLayout->
addWidget( l, row++, 0, 1, 2 );
519 gridLayout->
addWidget( w, row++, 0, 1, 2 );
541 gridLayout->
addItem( spacerItem, row++, 0 );
547 mButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
556 connect( mButtonBox, SIGNAL( accepted() ),
this, SLOT(
accept() ) );
559 connect( mLayer, SIGNAL( editingStarted() ),
this, SLOT( synchronizeEnabledState() ) );
560 connect( mLayer, SIGNAL( editingStopped() ),
this, SLOT( synchronizeEnabledState() ) );
569 void QgsAttributeForm::cleanPython()
571 if ( !mPyFormVarName.
isNull() )
573 QString expr =
QString(
"if locals().has_key('%1'): del %1\n" ).
arg( mPyFormVarName );
578 void QgsAttributeForm::initPython()
595 if ( ! initFilePath.
isEmpty() )
597 QFile inputFile( initFilePath );
599 if ( inputFile.
open( QFile::ReadOnly ) )
644 static int sFormId = 0;
645 mPyFormVarName =
QString(
"_qgis_featureform_%1_%2" ).
arg( mFormNr ).
arg( sFormId++ );
647 QString form =
QString(
"%1 = sip.wrapinstance( %2, qgis.gui.QgsAttributeForm )" )
648 .
arg( mPyFormVarName )
649 .
arg((
unsigned long )
this );
656 if ( numArgs ==
"3" )
664 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 ) );
669 .arg( mPyFormVarName );
670 QgsAttributeFormInterface* iface = QgsPythonRunner::evalToSipObject<QgsAttributeFormInterface*>( expr,
"QgsAttributeFormInterface" );
680 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 ) );
690 switch ( widgetDef->
type() )
699 if ( fldIdx < vl->fields().count() && fldIdx >= 0 )
705 newWidget = eww->
widget();
706 addWidgetWrapper( eww );
725 newWidget = rww->
widget();
727 labelText = QString::null;
743 myContainer = groupBox;
744 newWidget = myContainer;
750 myContainer =
new QWidget( scrollArea );
756 newWidget = scrollArea;
770 QWidget* editor = createWidgetFromDef( childDef, myContainer, vl, context, labelText, labelOnTop );
774 gbLayout->
addWidget( editor, index, 0, 1, 2 );
781 gbLayout->
addWidget( mypLabel, index, 0, 1, 2 );
783 gbLayout->
addWidget( editor, index, 0, 1, 2 );
787 gbLayout->
addWidget( mypLabel, index, 0 );
795 spacer->
setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Preferred );
798 labelText = QString::null;
804 QgsDebugMsg(
"Unknown attribute editor widget type encountered..." );
830 void QgsAttributeForm::createWrappers()
835 Q_FOREACH (
QWidget* myWidget, myWidgets )
854 Q_FOREACH (
const QgsField& field, fields )
863 addWidgetWrapper( eww );
870 void QgsAttributeForm::connectWrappers()
872 bool isFirstEww =
true;
886 connect( eww, SIGNAL( valueChanged(
const QVariant& ) ),
this, SLOT( onAttributeChanged(
const QVariant& ) ) );
896 if ( e->
type() == QEvent::KeyPress )
899 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.
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.
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
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
Allows modification of attribute values.
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.