Modularize editor widgets

This commit is contained in:
Matthias Kuhn 2013-09-12 15:00:40 +02:00
parent 7628c8f34f
commit 770e52b0e5
39 changed files with 2454 additions and 626 deletions

1
.gitignore vendored
View File

@ -52,5 +52,6 @@ i18n/*.qm
scripts/qgisstyle
.kdev4/
qgis.kdev4
qgis.supp
src/core/qgscontexthelp_texts.cpp
src/core/qgsexpression_texts.cpp

View File

@ -44,6 +44,8 @@ INCLUDE_DIRECTORIES(
../src/gui/raster
../src/gui/attributetable
../src/gui/editorwidgets
../src/gui/editorwidgets/core
${CMAKE_BINARY_DIR} # qgsconfig.h, qgsversion.h
)

View File

@ -29,6 +29,7 @@
%Include qgsdistancearea.sip
%Include qgserror.sip
%Include qgsexpression.sip
%Include qgseditorwidgetconfig.sip
%Include qgsfeature.sip
%Include qgsfeatureiterator.sip
%Include qgsfeaturerequest.sip

View File

@ -0,0 +1,14 @@
/**
* Holds a set of configuration parameters for a editor widget wrapper.
* It's basically a set of key => value pairs.
*
* If you need more advanced structures than a simple key => value pair,
* you can use a value to hold any structure a QVariant can handle (and that's
* about anything you get through your compiler)
*
* These are the user configurable options in the field properties tab of the
* vector layer properties. They are saved in the project file per layer and field.
* You get these passed, for every new widget wrapper.
*/
typedef QMap<QString, QVariant> QgsEditorWidgetConfig;

View File

@ -0,0 +1,31 @@
/***************************************************************************
qgseditorconfigwidget.sip
--------------------------------------
Date : 24.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
class QgsEditorConfigWidget : QWidget
{
%TypeHeaderCode
#include <qgseditorconfigwidget.h>
%End
public:
explicit QgsEditorConfigWidget( QgsVectorLayer* vl, int fieldIdx, QWidget* parent /TransferThis/ );
int field();
QgsVectorLayer* layer();
virtual QgsEditorWidgetConfig config() = 0;
virtual void setConfig( const QgsEditorWidgetConfig& config ) = 0;
};

View File

@ -0,0 +1,34 @@
/***************************************************************************
qgseditorwidgetfactory.sip
--------------------------------------
Date : 21.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* Every attribute editor widget needs a factory, which inherits this class
*/
class QgsEditorWidgetFactory
{
%TypeHeaderCode
#include <qgseditorwidgetfactory.h>
%End
public:
QgsEditorWidgetFactory( const QString& name );
virtual ~QgsEditorWidgetFactory();
virtual QgsEditorWidgetWrapper* create( QgsVectorLayer* vl, int fieldIdx, QWidget* editor, QWidget* parent ) const = 0 /Factory/;
virtual QgsEditorConfigWidget* configWidget( QgsVectorLayer* vl, int fieldIdx, QWidget* parent ) const = 0 /Factory/;
virtual QgsEditorWidgetConfig readConfig( const QDomElement& configElement, QgsVectorLayer* layer, int fieldIdx );
virtual void writeConfig( const QgsEditorWidgetConfig& config, QDomElement& configElement, const QDomDocument& doc, const QgsVectorLayer* layer, int fieldIdx );
virtual QString name();
};

View File

@ -0,0 +1,32 @@
/***************************************************************************
qgseditorwidgetregistry.sip
--------------------------------------
Date : 21.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/**
* This class manages all known edit widget factories
*/
class QgsEditorWidgetRegistry : QObject
{
%TypeHeaderCode
#include <qgseditorwidgetregistry.h>
%End
public:
static QgsEditorWidgetRegistry* instance();
void registerWidget( const QString& widgetType, QgsEditorWidgetFactory* widgetFactory /Transfer/ );
QgsEditorWidgetWrapper* create( const QString& widgetType, QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, QWidget* editor = NULL, QWidget* parent = NULL ) /Factory/;
QgsEditorConfigWidget* createConfigWidget( const QString& widgetId, QgsVectorLayer* vl, int fieldIdx, QWidget* parent ) /Factory/;
const QMap<QString, QgsEditorWidgetFactory*> factories();
};

View File

@ -0,0 +1,42 @@
/***************************************************************************
qgseditorwidgetwrapper.sip
--------------------------------------
Date : 20.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
class QgsEditorWidgetWrapper : QObject
{
%TypeHeaderCode
#include <qgseditorwidgetwrapper.h>
%End
public:
explicit QgsEditorWidgetWrapper( QgsVectorLayer* vl, int fieldIdx, QWidget* editor = 0, QWidget* parent /TransferThis/ = 0 );
QWidget* widget();
virtual void setConfig( QMap<QString, QVariant> config );
virtual QVariant value() = 0;
QVariant config( QString key );
QgsVectorLayer* layer();
int field();
protected:
virtual QWidget* createWidget( QWidget* parent ) = 0 /Factory/;
signals:
void valueChanged( const QVariant& value );
public slots:
virtual void setValue( const QVariant& value ) = 0;
virtual void setEnabled( bool enabled );
};

View File

@ -127,3 +127,8 @@
%Include symbology-ng/qgsdatadefinedsymboldialog.sip
%Include symbology-ng/qgsstylev2exportimportdialog.sip
%Include symbology-ng/qgssvgselectorwidget.sip
%Include editorwidgets/qgseditorconfigwidget.sip
%Include editorwidgets/qgseditorwidgetfactory.sip
%Include editorwidgets/qgseditorwidgetregistry.sip
%Include editorwidgets/qgseditorwidgetwrapper.sip

View File

@ -422,7 +422,7 @@ INCLUDE_DIRECTORIES(
../core
../core/gps
../core/composer ../core/raster ../core/symbology-ng
../gui ../gui/symbology-ng ../gui/attributetable ../gui/raster
../gui ../gui/symbology-ng ../gui/attributetable ../gui/raster ../gui/editorwidgets ../gui/editorwidgets/core
../plugins
../python
gps

View File

@ -57,6 +57,7 @@ class QgsPoint;
class QgsProviderRegistry;
class QgsPythonUtils;
class QgsRectangle;
class QgsUndoWidget;
class QgsVectorLayer;
@ -175,6 +176,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
/** Get the mapcanvas object from the app */
QgsMapCanvas *mapCanvas();
/** Return the messageBar object which allows to display unobtrusive messages to the user.*/
QgsMessageBar* messageBar();
/** Get the mapcanvas object from the app */
@ -240,7 +242,6 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
/** overloaded function used to sort menu entries alphabetically */
QMenu* createPopupMenu();
//! Actions to be inserted in menus and toolbars
QAction *actionNewProject() { return mActionNewProject; }
QAction *actionOpenProject() { return mActionOpenProject; }

View File

@ -24,6 +24,8 @@
#include "qgisapp.h"
#include "qgsproject.h"
#include "qgslogger.h"
#include "qgseditorwidgetfactory.h"
#include "qgseditorwidgetregistry.h"
#include <QTableWidgetItem>
#include <QFile>
@ -47,6 +49,16 @@ QgsAttributeTypeDialog::QgsAttributeTypeDialog( QgsVectorLayer *vl )
connect( tableWidget, SIGNAL( cellChanged( int, int ) ), this, SLOT( vCellChanged( int, int ) ) );
connect( valueRelationEditExpression, SIGNAL( clicked() ), this, SLOT( editValueRelationExpression() ) );
QMapIterator<QString, QgsEditorWidgetFactory*> i( QgsEditorWidgetRegistry::instance()->factories() );
while ( i.hasNext() )
{
i.next();
QListWidgetItem* item = new QListWidgetItem( selectionListWidget );
item->setText( i.value()->name() );
item->setData( Qt::UserRole, i.key() );
selectionListWidget->addItem( item );
}
valueRelationLayer->clear();
foreach ( QgsMapLayer *l, QgsMapLayerRegistry::instance()->mapLayers() )
{
@ -69,6 +81,53 @@ QgsVectorLayer::EditType QgsAttributeTypeDialog::editType()
return mEditType;
}
const QString QgsAttributeTypeDialog::editorWidgetV2Type()
{
QListWidgetItem* item = selectionListWidget->currentItem();
if ( item )
{
return item->data( Qt::UserRole ).toString();
}
else
{
return QString();
}
}
const QString QgsAttributeTypeDialog::editorWidgetV2Text()
{
QListWidgetItem* item = selectionListWidget->currentItem();
if ( item )
{
return item->text();
}
else
{
return QString();
}
}
const QMap<QString, QVariant> QgsAttributeTypeDialog::editorWidgetV2Config()
{
QListWidgetItem* item = selectionListWidget->currentItem();
if ( item )
{
QString widgetType = item->data( Qt::UserRole ).toString();
QgsEditorConfigWidget* cfgWdg = mEditorConfigWidgets[ widgetType ];
if ( cfgWdg )
{
return cfgWdg->config();
}
}
return QMap<QString, QVariant>();
}
void QgsAttributeTypeDialog::setWidgetV2Config( const QMap<QString, QVariant>& config )
{
mWidgetV2Config = config;
}
QgsVectorLayer::RangeData QgsAttributeTypeDialog::rangeData()
{
return mRangeData;
@ -357,6 +416,10 @@ void QgsAttributeTypeDialog::setPageForEditType( QgsVectorLayer::EditType editTy
case QgsVectorLayer::Color:
setPage( 16 );
break;
case QgsVectorLayer::EditorWidgetV2:
setPage( 17 );
break;
}
}
@ -544,6 +607,7 @@ void QgsAttributeTypeDialog::setIndex( int index, QgsVectorLayer::EditType editT
case QgsVectorLayer::TextEdit:
case QgsVectorLayer::UuidGenerator:
case QgsVectorLayer::Color:
case QgsVectorLayer::EditorWidgetV2:
break;
}
}
@ -612,7 +676,40 @@ void QgsAttributeTypeDialog::setStackPage( int index )
stackedWidget->setCurrentIndex( 15 );
break;
default:
stackedWidget->setCurrentIndex( index );
if ( selectionListWidget->item( index )->data( Qt::UserRole ).isNull() )
{
stackedWidget->setCurrentIndex( index );
}
else
{
QString factoryId = selectionListWidget->item( index )->data( Qt::UserRole ).toString();
// Set to (empty) editor widget page
stackedWidget->setCurrentIndex( 16 );
if ( mEditorConfigWidgets.contains( factoryId ) )
{
mEditorConfigWidgets[factoryId]->show();
}
else
{
QgsEditorConfigWidget* cfgWdg = QgsEditorWidgetRegistry::instance()->createConfigWidget( factoryId, mLayer, mIndex, this );
QgsEditorConfigWidget* oldWdg = pageEditorWidget->findChild<QgsEditorConfigWidget*>();
if ( oldWdg )
{
oldWdg->hide();
}
if ( cfgWdg )
{
cfgWdg->setConfig( mWidgetV2Config );
pageEditorWidget->layout()->addWidget( cfgWdg );
mEditorConfigWidgets.insert( factoryId, cfgWdg );
}
}
}
break;
}
@ -740,6 +837,9 @@ void QgsAttributeTypeDialog::accept()
case 16:
mEditType = QgsVectorLayer::Color;
break;
case 17:
mEditType = QgsVectorLayer::EditorWidgetV2;
break;
}
QDialog::accept();

View File

