void QgsServerProjectParser::addLayerProjectSettings( QDomElement& layerElem, QDomDocument& doc, QgsMapLayer* currentLayer ) const
{
  if ( !currentLayer )
  {
    return;
  }
  // Layer tree name
  QDomElement treeNameElem = doc.createElement( "TreeName" );
  QDomText treeNameText = doc.createTextNode( currentLayer->name() );
  treeNameElem.appendChild( treeNameText );
  layerElem.appendChild( treeNameElem );

  if ( currentLayer->type() == QgsMapLayer::VectorLayer )
  {
    QgsVectorLayer* vLayer = static_cast<QgsVectorLayer*>( currentLayer );
    const QSet<QString>& excludedAttributes = vLayer->excludeAttributesWMS();
    int displayFieldIdx = vLayer->fieldNameIndex( vLayer->displayField() );
    QString displayField = displayFieldIdx < 0 ? "maptip" : vLayer->displayField();

    //attributes
    QDomElement attributesElem = doc.createElement( "Attributes" );
    const QgsFields& layerFields = vLayer->pendingFields();
    for ( int idx = 0; idx < layerFields.count(); ++idx )
    {
      const QgsField& field = layerFields[idx];
      if ( excludedAttributes.contains( field.name() ) )
      {
        continue;
      }
      // field alias in case of displayField
      if ( idx == displayFieldIdx )
      {
        displayField = vLayer->attributeDisplayName( idx );
      }
      QDomElement attributeElem = doc.createElement( "Attribute" );
      attributeElem.setAttribute( "name", field.name() );
      attributeElem.setAttribute( "type", QVariant::typeToName( field.type() ) );
      attributeElem.setAttribute( "typeName", field.typeName() );
      QString alias = vLayer->attributeAlias( idx );
      if ( !alias.isEmpty() )
      {
        attributeElem.setAttribute( "alias", alias );
      }

      //edit type to text
      attributeElem.setAttribute( "editType", vLayer->editFormConfig()->widgetType( idx ) );
      attributeElem.setAttribute( "comment", field.comment() );
      attributeElem.setAttribute( "length", field.length() );
      attributeElem.setAttribute( "precision", field.precision() );
      attributesElem.appendChild( attributeElem );
    }
    //displayfield
    layerElem.setAttribute( "displayField", displayField );

    //geometry type
    layerElem.setAttribute( "geometryType", QGis::featureType( vLayer->wkbType() ) );

    layerElem.appendChild( attributesElem );
  }
}
QWidget *QgsAttributeTableDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
  Q_UNUSED( option );
  QgsVectorLayer *vl = layer( index.model() );
  if ( !vl )
    return nullptr;

  int fieldIdx = index.model()->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt();

  QgsAttributeEditorContext context( masterModel( index.model() )->editorContext(), QgsAttributeEditorContext::Popup );
  QgsEditorWidgetWrapper *eww = QgsGui::editorWidgetRegistry()->create( vl, fieldIdx, nullptr, parent, context );
  QWidget *w = eww->widget();

  w->setAutoFillBackground( true );
  w->setFocusPolicy( Qt::StrongFocus ); // to make sure QMouseEvents are propagated to the editor widget

  const int fieldOrigin = vl->fields().fieldOrigin( fieldIdx );
  bool readOnly = true;
  if ( fieldOrigin == QgsFields::OriginJoin )
  {
    int srcFieldIndex;
    const QgsVectorLayerJoinInfo *info = vl->joinBuffer()->joinForFieldIndex( fieldIdx, vl->fields(), srcFieldIndex );

    if ( info && info->isEditable() )
      readOnly = info->joinLayer()->editFormConfig().readOnly( srcFieldIndex );
  }
  else
    readOnly = vl->editFormConfig().readOnly( fieldIdx );

  eww->setEnabled( !readOnly );

  return w;
}
QWidget* QgsAttributeTableDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
  Q_UNUSED( option );
  QgsVectorLayer *vl = layer( index.model() );
  if ( !vl )
    return nullptr;

  int fieldIdx = index.model()->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt();

  QString widgetType = vl->editFormConfig()->widgetType( fieldIdx );
  QgsEditorWidgetConfig cfg = vl->editFormConfig()->widgetConfig( fieldIdx );
  QgsAttributeEditorContext context( masterModel( index.model() )->editorContext(), QgsAttributeEditorContext::Popup );
  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, vl, fieldIdx, cfg, nullptr, parent, context );
  QWidget* w = eww->widget();

  w->setAutoFillBackground( true );

  eww->setEnabled( !vl->editFormConfig()->readOnly( fieldIdx ) );

  return w;
}
void QgsEditorWidgetRegistry::writeMapLayer( QgsMapLayer* mapLayer, QDomElement& layerElem, QDomDocument& doc ) const
{
  if ( mapLayer->type() != QgsMapLayer::VectorLayer )
  {
    return;
  }

  QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
  if ( !vectorLayer )
  {
    return;
  }

  QDomNode editTypesNode = doc.createElement( "edittypes" );

  QgsFields fields = vectorLayer->fields();
  for ( int idx = 0; idx < fields.count(); ++idx )
  {
    QgsField field = fields.at( idx );
    const QString& widgetType = vectorLayer->editFormConfig()->widgetType( idx );
    if ( !mWidgetFactories.contains( widgetType ) )
    {
      QgsMessageLog::logMessage( tr( "Could not save unknown editor widget type '%1'." ).arg( widgetType ) );
      continue;
    }


    QDomElement editTypeElement = doc.createElement( "edittype" );
    editTypeElement.setAttribute( "name", field.name() );
    editTypeElement.setAttribute( "widgetv2type", widgetType );

    if ( mWidgetFactories.contains( widgetType ) )
    {
      QDomElement ewv2CfgElem = doc.createElement( "widgetv2config" );
      ewv2CfgElem.setAttribute( "fieldEditable", !vectorLayer->editFormConfig()->readOnly( idx ) );
      ewv2CfgElem.setAttribute( "labelOnTop", vectorLayer->editFormConfig()->labelOnTop( idx ) );
      ewv2CfgElem.setAttribute( "notNull", vectorLayer->editFormConfig()->notNull( idx ) );
      ewv2CfgElem.setAttribute( "constraint", vectorLayer->editFormConfig()->expression( idx ) );
      ewv2CfgElem.setAttribute( "constraintDescription", vectorLayer->editFormConfig()->expressionDescription( idx ) );

      mWidgetFactories[widgetType]->writeConfig( vectorLayer->editFormConfig()->widgetConfig( idx ), ewv2CfgElem, doc, vectorLayer, idx );

      editTypeElement.appendChild( ewv2CfgElem );
    }

    editTypesNode.appendChild( editTypeElement );
  }

  layerElem.appendChild( editTypesNode );
}
void QgsEditorWidgetRegistry::readMapLayer( QgsMapLayer* mapLayer, const QDomElement& layerElem )
{
  if ( mapLayer->type() != QgsMapLayer::VectorLayer )
  {
    return;
  }

  QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
  Q_ASSERT( vectorLayer );

  QDomNodeList editTypeNodes = layerElem.namedItem( "edittypes" ).childNodes();

  for ( int i = 0; i < editTypeNodes.size(); i++ )
  {
    QDomNode editTypeNode = editTypeNodes.at( i );
    QDomElement editTypeElement = editTypeNode.toElement();

    QString name = editTypeElement.attribute( "name" );

    int idx = vectorLayer->fieldNameIndex( name );
    if ( idx == -1 )
      continue;

    QString ewv2Type = editTypeElement.attribute( "widgetv2type" );
    QgsEditorWidgetConfig cfg;

    if ( mWidgetFactories.contains( ewv2Type ) )
    {
      vectorLayer->editFormConfig()->setWidgetType( idx, ewv2Type );
      QDomElement ewv2CfgElem = editTypeElement.namedItem( "widgetv2config" ).toElement();

      if ( !ewv2CfgElem.isNull() )
      {
        cfg = mWidgetFactories[ewv2Type]->readEditorConfig( ewv2CfgElem, vectorLayer, idx );
      }

      vectorLayer->editFormConfig()->setReadOnly( idx, ewv2CfgElem.attribute( "fieldEditable", "1" ) != "1" );
      vectorLayer->editFormConfig()->setLabelOnTop( idx, ewv2CfgElem.attribute( "labelOnTop", "0" ) == "1" );
      vectorLayer->editFormConfig()->setNotNull( idx, ewv2CfgElem.attribute( "notNull", "0" ) == "1" );
      vectorLayer->editFormConfig()->setExpression( idx, ewv2CfgElem.attribute( "constraint", QString() ) );
      vectorLayer->editFormConfig()->setExpressionDescription( idx, ewv2CfgElem.attribute( "constraintDescription", QString() ) );

      vectorLayer->editFormConfig()->setWidgetConfig( idx, cfg );
    }
    else
    {
      QgsMessageLog::logMessage( tr( "Unknown attribute editor widget '%1'" ).arg( ewv2Type ) );
    }
  }
}
QWidget* QgsAttributeTableDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
  Q_UNUSED( option );
  QgsVectorLayer *vl = layer( index.model() );
  if ( !vl )
    return nullptr;

  int fieldIdx = index.model()->data( index, QgsAttributeTableModel::FieldIndexRole ).toInt();

  QgsAttributeEditorContext context( masterModel( index.model() )->editorContext(), QgsAttributeEditorContext::Popup );
  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( vl, fieldIdx, nullptr, parent, context );
  QWidget* w = eww->widget();

  w->setAutoFillBackground( true );
  w->setFocusPolicy( Qt::StrongFocus ); // to make sure QMouseEvents are propagated to the editor widget

  eww->setEnabled( !vl->editFormConfig().readOnly( fieldIdx ) );

  return w;
}