@ -20,6 +20,7 @@
#include "ui_qgsattributetypeedit.h"
#include "qgsvectorlayer.h"
#include "qgseditorconfigwidget.h"
class QDialog;
class QLayout;
@ -58,6 +59,14 @@ class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttribut
*/
QgsVectorLayer::EditType editType();
const QString editorWidgetV2Type();
const QString editorWidgetV2Text();
const QMap<QString, QVariant> editorWidgetV2Config();
void setWidgetV2Config( const QMap<QString, QVariant>& config );
/**
* Setter to value map variable to display actual value
* @param valueMap map which is to be dispayed in this dialog
@ -224,6 +233,10 @@ class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttribut
QgsVectorLayer::EditType mEditType;
QString mDateFormat;
QSize mWidgetSize;
QMap<QString, QVariant> mWidgetV2Config;
QMap< QString, QgsEditorConfigWidget* > mEditorConfigWidgets;
};
#endif

View File

@ -13,16 +13,19 @@
* *
***************************************************************************/
#include "qgsfieldsproperties.h"
#include "qgsvectorlayer.h"
#include "qgseditorwidgetfactory.h"
#include "qgseditorwidgetregistry.h"
#include "qgsaddattrdialog.h"
#include "qgsaddtaborgroup.h"
#include "qgsapplication.h"
#include "qgsattributetypedialog.h"
#include "qgsfieldcalculator.h"
#include "qgsfieldsproperties.h"
#include "qgslogger.h"
#include "qgsmaplayerregistry.h"
#include "qgsattributetypedialog.h"
#include "qgsaddattrdialog.h"
#include "qgsfieldcalculator.h"
#include "qgsproject.h"
#include "qgsvectordataprovider.h"
#include "qgsaddtaborgroup.h"
#include "qgsvectorlayer.h"
#include <QTreeWidgetItem>
#include <QWidget>
@ -34,129 +37,6 @@
#include <QSettings>
#include <QFileDialog>
QTreeWidgetItem* QgsAttributesTree::addContainer( QTreeWidgetItem* parent, QString title )
{
QTreeWidgetItem *newItem = new QTreeWidgetItem( QList<QString>() << title );
newItem->setBackground( 0 , QBrush( Qt::lightGray ) );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
newItem->setData( 0 , Qt::UserRole , "container" );
parent->addChild( newItem );
newItem->setExpanded( true );
return newItem;
}
QTreeWidgetItem* QgsAttributesTree::addItem( QTreeWidgetItem* parent , QString fieldName )
{
QTreeWidgetItem* attributeItem = new QTreeWidgetItem( QList<QString>() << fieldName );
attributeItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
attributeItem->setData( 0 , Qt::UserRole , "field" );
parent->addChild( attributeItem );
return attributeItem;
}
/*
* Is called when mouse is moved over attributes tree before a
* drop event. Used to inhibit dropping fields onto the root item.
*/
void QgsAttributesTree::dragMoveEvent( QDragMoveEvent *event )
{
QTreeWidgetItem* targetItem = itemAt( event->pos() );
const QMimeData* data = event->mimeData();
if ( data->hasFormat( "application/x-qabstractitemmodeldatalist" ) )
{
QString itemType;
if ( event->source() == this )
{
QByteArray itemData = data->data( "application/x-qabstractitemmodeldatalist" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
int r, c;
QMap<int, QVariant> roleDataMap;
stream >> r >> c >> roleDataMap;
itemType = roleDataMap.value( Qt::UserRole ).toString();
}
else
{
itemType = "field";
}
// Forbid dropping fields on root item
if ( itemType == "field" && !targetItem )
{
event->ignore();
return;
}
// Inner drag and drop actions are always MoveAction
if ( event->source() == this )
{
event->setDropAction( Qt::MoveAction );
}
}
QTreeWidget::dragMoveEvent( event );
}
bool QgsAttributesTree::dropMimeData( QTreeWidgetItem * parent, int index, const QMimeData * data, Qt::DropAction action )
{
Q_UNUSED( index )
bool bDropSuccessful = false;
if ( action == Qt::IgnoreAction )
{
bDropSuccessful = true;
}
else if ( data->hasFormat( "application/x-qabstractitemmodeldatalist" ) )
{
QByteArray itemData = data->data( "application/x-qabstractitemmodeldatalist" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
int row, col;
while ( !stream.atEnd() )
{
QMap<int, QVariant> roleDataMap;
stream >> row >> col >> roleDataMap;
if ( col == 1 )
{
/* do something with the data */
QString itemName = roleDataMap.value( Qt::DisplayRole ).toString();
if ( parent )
{
addItem( parent, itemName );
bDropSuccessful = true;
}
else // Should never happen as we ignore drops of fields onto the root element in dragMoveEvent, but actually does happen. Qt?
{
// addItem( invisibleRootItem(), itemName );
// bDropSuccessful = true;
}
}
}
}
return bDropSuccessful;
}
void QgsAttributesTree::dropEvent( QDropEvent *event )
{
if ( !event->mimeData()->hasFormat( "application/x-qabstractitemmodeldatalist" ) )
return;
if ( event->source() == this )
{
event->setDropAction( Qt::MoveAction );
}
QTreeWidget::dropEvent( event );
}
QgsFieldsProperties::QgsFieldsProperties( QgsVectorLayer *layer, QWidget* parent )
: QWidget( parent ), mLayer( layer )
{
@ -185,23 +65,36 @@ QgsFieldsProperties::QgsFieldsProperties( QgsVectorLayer *layer, QWidget* parent
// tab and group display
mAddItemButton->setEnabled( false );
QVBoxLayout *attrTreeLayout = new QVBoxLayout( mAttributesTreeFrame );
QVBoxLayout *attrListLayout = new QVBoxLayout( mAttributesListFrame );
mDesignerTree = new DesignerTree( mAttributesTreeFrame );
mDesignerListLayout->addWidget( mDesignerTree );
mDesignerTree->setHeaderLabels( QStringList() << tr( "Label" ) );
attrTreeLayout->setMargin( 0 );
attrListLayout->setMargin( 0 );
mAttributesTree = new QgsAttributesTree( mAttributesTreeFrame );
mAttributesList = new QTableWidget( mAttributesListFrame );
attrTreeLayout->addWidget( mAttributesTree );
attrListLayout->addWidget( mAttributesList );
mAttributesTreeFrame->setLayout( attrTreeLayout );
mAttributesListFrame->setLayout( attrListLayout );
mFieldsList = new DragList( mAttributesListFrame );
mAttributesListLayout->addWidget( mFieldsList );
connect( mAttributesTree, SIGNAL( itemSelectionChanged() ), this, SLOT( onAttributeSelectionChanged() ) );
connect( mAttributesList, SIGNAL( itemSelectionChanged() ), this, SLOT( onAttributeSelectionChanged() ) );
mFieldsList->setColumnCount( attrColCount );
mFieldsList->setSelectionBehavior( QAbstractItemView::SelectRows );
mFieldsList->setDragDropMode( QAbstractItemView::DragOnly );
mFieldsList->setHorizontalHeaderItem( attrIdCol, new QTableWidgetItem( tr( "Id" ) ) );
mFieldsList->setHorizontalHeaderItem( attrNameCol, new QTableWidgetItem( tr( "Name" ) ) );
mFieldsList->setHorizontalHeaderItem( attrTypeCol, new QTableWidgetItem( tr( "Type" ) ) );
mFieldsList->setHorizontalHeaderItem( attrTypeNameCol, new QTableWidgetItem( tr( "Type name" ) ) );
mFieldsList->setHorizontalHeaderItem( attrLengthCol, new QTableWidgetItem( tr( "Length" ) ) );
mFieldsList->setHorizontalHeaderItem( attrPrecCol, new QTableWidgetItem( tr( "Precision" ) ) );
mFieldsList->setHorizontalHeaderItem( attrCommentCol, new QTableWidgetItem( tr( "Comment" ) ) );
mFieldsList->setHorizontalHeaderItem( attrEditTypeCol, new QTableWidgetItem( tr( "Edit widget" ) ) );
mFieldsList->setHorizontalHeaderItem( attrWMSCol, new QTableWidgetItem( "WMS" ) );
mFieldsList->setHorizontalHeaderItem( attrWFSCol, new QTableWidgetItem( "WFS" ) );
mFieldsList->setHorizontalHeaderItem( attrAliasCol, new QTableWidgetItem( tr( "Alias" ) ) );
mAttributesList->sortByColumn( 0, Qt::AscendingOrder );
mAttributesTree->setHeaderLabels( QStringList() << tr( "Label" ) );
mFieldsList->setSortingEnabled( true );
mFieldsList->sortByColumn( 0, Qt::AscendingOrder );
mFieldsList->setSelectionBehavior( QAbstractItemView::SelectRows );
mFieldsList->setSelectionMode( QAbstractItemView::ExtendedSelection );
mFieldsList->verticalHeader()->hide();
connect( mDesignerTree, SIGNAL( itemSelectionChanged() ), this, SLOT( onAttributeSelectionChanged() ) );
connect( mFieldsList, SIGNAL( itemSelectionChanged() ), this, SLOT( onAttributeSelectionChanged() ) );
leEditForm->setText( layer->editForm() );
leEditFormInit->setText( layer->editFormInit() );
@ -227,8 +120,8 @@ void QgsFieldsProperties::init()
void QgsFieldsProperties::onAttributeSelectionChanged()
{
bool isAddPossible = false;
if ( mAttributesTree->selectedItems().count() == 1 && mAttributesList->selectedItems().count() > 0 )
if ( mAttributesTree->selectedItems()[0]->data( 0, Qt::UserRole ) != "field" )
if ( mDesignerTree->selectedItems().count() == 1 && mFieldsList->selectedItems().count() > 0 )
if ( mDesignerTree->selectedItems()[0]->data( 0, DesignerTreeRole ).value<DesignerTreeItemData>().type() == DesignerTreeItemData::Container )
isAddPossible = true;
mAddItemButton->setEnabled( isAddPossible );
}
@ -239,18 +132,18 @@ QTreeWidgetItem *QgsFieldsProperties::loadAttributeEditorTreeItem( QgsAttributeE
switch ( widgetDef->type() )
{
case QgsAttributeEditorElement::AeTypeField:
newWidget = mAttributesTree->addItem( parent, widgetDef->name() );
newWidget = mDesignerTree->addItem( parent, DesignerTreeItemData( DesignerTreeItemData::Field, widgetDef->name() ) );
break;
case QgsAttributeEditorElement::AeTypeContainer:
{
newWidget = mAttributesTree->addContainer( parent, widgetDef->name() );
newWidget = mDesignerTree->addItem( parent, DesignerTreeItemData( DesignerTreeItemData::Container, widgetDef->name() ) );
const QgsAttributeEditorContainer* container = dynamic_cast<const QgsAttributeEditorContainer*>( widgetDef );
QList<QgsAttributeEditorElement*> children = container->children();
for ( QList<QgsAttributeEditorElement*>::const_iterator it = children.begin(); it != children.end(); ++it )
Q_FOREACH( QgsAttributeEditorElement* wdg, container->children() )
{
loadAttributeEditorTreeItem( *it, newWidget );
loadAttributeEditorTreeItem( wdg, newWidget );
}
}
break;
@ -265,110 +158,99 @@ QTreeWidgetItem *QgsFieldsProperties::loadAttributeEditorTreeItem( QgsAttributeE
void QgsFieldsProperties::loadAttributeEditorTree()
{
// tabs and groups info
mAttributesTree->clear();
mAttributesTree->setSortingEnabled( false );
mAttributesTree->setSelectionBehavior( QAbstractItemView::SelectRows );
mAttributesTree->setDragDropMode( QAbstractItemView::InternalMove );
mAttributesTree->setAcceptDrops( true );
mAttributesTree->setDragDropMode( QAbstractItemView::DragDrop );
mDesignerTree->clear();
mDesignerTree->setSortingEnabled( false );
mDesignerTree->setSelectionBehavior( QAbstractItemView::SelectRows );
mDesignerTree->setDragDropMode( QAbstractItemView::InternalMove );
mDesignerTree->setAcceptDrops( true );
mDesignerTree->setDragDropMode( QAbstractItemView::DragDrop );
QList<QgsAttributeEditorElement*> widgets = mLayer->attributeEditorElements();
for ( QList<QgsAttributeEditorElement*>::const_iterator it = widgets.begin(); it != widgets.end(); ++it )
Q_FOREACH( QgsAttributeEditorElement* wdg, mLayer->attributeEditorElements() )
{
loadAttributeEditorTreeItem( *it, mAttributesTree->invisibleRootItem() );
loadAttributeEditorTreeItem( wdg, mDesignerTree->invisibleRootItem() );
}
}
void QgsFieldsProperties::loadRows()
{
disconnect( mAttributesList, SIGNAL( cellChanged( int, int ) ), this, SLOT( attributesListCellChanged( int, int ) ) );
disconnect( mFieldsList, SIGNAL( cellChanged( int, int ) ), this, SLOT( attributesListCellChanged( int, int ) ) );
const QgsFields &fields = mLayer->pendingFields();
mIndexedWidgets.clear();
mAttributesList->clear();
mAttributesList->setRowCount( 0 );
mAttributesList->setColumnCount( attrColCount );
mAttributesList->setSelectionBehavior( QAbstractItemView::SelectRows );
mAttributesList->setDragDropMode( QAbstractItemView::DragOnly );
mAttributesList->setHorizontalHeaderItem( attrIdCol, new QTableWidgetItem( tr( "Id" ) ) );
mAttributesList->setHorizontalHeaderItem( attrNameCol, new QTableWidgetItem( tr( "Name" ) ) );
mAttributesList->setHorizontalHeaderItem( attrTypeCol, new QTableWidgetItem( tr( "Type" ) ) );
mAttributesList->setHorizontalHeaderItem( attrTypeNameCol, new QTableWidgetItem( tr( "Type name" ) ) );
mAttributesList->setHorizontalHeaderItem( attrLengthCol, new QTableWidgetItem( tr( "Length" ) ) );
mAttributesList->setHorizontalHeaderItem( attrPrecCol, new QTableWidgetItem( tr( "Precision" ) ) );
mAttributesList->setHorizontalHeaderItem( attrCommentCol, new QTableWidgetItem( tr( "Comment" ) ) );
mAttributesList->setHorizontalHeaderItem( attrEditTypeCol, new QTableWidgetItem( tr( "Edit widget" ) ) );
mAttributesList->setHorizontalHeaderItem( attrWMSCol, new QTableWidgetItem( "WMS" ) );
mAttributesList->setHorizontalHeaderItem( attrWFSCol, new QTableWidgetItem( "WFS" ) );
mAttributesList->setHorizontalHeaderItem( attrAliasCol, new QTableWidgetItem( tr( "Alias" ) ) );
mAttributesList->setSortingEnabled( true );
mAttributesList->setSelectionBehavior( QAbstractItemView::SelectRows );
mAttributesList->setSelectionMode( QAbstractItemView::ExtendedSelection );
mAttributesList->verticalHeader()->hide();
mFieldsList->setRowCount( 0 );
for ( int i = 0; i < fields.count(); ++i )
attributeAdded( i );
mAttributesList->resizeColumnsToContents();
connect( mAttributesList, SIGNAL( cellChanged( int, int ) ), this, SLOT( attributesListCellChanged( int, int ) ) );
mFieldsList->resizeColumnsToContents();
connect( mFieldsList, SIGNAL( cellChanged( int, int ) ), this, SLOT( attributesListCellChanged( int, int ) ) );
}
void QgsFieldsProperties::setRow( int row, int idx, const QgsField &field )
{
mAttributesList->setItem( row, attrIdCol, new QTableWidgetItem( idx ) );
mIndexedWidgets.insert( idx, mAttributesList->item( row, 0 ) );
mAttributesList->setItem( row, attrNameCol, new QTableWidgetItem( field.name() ) );
mAttributesList->setItem( row, attrTypeCol, new QTableWidgetItem( QVariant::typeToName( field.type() ) ) );
mAttributesList->setItem( row, attrTypeNameCol, new QTableWidgetItem( field.typeName() ) );
mAttributesList->setItem( row, attrLengthCol, new QTableWidgetItem( QString::number( field.length() ) ) );
mAttributesList->setItem( row, attrPrecCol, new QTableWidgetItem( QString::number( field.precision() ) ) );
mAttributesList->setItem( row, attrCommentCol, new QTableWidgetItem( field.comment() ) );
QTableWidgetItem* dataItem = new QTableWidgetItem( idx );
DesignerTreeItemData itemData( DesignerTreeItemData::Field, field.name() );
dataItem->setData( DesignerTreeRole, itemData.asQVariant() );
mFieldsList->setItem( row, attrIdCol, dataItem );
mIndexedWidgets.insert( idx, mFieldsList->item( row, 0 ) );
mFieldsList->setItem( row, attrNameCol, new QTableWidgetItem( field.name() ) );
mFieldsList->setItem( row, attrTypeCol, new QTableWidgetItem( QVariant::typeToName( field.type() ) ) );
mFieldsList->setItem( row, attrTypeNameCol, new QTableWidgetItem( field.typeName() ) );
mFieldsList->setItem( row, attrLengthCol, new QTableWidgetItem( QString::number( field.length() ) ) );
mFieldsList->setItem( row, attrPrecCol, new QTableWidgetItem( QString::number( field.precision() ) ) );
mFieldsList->setItem( row, attrCommentCol, new QTableWidgetItem( field.comment() ) );
for ( int i = 0; i < attrEditTypeCol; i++ )
mAttributesList->item( row, i )->setFlags( mAttributesList->item( row, i )->flags() & ~Qt::ItemIsEditable );
mFieldsList->item( row, i )->setFlags( mFieldsList->item( row, i )->flags() & ~Qt::ItemIsEditable );
FieldConfig cfg( mLayer, idx );
cfg.mEditType = mLayer->editType( idx );
QPushButton *pb = new QPushButton( editTypeButtonText( cfg.mEditType ) );
mAttributesList->setCellWidget( row, attrEditTypeCol, pb );
QPushButton *pb;
if ( cfg.mEditType == QgsVectorLayer::EditorWidgetV2 )
{
pb = new QPushButton( QgsEditorWidgetRegistry::instance()->name( cfg.mEditorWidgetV2Type ) );
pb->setProperty( "EditWidgetV2", cfg.mEditType );
}
else
{
pb = new QPushButton( editTypeButtonText( cfg.mEditType ) );
}
mFieldsList->setCellWidget( row, attrEditTypeCol, pb );
connect( pb, SIGNAL( pressed() ), this, SLOT( attributeTypeDialog( ) ) );
cfg.mButton = pb;
setConfigForRow( row, cfg );
//set the alias for the attribute
mAttributesList->setItem( row, attrAliasCol, new QTableWidgetItem( mLayer->attributeAlias( idx ) ) );
mFieldsList->setItem( row, attrAliasCol, new QTableWidgetItem( mLayer->attributeAlias( idx ) ) );
//published WMS/WFS attributes
QTableWidgetItem* wmsAttrItem = new QTableWidgetItem();
wmsAttrItem->setCheckState( mLayer->excludeAttributesWMS().contains( field.name() ) ? Qt::Unchecked : Qt::Checked );
wmsAttrItem->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable );
mAttributesList->setItem( row, attrWMSCol, wmsAttrItem );
mFieldsList->setItem( row, attrWMSCol, wmsAttrItem );
QTableWidgetItem* wfsAttrItem = new QTableWidgetItem();
wfsAttrItem->setCheckState( mLayer->excludeAttributesWFS().contains( field.name() ) ? Qt::Unchecked : Qt::Checked );
wfsAttrItem->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable );
mAttributesList->setItem( row, attrWFSCol, wfsAttrItem );
mFieldsList->setItem( row, attrWFSCol, wfsAttrItem );
}
void QgsFieldsProperties::on_mAddItemButton_clicked()
{
QList<QTableWidgetItem*> listItems = mAttributesList->selectedItems();
QList<QTreeWidgetItem*> treeItems = mAttributesTree->selectedItems();
QList<QTableWidgetItem*> listItems = mFieldsList->selectedItems();
QList<QTreeWidgetItem*> treeItems = mDesignerTree->selectedItems();
if ( treeItems.count() != 1 && listItems.count() == 0 )
return;
QTreeWidgetItem *parent = treeItems[0];
if ( parent->data( 0, Qt::UserRole ) == "field" )
if ( parent->data( 0, DesignerTreeRole ).value<DesignerTreeItemData>().type() != DesignerTreeItemData::Container )
return;
for ( QList<QTableWidgetItem*>::const_iterator it = listItems.begin(); it != listItems.end(); it++ )
Q_FOREACH( QTableWidgetItem* item, listItems )
{
if (( *it )->column() == attrNameCol )
mAttributesTree->addItem( parent , ( *it )->text() );
if ( item->column() == 0 ) // Information is in the first column
mDesignerTree->addItem( parent , item->data( DesignerTreeRole ).value<DesignerTreeItemData>() );
}
}
@ -376,12 +258,12 @@ void QgsFieldsProperties::on_mAddTabOrGroupButton_clicked()
{
QList<QgsAddTabOrGroup::TabPair> tabList;
for ( QTreeWidgetItemIterator it( mAttributesTree ); *it; ++it )
for ( QTreeWidgetItemIterator it( mDesignerTree ); *it; ++it )
{
if (( *it )->data( 0 , Qt::UserRole ) == "container" )
DesignerTreeItemData itemData = ( *it )->data( 0, DesignerTreeRole ).value<DesignerTreeItemData>();
if ( itemData.type() == DesignerTreeItemData::Container )
{
tabList.append( QgsAddTabOrGroup::TabPair(( *it )->text( 0 ), *it ) );
tabList.append( QgsAddTabOrGroup::TabPair( itemData.name(), *it ) );
}
}
QgsAddTabOrGroup addTabOrGroup( mLayer, tabList, this );
@ -392,27 +274,23 @@ void QgsFieldsProperties::on_mAddTabOrGroupButton_clicked()
QString name = addTabOrGroup.name();
if ( addTabOrGroup.tabButtonIsChecked() )
{
mAttributesTree->addContainer( mAttributesTree->invisibleRootItem(), name );
mDesignerTree->addContainer( mDesignerTree->invisibleRootItem(), name );
}
else
{
QTreeWidgetItem* tabItem = addTabOrGroup.tab();
mAttributesTree->addContainer( tabItem , name );
mDesignerTree->addContainer( tabItem , name );
}
}
void QgsFieldsProperties::on_mRemoveTabGroupItemButton_clicked()
{
QList<QTreeWidgetItem*> items = mAttributesTree->selectedItems();
for ( QList<QTreeWidgetItem*>::const_iterator it = items.begin(); it != items.end(); it++ )
{
delete *it;
}
qDeleteAll( mDesignerTree->selectedItems() );
}
void QgsFieldsProperties::on_mMoveDownItem_clicked()
{
QList<QTreeWidgetItem*> itemList = mAttributesTree->selectedItems();
QList<QTreeWidgetItem*> itemList = mDesignerTree->selectedItems();
if ( itemList.count() != 1 )
return;
@ -420,7 +298,7 @@ void QgsFieldsProperties::on_mMoveDownItem_clicked()
QTreeWidgetItem* parent = itemToMoveDown->parent();
if ( !parent )
{
parent = mAttributesTree->invisibleRootItem();
parent = mDesignerTree->invisibleRootItem();
}
int itemIndex = parent->indexOfChild( itemToMoveDown );
@ -436,7 +314,7 @@ void QgsFieldsProperties::on_mMoveDownItem_clicked()
void QgsFieldsProperties::on_mMoveUpItem_clicked()
{
QList<QTreeWidgetItem*> itemList = mAttributesTree->selectedItems();
QList<QTreeWidgetItem*> itemList = mDesignerTree->selectedItems();
if ( itemList.count() != 1 )
return;
@ -444,7 +322,7 @@ void QgsFieldsProperties::on_mMoveUpItem_clicked()
QTreeWidgetItem* parent = itemToMoveUp->parent();
if ( !parent )
{
parent = mAttributesTree->invisibleRootItem();
parent = mDesignerTree->invisibleRootItem();
}
int itemIndex = parent->indexOfChild( itemToMoveUp );
@ -468,9 +346,9 @@ void QgsFieldsProperties::attributeTypeDialog()
int index = -1;
int row = -1;
foreach ( QTableWidgetItem* wdg, mIndexedWidgets )
Q_FOREACH( QTableWidgetItem* wdg, mIndexedWidgets )
{
cfg = wdg->data( Qt::UserRole ).value<FieldConfig>();
cfg = wdg->data( FieldConfigRole ).value<FieldConfig>();
if ( cfg.mButton == pb )
{
index = mIndexedWidgets.indexOf( wdg );
@ -495,6 +373,7 @@ void QgsFieldsProperties::attributeTypeDialog()
attributeTypeDialog.setWidgetSize( cfg.mWidgetSize );
attributeTypeDialog.setFieldEditable( cfg.mEditable );
attributeTypeDialog.setLabelOnTop( cfg.mLabelOnTop );
attributeTypeDialog.setWidgetV2Config( cfg.mEditorWidgetV2Config );
attributeTypeDialog.setIndex( index, cfg.mEditType );
attributeTypeDialog.setFieldEditableEnabled( cfg.mEditableEnabled );
@ -541,21 +420,35 @@ void QgsFieldsProperties::attributeTypeDialog()
case QgsVectorLayer::UuidGenerator:
case QgsVectorLayer::Color:
break;
case QgsVectorLayer::EditorWidgetV2:
cfg.mEditorWidgetV2Type = attributeTypeDialog.editorWidgetV2Type();
cfg.mEditorWidgetV2Config = attributeTypeDialog.editorWidgetV2Config();
break;
}
if ( cfg.mEditType == QgsVectorLayer::EditorWidgetV2 )
{
pb->setText( attributeTypeDialog.editorWidgetV2Text() );
pb->setProperty( "EditWidgetV2", cfg.mEditType );
}
else
{
pb->setText( editTypeButtonText( cfg.mEditType ) );
pb->setProperty( "EditWidgetV2", QVariant() );
}
setConfigForRow( row, cfg );
pb->setText( editTypeButtonText( cfg.mEditType ) );
}
void QgsFieldsProperties::attributeAdded( int idx )
{
bool sorted = mAttributesList->isSortingEnabled();
mAttributesList->setSortingEnabled( false );
bool sorted = mFieldsList->isSortingEnabled();
mFieldsList->setSortingEnabled( false );
const QgsFields &fields = mLayer->pendingFields();
int row = mAttributesList->rowCount();
mAttributesList->insertRow( row );
int row = mFieldsList->rowCount();
mFieldsList->insertRow( row );
setRow( row, idx, fields[idx] );
for ( int i = idx; i < mIndexedWidgets.count(); i++ )
@ -563,14 +456,14 @@ void QgsFieldsProperties::attributeAdded( int idx )
mIndexedWidgets[i]->setData( Qt::DisplayRole, i );
}
mAttributesList->setCurrentCell( row, idx );
mAttributesList->setSortingEnabled( sorted );
mFieldsList->setCurrentCell( row, idx );
mFieldsList->setSortingEnabled( sorted );
}
void QgsFieldsProperties::attributeDeleted( int idx )
{
mAttributesList->removeRow( mIndexedWidgets.at( idx )->row() );
mFieldsList->removeRow( mIndexedWidgets.at( idx )->row() );
mIndexedWidgets.removeAt( idx );
for ( int i = idx; i < mIndexedWidgets.count(); i++ )
{
@ -623,7 +516,7 @@ QgsFieldsProperties::FieldConfig QgsFieldsProperties::configForRow( int row )
{
if ( wdg->row() == row )
{
return wdg->data( Qt::UserRole ).value<FieldConfig>();
return wdg->data( FieldConfigRole ).value<FieldConfig>();
}
}
@ -638,7 +531,7 @@ void QgsFieldsProperties::setConfigForRow( int row, QgsFieldsProperties::FieldCo
{
if ( wdg->row() == row )
{
wdg->setData( Qt::UserRole, QVariant::fromValue<FieldConfig>( cfg ) );
wdg->setData( FieldConfigRole, QVariant::fromValue<FieldConfig>( cfg ) );
return;
}
}
@ -668,7 +561,7 @@ void QgsFieldsProperties::on_mAddAttributeButton_clicked()
void QgsFieldsProperties::on_mDeleteAttributeButton_clicked()
{
QSet<int> attrs;
foreach ( QTableWidgetItem* item, mAttributesList->selectedItems() )
foreach ( QTableWidgetItem* item, mFieldsList->selectedItems() )
{
if ( item->column() == 0 )
{
@ -708,7 +601,7 @@ void QgsFieldsProperties::attributesListCellChanged( int row, int column )
{
if ( column == attrAliasCol && mLayer ) //only consider attribute aliases in this function
{
int idx = mAttributesList->item( row, attrIdCol )->text().toInt();
int idx = mFieldsList->item( row, attrIdCol )->text().toInt();
const QgsFields &fields = mLayer->pendingFields();
@ -717,7 +610,7 @@ void QgsFieldsProperties::attributesListCellChanged( int row, int column )
return; // index must be wrong
}
QTableWidgetItem *aliasItem = mAttributesList->item( row, column );
QTableWidgetItem *aliasItem = mFieldsList->item( row, column );
if ( aliasItem )
{
mLayer->addAttributeAlias( idx, aliasItem->text() );
@ -768,6 +661,7 @@ void QgsFieldsProperties::setupEditTypes()
editTypeMap.insert( QgsVectorLayer::Photo, tr( "Photo" ) );
editTypeMap.insert( QgsVectorLayer::WebView, tr( "Web view" ) );
editTypeMap.insert( QgsVectorLayer::Color, tr( "Color" ) );
editTypeMap.insert( QgsVectorLayer::EditorWidgetV2, tr( "Editor Widget" ) );
}
QString QgsFieldsProperties::editTypeButtonText( QgsVectorLayer::EditType type )
@ -775,30 +669,42 @@ QString QgsFieldsProperties::editTypeButtonText( QgsVectorLayer::EditType type )
return editTypeMap[ type ];
}
QgsVectorLayer::EditType QgsFieldsProperties::editTypeFromButtonText( QString text )
QgsVectorLayer::EditType QgsFieldsProperties::editTypeFromButton( QPushButton* btn )
{
return editTypeMap.key( text );
QVariant editWidgetId = btn->property( "EditWidgetV2" );
if ( editWidgetId.isNull() )
return editTypeMap.key( btn->text() );
else
return QgsVectorLayer::EditorWidgetV2;
}
QgsAttributeEditorElement* QgsFieldsProperties::createAttributeEditorWidget( QTreeWidgetItem* item, QObject *parent )
{
QgsAttributeEditorElement* widgetDef;
if ( item->data( 0, Qt::UserRole ) == "field" )
DesignerTreeItemData itemData = item->data( 0, DesignerTreeRole ).value<DesignerTreeItemData>();
switch ( itemData.type() )
{
int idx = *( mLayer->dataProvider()->fieldNameMap() ).find( item->text( 0 ) );
widgetDef = new QgsAttributeEditorField( item->text( 0 ), idx, parent );
}
else
{
QgsAttributeEditorContainer* container = new QgsAttributeEditorContainer( item->text( 0 ), parent );
for ( int t = 0; t < item->childCount(); t++ )
case DesignerTreeItemData::Field:
{
container->addChildElement( createAttributeEditorWidget( item->child( t ), container ) );
int idx = mLayer->fieldNameIndex( itemData.name() );
widgetDef = new QgsAttributeEditorField( itemData.name(), idx, parent );
break;
}
widgetDef = container;
case DesignerTreeItemData::Container:
{
QgsAttributeEditorContainer* container = new QgsAttributeEditorContainer( itemData.name(), parent );
for ( int t = 0; t < item->childCount(); t++ )
{
container->addChildElement( createAttributeEditorWidget( item->child( t ), container ) );
}
widgetDef = container;
break;
}
}
return widgetDef;
@ -840,12 +746,12 @@ void QgsFieldsProperties::apply()
{
QSet<QString> excludeAttributesWMS, excludeAttributesWFS;
for ( int i = 0; i < mAttributesList->rowCount(); i++ )
for ( int i = 0; i < mFieldsList->rowCount(); i++ )
{
int idx = mAttributesList->item( i, attrIdCol )->text().toInt();
int idx = mFieldsList->item( i, attrIdCol )->text().toInt();
FieldConfig cfg = configForRow( i );
QPushButton *pb = qobject_cast<QPushButton *>( mAttributesList->cellWidget( i, attrEditTypeCol ) );
QPushButton *pb = qobject_cast<QPushButton *>( mFieldsList->cellWidget( i, attrEditTypeCol ) );
if ( !pb )
continue;
@ -895,28 +801,33 @@ void QgsFieldsProperties::apply()
case QgsVectorLayer::UuidGenerator:
case QgsVectorLayer::Color:
break;
case QgsVectorLayer::EditorWidgetV2:
mLayer->setEditorWidgetV2( idx, cfg.mEditorWidgetV2Type );
mLayer->setEditorWidgetV2Config( idx, cfg.mEditorWidgetV2Config );
break;
}
if ( mAttributesList->item( i, attrWMSCol )->checkState() == Qt::Unchecked )
if ( mFieldsList->item( i, attrWMSCol )->checkState() == Qt::Unchecked )
{
excludeAttributesWMS.insert( mAttributesList->item( i, attrNameCol )->text() );
excludeAttributesWMS.insert( mFieldsList->item( i, attrNameCol )->text() );
}
if ( mAttributesList->item( i, attrWFSCol )->checkState() == Qt::Unchecked )
if ( mFieldsList->item( i, attrWFSCol )->checkState() == Qt::Unchecked )
{
excludeAttributesWFS.insert( mAttributesList->item( i, attrNameCol )->text() );
excludeAttributesWFS.insert( mFieldsList->item( i, attrNameCol )->text() );
}
}
//tabs and groups
mLayer->clearAttributeEditorWidgets();
for ( int t = 0; t < mAttributesTree->invisibleRootItem()->childCount(); t++ )
for ( int t = 0; t < mDesignerTree->invisibleRootItem()->childCount(); t++ )
{
QTreeWidgetItem* tabItem = mAttributesTree->invisibleRootItem()->child( t );
QTreeWidgetItem* tabItem = mDesignerTree->invisibleRootItem()->child( t );
mLayer->addAttributeEditorWidget( createAttributeEditorWidget( tabItem, mLayer ) );
}
mLayer->setEditorLayout(( QgsVectorLayer::EditorLayout )mEditorLayoutComboBox->currentIndex() );
mLayer->setEditorLayout(( QgsVectorLayer::EditorLayout ) mEditorLayoutComboBox->currentIndex() );
mLayer->setEditForm( leEditForm->text() );
mLayer->setEditFormInit( leEditFormInit->text() );
mLayer->setFeatureFormSuppress(( QgsVectorLayer::FeatureFormSuppress )mFormSuppressCmbBx->currentIndex() );
@ -925,6 +836,9 @@ void QgsFieldsProperties::apply()
mLayer->setExcludeAttributesWFS( excludeAttributesWFS );
}
/*
* FieldConfig implementation
*/
QgsFieldsProperties::FieldConfig::FieldConfig()
: mButton( NULL )
@ -944,4 +858,238 @@ QgsFieldsProperties::FieldConfig::FieldConfig( QgsVectorLayer* layer, int idx )
mEditType = layer->editType( idx );
mDateFormat = layer->dateFormat( idx );
mWidgetSize = layer->widgetSize( idx );
mEditorWidgetV2Type = layer->editorWidgetV2( idx );
mEditorWidgetV2Config = layer->editorWidgetV2Config( idx );
}
/*
* DragList implementation
*/
QStringList QgsFieldsProperties::DragList::mimeTypes() const
{
return QStringList() << QLatin1String( "application/x-qgsattributetabledesignerelement" );
}
QMimeData* QgsFieldsProperties::DragList::mimeData( const QList<QTableWidgetItem*> items ) const
{
if ( items.count() <= 0 )
return NULL;
QStringList types = mimeTypes();
if ( types.isEmpty() )
return NULL;
QMimeData* data = new QMimeData();
QString format = types.at( 0 );
QByteArray encoded;
QDataStream stream( &encoded, QIODevice::WriteOnly );
Q_FOREACH( const QTableWidgetItem* item, items )
{
// Relevant information is always in the UserRole of the first column
if ( item && item->column() == 0 )
{
DesignerTreeItemData itemData = item->data( DesignerTreeRole ).value<DesignerTreeItemData>();
stream << itemData;
}
}
data->setData( format, encoded );
return data;
}
/*
* DesignerTree implementation
*/
QTreeWidgetItem* QgsFieldsProperties::DesignerTree::addContainer( QTreeWidgetItem* parent, QString title )
{
QTreeWidgetItem *newItem = new QTreeWidgetItem( QStringList() << title );
newItem->setBackground( 0 , QBrush( Qt::lightGray ) );
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
newItem->setData( 0, DesignerTreeRole, DesignerTreeItemData( DesignerTreeItemData::Container, title ).asQVariant() );
parent->addChild( newItem );
newItem->setExpanded( true );
return newItem;
}
QTreeWidgetItem* QgsFieldsProperties::DesignerTree::addItem( QTreeWidgetItem* parent, DesignerTreeItemData data )
{
QTreeWidgetItem* newItem = new QTreeWidgetItem( QStringList() << data.name() );
newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
if ( data.type() == DesignerTreeItemData::Container )
{
newItem->setFlags( Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
newItem->setBackground( 0 , QBrush( Qt::lightGray ) );
#if 0
switch ( data.type() )
{
case DesignerTreeItemData::Field:
newItem->setIcon( 0, QgsApplication::getThemeIcon( "/mFieldIcon.svg" ) );
break;
case DesignerTreeItemData::Relation:
newItem->setIcon( 0, QgsApplication::getThemeIcon( "/mRelationIcon.svg" ) );
break;
case DesignerTreeItemData::Container:
newItem->setIcon( 0, QgsApplication::getThemeIcon( "/mContainerIcon.svg" ) );
break;
}
#endif
}
newItem->setData( 0 , DesignerTreeRole, data.asQVariant() );
parent->addChild( newItem );
return newItem;
}
/**
* Is called when mouse is moved over attributes tree before a
* drop event. Used to inhibit dropping fields onto the root item.
*/
void QgsFieldsProperties::DesignerTree::dragMoveEvent( QDragMoveEvent *event )
{
QTreeWidgetItem* targetItem = itemAt( event->pos() );
const QMimeData* data = event->mimeData();
if ( data->hasFormat( "application/x-qgsattributetabledesignerelement" ) )
{
DesignerTreeItemData itemElement;
QByteArray itemData = data->data( "application/x-qgsattributetabledesignerelement" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
stream >> itemElement;
// Forbid dropping fields on root item
if ( itemElement.type() == DesignerTreeItemData::Field && !targetItem )
{
event->ignore();
return;
}
// Inner drag and drop actions are always MoveAction
if ( event->source() == this )
{
event->setDropAction( Qt::MoveAction );
}
}
else
{
event->ignore();
}
QTreeWidget::dragMoveEvent( event );
}
bool QgsFieldsProperties::DesignerTree::dropMimeData( QTreeWidgetItem* parent, int index, const QMimeData * data, Qt::DropAction action )
{
Q_UNUSED( index )
bool bDropSuccessful = false;
if ( action == Qt::IgnoreAction )
{
bDropSuccessful = true;
}
else if ( data->hasFormat( "application/x-qgsattributetabledesignerelement" ) )
{
QByteArray itemData = data->data( "application/x-qgsattributetabledesignerelement" );
QDataStream stream( &itemData, QIODevice::ReadOnly );
DesignerTreeItemData itemElement;
while ( !stream.atEnd() )
{
stream >> itemElement;
if ( parent )
{
addItem( parent, itemElement );
bDropSuccessful = true;
}
else // Should never happen as we ignore drops of fields onto the root element in dragMoveEvent, but actually does happen. Qt?
{
// addItem( invisibleRootItem(), itemName );
// bDropSuccessful = true;
}
}
}
return bDropSuccessful;
}
void QgsFieldsProperties::DesignerTree::dropEvent( QDropEvent* event )
{
if ( !event->mimeData()->hasFormat( "application/x-qgsattributetabledesignerelement" ) )
return;
if ( event->source() == this )
{
event->setDropAction( Qt::MoveAction );
}
QTreeWidget::dropEvent( event );
}
QStringList QgsFieldsProperties::DesignerTree::mimeTypes() const
{
return QStringList() << QLatin1String( "application/x-qgsattributetabledesignerelement" );
}
QMimeData* QgsFieldsProperties::DesignerTree::mimeData( const QList<QTreeWidgetItem*> items ) const
{
if ( items.count() <= 0 )
return NULL;
QStringList types = mimeTypes();
if ( types.isEmpty() )
return NULL;
QMimeData* data = new QMimeData();
QString format = types.at( 0 );
QByteArray encoded;
QDataStream stream( &encoded, QIODevice::WriteOnly );
Q_FOREACH( const QTreeWidgetItem* item, items )
{
if ( item )
{
// Relevant information is always in the DesignerTreeRole of the first column
DesignerTreeItemData itemData = item->data( 0, DesignerTreeRole ).value<DesignerTreeItemData>();
stream << itemData;
}
}
data->setData( format, encoded );
return data;
}
/*
* Serialization helpers for DesigerTreeItemData so we can stuff this easily into QMimeData
*/
QDataStream& operator<<( QDataStream& stream, const QgsFieldsProperties::DesignerTreeItemData& data )
{
stream << ( quint32 )data.type() << data.name();
return stream;
}
QDataStream& operator>>( QDataStream& stream, QgsFieldsProperties::DesignerTreeItemData& data )
{
QString name;
quint32 type;
stream >> type >> name;
data.setType(( QgsFieldsProperties::DesignerTreeItemData::Type )type );
data.setName( name );
return stream;
}

View File

@ -20,33 +20,101 @@
#include <QPushButton>
#include <QTreeWidget>
#include <QTableWidget>
#include <QMimeData>
#include "qgsvectorlayer.h"
#include "ui_qgsfieldspropertiesbase.h"
class APP_EXPORT QgsAttributesTree : public QTreeWidget
{
Q_OBJECT
public:
QgsAttributesTree( QWidget* parent = 0 )
: QTreeWidget( parent )
{}
QTreeWidgetItem* addContainer( QTreeWidgetItem* parent , QString title );
QTreeWidgetItem* addItem( QTreeWidgetItem* parent , QString fieldName );
protected:
virtual void dragMoveEvent( QDragMoveEvent *event );
virtual void dropEvent( QDropEvent *event );
virtual bool dropMimeData( QTreeWidgetItem * parent, int index, const QMimeData * data, Qt::DropAction action );
/* Qt::DropActions supportedDropActions() const;*/
};
class APP_EXPORT QgsFieldsProperties : public QWidget, private Ui_QgsFieldsPropertiesBase
{
Q_OBJECT
public:
enum FieldPropertiesRoles
{
DesignerTreeRole = Qt::UserRole,
FieldConfigRole
};
class DesignerTreeItemData
{
public:
enum Type
{
Field,
Container
};
DesignerTreeItemData()
{}
DesignerTreeItemData( Type type, const QString& name )
: mType( type )
, mName( name ) {}
QString name() const { return mName; }
void setName( const QString& name ) { mName = name; }
Type type() const { return mType; }
void setType( const Type& type ) { mType = type; }
QVariant asQVariant() { return QVariant::fromValue<DesignerTreeItemData>( *this ); }
protected:
Type mType;
QString mName;
};
/**
* This class overrides mime type handling to be able to work with
* the drag and drop attribute editor.
*
* The mime type is application/x-qgsattributetablefield
*/
class DragList : public QTableWidget
{
public:
DragList( QWidget* parent = 0 )
: QTableWidget( parent )
{}
// QTreeWidget interface
protected:
virtual QStringList mimeTypes() const;
virtual QMimeData* mimeData( const QList<QTableWidgetItem*> items ) const;
};
/**
* Graphical representation for the attribute editor drag and drop editor
*/
class DesignerTree : public QTreeWidget
{
public:
DesignerTree( QWidget* parent = 0 )
: QTreeWidget( parent )
{}
QTreeWidgetItem* addItem( QTreeWidgetItem* parent, DesignerTreeItemData data );
QTreeWidgetItem* addContainer( QTreeWidgetItem* parent, QString title );
protected:
virtual void dragMoveEvent( QDragMoveEvent *event );
virtual void dropEvent( QDropEvent *event );
virtual bool dropMimeData( QTreeWidgetItem * parent, int index, const QMimeData * data, Qt::DropAction action );
/* Qt::DropActions supportedDropActions() const;*/
// QTreeWidget interface
protected:
virtual QStringList mimeTypes() const;
virtual QMimeData* mimeData( const QList<QTreeWidgetItem*> items ) const;
};
/**
* Holds the configuration for a field
*/
class FieldConfig
{
public:
@ -64,6 +132,8 @@ class APP_EXPORT QgsFieldsProperties : public QWidget, private Ui_QgsFieldsPrope
QPushButton* mButton;
QString mDateFormat;
QSize mWidgetSize;
QString mEditorWidgetV2Type;
QMap<QString, QVariant> mEditorWidgetV2Config;
};
public:
@ -125,8 +195,8 @@ class APP_EXPORT QgsFieldsProperties : public QWidget, private Ui_QgsFieldsPrope
void setConfigForRow( int row, FieldConfig cfg );
QgsVectorLayer* mLayer;
QgsAttributesTree* mAttributesTree;
QTableWidget* mAttributesList;
DesignerTree* mDesignerTree;
DragList* mFieldsList;
// Holds all the first column items (header: id) of the table.
// The index in the list is the fieldIdx, and therefore acts as a mapping
@ -152,10 +222,14 @@ class APP_EXPORT QgsFieldsProperties : public QWidget, private Ui_QgsFieldsPrope
static QMap< QgsVectorLayer::EditType, QString > editTypeMap;
static void setupEditTypes();
static QString editTypeButtonText( QgsVectorLayer::EditType type );
static QgsVectorLayer::EditType editTypeFromButtonText( QString text );
static QgsVectorLayer::EditType editTypeFromButton( QPushButton* btn );
};
QDataStream& operator<< ( QDataStream& stream, const QgsFieldsProperties::DesignerTreeItemData& data );
QDataStream& operator>> ( QDataStream& stream, QgsFieldsProperties::DesignerTreeItemData& data );
Q_DECLARE_METATYPE( QgsFieldsProperties::FieldConfig )
Q_DECLARE_METATYPE( QgsFieldsProperties::DesignerTreeItemData )
#endif // QGSFIELDSPROPERTIES_H

View File

@ -382,6 +382,7 @@ SET(QGIS_CORE_HDRS
qgsdataitem.h
qgsdistancearea.h
qgscsexception.h
qgseditorwidgetconfig.h
qgserror.h
qgsexception.h
qgsexpression.h

View File

@ -62,7 +62,7 @@ class CORE_EXPORT QgsDistanceArea
void setSourceAuthId( QString authid );
//! returns source spatial reference system
long sourceCrs() { return mSourceRefSys; }
long sourceCrs() const { return mSourceRefSys; }
//! What sort of coordinate system is being used?
bool geographic() { return mCoordTransform->sourceCrs().geographicFlag(); }

View File

@ -0,0 +1,19 @@
#include <QMap>
#include <QString>
#include <QVariant>
/**
* Holds a set of configuration parameters for a editor widget wrapper.
* It's basically a set of key => value pairs.
*
* If you need more advanced structures than a simple key => value pair,
* you can use a value to hold any structure a QVariant can handle (and that's
* about anything you get through your compiler)
*
* These are the user configurable options in the field properties tab of the
* vector layer properties. They are saved in the project file per layer and field.
* You get these passed, for every new widget wrapper.
*/
typedef QMap<QString, QVariant> QgsEditorWidgetConfig;

View File

@ -1666,15 +1666,10 @@ void QgsExpression::initGeomCalculator()
mCalc->setEllipsoidalMode( false );
}
void QgsExpression::setGeomCalculator( QgsDistanceArea &calc )
void QgsExpression::setGeomCalculator( const QgsDistanceArea &calc )
{
if ( !mCalc )
mCalc = new QgsDistanceArea();
// Copy from supplied calculator
mCalc->setEllipsoid( calc.ellipsoid() );
mCalc->setEllipsoidalMode( calc.ellipsoidalEnabled() );
mCalc->setSourceCrs( calc.sourceCrs() );
delete mCalc;
mCalc = new QgsDistanceArea( calc );
}
bool QgsExpression::prepare( const QgsFields& fields )

View File

@ -162,7 +162,7 @@ class CORE_EXPORT QgsExpression
//! Sets the geometry calculator used in evaluation of expressions,
// instead of the default.
void setGeomCalculator( QgsDistanceArea &calc );
void setGeomCalculator( const QgsDistanceArea &calc );
/** This function currently replaces each expression between [% and %]
in the string with the result of its evaluation on the feature

View File

@ -1964,6 +1964,7 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage
case UniqueValuesEditable:
case UuidGenerator:
case Color:
case EditorWidgetV2: // Will get a signal and read there
break;
}
}
@ -2086,6 +2087,7 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage
QgsAttributeEditorElement *attributeEditorWidget = attributeEditorElementFromDomElement( elem, this );
mAttributeEditorElements.append( attributeEditorWidget );
}
return true;
}
@ -2103,7 +2105,8 @@ QgsAttributeEditorElement* QgsVectorLayer::attributeEditorElementFromDomElement(
{
QDomElement childElem = childNodeList.at( i ).toElement();
QgsAttributeEditorElement* myElem = attributeEditorElementFromDomElement( childElem, container );
container->addChildElement( myElem );
if ( myElem )
container->addChildElement( myElem );
}
newElement = container;
@ -2114,7 +2117,6 @@ QgsAttributeEditorElement* QgsVectorLayer::attributeEditorElementFromDomElement(
int idx = *( dataProvider()->fieldNameMap() ).find( name );
newElement = new QgsAttributeEditorField( name, idx, parent );
}
return newElement;
}
@ -2282,6 +2284,7 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
case Immutable:
case UuidGenerator:
case Color:
case EditorWidgetV2: // Will get a signal and save there
break;
}
@ -2479,6 +2482,16 @@ void QgsVectorLayer::addAttributeEditorWidget( QgsAttributeEditorElement* data )
mAttributeEditorElements.append( data );
}
const QString QgsVectorLayer::editorWidgetV2( int fieldIdx )
{
return mEditorWidgetV2Types.value( fieldIdx );
}
const QgsEditorWidgetConfig QgsVectorLayer::editorWidgetV2Config( int fieldIdx )
{
return mEditorWidgetV2Configs.value( fieldIdx );
}
QString QgsVectorLayer::attributeAlias( int attributeIndex ) const
{
if ( attributeIndex < 0 || attributeIndex >= pendingFields().count() )
@ -3006,6 +3019,16 @@ void QgsVectorLayer::setEditorLayout( EditorLayout editorLayout )
mEditorLayout = editorLayout;
}
void QgsVectorLayer::setEditorWidgetV2( int attrIdx, const QString& widgetType )
{
mEditorWidgetV2Types[ attrIdx ] = widgetType;
}
void QgsVectorLayer::setEditorWidgetV2Config( int attrIdx, const QMap<QString, QVariant>& config )
{
mEditorWidgetV2Configs[ attrIdx ] = config;
}
QString QgsVectorLayer::editForm()
{
return mEditForm;
@ -3842,19 +3865,40 @@ QDomElement QgsAttributeEditorContainer::toDomElement( QDomDocument& doc ) const
{
QDomElement elem = doc.createElement( "attributeEditorContainer" );
elem.setAttribute( "name", mName );
for ( QList< QgsAttributeEditorElement* >::const_iterator it = mChildren.begin(); it != mChildren.end(); ++it )
Q_FOREACH( QgsAttributeEditorElement* child, mChildren )
{
elem.appendChild(( *it )->toDomElement( doc ) );
elem.appendChild( child->toDomElement( doc ) );
}
return elem;
}
void QgsAttributeEditorContainer::addChildElement( QgsAttributeEditorElement *widget )
{
mChildren.append( widget );
}
QList<QgsAttributeEditorElement*> QgsAttributeEditorContainer::findElements( QgsAttributeEditorElement::AttributeEditorType type ) const
{
QList<QgsAttributeEditorElement*> results;
Q_FOREACH( QgsAttributeEditorElement* elem, mChildren )
{
if ( elem->type() == type )
{
results.append( elem );
}
if ( elem->type() == AeTypeContainer )
{
QgsAttributeEditorContainer* cont = dynamic_cast<QgsAttributeEditorContainer*>( elem );
results += cont->findElements( type );
}
}
return results;
}
QDomElement QgsAttributeEditorField::toDomElement( QDomDocument& doc ) const
{
QDomElement elem = doc.createElement( "attributeEditorField" );

View File

@ -27,6 +27,7 @@
#include "qgsmaplayer.h"
#include "qgsfeature.h"
#include "qgsfeatureiterator.h"
#include "qgseditorwidgetconfig.h"
#include "qgsfield.h"
#include "qgssnapper.h"
#include "qgsfield.h"
@ -36,11 +37,12 @@ class QImage;
class QgsAttributeAction;
class QgsCoordinateTransform;
class QgsEditorWidgetWrapper;
class QgsFeatureRequest;
class QgsGeometry;
class QgsGeometryVertexIndex;
class QgsMapToPixel;
class QgsLabel;
class QgsMapToPixel;
class QgsRectangle;
class QgsVectorDataProvider;
class QgsSingleSymbolRendererV2;
@ -69,7 +71,6 @@ class CORE_EXPORT QgsAttributeEditorElement : public QObject
AeTypeInvalid
};
QgsAttributeEditorElement( AttributeEditorType type, QString name, QObject *parent = NULL )
: QObject( parent ), mType( type ), mName( name ) {}
@ -96,7 +97,9 @@ class CORE_EXPORT QgsAttributeEditorContainer : public QgsAttributeEditorElement
virtual QDomElement toDomElement( QDomDocument& doc ) const;
virtual void addChildElement( QgsAttributeEditorElement *widget );
virtual bool isGroupBox() const { return true; }
QList<QgsAttributeEditorElement*> children() const { return mChildren; }
virtual QList<QgsAttributeEditorElement*> findElements( AttributeEditorType type ) const;
private:
QList<QgsAttributeEditorElement*> mChildren;
@ -431,19 +434,20 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
Classification,
EditRange,
SliderRange,
CheckBox, /**< @note added in 1.4 */
CheckBox, /**< @note added in 1.4 */
FileName,
Enumeration,
Immutable, /**< The attribute value should not be changed in the attribute form */
Hidden, /**< The attribute value should not be shown in the attribute form @note added in 1.4 */
TextEdit, /**< multiline edit @note added in 1.4*/
Calendar, /**< calendar widget @note added in 1.5 */
DialRange, /**< dial range @note added in 1.5 */
ValueRelation, /**< value map from an table @note added in 1.8 */
UuidGenerator, /**< uuid generator - readonly and automatically intialized @note added in 1.9 */
Photo, /**< phote widget @note added in 1.9 */
WebView, /**< webview widget @note added in 1.9 */
Color, /**< color @note added in 1.9 */
Immutable, /**< The attribute value should not be changed in the attribute form */
Hidden, /**< The attribute value should not be shown in the attribute form @note added in 1.4 */
TextEdit, /**< multiline edit @note added in 1.4*/
Calendar, /**< calendar widget @note added in 1.5 */
DialRange, /**< dial range @note added in 1.5 */
ValueRelation, /**< value map from an table @note added in 1.8 */
UuidGenerator, /**< uuid generator - readonly and automatically intialized @note added in 1.9 */
Photo, /**< phote widget @note added in 1.9 */
WebView, /**< webview widget @note added in 1.9 */
Color, /**< color @note added in 1.9 */
EditorWidgetV2, /**< modularized edit widgets @note added in 2.1 */
};
/** Types of feature form suppression after feature creation
@ -1034,27 +1038,57 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
@note added in version 1.2 */
bool addAttribute( const QgsField &field );
/**Sets an alias (a display name) for attributes to display in dialogs
@note added in version 1.2*/
/**
* Sets an alias (a display name) for attributes to display in dialogs
* @note added in version 1.2
*/
void addAttributeAlias( int attIndex, QString aliasString );
/**Adds a tab (for the attribute editor form) holding groups and fields
@note added in version 1.9*/
/**
* Adds a tab (for the attribute editor form) holding groups and fields
* @note added in version 2.0
*/
void addAttributeEditorWidget( QgsAttributeEditorElement* data );
/**Returns a list of tabs holding groups and fields
@note added in version 1.9*/
/**
* Get the id for the editor widget used to represent the field at the given index
*
* @param fieldIdx The index of the field
*
* @return The id for the editor widget or a NULL string if not applicable
*/
const QString editorWidgetV2( int fieldIdx );
/**
* Get the configuration for the editor widget used to represent the field at the given index
*
* @param fieldIdx The index of the field
*
* @return The id for the editor widget or a NULL string if not configured
*/
const QgsEditorWidgetConfig editorWidgetV2Config( int fieldIdx );
/**
* Returns a list of tabs holding groups and fields
* @note added in version 2.0
*/
QList< QgsAttributeEditorElement* > &attributeEditorElements();
/**Clears all the tabs for the attribute editor form
@note added in version 1.9*/
/**
* Clears all the tabs for the attribute editor form
* @note added in version 2.0
*/
void clearAttributeEditorWidgets();
/**Returns the alias of an attribute name or an empty string if there is no alias
@note added in version 1.2*/
/**
* Returns the alias of an attribute name or an empty string if there is no alias
* @note added in version 1.2
*/
QString attributeAlias( int attributeIndex ) const;
/**Convenience function that returns the attribute alias if defined or the field name else
@note added in version 1.2*/
/**
* Convenience function that returns the attribute alias if defined or the field name else
* @note added in version 1.2
*/
QString attributeDisplayName( int attributeIndex ) const;
const QMap< QString, QString >& attributeAliases() const { return mAttributeAliasMap; }
@ -1118,6 +1152,10 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** set the active layout for the attribute editor for this layer (added in 1.9) */
void setEditorLayout( EditorLayout editorLayout );
void setEditorWidgetV2( int attrIdx, const QString& widgetType );
void setEditorWidgetV2Config( int attrIdx, const QMap<QString, QVariant>& config );
/** set string representing 'true' for a checkbox (added in 1.4) */
void setCheckedState( int idx, QString checked, QString notChecked );
@ -1268,6 +1306,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
int layerTransparency() const;
QString metadata();
/** @note not available in python bindings */
inline QgsGeometryCache* cache() { return mCache; }
public slots:
/**
* Select feature by its ID
@ -1323,11 +1367,6 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
@note added in 1.7 */
void checkJoinLayerRemove( QString theLayerId );
QString metadata();
/** @note not available in python bindings */
inline QgsGeometryCache* cache() { return mCache; }
/**
* @brief Is called when the cache image is being deleted. Overwrite and use to clean up.
* @note added in 2.0
@ -1564,6 +1603,9 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
QMap< QString, QString> mDateFormats;
QMap< QString, QSize> mWidgetSize;
QMap<int, QString> mEditorWidgetV2Types;
QMap<int, QMap<QString, QVariant> > mEditorWidgetV2Configs;
/** Defines the default layout to use for the attribute editor (Drag and drop, UI File, Generated) */
EditorLayout mEditorLayout;

View File

@ -48,6 +48,11 @@ attributetable/qgsfeaturelistviewdelegate.cpp
attributetable/qgsfeatureselectionmodel.cpp
attributetable/qgsdualview.cpp
editorwidgets/core/qgseditorconfigwidget.cpp
editorwidgets/core/qgseditorwidgetfactory.cpp
editorwidgets/core/qgseditorwidgetregistry.cpp
editorwidgets/core/qgseditorwidgetwrapper.cpp
qgisgui.cpp
qgisinterface.cpp
qgsannotationitem.cpp
@ -97,6 +102,7 @@ qgsnewvectorlayerdialog.cpp
qgsnumericsortlistviewitem.cpp
qgsoptionsdialogbase.cpp
qgscredentialdialog.cpp
qgsattributeeditorcontext.cpp
qgsowssourceselect.cpp
qgsprojectbadlayerguihandler.cpp
qgsprojectionselector.cpp
@ -177,6 +183,10 @@ attributetable/qgsfeatureselectionmodel.h
attributetable/qgsfeaturelistviewdelegate.h
attributetable/qgsdualview.h
editorwidgets/core/qgseditorconfigwidget.h
editorwidgets/core/qgseditorwidgetregistry.h
editorwidgets/core/qgseditorwidgetwrapper.h
qgsattributedialog.h
qgsattributeeditor.h
qgsblendmodecombobox.h
@ -236,6 +246,7 @@ QT4_WRAP_CPP(QGIS_GUI_MOC_SRCS ${QGIS_GUI_MOC_HDRS})
SET(QGIS_GUI_HDRS
qgisgui.h
qgisinterface.h
qgsattributeeditorcontext.h
qgsbusyindicatordialog.h
qgscharacterselectdialog.h
qgscolordialog.h
@ -296,6 +307,11 @@ attributetable/qgsfeaturelistviewdelegate.h
attributetable/qgsfeatureselectionmodel.h
attributetable/qgsdualview.h
editorwidgets/core/qgseditorconfigwidget.h
editorwidgets/core/qgseditorwidgetfactory.h
editorwidgets/core/qgseditorwidgetregistry.h
editorwidgets/core/qgseditorwidgetwrapper.h
raster/qgsrasterrendererwidget.h
)
@ -339,6 +355,8 @@ INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/symbology-ng
${CMAKE_CURRENT_SOURCE_DIR}/attributetable
${CMAKE_CURRENT_SOURCE_DIR}/editorwidgets
${CMAKE_CURRENT_SOURCE_DIR}/editorwidgets/core
../core
../core/composer
../core/raster

View File

@ -0,0 +1,36 @@
/***************************************************************************
qgseditorconfigwidget.cpp
--------------------------------------
Date : 24.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgseditorconfigwidget.h"
QgsEditorConfigWidget::QgsEditorConfigWidget( QgsVectorLayer* vl, int fieldIdx, QWidget* parent )
: QWidget( parent )
, mLayer( vl )
, mField( fieldIdx )
{
}
int QgsEditorConfigWidget::field()
{
return mField;
}
QgsVectorLayer*QgsEditorConfigWidget::layer()
{
return mLayer;
}

View File

@ -0,0 +1,84 @@
/***************************************************************************
qgseditorconfigwidget.h
--------------------------------------
Date : 24.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSEDITORCONFIGWIDGET_H
#define QGSEDITORCONFIGWIDGET_H
#include <QWidget>
#include "qgseditorwidgetwrapper.h"
class QgsVectorLayer;
/**
* This class should be subclassed for every configurable editor widget type.
*
* It implements the GUI configuration widget and transforms this to/from a configuration.
*
* It will only be instantiated by {@see QgsEditorWidgetFactory}
*/
class GUI_EXPORT QgsEditorConfigWidget : public QWidget
{
Q_OBJECT
public:
/**
* Create a new configuration widget
*
* @param vl The layer for which the configuration dialog will be created
* @param fieldIdx The index of the field on the layer for which this dialog will be created
* @param parent A parent widget
*/
explicit QgsEditorConfigWidget( QgsVectorLayer* vl, int fieldIdx, QWidget* parent );
/**
* @brief Create a configuration from the current GUI state
*
* @return A widget configuration
*/
virtual QgsEditorWidgetConfig config() = 0;
/**
* @brief Update the configuration widget to represent the given configuration.
*
* @param config The configuration which should be represented by this widget
*/
virtual void setConfig( const QgsEditorWidgetConfig& config ) = 0;
/**
* Returns the field for which this configuration widget applies
*
* @return The field index
*/
int field();
/**
* Returns the layer for which this configuration widget applies
*
* @return The layer
*/
QgsVectorLayer* layer();
/**
* Destructor
*/
virtual ~QgsEditorConfigWidget() {}
private:
QgsVectorLayer* mLayer;
int mField;
};
#endif // QGSEDITORCONFIGWIDGET_H

View File

@ -0,0 +1,49 @@
/***************************************************************************
qgseditorwidgetfactory.cpp
--------------------------------------
Date : 21.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgseditorwidgetfactory.h"
QgsEditorWidgetFactory::QgsEditorWidgetFactory( const QString& name )
: mName( name )
{
}
QgsEditorWidgetFactory::~QgsEditorWidgetFactory()
{
}
QString QgsEditorWidgetFactory::name()
{
return mName;
}
QgsEditorWidgetConfig QgsEditorWidgetFactory::readConfig( const QDomElement& configElement, QgsVectorLayer* layer, int fieldIdx )
{
Q_UNUSED( configElement );
Q_UNUSED( layer );
Q_UNUSED( fieldIdx );
return QgsEditorWidgetConfig();
}
void QgsEditorWidgetFactory::writeConfig( const QgsEditorWidgetConfig& config, QDomElement& configElement, const QDomDocument& doc, const QgsVectorLayer* layer, int fieldIdx )
{
Q_UNUSED( config );
Q_UNUSED( configElement );
Q_UNUSED( doc );
Q_UNUSED( layer );
Q_UNUSED( fieldIdx );
}

View File

@ -0,0 +1,163 @@
/***************************************************************************
qgseditorwidgetfactory.h
--------------------------------------
Date : 21.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSEDITORWIDGETFACTORY_H
#define QGSEDITORWIDGETFACTORY_H
#include "qgseditorwidgetwrapper.h"
#include "qgsapplication.h"
#include <QDomNode>
#include <QMap>
#include <QString>
class QgsEditorConfigWidget;
/**
* Every attribute editor widget needs a factory, which inherits this class
*
* It provides metadata for the widgets such as the name (human readable), it serializes
* the configuration to an xml structure and loads the configuration from there.
*
* It also has factory methods to create a widget wrapper for the attribute editor itself
* and another factory method to create a configuration dialog.
*/
class GUI_EXPORT QgsEditorWidgetFactory
{
public:
/**
* Constructor
*
* @param name A human readable name for this widget type
*/
QgsEditorWidgetFactory( const QString& name );
virtual ~QgsEditorWidgetFactory();
/**
* Override this in your implementation.
* Create a new editor widget wrapper. Call {@link QgsEditorWidgetRegistry::create()}
* instead of calling this method directly.
*
* @param vl The vector layer on which this widget will act
* @param fieldIdx The field index on which this widget will act
* @param editor An editor widget if already existent. If NULL is provided, a new widget will be created.
* @param parent The parent for the wrapper class and any created widget.
*
* @return A new widget wrapper
*/
virtual QgsEditorWidgetWrapper* create( QgsVectorLayer* vl, int fieldIdx, QWidget* editor, QWidget* parent ) const = 0;
/**
* Return The human readable name of this widget type
*
* By default returns the name specified when constructing and does not need to be overwritten
*
* @return a name
*/
virtual QString name();
/**
* Override this in your implementation.
* Create a new configuration widget for this widget type.
*
* @param vl The layer for which the widget will be created
* @param fieldIdx The field index for which the widget will be created
* @param parent The parent widget of the created config widget
*
* @return A configuration widget
*/
virtual QgsEditorConfigWidget* configWidget( QgsVectorLayer* vl, int fieldIdx, QWidget* parent ) const = 0;
/**
* Read the config from an XML file and map it to a proper {@link QgsEditorWidgetConfig}.
*
* @param configElement The configuration element from the project file
* @param layer The layer for which this configuration applies
* @param fieldIdx The field on the layer for which this configuration applies
*
* @return A configuration object. This will be passed to your widget wrapper later on
*/
virtual QgsEditorWidgetConfig readConfig( const QDomElement& configElement, QgsVectorLayer* layer, int fieldIdx );
/**
* Serialize your configuration and save it in a xml doc.
*
* @param config The configuration to serialize
* @param configElement The element, where you can write your configuration into
* @param doc The document. You can use this to create new nodes
* @param layer The layer for which this configuration applies
* @param fieldIdx The field on the layer for which this configuration applies
*/
virtual void writeConfig( const QgsEditorWidgetConfig& config, QDomElement& configElement, const QDomDocument& doc, const QgsVectorLayer* layer, int fieldIdx );
private:
QString mName;
};
/**
* This is a templated wrapper class, which inherits QgsEditWidgetFactory and does the boring work for you.
* C++ only
*/
template<typename F, typename G>
class GUI_EXPORT QgsEditWidgetFactoryHelper : public QgsEditorWidgetFactory
{
public:
QgsEditWidgetFactoryHelper( QString name )
: QgsEditorWidgetFactory( name ) {}
QgsEditorWidgetWrapper* create( QgsVectorLayer* vl, int fieldIdx, QWidget* editor, QWidget* parent ) const
{
return new F( vl, fieldIdx, editor, parent );
}
QgsEditorConfigWidget* configWidget( QgsVectorLayer* vl, int fieldIdx, QWidget* parent )
{
return new G( vl, fieldIdx, parent );
}
/**
* Read the config from an XML file and map it to a proper {@link QgsEditorWidgetConfig}.
*
* Implement this method yourself somewhere with the class template parameters
* specified. To keep things clean, every implementation of this class should be placed
* next to the associated widget factory implementation.
*
* @param configElement The configuration element from the project file
* @param layer The layer for which this configuration applies
* @param fieldIdx The field on the layer for which this configuration applies
*
* @return A configuration object. This will be passed to your widget wrapper later on
*/
virtual QgsEditorWidgetConfig readConfig( const QDomElement& configElement, QgsVectorLayer* layer, int fieldIdx );
/**
* Serialize your configuration and save it in a xml doc.
*
* Implement this method yourself somewhere with the class template parameters
* specified. To keep things clean, every implementation of this class should be placed
* next to the associated widget factory implementation.
*
* @param config The configuration to serialize
* @param configElement The element, where you can write your configuration into
* @param doc The document. You can use this to create new nodes
* @param layer The layer for which this configuration applies
* @param fieldIdx The field on the layer for which this configuration applies
*/
virtual void writeConfig( const QgsEditorWidgetConfig& config, QDomElement& configElement, const QDomDocument& doc, const QgsVectorLayer* layer, int fieldIdx );
};
#endif // QGSEDITORWIDGETFACTORY_H

View File

@ -0,0 +1,218 @@
/***************************************************************************
qgseditorwidgetregistry.cpp
--------------------------------------
Date : 24.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgseditorwidgetregistry.h"
#include "qgseditorwidgetfactory.h"
#include "qgsproject.h"
#include "qgsvectorlayer.h"
#include "qgsmessagelog.h"
QgsEditorWidgetRegistry QgsEditorWidgetRegistry::sInstance;
QgsEditorWidgetRegistry* QgsEditorWidgetRegistry::instance()
{
return &sInstance;
}
QgsEditorWidgetRegistry::QgsEditorWidgetRegistry()
{
connect( QgsProject::instance(), SIGNAL( readMapLayer( QgsMapLayer*, const QDomElement& ) ), this, SLOT( readMapLayer( QgsMapLayer*, const QDomElement& ) ) );
connect( QgsProject::instance(), SIGNAL( writeMapLayer( QgsMapLayer*, QDomElement&, QDomDocument& ) ), this, SLOT( writeMapLayer( QgsMapLayer*, QDomElement&, QDomDocument& ) ) );
}
QgsEditorWidgetRegistry::~QgsEditorWidgetRegistry()
{
qDeleteAll( mWidgetFactories.values() );
}
QgsEditorWidgetWrapper* QgsEditorWidgetRegistry::create( const QString& widgetId, QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, QWidget* editor, QWidget* parent )
{
if ( mWidgetFactories.contains( widgetId ) )
{
QgsEditorWidgetWrapper* ww = mWidgetFactories[widgetId]->create( vl, fieldIdx, editor, parent );
if ( ww )
{
ww->setConfig( config );
return ww;
}
}
return 0;
}
QgsEditorConfigWidget* QgsEditorWidgetRegistry::createConfigWidget( const QString& widgetId, QgsVectorLayer* vl, int fieldIdx, QWidget* parent )
{
if ( mWidgetFactories.contains( widgetId ) )
{
return mWidgetFactories[widgetId]->configWidget( vl, fieldIdx, parent );
}
return 0;
}
QString QgsEditorWidgetRegistry::name( const QString& widgetId )
{
if ( mWidgetFactories.contains( widgetId ) )
{
return mWidgetFactories[widgetId]->name();
}
return QString();
}
const QMap<QString, QgsEditorWidgetFactory*> QgsEditorWidgetRegistry::factories()
{
return mWidgetFactories;
}
bool QgsEditorWidgetRegistry::registerWidget( const QString& widgetId, QgsEditorWidgetFactory* widgetFactory )
{
if ( !widgetFactory )
{
QgsMessageLog::instance()->logMessage( "QgsEditorWidgetRegistry: Factory not valid." );
return false;
}
else if ( mWidgetFactories.contains( widgetId ) )
{
QgsMessageLog::instance()->logMessage( QString( "QgsEditorWidgetRegistry: Factory with id %1 already registered." ).arg( widgetId ) );
return false;
}
else
{
mWidgetFactories.insert( widgetId, widgetFactory );
return true;
}
}
void QgsEditorWidgetRegistry::readMapLayer( QgsMapLayer* mapLayer, const QDomElement& layerElem )
{
if ( mapLayer->type() != QgsMapLayer::VectorLayer )
{
return;
}
QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
if ( !vectorLayer )
{
return;
}
for ( int idx = 0; idx < vectorLayer->pendingFields().count(); ++idx )
{
if ( vectorLayer->editType( idx ) != QgsVectorLayer::EditorWidgetV2 )
{
continue;
}
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" );
if ( vectorLayer->fieldNameIndex( name ) != idx )
continue;
QgsVectorLayer::EditType editType =
( QgsVectorLayer::EditType ) editTypeElement.attribute( "type" ).toInt();
if ( editType != QgsVectorLayer::EditorWidgetV2 )
continue;
QString ewv2Type = editTypeElement.attribute( "widgetv2type" );
if ( mWidgetFactories.contains( ewv2Type ) )
{
vectorLayer->setEditorWidgetV2( idx, ewv2Type );
QDomElement ewv2CfgElem = editTypeElement.namedItem( "widgetv2config" ).toElement();
if ( !ewv2CfgElem.isNull() )
{
QMap<QString, QVariant> cfg = mWidgetFactories[ewv2Type]->readConfig( ewv2CfgElem, vectorLayer, idx );
vectorLayer->setEditorWidgetV2Config( idx, cfg );
}
}
else
{
QgsMessageLog::logMessage( tr( "Unknown attribute editor widget '%1'" ).arg( ewv2Type ) );
}
}
}
}
void QgsEditorWidgetRegistry::writeMapLayer( QgsMapLayer* mapLayer, QDomElement& layerElem, QDomDocument& doc )
{
if ( mapLayer->type() != QgsMapLayer::VectorLayer )
{
return;
}
QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
if ( !vectorLayer )
{
return;
}
for ( int idx = 0; idx < vectorLayer->pendingFields().count(); ++idx )
{
if ( vectorLayer->editType( idx ) != QgsVectorLayer::EditorWidgetV2 )
{
continue;
}
const QString& widgetType = vectorLayer->editorWidgetV2( idx );
if ( !mWidgetFactories.contains( widgetType ) )
{
QgsMessageLog::logMessage( tr( "Could not save unknown editor widget type '%1'." ).arg( widgetType ) );
continue;
}
QDomNodeList editTypeNodes = layerElem.namedItem( "edittypes" ).childNodes();
for ( int i = 0; i < editTypeNodes.size(); i++ )
{
QDomElement editTypeElement = editTypeNodes.at( i ).toElement();
QString name = editTypeElement.attribute( "name" );
if ( vectorLayer->fieldNameIndex( name ) != idx )
continue;
QgsVectorLayer::EditType editType =
( QgsVectorLayer::EditType ) editTypeElement.attribute( "type" ).toInt();
if ( editType != QgsVectorLayer::EditorWidgetV2 )
continue;
editTypeElement.setAttribute( "widgetv2type", widgetType );
if ( mWidgetFactories.contains( widgetType ) )
{
QDomElement ewv2CfgElem = doc.createElement( "widgetv2config" );
mWidgetFactories[widgetType]->writeConfig( vectorLayer->editorWidgetV2Config( idx ), ewv2CfgElem, doc, vectorLayer, idx );
editTypeElement.appendChild( ewv2CfgElem );
}
else
{
QgsMessageLog::logMessage( tr( "Unknown attribute editor widget '%1'" ).arg( widgetType ) );
}
}
}
}

View File

@ -0,0 +1,119 @@
/***************************************************************************
qgseditorwidgetregistry.h
--------------------------------------
Date : 24.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSEDITORWIDGETREGISTRY_H
#define QGSEDITORWIDGETREGISTRY_H
#include <QObject>
#include <QMap>
#include "qgseditorwidgetfactory.h"
class QgsMapLayer;
class QDomNode;
/**
* This class manages all known edit widget factories
*/
class GUI_EXPORT QgsEditorWidgetRegistry : public QObject
{
Q_OBJECT
public:
/**
* This class is a singleton and has therefore to be accessed with this method instead
* of a constructor.
*
* @return
*/
static QgsEditorWidgetRegistry* instance();
~QgsEditorWidgetRegistry();
/**
* Create an attribute editor widget wrapper of a given type for a given field.
* The editor may be NULL if you want the widget wrapper to create a default widget.
*
* @param widgetId The id of the widget type to create an attribute editor for
* @param vl The vector layer for which this widget will be created
* @param fieldIdx The field index on the specified layer for which this widget will be created
* @param config A configuration which should be used for the widget creation
* @param editor An editor widget which will be used instead of an autocreated widget
* @param parent The parent which will be used for the created wrapper and the created widget
*
* @return A new widget wrapper
*/
QgsEditorWidgetWrapper* create( const QString& widgetId, QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, QWidget* editor, QWidget* parent );
/**
* Creates a configuration widget
*
* @param widgetId The id of the widget type to create a configuration widget for
* @param vl The vector layer for which this widget will be created
* @param fieldIdx The field index on the specified layer for which this widget will be created
* @param parent The parent widget for the created widget
*
* @return A new configuration widget
*/
QgsEditorConfigWidget* createConfigWidget( const QString& widgetId, QgsVectorLayer* vl, int fieldIdx, QWidget* parent );
/**
* Get the human readable name for a widget type
*
* @param widgetId The widget type to get the name for
*
* @return A human readable name
*/
QString name( const QString& widgetId );
/**
* Get access to all registered factories
*
* @return All ids and factories
*/
const QMap<QString, QgsEditorWidgetFactory*> factories();
/**
* The other part which does the boring work for you
*/
template <class W, class C>
void registerWidget( const QString& widgetType, const QString& name )
{
mWidgetFactories.insert( widgetType, new QgsEditWidgetFactoryHelper<W, C>( name ) );
}
/**
* Register a new widget factory with the given id
*
* @param widgetId The id which will be used later to refer to this widget type
* @param widgetFactory The factory which will create this widget type
*
* @return true, if successful, false, if the widgetId is already in use or widgetFactory is NULL
*/
bool registerWidget( const QString& widgetId, QgsEditorWidgetFactory* widgetFactory );
protected:
QgsEditorWidgetRegistry();
private slots:
void readMapLayer( QgsMapLayer* mapLayer , const QDomElement& layerElem );
void writeMapLayer( QgsMapLayer* mapLayer , QDomElement& layerElem, QDomDocument& doc );
private:
QMap<QString, QgsEditorWidgetFactory*> mWidgetFactories;
static QgsEditorWidgetRegistry sInstance;
};
#endif // QGSEDITORWIDGETREGISTRY_H

View File

@ -0,0 +1,94 @@
/***************************************************************************
qgseditorwidgetwrapper.cpp
--------------------------------------
Date : 20.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgseditorwidgetwrapper.h"
#include <QWidget>
QgsEditorWidgetWrapper::QgsEditorWidgetWrapper( QgsVectorLayer* vl, int fieldIdx, QWidget* editor, QWidget* parent )
: QObject( parent )
, mWidget( editor )
, mParent( parent )
, mLayer( vl )
{
mField = fieldIdx;
}
QWidget* QgsEditorWidgetWrapper::widget()
{
if ( !mWidget )
{
mWidget = createWidget( mParent );
mWidget->setProperty( "EWV2Wrapper", QVariant::fromValue( this ) );
initWidget( mWidget );
}
return mWidget;
}
void QgsEditorWidgetWrapper::setConfig( const QgsEditorWidgetConfig& config )
{
mConfig = config;
// If an editor widget was supplied, we can initialize this now
if ( mWidget )
{
mWidget->setProperty( "EWV2Wrapper", QVariant::fromValue( this ) );
initWidget( mWidget );
}
}
QVariant QgsEditorWidgetWrapper::config( QString key, QVariant defaultVal )
{
if ( mConfig.contains( key ) )
{
return mConfig[key];
}
return defaultVal;
}
QgsVectorLayer* QgsEditorWidgetWrapper::layer()
{
return mLayer;
}
int QgsEditorWidgetWrapper::field()
{
return mField;
}
QgsEditorWidgetWrapper* QgsEditorWidgetWrapper::fromWidget( QWidget* widget )
{
QVariant w = widget->property( "EWV2Wrapper" );
if ( w.isNull() )
{
return NULL;
}
return w.value<QgsEditorWidgetWrapper*>();
}
void QgsEditorWidgetWrapper::initWidget( QWidget* editor )
{
Q_UNUSED( editor )
}
void QgsEditorWidgetWrapper::setEnabled( bool enabled )
{
if ( mWidget )
{
mWidget->setEnabled( enabled );
}
}

View File

@ -0,0 +1,181 @@
/***************************************************************************
qgseditorwidgetwrapper.h
--------------------------------------
Date : 20.4.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSEDITORWIDGETWRAPPER_H
#define QGSEDITORWIDGETWRAPPER_H
#include <QObject>
#include <QMap>
#include <QVariant>
class QgsVectorLayer;
#include "qgseditorwidgetconfig.h"
/**
* Manages an editor widget
* Widget and wrapper share the same parent
*
* A wrapper controls one attribute editor widget and is able to create a default
* widget or use a pre-existent widget. It is able to set the widget to the value implied
* by a field of a vector layer, or return the value it currently holds. Every time it is changed
* it has to emit a valueChanged signal (this does not yet mean, that the value is accepted).
*
*/
class GUI_EXPORT QgsEditorWidgetWrapper : public QObject
{
Q_OBJECT
public:
/**
* Create a new widget wrapper
*
* @param vl The layer on which the field is
* @param fieldIdx The field which will be controlled
* @param editor An editor widget. Can be NULL if one should be autogenerated.
* @param parent A parent widget for this widget wrapper and the created widget.
*/
explicit QgsEditorWidgetWrapper( QgsVectorLayer* vl, int fieldIdx, QWidget* editor = 0, QWidget* parent = 0 );
/**
* Will be used to access the widget's value. Read the value from the widget and
* return it properly formatted to be saved in the attribute.
*
* @return The current value the widget represents
*/
virtual QVariant value() = 0;
/**
* @brief Access the widget managed by this wrapper
*
* @return The widget
*/
QWidget* widget();
/**
* @brief Access the widget managed by this wrapper and cast it to a given type
* Example: QPushButton* pb = wrapper->widget<QPushButton*>();
*
* @return The widget as template type or NULL, if it cannot be cast to this type.
*/
template <class T>
T* widget() { return dynamic_cast<T>( mWidget ); }
/**
* Will set the config of this wrapper to the specified config.
*
* @param config The config for this wrapper
*/
void setConfig( const QgsEditorWidgetConfig& config );
/**
* Use this inside your overriden classes to access the configuration.
*
* @param key The configuration option you want to load
* @param defaultVal Default value
*
* @return the value assigned to this configuration option
*/
QVariant config( QString key, QVariant defaultVal = QVariant() );
/**
* Returns the whole config
*
* @return The configuration
*/
const QgsEditorWidgetConfig config();
/**
* Access the QgsVectorLayer, you are working on
*
* @return The layer
*
* @see field()
*/
QgsVectorLayer* layer();
/**
* Access the field index.
*
* @return The index of the field you are working on
*
* @see layer()
*/
int field();
/**
* Will return a wrapper for a given widget
* @param widget The widget which was created by a wrapper
* @return The wrapper for the widget or NULL
*/
static QgsEditorWidgetWrapper* fromWidget( QWidget* widget );
protected:
/**
* This method should create a new widget with the provided parent. This will only be called
* if the form did not already provide a widget, so it is not guaranteed to be called!
* You should not do initialisation stuff, which also has to be done for custom editor
* widgets inside this method. Things like filling comboboxes and assigning other data which
* will also be used to make widgets on forms created in the QtDesigner usable should be assigned
* in {@link initWidget(QWidget*)}.
*
* @param parent You should set this parent on the created widget.
* @return A new widget
*/
virtual QWidget* createWidget( QWidget* parent ) = 0;
/**
* This method should initialize the editor widget with runtime data. Fill your comboboxes here.
*
* @param editor The widget which will represent this attribute editor in a form.
*/
virtual void initWidget( QWidget* editor );
signals:
/**
* Emit this signal, whenever the value changed.
*
* @param value The new value
*/
void valueChanged( const QVariant& value );
public slots:
/**
* Is called, when the value of the widget needs to be changed. Update the widget representation
* to reflect the new value.
*
* @param value The new value of the attribute
*/
virtual void setValue( const QVariant& value ) = 0;
/**
* Is used to enable or disable the edit functionality of the managed widget.
* By default this will enable or disable the whole widget
*
* @param enabled Enable or Disable?
*/
virtual void setEnabled( bool enabled );
private:
QgsEditorWidgetConfig mConfig;
QWidget* mWidget;
QWidget* mParent;
QgsVectorLayer* mLayer;
int mField;
};
// We'll use this class inside a QVariant in the widgets properties
Q_DECLARE_METATYPE( QgsEditorWidgetWrapper* )
#endif // QGSEDITORWIDGETWRAPPER_H

View File

@ -15,6 +15,7 @@
* *
***************************************************************************/
#include "qgsattributedialog.h"
#include "qgseditorwidgetwrapper.h"
#include "qgsfield.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
@ -42,52 +43,73 @@
#include <QWebView>
#include <QPushButton>
int QgsAttributeDialog::smFormCounter = 0;
int QgsAttributeDialog::sFormCounter = 0;
QString QgsAttributeDialog::sSettingsPath = "/Windows/AttributeDialog/";
QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeature, bool featureOwner, QgsDistanceArea myDa, QWidget* parent, bool showDialogButtons )
QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer* vl, QgsFeature* thepFeature, bool featureOwner, QWidget* parent, bool showDialogButtons, QgsAttributeEditorContext context )
: QObject( parent )
, mDialog( 0 )
, mSettingsPath( "/Windows/AttributeDialog/" )
, mContext( context )
, mLayer( vl )
, mFeature( thepFeature )
, mFeatureOwner( featureOwner )
, mHighlight( 0 )
, mFormNr( -1 )
, mFormNr( sFormCounter++ )
, mShowDialogButtons( showDialogButtons )
{
if ( !mFeature || !vl->dataProvider() )
mContext.adjustForLayer( mLayer );
init();
}
QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer* vl, QgsFeature* thepFeature, bool featureOwner, QgsDistanceArea myDa, QWidget* parent, bool showDialogButtons )
: QObject( parent )
, mDialog( 0 )
, mContext( )
, mLayer( vl )
, mFeature( thepFeature )
, mFeatureOwner( featureOwner )
, mHighlight( 0 )
, mFormNr( sFormCounter++ )
, mShowDialogButtons( showDialogButtons )
{
mContext.setDistanceArea( myDa );
mContext.adjustForLayer( mLayer );
init();
}
void QgsAttributeDialog::init()
{
if ( !mFeature || !mLayer->dataProvider() )
return;
const QgsFields &theFields = vl->pendingFields();
const QgsFields &theFields = mLayer->pendingFields();
if ( theFields.isEmpty() )
return;
QgsAttributes myAttributes = mFeature->attributes();
QDialogButtonBox *buttonBox = NULL;
if ( vl->editorLayout() == QgsVectorLayer::UiFileLayout && !vl->editForm().isEmpty() )
if ( mLayer->editorLayout() == QgsVectorLayer::UiFileLayout && !mLayer->editForm().isEmpty() )
{
// UI-File defined layout
QFile file( vl->editForm() );
QFile file( mLayer->editForm() );
if ( file.open( QFile::ReadOnly ) )
{
QUiLoader loader;
QFileInfo fi( vl->editForm() );
QFileInfo fi( mLayer->editForm() );
loader.setWorkingDirectory( fi.dir() );
QWidget *myWidget = loader.load( &file, parent );
QWidget *myWidget = loader.load( &file, qobject_cast<QWidget*>( parent() ) );
file.close();
mDialog = qobject_cast<QDialog*>( myWidget );
buttonBox = myWidget->findChild<QDialogButtonBox*>();
}
}
else if ( vl->editorLayout() == QgsVectorLayer::TabLayout )
else if ( mLayer->editorLayout() == QgsVectorLayer::TabLayout )
{
// Tab display
mDialog = new QDialog( parent );
mDialog = new QDialog( qobject_cast<QWidget*>( parent() ) );
QGridLayout *gridLayout;
QTabWidget *tabWidget;
@ -99,7 +121,7 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
tabWidget = new QTabWidget( mDialog );
gridLayout->addWidget( tabWidget );
foreach ( const QgsAttributeEditorElement *widgDef, vl->attributeEditorElements() )
foreach ( const QgsAttributeEditorElement *widgDef, mLayer->attributeEditorElements() )
{
QWidget* tabPage = new QWidget( tabWidget );
@ -108,7 +130,9 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
if ( widgDef->type() == QgsAttributeEditorElement::AeTypeContainer )
{
tabPageLayout->addWidget( QgsAttributeEditor::createWidgetFromDef( widgDef, tabPage, vl, myAttributes, mProxyWidgets, false ) );
QString dummy1;
bool dummy2;
tabPageLayout->addWidget( QgsAttributeEditor::createWidgetFromDef( widgDef, tabPage, mLayer, *mFeature, mContext, dummy1, dummy2 ) );
}
else
{
@ -121,9 +145,10 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
gridLayout->addWidget( buttonBox );
}
// Still no dialog: create the default generated dialog
if ( !mDialog )
{
mDialog = new QDialog( parent );
mDialog = new QDialog( qobject_cast<QWidget*>( parent() ) );
QGridLayout *gridLayout;
QFrame *mFrame;
@ -174,35 +199,35 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
for ( int fldIdx = 0; fldIdx < theFields.count(); ++fldIdx )
{
//show attribute alias if available
QString myFieldName = vl->attributeDisplayName( fldIdx );
QString myFieldName = mLayer->attributeDisplayName( fldIdx );
// by default (until user defined alias) append date format
// (validator does not allow to enter a value in wrong format)
const QgsField &myField = theFields[fldIdx];
if ( myField.type() == QVariant::Date && vl->attributeAlias( fldIdx ).isEmpty() )
if ( myField.type() == QVariant::Date && mLayer->attributeAlias( fldIdx ).isEmpty() )
{
myFieldName += " (" + vl->dateFormat( fldIdx ) + ")";
myFieldName += " (" + mLayer->dateFormat( fldIdx ) + ")";
}
QWidget *myWidget = QgsAttributeEditor::createAttributeEditor( 0, 0, vl, fldIdx, myAttributes[fldIdx], mProxyWidgets );
QWidget *myWidget = QgsAttributeEditor::createAttributeEditor( mDialog, 0, mLayer, fldIdx, mFeature->attribute( fldIdx ), mContext );
if ( !myWidget )
continue;
QLabel *mypLabel = new QLabel( myFieldName, mypInnerFrame );
if ( vl->editType( fldIdx ) != QgsVectorLayer::Immutable )
if ( mLayer->editType( fldIdx ) != QgsVectorLayer::Immutable )
{
if ( vl->isEditable() && vl->fieldEditable( fldIdx ) )
if ( mLayer->isEditable() && mLayer->fieldEditable( fldIdx ) )
{
myWidget->setEnabled( true );
}
else if ( vl->editType( fldIdx ) == QgsVectorLayer::Photo )
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::Photo )
{
foreach ( QWidget *w, myWidget->findChildren<QWidget *>() )
{
w->setEnabled( qobject_cast<QLabel *>( w ) ? true : false );
}
}
else if ( vl->editType( fldIdx ) == QgsVectorLayer::WebView )
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::WebView )
{
foreach ( QWidget *w, myWidget->findChildren<QWidget *>() )
{
@ -214,13 +239,21 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
w->setEnabled( false );
}
}
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::EditorWidgetV2 )
{
QgsEditorWidgetWrapper* ww = QgsEditorWidgetWrapper::fromWidget( myWidget );
if ( ww )
{
ww->setEnabled( false );
}
}
else
{
myWidget->setEnabled( false );
}
}
if ( vl->labelOnTop( fldIdx ) )
if ( mLayer->labelOnTop( fldIdx ) )
{
mypInnerLayout->addWidget( mypLabel, index++, 0, 1, 2 );
mypInnerLayout->addWidget( myWidget, index++, 0, 1, 2 );
@ -261,28 +294,36 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
foreach ( QWidget *myWidget, myWidgets )
{
QgsAttributeEditor::createAttributeEditor( mDialog, myWidget, vl, fldIdx, myAttributes[fldIdx], mProxyWidgets );
QgsAttributeEditor::createAttributeEditor( mDialog, myWidget, mLayer, fldIdx, mFeature->attribute( fldIdx ), mContext );
if ( vl->editType( fldIdx ) != QgsVectorLayer::Immutable )
if ( mLayer->editType( fldIdx ) != QgsVectorLayer::Immutable )
{
if ( vl->isEditable() && vl->fieldEditable( fldIdx ) )
if ( mLayer->isEditable() && mLayer->fieldEditable( fldIdx ) )
{
myWidget->setEnabled( true );
}
else if ( vl->editType( fldIdx ) == QgsVectorLayer::Photo )
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::Photo )
{
foreach ( QWidget *w, myWidget->findChildren<QWidget *>() )
{
w->setEnabled( qobject_cast<QLabel *>( w ) ? true : false );
}
}
else if ( vl->editType( fldIdx ) == QgsVectorLayer::WebView )
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::WebView )
{
foreach ( QWidget *w, myWidget->findChildren<QWidget *>() )
{
w->setEnabled( qobject_cast<QWebView *>( w ) ? true : false );
}
}
else if ( mLayer->editType( fldIdx ) == QgsVectorLayer::EditorWidgetV2 )
{
QgsEditorWidgetWrapper* ww = QgsEditorWidgetWrapper::fromWidget( myWidget );
if ( ww )
{
ww->setEnabled( false );
}
}
else
{
myWidget->setEnabled( false );
@ -308,15 +349,15 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
if ( !mFeature->geometry() && exp.needsGeometry() )
{
QgsFeature f;
if ( vl->getFeatures( QgsFeatureRequest().setFilterFid( mFeature->id() ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) && f.geometry() )
if ( mLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeature->id() ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) && f.geometry() )
{
mFeature->setGeometry( *f.geometry() );
}
}
exp.setGeomCalculator( myDa );
exp.setGeomCalculator( mContext.distanceArea() );
QVariant value = exp.evaluate( mFeature, vl->pendingFields() );
QVariant value = exp.evaluate( mFeature, mLayer->pendingFields() );
if ( !exp.hasEvalError() )
{
@ -344,7 +385,7 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
mDialog->setObjectName( "QgsAttributeDialogBase" );
if ( mDialog->windowTitle().isEmpty() )
mDialog->setWindowTitle( tr( "Attributes - %1" ).arg( vl->name() ) );
mDialog->setWindowTitle( tr( "Attributes - %1" ).arg( mLayer->name() ) );
}
if ( mShowDialogButtons )
@ -353,7 +394,7 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
{
buttonBox->clear();
if ( vl->isEditable() )
if ( mLayer->isEditable() )
{
buttonBox->setStandardButtons( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
connect( buttonBox, SIGNAL( accepted() ), mDialog, SLOT( accept() ) );
@ -379,7 +420,7 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
connect( mDialog, SIGNAL( destroyed() ), this, SLOT( dialogDestroyed() ) );
if ( !vl->editFormInit().isEmpty() )
if ( !mLayer->editFormInit().isEmpty() )
{
#if 0
// would be nice if only PyQt's QVariant.toPyObject() wouldn't take ownership
@ -387,7 +428,7 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
vl->setProperty( "featureForm.id", QVariant( mpFeature->id() ) );
#endif
QString module = vl->editFormInit();
QString module = mLayer->editFormInit();
int pos = module.lastIndexOf( "." );
if ( pos >= 0 )
{
@ -402,15 +443,13 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
QgsPythonRunner::run( reload );
mFormNr = smFormCounter++;
QString form = QString( "_qgis_featureform_%1 = sip.wrapinstance( %2, QtGui.QDialog )" )
.arg( mFormNr )
.arg(( unsigned long ) mDialog );
QString layer = QString( "_qgis_layer_%1 = sip.wrapinstance( %2, qgis.core.QgsVectorLayer )" )
.arg( vl->id() )
.arg(( unsigned long ) vl );
.arg( mLayer->id() )
.arg(( unsigned long ) mLayer );
// Generate the unique ID of this feature. We used to use feature ID but some providers
// return a ID that is an invalid python variable when we have new unsaved features.
@ -426,9 +465,9 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
mReturnvarname = QString( "_qgis_feature_form_%1" ).arg( dt.toString( "yyyyMMddhhmmsszzz" ) );
QString expr = QString( "%5 = %1(_qgis_featureform_%2, _qgis_layer_%3, %4)" )
.arg( vl->editFormInit() )
.arg( mLayer->editFormInit() )
.arg( mFormNr )
.arg( vl->id() )
.arg( mLayer->id() )
.arg( featurevarname )
.arg( mReturnvarname );
@ -437,7 +476,7 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
}
// Only restore the geometry of the dialog if it's not a custom one.
if ( vl->editorLayout() != QgsVectorLayer::UiFileLayout )
if ( mLayer->editorLayout() != QgsVectorLayer::UiFileLayout )
{
restoreGeometry();
}
@ -480,7 +519,7 @@ void QgsAttributeDialog::accept()
{
QVariant value;
if ( QgsAttributeEditor::retrieveValue( mProxyWidgets.value( idx ), mLayer, idx, value ) )
if ( QgsAttributeEditor::retrieveValue( mContext.proxyWidget( mLayer, idx ), mLayer, idx, value ) )
mFeature->setAttribute( idx, value );
}
}

View File

@ -18,21 +18,37 @@
#define QGSATTRIBUTEDIALOG_H
#include "qgsfeature.h"
#include "qgsattributeeditorcontext.h"
class QDialog;
class QgsFeature;
class QLayout;
class QgsField;
class QgsVectorLayer;
class QgsHighlight;
class QgsDistanceArea;
class QgsFeature;
class QgsField;
class QgsHighlight;
class QgsVectorLayer;
class GUI_EXPORT QgsAttributeDialog : public QObject
{
Q_OBJECT
public:
/**
* @brief QgsAttributeDialog
* @param vl
* @param thepFeature
* @param featureOwner
* @param myDa
* @param parent
* @param showDialogButtons
*
* @deprecated
*/
QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeature, bool featureOwner, QgsDistanceArea myDa, QWidget* parent = 0, bool showDialogButtons = true );
QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeature, bool featureOwner, QWidget* parent = 0, bool showDialogButtons = true, QgsAttributeEditorContext context = QgsAttributeEditorContext() );
~QgsAttributeDialog();
/** Saves the size and position for the next time
@ -63,18 +79,22 @@ class GUI_EXPORT QgsAttributeDialog : public QObject
bool eventFilter( QObject *obj, QEvent *event );
private:
void init();
QDialog *mDialog;
QString mSettingsPath;
// Used to sync multiple widgets for the same field
QMap<int, QWidget*> mProxyWidgets;
QgsAttributeEditorContext mContext;
QgsVectorLayer *mLayer;
QgsFeature *mFeature;
QgsFeature* mFeature;
bool mFeatureOwner;
QgsHighlight *mHighlight;
int mFormNr;
static int smFormCounter;
bool mShowDialogButtons;
QString mReturnvarname;
static int sFormCounter;
static QString sSettingsPath;
};
#endif

View File

@ -15,18 +15,25 @@
* *
***************************************************************************/
#include "qgseditorwidgetfactory.h"
#include "qgseditorwidgetregistry.h"
#include "qgseditorwidgetwrapper.h"
#include "qgsattributedialog.h"
#include "qgsattributeeditorcontext.h"
#include "qgsattributeeditor.h"
#include <qgsvectorlayer.h>
#include <qgsvectordataprovider.h>
#include <qgscategorizedsymbolrendererv2.h>
#include <qgslonglongvalidator.h>
#include <qgsfieldvalidator.h>
#include <qgsmaplayerregistry.h>
#include <qgslogger.h>
#include <qgsexpression.h>
#include <qgsfilterlineedit.h>
#include <qgscolorbutton.h>
#include <qgsnetworkaccessmanager.h>
#include "qgscategorizedsymbolrendererv2.h"
#include "qgscolorbutton.h"
#include "qgsexpression.h"
#include "qgsfieldvalidator.h"
#include "qgsfilterlineedit.h"
#include "qgslogger.h"
#include "qgslonglongvalidator.h"
#include "qgsmaplayerregistry.h"
#include "qgsnetworkaccessmanager.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include <QScrollArea>
#include <QPushButton>
@ -265,11 +272,21 @@ QListWidget *QgsAttributeEditor::listWidget( QWidget *editor, QWidget *parent )
QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value )
{
QMap<int, QWidget*> dummyProxyWidgets;
return createAttributeEditor( parent, editor, vl, idx, value, dummyProxyWidgets );
QgsAttributeEditorContext context;
context.addProxyWidgets( vl, QMap<int, QWidget*>() );
return createAttributeEditor( parent, editor, vl, idx, value, context );
}
QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value, QMap<int, QWidget*> &proxyWidgets )
{
QgsAttributeEditorContext context;
context.addProxyWidgets( vl, proxyWidgets );
return createAttributeEditor( parent, editor, vl, idx, value, context );
}
QWidget* QgsAttributeEditor::createAttributeEditor( QWidget* parent, QWidget* editor, QgsVectorLayer* vl, int idx, const QVariant& value, QgsAttributeEditorContext& context )
{
if ( !vl )
return 0;
@ -444,6 +461,18 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *ed
}
break;
case QgsVectorLayer::EditorWidgetV2:
{
const QString& widgetType = vl->editorWidgetV2( idx );
const QgsEditorWidgetConfig widgetConfig = vl->editorWidgetV2Config( idx );
QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( widgetType, vl, idx, widgetConfig, editor, parent );
if ( eww )
myWidget = eww->widget();
}
break;
case QgsVectorLayer::Classification:
{
QMap<QString, QString> classes;
@ -658,11 +687,10 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *ed
QgsStringRelay* relay = NULL;
QMap<int, QWidget*>::const_iterator it = proxyWidgets.find( idx );
if ( it != proxyWidgets.end() )
QWidget* pwdg = context.proxyWidget( vl, idx );
if ( pwdg )
{
QObject* obj = qvariant_cast<QObject*>(( *it )->property( "QgisAttrEditProxy" ) );
relay = qobject_cast<QgsStringRelay*>( obj );
relay = pwdg->property( "QgisAttrEditProxy" ).value<QgsStringRelay*>();
}
else
{
@ -697,7 +725,7 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *ed
if ( !cb || cb->isEditable() )
{
myWidget->setProperty( "QgisAttrEditSlot", QVariant( QByteArray( wSlot ) ) );
myWidget->setProperty( "QgisAttrEditProxy", QVariant( QMetaType::QObjectStar, &relay ) );
myWidget->setProperty( "QgisAttrEditProxy", QVariant::fromValue<QgsStringRelay*>( relay ) );
}
}
}
@ -893,8 +921,7 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *ed
break;
}
QMap<int, QWidget*>::const_iterator it = proxyWidgets.find( idx );
if ( it != proxyWidgets.end() )
if ( context.proxyWidget( vl, idx ) )
{
if ( !synchronized )
{
@ -903,7 +930,7 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *ed
}
else
{
proxyWidgets.insert( idx, myWidget );
context.addProxyWidget( vl, idx, myWidget );
}
setValue( myWidget, vl, idx, value );
@ -916,6 +943,14 @@ bool QgsAttributeEditor::retrieveValue( QWidget *widget, QgsVectorLayer *vl, int
if ( !widget )
return false;
QgsEditorWidgetWrapper* wrapper = QgsEditorWidgetWrapper::fromWidget( widget );
if ( wrapper )
{
value = wrapper->value();
return true;
}
const QgsField &theField = vl->pendingFields()[idx];
QgsVectorLayer::EditType editType = vl->editType( idx );
bool modified = false;
@ -1332,12 +1367,20 @@ bool QgsAttributeEditor::setValue( QWidget *editor, QgsVectorLayer *vl, int idx,
case QgsVectorLayer::Hidden:
break;
case QgsVectorLayer::EditorWidgetV2:
QgsEditorWidgetWrapper* wrapper = QgsEditorWidgetWrapper::fromWidget( editor );
if ( wrapper )
{
wrapper->setValue( value );
}
break;
}
return true;
}
QWidget* QgsAttributeEditor::createWidgetFromDef( const QgsAttributeEditorElement* widgetDef, QWidget* parent, QgsVectorLayer* vl, QgsAttributes &attrs, QMap<int, QWidget*> &proxyWidgets, bool createGroupBox )
QWidget* QgsAttributeEditor::createWidgetFromDef( const QgsAttributeEditorElement* widgetDef, QWidget* parent, QgsVectorLayer* vl, const QgsFeature& feat, QgsAttributeEditorContext& context, QString& labelText, bool& labelOnTop )
{
QWidget *newWidget = 0;
@ -1347,7 +1390,7 @@ QWidget* QgsAttributeEditor::createWidgetFromDef( const QgsAttributeEditorElemen
{
const QgsAttributeEditorField* fieldDef = dynamic_cast<const QgsAttributeEditorField*>( widgetDef );
int fldIdx = fieldDef->idx();
newWidget = createAttributeEditor( parent, 0, vl, fldIdx, attrs.value( fldIdx, QVariant() ), proxyWidgets );
newWidget = createAttributeEditor( parent, 0, vl, fldIdx, feat.attributes().value( fldIdx, QVariant() ), context );
if ( newWidget )
{
@ -1382,7 +1425,8 @@ QWidget* QgsAttributeEditor::createWidgetFromDef( const QgsAttributeEditorElemen
}
}
}
labelOnTop = vl->labelOnTop( fieldDef->idx() );
labelText = vl->attributeDisplayName( fieldDef->idx() );
break;
}
@ -1391,7 +1435,7 @@ QWidget* QgsAttributeEditor::createWidgetFromDef( const QgsAttributeEditorElemen
const QgsAttributeEditorContainer* container = dynamic_cast<const QgsAttributeEditorContainer*>( widgetDef );
QWidget* myContainer;
if ( createGroupBox )
if ( container->isGroupBox() )
{
QGroupBox* groupBox = new QGroupBox( parent );
groupBox->setTitle( container->name() );
@ -1418,26 +1462,23 @@ QWidget* QgsAttributeEditor::createWidgetFromDef( const QgsAttributeEditorElemen
QList<QgsAttributeEditorElement*> children = container->children();
for ( QList<QgsAttributeEditorElement*>::const_iterator it = children.begin(); it != children.end(); ++it )
Q_FOREACH( QgsAttributeEditorElement* childDef, children )
{
QgsAttributeEditorElement* childDef = *it;
QWidget* editor = createWidgetFromDef( childDef, myContainer, vl, attrs, proxyWidgets, true );
QString labelText;
bool labelOnTop;
QWidget* editor = createWidgetFromDef( childDef, myContainer, vl, feat, context, labelText, labelOnTop );
if ( childDef->type() == QgsAttributeEditorElement::AeTypeContainer )
if ( labelText == QString::null )
{
gbLayout->addWidget( editor, index, 0, 1, 2 );
}
else
{
const QgsAttributeEditorField* fieldDef = dynamic_cast<const QgsAttributeEditorField*>( childDef );
//show attribute alias if available
QString myFieldName = vl->attributeDisplayName( fieldDef->idx() );
QLabel *mypLabel = new QLabel( myFieldName, myContainer );
if ( vl->labelOnTop( fieldDef->idx() ) )
QLabel* mypLabel = new QLabel( labelText );
if ( labelOnTop )
{
gbLayout->addWidget( mypLabel, index++, 0, 1, 2 );
gbLayout->addWidget( mypLabel, index, 0, 1, 2 );
++index;
gbLayout->addWidget( editor, index, 0, 1 , 2 );
}
else
@ -1451,6 +1492,8 @@ QWidget* QgsAttributeEditor::createWidgetFromDef( const QgsAttributeEditorElemen
}
gbLayout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding ), index , 0 );
labelText = QString::null;
labelOnTop = true;
break;
}

View File

@ -19,15 +19,19 @@
#include <QVariant>
#include <QMetaType>
#include <QGridLayout>
#include "qgsfeature.h"
class QObject;
class QWidget;
class QgsVectorLayer;
class QComboBox;
class QListWidget;
class QgsAttributeEditorContext;
class QgsAttributeEditorElement;
class QgsDualView;
class QgsVectorLayer;
/* \brief create attribute widget for editing */
class GUI_EXPORT QgsAttributeEditor : public QObject
@ -35,11 +39,11 @@ class GUI_EXPORT QgsAttributeEditor : public QObject
Q_OBJECT
public:
QgsAttributeEditor( QObject *parent, QgsVectorLayer *vl = 0, int idx = -1 )
QgsAttributeEditor( QObject* parent, QgsVectorLayer* vl = 0, int idx = -1 )
: QObject( parent )
, mLayer( vl )
, mIdx( idx )
{};
{}
/**
* Creates or prepares a attributre editor widget
* @param parent The parent object
@ -49,8 +53,10 @@ class GUI_EXPORT QgsAttributeEditor : public QObject
* @param value the value to initiate this widget with
* @param proxyWidgets an array of widgets, which will act as a value proxy if the same field is inserted multiple times
*
* @deprecated
*/
static QWidget *createAttributeEditor( QWidget *parent, QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value, QMap<int, QWidget*> &proxyWidgets );
static QWidget* createAttributeEditor( QWidget* parent, QWidget* editor, QgsVectorLayer* vl, int idx, const QVariant &value, QMap<int, QWidget*>& proxyWidgets );
/**
* Creates or prepares a attributre editor widget
* @param parent The parent object
@ -60,24 +66,42 @@ class GUI_EXPORT QgsAttributeEditor : public QObject
* @param value the value to initiate this widget with
*
*/
static QWidget *createAttributeEditor( QWidget *parent, QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value );
static QWidget* createAttributeEditor( QWidget* parent, QWidget* editor, QgsVectorLayer* vl, int idx, const QVariant& value );
/**
* Creates or prepares a attributre editor widget
* @param parent The parent object
* @param editor The widget to prepare. Set to null if it should be generated
* @param vl The vector layer to use as data source
* @param idx The field index this widget refers to
* @param value the value to initiate this widget with
* @param context the context used for the created attribute editor
*
*/
static QWidget* createAttributeEditor( QWidget* parent, QWidget* editor, QgsVectorLayer* vl, int idx, const QVariant& value, QgsAttributeEditorContext& context );
/**
* Creates a widget form a QgsAttributeEditorElement definition. Will recursively generate containers and widgets.
* @param widgetDef The definition for the widget
* @param parent The parent object
* @param vl The vector layer to use as data source
* @param attrs Attributes for the current feature.
* @param proxyWidgets An array of widgets, which will act as a value proxy if the same field is inserted multiple times
* @param createGroupBox If the element is a container, should a GroupBox be created to hold the children?
* @param feat The feature to create the widget for
* @param context the context used for the created attribute editor
* @param [out] labelText An optional label text will be written into the referenced QString. It will be set to
* a QString::null value if no label should be shown
* @param [out] labelOnTop Will be set to true if the label should be placed on top of the field.
* If set to false, the label should be shown left or right of the field
*
*/
static QWidget *createWidgetFromDef( const QgsAttributeEditorElement* widgetDef, QWidget* parent, QgsVectorLayer* vl, QgsAttributes &attrs, QMap<int, QWidget*> &proxyWidgets, bool createGroupBox );
static QWidget *createWidgetFromDef( const QgsAttributeEditorElement* widgetDef, QWidget* parent, QgsVectorLayer* vl, const QgsFeature &feat, QgsAttributeEditorContext& context, QString& labelText, bool& labelOnTop );
static bool retrieveValue( QWidget *widget, QgsVectorLayer *vl, int idx, QVariant &value );
static bool setValue( QWidget *widget, QgsVectorLayer *vl, int idx, const QVariant &value );
private:
static QComboBox *comboBox( QWidget *editor, QWidget *parent );
static QListWidget *listWidget( QWidget *editor, QWidget *parent );
static QgsDualView* dualView( QWidget* editor, QWidget* parent );
public slots:
void selectFileName();
@ -115,4 +139,6 @@ class GUI_EXPORT QgsStringRelay : public QObject
QList<QWidget*> mProxyList;
};
Q_DECLARE_METATYPE( QgsStringRelay* )
#endif

View File

@ -0,0 +1,42 @@
/***************************************************************************
qgsattributeeditorcontext.cpp
--------------------------------------
Date : 30.7.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsattributeeditorcontext.h"
QgsAttributeEditorContext::QgsAttributeEditorContext()
{
}
QWidget*QgsAttributeEditorContext::proxyWidget( QgsVectorLayer* vl, int fieldIdx )
{
return mProxyWidgets.value( vl ).value( fieldIdx );
}
void QgsAttributeEditorContext::addProxyWidgets( QgsVectorLayer* vl, QMap<int, QWidget*> proxyWidgets )
{
mProxyWidgets[ vl ].unite( proxyWidgets );
}
void QgsAttributeEditorContext::addProxyWidget( QgsVectorLayer* vl, int idx, QWidget* widget )
{
mProxyWidgets[ vl ].insert( idx, widget );
}
void QgsAttributeEditorContext::adjustForLayer( QgsVectorLayer* layer )
{
mDistanceArea.setSourceCrs( layer->crs() );
}

View File

@ -0,0 +1,59 @@
/***************************************************************************
qgsattributeeditorcontext.h
--------------------------------------
Date : 30.7.2013
Copyright : (C) 2013 Matthias Kuhn
Email : matthias dot kuhn at gmx dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSATTRIBUTEEDITORCONTEXT_H
#define QGSATTRIBUTEEDITORCONTEXT_H
#include <QMap>
#include <QWidget>
#include <qgsdistancearea.h>
#include <qgsvectorlayer.h>
/**
* This class contains context information for attribute editor widgets.
* It will be passed to embedded widgets whenever this occurs (e.g. when
* showing an embedded form due to relations)
*/
class GUI_EXPORT QgsAttributeEditorContext
{
public:
QgsAttributeEditorContext();
QWidget* proxyWidget( QgsVectorLayer* vl, int fieldIdx );
void addProxyWidgets( QgsVectorLayer* vl, QMap<int, QWidget*> proxyWidgets );
void addProxyWidget( QgsVectorLayer* vl, int idx, QWidget* widget );
void setDistanceArea( const QgsDistanceArea& distanceArea ) { mDistanceArea = distanceArea; }
inline const QgsDistanceArea& distanceArea() { return mDistanceArea; }
/**
* When copying the context for another layer, call this.
* Will adjast the distance area for this layer
*
* @param layer The layer to adjust for.
*/
void adjustForLayer( QgsVectorLayer* layer );
private:
//! vectorlayer => ( fieldIdx, proxyWidget )
QMap<QgsVectorLayer*, QMap<int, QWidget*> > mProxyWidgets;
QgsDistanceArea mDistanceArea;
};
#endif // QGSATTRIBUTEEDITORCONTEXT_H

View File

@ -7,23 +7,13 @@
<x>0</x>
<y>0</y>
<width>751</width>
<height>487</height>
<height>451</height>
</rect>
</property>
<property name="windowTitle">
<string>Attribute Edit Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="4" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0" rowspan="5">
<widget class="QListWidget" name="selectionListWidget">
<item>
@ -123,6 +113,16 @@
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QStackedWidget" name="stackedWidget">
<property name="sizePolicy">
@ -878,6 +878,9 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="pageEditorWidget">
<layout class="QHBoxLayout" name="horizontalLayout"/>
</widget>
</widget>
</item>
<item row="0" column="1">

View File

@ -6,32 +6,11 @@
<rect>
<x>0</x>
<y>0</y>
<width>871</width>
<height>712</height>
<width>613</width>
<height>634</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="1" column="5">
<widget class="QLabel" name="label_3">
<property name="toolTip">
<string>QGIS forms can have a Python function that is called when the form is opened.
Use this function to add extra logic to your forms.
An example is (in module MyForms.py):
def open(dialog, layer, feature):
geom = feature.geometry()
control = dialog.findChild(QWidget,&quot;MyLineEdit&quot;)
Reference in Python Init Function like so: MyForms.open
MyForms.py must live on PYTHONPATH, .qgis/python, or inside the project folder.</string>
</property>
<property name="text">
<string>Python Init function</string>
</property>
</widget>
</item>
<item row="0" column="4">
<spacer>
<property name="orientation">
@ -45,6 +24,13 @@ MyForms.py must live on PYTHONPATH, .qgis/python, or inside the project folder.<
</property>
</spacer>
</item>
<item row="0" column="5">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Attribute editor layout:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QToolButton" name="mAddAttributeButton">
<property name="sizePolicy">
@ -68,13 +54,19 @@ MyForms.py must live on PYTHONPATH, .qgis/python, or inside the project folder.<
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLineEdit" name="leEditFormInit"/>
</item>
<item row="0" column="5">
<widget class="QLabel" name="label_2">
<item row="0" column="3">
<widget class="QToolButton" name="mCalculateFieldButton">
<property name="toolTip">
<string>Field calculator</string>
</property>
<property name="whatsThis">
<string>Click to toggle table editing</string>
</property>
<property name="text">
<string>Attribute editor layout:</string>
<string/>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
@ -94,43 +86,37 @@ MyForms.py must live on PYTHONPATH, .qgis/python, or inside the project folder.<
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QComboBox" name="mEditorLayoutComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Autogenerate</string>
</property>
</item>
<item>
<property name="text">
<string>Drag and drop designer</string>
</property>
</item>
<item>
<property name="text">
<string>Provide ui-file</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0" colspan="7">
<widget class="QSplitter" name="mSplitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="mAttributesListFrame" native="true">
<widget class="QWidget" name="mRelationsAndFieldsFrame" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QWidget" name="mAttributesListFrame" native="true">
<layout class="QGridLayout" name="mAttributesListLayout">
<property name="margin">
<number>0</number>
</property>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QStackedWidget" name="mAttributeEditorOptionsWidget">
<property name="currentIndex">
@ -138,6 +124,9 @@ MyForms.py must live on PYTHONPATH, .qgis/python, or inside the project folder.<
</property>
<widget class="QWidget" name="page">
<layout class="QGridLayout" name="gridLayout_2">
<property name="margin">
<number>0</number>
</property>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
@ -175,150 +164,178 @@ MyForms.py must live on PYTHONPATH, .qgis/python, or inside the project folder.<
</layout>
</widget>
<widget class="QWidget" name="page_2">
<widget class="QWidget" name="mAttributesTreeButtonFrame" native="true">
<property name="geometry">
<rect>
<x>9</x>
<y>9</y>
<width>30</width>
<height>548</height>
</rect>
<layout class="QGridLayout" name="gridLayout_5">
<property name="horizontalSpacing">
<number>0</number>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<property name="margin">
<number>0</number>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
<item row="0" column="0">
<widget class="QWidget" name="mAttributesTreeButtonFrame" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>186</height>
</size>
<property name="margin">
<number>0</number>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="mAddTabOrGroupButton">
<property name="text">
<string>+</string>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>186</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="mAddTabOrGroupButton">
<property name="text">
<string>+</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionSignPlus.png</normaloff>:/images/themes/default/mActionSignPlus.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mRemoveTabGroupItemButton">
<property name="text">
<string>-</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionSignMinus.png</normaloff>:/images/themes/default/mActionSignMinus.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mAddItemButton">
<property name="text">
<string>&gt;</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionArrowRight.png</normaloff>:/images/themes/default/mActionArrowRight.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mMoveUpItem">
<property name="text">
<string>^</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionArrowUp.png</normaloff>:/images/themes/default/mActionArrowUp.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mMoveDownItem">
<property name="text">
<string>v</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionArrowDown.png</normaloff>:/images/themes/default/mActionArrowDown.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>176</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QWidget" name="mAttributesTreeFrame" native="true">
<property name="autoFillBackground">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="mDesignerListLayout">
<property name="margin">
<number>0</number>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionSignPlus.png</normaloff>:/images/themes/default/mActionSignPlus.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mRemoveTabGroupItemButton">
<property name="text">
<string>-</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionSignMinus.png</normaloff>:/images/themes/default/mActionSignMinus.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mAddItemButton">
<property name="text">
<string>&gt;</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionArrowRight.png</normaloff>:/images/themes/default/mActionArrowRight.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mMoveUpItem">
<property name="text">
<string>^</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionArrowUp.png</normaloff>:/images/themes/default/mActionArrowUp.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mMoveDownItem">
<property name="text">
<string>v</string>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionArrowDown.png</normaloff>:/images/themes/default/mActionArrowDown.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>176</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="mAttributesTreeFrame" native="true">
<property name="geometry">
<rect>
<x>45</x>
<y>9</y>
<width>702</width>
<height>548</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
</widget>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
<item row="0" column="3">
<widget class="QToolButton" name="mCalculateFieldButton">
<property name="toolTip">
<string>Field calculator</string>
<item row="0" column="6">
<widget class="QComboBox" name="mEditorLayoutComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="whatsThis">
<string>Click to toggle table editing</string>
<item>
<property name="text">
<string>Autogenerate</string>
</property>
</item>
<item>
<property name="text">
<string>Drag and drop designer</string>
</property>
</item>
<item>
<property name="text">
<string>Provide ui-file</string>
</property>
</item>
</widget>
</item>
<item row="1" column="5">
<widget class="QLabel" name="label_3">
<property name="toolTip">
<string>QGIS forms can have a Python function that is called when the form is opened.
Use this function to add extra logic to your forms.
An example is (in module MyForms.py):
def open(dialog, layer, feature):
geom = feature.geometry()
control = dialog.findChild(QWidget,&quot;MyLineEdit&quot;)
Reference in Python Init Function like so: MyForms.open
MyForms.py must live on PYTHONPATH, .qgis/python, or inside the project folder.</string>
</property>
<property name="text">
<string/>
</property>
<property name="checkable">
<bool>false</bool>
<string>Python Init function</string>
</property>
</widget>
</item>
@ -393,6 +410,24 @@ MyForms.py must live on PYTHONPATH, .qgis/python, or inside the project folder.<
</item>
</layout>
</item>
<item row="1" column="6">
<widget class="QLineEdit" name="leEditFormInit">
<property name="toolTip">
<string>QGIS forms can have a Python function that is called when the form is opened.
Use this function to add extra logic to your forms.
An example is (in module MyForms.py):
def open(dialog, layer, feature):
geom = feature.geometry()
control = dialog.findChild(QWidget,&quot;MyLineEdit&quot;)
Reference in Python Init Function like so: MyForms.open
MyForms.py must live on PYTHONPATH, .qgis/python, or inside the project folder.</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources>