From 6b7ad07597bd4d362e50e65859abae1f498488a9 Mon Sep 17 00:00:00 2001 From: jef Date: Tue, 10 Nov 2009 18:30:57 +0000 Subject: [PATCH] [FEATURE] customizable attribute forms using Qt Designer dialog UIs - add support for checkbox edit type and edit forms for vector layers - selection of ui file in vector layer properties (general tab) - the forms are opened when a feature is added or via identify. The widgets on the ui have to be named like the attribute they are supposed to edit or show. If the vector layer is not in editing mode, the widgets will be disabled git-svn-id: http://svn.osgeo.org/qgis/trunk@12077 c8812cc2-4d05-0410-92ff-de0c093fc19c --- python/CMakeLists.txt | 16 +- python/core/qgsvectorlayer.sip | 30 +- src/analysis/vector/qgsoverlayanalyzer.cpp | 1 - src/app/CMakeLists.txt | 2 + .../qgsattributetabledelegate.cpp | 2 +- src/app/qgsattributedialog.cpp | 215 +++++++++---- src/app/qgsattributedialog.h | 24 +- src/app/qgsattributeeditor.cpp | 296 +++++++++++++----- src/app/qgsattributeeditor.h | 6 +- src/app/qgsattributetypedialog.cpp | 17 + src/app/qgsattributetypedialog.h | 16 +- src/app/qgsidentifyresults.cpp | 158 ++++------ src/app/qgsidentifyresults.h | 9 +- src/app/qgsmaptooladdfeature.cpp | 2 +- src/app/qgsvectorlayerproperties.cpp | 31 ++ src/app/qgsvectorlayerproperties.h | 2 + src/core/qgsvectorlayer.cpp | 52 ++- src/core/qgsvectorlayer.h | 18 +- src/ui/qgsattributedialogbase.ui | 71 ----- src/ui/qgsattributetypeedit.ui | 62 +++- src/ui/qgsvectorlayerpropertiesbase.ui | 25 +- 21 files changed, 706 insertions(+), 349 deletions(-) delete mode 100644 src/ui/qgsattributedialogbase.ui diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 1442718aa9e..b7b2eb94e21 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,15 +1,15 @@ SUBDIRS(plugins) IF (WIN32) - SET(BINDINGS_CORE_LIB ${CMAKE_CURRENT_BINARY_DIR}/core/core.pyd) - SET(BINDINGS_GUI_LIB ${CMAKE_CURRENT_BINARY_DIR}/gui/gui.pyd) - SET(BINDINGS_ANALYSIS_LIB ${CMAKE_CURRENT_BINARY_DIR}/analysis/analysis.pyd) + SET(BINDINGS_CORE_LIB ${CMAKE_CURRENT_BINARY_DIR}/core/core.pyd) + SET(BINDINGS_GUI_LIB ${CMAKE_CURRENT_BINARY_DIR}/gui/gui.pyd) + SET(BINDINGS_ANALYSIS_LIB ${CMAKE_CURRENT_BINARY_DIR}/analysis/analysis.pyd) IF (NOT MSVC) SET(QGIS_CORE_LIB ${CMAKE_BINARY_DIR}/src/core/libqgis_core.dll) SET(QGIS_GUI_LIB ${CMAKE_BINARY_DIR}/src/gui/libqgis_gui.dll) SET(QGIS_ANALYSIS_LIB ${CMAKE_BINARY_DIR}/src/analysis/libqgis_analysis.dll) ELSE (NOT MSVC) - SET(QGIS_CORE_LIB ${CMAKE_BINARY_DIR}/src/core/${CMAKE_CFG_INTDIR}/qgis_core.lib) - SET(QGIS_GUI_LIB ${CMAKE_BINARY_DIR}/src/gui/${CMAKE_CFG_INTDIR}/qgis_gui.lib) + SET(QGIS_CORE_LIB ${CMAKE_BINARY_DIR}/src/core/${CMAKE_CFG_INTDIR}/qgis_core.lib) + SET(QGIS_GUI_LIB ${CMAKE_BINARY_DIR}/src/gui/${CMAKE_CFG_INTDIR}/qgis_gui.lib) SET(QGIS_ANALYSIS_LIB ${CMAKE_BINARY_DIR}/src/analysis/${CMAKE_CFG_INTDIR}/qgis_analysis.lib) ENDIF (NOT MSVC) ELSE (WIN32) @@ -60,9 +60,9 @@ ENDIF (MSVC) ADD_CUSTOM_COMMAND(OUTPUT ${BINDINGS_CORE_MAKEFILE} ${BINDINGS_GUI_MAKEFILE} ${BINDINGS_ANALYSIS_MAKEFILE} PRE_BUILD COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_CURRENT_BINARY_DIR}/configure.py ${CMAKE_CFG_INTDIR} ${EXPORT} - DEPENDS ${QGIS_CORE_LIB} ${QGIS_GUI_LIB} ${QGIS_ANALYSIS_LIB} - ${CMAKE_CURRENT_BINARY_DIR}/configure.py - ${CORE_SIP_FILES} ${GUI_SIP_FILES} ${ANALYSIS_SIP_FILES}) + DEPENDS ${QGIS_CORE_LIB} ${QGIS_GUI_LIB} ${QGIS_ANALYSIS_LIB} + ${CMAKE_CURRENT_BINARY_DIR}/configure.py + ${CORE_SIP_FILES} ${GUI_SIP_FILES} ${ANALYSIS_SIP_FILES}) # Step 3: run make in core and gui subdirs ADD_CUSTOM_COMMAND(OUTPUT ${BINDINGS_CORE_LIB} PRE_LINK diff --git a/python/core/qgsvectorlayer.sip b/python/core/qgsvectorlayer.sip index fb453f7267b..20b835fba4e 100644 --- a/python/core/qgsvectorlayer.sip +++ b/python/core/qgsvectorlayer.sip @@ -13,9 +13,10 @@ public: Classification, EditRange, SliderRange + CheckBox, /* @note added in 1.4 */ FileName, - Enumeration, - Immutable + Enumeration, /* @note added in 1.4 */ + Immutable /* @note added in 1.4 */ }; struct RangeData { @@ -130,7 +131,7 @@ public: /** Write the symbology for the layer into the docment provided. * @param QDomNode the node that will have the style element added to it. * @param QDomDocument the document that will have the QDomNode added. - * @param errorMessage reference to string that will be updated with any error messages + * @param errorMessage reference to string that will be updated with any error messages * @return true in case of success. */ bool writeSymbology(QDomNode&, QDomDocument& doc, QString& errorMessage) const; @@ -154,7 +155,7 @@ public: * @param subset The subset string. This may be the where clause of a sql statement * or other defintion string specific to the underlying dataprovider * and data store. - * @return true, when setting the string was successful, false otherwise (added in 1.4) + * @return true, when setting the string was successful, false otherwise (@note added in 1.4) */ virtual bool setSubsetString(QString subset); @@ -387,6 +388,27 @@ public: /**set edit type*/ void setEditType(int idx, EditType edit); + /** set string representing 'true' for a checkbox + @note added in 1.4 + */ + void setCheckedState( int idx, QString checked, QString notChecked ); + + /** return string representing 'true' for a checkbox + @note added in 1.4 + */ + // FIXME: need SIP binding for QPair + // QPair checkedState( int idx ); + + /** get edit form + @note added in 1.4 + */ + QString editForm(); + + /** set edit form + @note added in 1.4 + */ + void setEditForm( QString ui ); + /**access value map*/ QMap &valueMap(int idx); diff --git a/src/analysis/vector/qgsoverlayanalyzer.cpp b/src/analysis/vector/qgsoverlayanalyzer.cpp index 6cf7a5c034f..800299d1fca 100644 --- a/src/analysis/vector/qgsoverlayanalyzer.cpp +++ b/src/analysis/vector/qgsoverlayanalyzer.cpp @@ -52,7 +52,6 @@ bool QgsOverlayAnalyzer::intersection( QgsVectorLayer* layerA, QgsVectorLayer* l QgsVectorFileWriter vWriter( shapefileName, dpA->encoding(), fieldsA, outputType, &crs ); QgsFeature currentFeature; - QgsGeometry* dissolveGeometry; //dissolve geometry (if dissolve enabled) QgsSpatialIndex index; //take only selection diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 6ae99b2a4fa..6cc2d43eb94 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -251,6 +251,7 @@ INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} composer legend attributetable ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/../ui + ${QT_QTUITOOLS_INCLUDE_DIR} ../core ../core/composer ../core/raster ../core/renderer ../core/symbology ../gui @@ -295,6 +296,7 @@ TARGET_LINK_LIBRARIES(qgis ${QT_QTSVG_LIBRARY} ${QT_QTNETWORK_LIBRARY} ${QT_QTSQL_LIBRARY} + ${QT_QTUITOOLS_LIBRARY} #should only be needed for win ${QT_QTMAIN_LIBRARY} qgis_core diff --git a/src/app/attributetable/qgsattributetabledelegate.cpp b/src/app/attributetable/qgsattributetabledelegate.cpp index bd97cb8cb92..dcbe695f90f 100644 --- a/src/app/attributetable/qgsattributetabledelegate.cpp +++ b/src/app/attributetable/qgsattributetabledelegate.cpp @@ -62,7 +62,7 @@ QWidget *QgsAttributeTableDelegate::createEditor( if ( vl == NULL ) return NULL; - QWidget *widget = QgsAttributeEditor::createAttributeEditor( parent, vl, fieldIdx( index ), index.model()->data( index, Qt::EditRole ) ); + QWidget *widget = QgsAttributeEditor::createAttributeEditor( parent, 0, vl, fieldIdx( index ), index.model()->data( index, Qt::EditRole ) ); return widget; } diff --git a/src/app/qgsattributedialog.cpp b/src/app/qgsattributedialog.cpp index ae9d9964262..8e11129c0a4 100644 --- a/src/app/qgsattributedialog.cpp +++ b/src/app/qgsattributedialog.cpp @@ -30,82 +30,168 @@ #include #include #include +#include +#include +#include +#include +#include QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeature ) - : QDialog(), + : mDialog( 0 ), mSettingsPath( "/Windows/AttributeDialog/" ), mLayer( vl ), mpFeature( thepFeature ) { - setupUi( this ); if ( mpFeature == NULL || vl->dataProvider() == NULL ) return; const QgsFieldMap &theFieldMap = vl->pendingFields(); - if ( theFieldMap.isEmpty() ) return; QgsAttributeMap myAttributes = mpFeature->attributeMap(); - // - //Set up dynamic inside a scroll box - // - QVBoxLayout * mypOuterLayout = new QVBoxLayout(); - mypOuterLayout->setContentsMargins( 0, 0, 0, 0 ); - //transfers layout ownership so no need to call delete - mFrame->setLayout( mypOuterLayout ); - QScrollArea * mypScrollArea = new QScrollArea(); - //transfers scroll area ownership so no need to call delete - mypOuterLayout->addWidget( mypScrollArea ); - QFrame * mypInnerFrame = new QFrame(); - mypInnerFrame->setFrameShape( QFrame::NoFrame ); - mypInnerFrame->setFrameShadow( QFrame::Plain ); - //transfers frame ownership so no need to call delete - mypScrollArea->setWidget( mypInnerFrame ); - mypScrollArea->setWidgetResizable( true ); - QGridLayout * mypInnerLayout = new QGridLayout( mypInnerFrame ); - int index = 0; - for ( QgsAttributeMap::const_iterator it = myAttributes.begin(); - it != myAttributes.end(); - ++it ) + QDialogButtonBox *buttonBox = NULL; + + if ( !vl->editForm().isEmpty() ) { - const QgsField &field = theFieldMap[it.key()]; + QFile file( vl->editForm() ); + file.open( QFile::ReadOnly ); + QUiLoader loader; + QWidget *myWidget = loader.load( &file, NULL ); + file.close(); - //show attribute alias if available - QString myFieldName = vl->attributeDisplayName( it.key() ); - int myFieldType = field.type(); - - QWidget *myWidget = QgsAttributeEditor::createAttributeEditor( 0, vl, it.key(), it.value() ); - if ( !myWidget ) - continue; - - QLabel * mypLabel = new QLabel(); - mypInnerLayout->addWidget( mypLabel, index, 0 ); - if ( myFieldType == QVariant::Int ) - { - mypLabel->setText( myFieldName + tr( " (int)" ) ); - } - else if ( myFieldType == QVariant::Double ) - { - mypLabel->setText( myFieldName + tr( " (dbl)" ) ); - } - else //string - { - //any special behaviour for string goes here - mypLabel->setText( myFieldName + tr( " (txt)" ) ); - } - - mypInnerLayout->addWidget( myWidget, index, 1 ); - mpIndizes << it.key(); - mpWidgets << myWidget; - ++index; + mDialog = qobject_cast( myWidget ); + buttonBox = myWidget->findChild(); } - // Set focus to first widget in list, to help entering data without moving the mouse. - if ( mpWidgets.size() > 0 ) + + if ( !mDialog ) { - mpWidgets.first()->setFocus( Qt::OtherFocusReason ); + mDialog = new QDialog(); + + QGridLayout *gridLayout; + QFrame *mFrame; + + if ( mDialog->objectName().isEmpty() ) + mDialog->setObjectName( QString::fromUtf8( "QgsAttributeDialogBase" ) ); + + mDialog->resize( 447, 343 ); + gridLayout = new QGridLayout( mDialog ); + gridLayout->setSpacing( 6 ); + gridLayout->setMargin( 11 ); + gridLayout->setObjectName( QString::fromUtf8( "gridLayout" ) ); + mFrame = new QFrame( mDialog ); + mFrame->setObjectName( QString::fromUtf8( "mFrame" ) ); + mFrame->setFrameShape( QFrame::StyledPanel ); + mFrame->setFrameShadow( QFrame::Raised ); + + gridLayout->addWidget( mFrame, 0, 0, 1, 1 ); + + buttonBox = new QDialogButtonBox( mDialog ); + buttonBox->setObjectName( QString::fromUtf8( "buttonBox" ) ); + gridLayout->addWidget( buttonBox, 2, 0, 1, 1 ); + + // + //Set up dynamic inside a scroll box + // + QVBoxLayout * mypOuterLayout = new QVBoxLayout(); + mypOuterLayout->setContentsMargins( 0, 0, 0, 0 ); + //transfers layout ownership so no need to call delete + + mFrame->setLayout( mypOuterLayout ); + QScrollArea * mypScrollArea = new QScrollArea(); + //transfers scroll area ownership so no need to call delete + mypOuterLayout->addWidget( mypScrollArea ); + QFrame *mypInnerFrame = new QFrame(); + mypInnerFrame->setFrameShape( QFrame::NoFrame ); + mypInnerFrame->setFrameShadow( QFrame::Plain ); + //transfers frame ownership so no need to call delete + mypScrollArea->setWidget( mypInnerFrame ); + mypScrollArea->setWidgetResizable( true ); + QGridLayout * mypInnerLayout = new QGridLayout( mypInnerFrame ); + + int index = 0; + for ( QgsAttributeMap::const_iterator it = myAttributes.begin(); it != myAttributes.end(); ++it ) + { + const QgsField &field = theFieldMap[it.key()]; + + //show attribute alias if available + QString myFieldName = vl->attributeDisplayName( it.key() ); + int myFieldType = field.type(); + + QWidget *myWidget = QgsAttributeEditor::createAttributeEditor( 0, 0, vl, it.key(), it.value() ); + if ( !myWidget ) + continue; + + QLabel * mypLabel = new QLabel(); + mypInnerLayout->addWidget( mypLabel, index, 0 ); + if ( myFieldType == QVariant::Int ) + { + mypLabel->setText( myFieldName + tr( " (int)" ) ); + } + else if ( myFieldType == QVariant::Double ) + { + mypLabel->setText( myFieldName + tr( " (dbl)" ) ); + } + else //string + { + //any special behaviour for string goes here + mypLabel->setText( myFieldName + tr( " (txt)" ) ); + } + + myWidget->setEnabled( vl->isEditable() ); + + mypInnerLayout->addWidget( myWidget, index, 1 ); + mpIndizes << it.key(); + mpWidgets << myWidget; + ++index; + } + // Set focus to first widget in list, to help entering data without moving the mouse. + if ( mpWidgets.size() > 0 ) + { + mpWidgets.first()->setFocus( Qt::OtherFocusReason ); + } } + else + { + for ( QgsAttributeMap::const_iterator it = myAttributes.begin(); it != myAttributes.end(); ++it ) + { + const QgsField &field = theFieldMap[it.key()]; + + QWidget *myWidget = mDialog->findChild( field.name() ); + if ( !myWidget ) + continue; + + QgsAttributeEditor::createAttributeEditor( mDialog, myWidget, vl, it.key(), it.value() ); + + myWidget->setEnabled( vl->isEditable() ); + + mpIndizes << it.key(); + mpWidgets << myWidget; + } + } + + if ( buttonBox ) + { + buttonBox->clear(); + + if( vl->isEditable() ) + { + buttonBox->setStandardButtons( QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); + connect( buttonBox, SIGNAL( accepted() ), mDialog, SLOT( accept() ) ); + connect( buttonBox, SIGNAL( accepted() ), this, SLOT( accept() ) ); + } + else + { + buttonBox->setStandardButtons( QDialogButtonBox::Cancel ); + } + + connect( buttonBox, SIGNAL( rejected() ), mDialog, SLOT( reject() ) ); + connect( buttonBox, SIGNAL( rejected() ), this, SLOT( rejected() ) ); + } + + QMetaObject::connectSlotsByName( mDialog ); + restoreGeometry(); } @@ -117,12 +203,13 @@ QgsAttributeDialog::~QgsAttributeDialog() void QgsAttributeDialog::accept() { + if ( !mLayer->isEditable() ) + return; + //write the new values back to the feature QgsAttributeMap myAttributes = mpFeature->attributeMap(); int myIndex = 0; - for ( QgsAttributeMap::const_iterator it = myAttributes.begin(); - it != myAttributes.end(); - ++it ) + for ( QgsAttributeMap::const_iterator it = myAttributes.begin(); it != myAttributes.end(); ++it ) { QVariant value; @@ -132,17 +219,21 @@ void QgsAttributeDialog::accept() ++myIndex; } - QDialog::accept(); +} + +int QgsAttributeDialog::exec() +{ + return mDialog->exec(); } void QgsAttributeDialog::saveGeometry() { QSettings settings; - settings.setValue( mSettingsPath + "geometry", QDialog::saveGeometry() ); + settings.setValue( mSettingsPath + "geometry", mDialog->saveGeometry() ); } void QgsAttributeDialog::restoreGeometry() { QSettings settings; - QDialog::restoreGeometry( settings.value( mSettingsPath + "geometry" ).toByteArray() ); + mDialog->restoreGeometry( settings.value( mSettingsPath + "geometry" ).toByteArray() ); } diff --git a/src/app/qgsattributedialog.h b/src/app/qgsattributedialog.h index 54dbba0ed35..e3580e2f881 100644 --- a/src/app/qgsattributedialog.h +++ b/src/app/qgsattributedialog.h @@ -18,10 +18,7 @@ #ifndef QGSATTRIBUTEDIALOG_H #define QGSATTRIBUTEDIALOG_H -#include "ui_qgsattributedialogbase.h" - #include "qgsfeature.h" -#include class QDialog; class QgsFeature; @@ -29,7 +26,7 @@ class QLayout; class QgsField; class QgsVectorLayer; -class QgsAttributeDialog: public QDialog, private Ui::QgsAttributeDialogBase +class QgsAttributeDialog : public QObject { Q_OBJECT @@ -37,26 +34,33 @@ class QgsAttributeDialog: public QDialog, private Ui::QgsAttributeDialogBase QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature * thepFeature ); ~QgsAttributeDialog(); - /** Overloaded accept method which will write the feature field - * values, then delegate to QDialog::accept() - */ - void accept(); /** Saves the size and position for the next time * this dialog box was used. */ + void saveGeometry(); + /** Restores the size and position from the last time * this dialog box was used. */ void restoreGeometry(); + public slots: + /** Overloaded accept method which will write the feature field + * values, then delegate to QDialog::accept() + */ + void accept(); + + int exec(); + private: + + QDialog *mDialog; QString mSettingsPath; QList mpWidgets; QList mpIndizes; QgsVectorLayer *mLayer; - QgsFeature * mpFeature; - + QgsFeature *mpFeature; }; #endif diff --git a/src/app/qgsattributeeditor.cpp b/src/app/qgsattributeeditor.cpp index cd51e59cef4..54aeaf39d3d 100644 --- a/src/app/qgsattributeeditor.cpp +++ b/src/app/qgsattributeeditor.cpp @@ -24,8 +24,11 @@ #include #include +#include +#include #include #include +#include #include #include #include @@ -51,12 +54,23 @@ void QgsAttributeEditor::selectFileName( void ) le->setText( fileName ); } -QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QgsVectorLayer *vl, int idx, const QVariant &value ) +QComboBox *QgsAttributeEditor::comboBox( QWidget *editor, QWidget *parent ) +{ + QComboBox *cb = NULL; + if ( editor ) + cb = qobject_cast( editor ); + else + cb = new QComboBox( parent ); + + return cb; +} + +QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value ) { if ( !vl ) return NULL; - QWidget *myWidget; + QWidget *myWidget = NULL; QgsVectorLayer::EditType editType = vl->editType( idx ); const QgsField &field = vl->pendingFields()[idx]; QVariant::Type myFieldType = field.type(); @@ -68,13 +82,16 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QgsVectorLa QList values; vl->dataProvider()->uniqueValues( idx, values ); - QComboBox *cb = new QComboBox( parent ); - cb->setEditable( true ); + QComboBox *cb = comboBox( editor, parent ); + if ( cb ) + { + cb->setEditable( true ); - for ( QList::iterator it = values.begin(); it != values.end(); it++ ) - cb->addItem( it->toString() ); + for ( QList::iterator it = values.begin(); it != values.end(); it++ ) + cb->addItem( it->toString() ); - myWidget = cb; + myWidget = cb; + } } break; @@ -83,14 +100,17 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QgsVectorLa QStringList enumValues; vl->dataProvider()->enumValues( idx, enumValues ); - QComboBox *cb = new QComboBox( parent ); - QStringList::const_iterator s_it = enumValues.constBegin(); - for ( ; s_it != enumValues.constEnd(); ++s_it ) + QComboBox *cb = comboBox( editor, parent ); + if ( cb ) { - cb->addItem( *s_it ); - } + QStringList::const_iterator s_it = enumValues.constBegin(); + for ( ; s_it != enumValues.constEnd(); ++s_it ) + { + cb->addItem( *s_it ); + } - myWidget = cb; + myWidget = cb; + } } break; @@ -98,14 +118,16 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QgsVectorLa { const QMap &map = vl->valueMap( idx ); - QComboBox *cb = new QComboBox( parent ); - - for ( QMap::const_iterator it = map.begin(); it != map.end(); it++ ) + QComboBox *cb = comboBox( editor, parent ); + if ( cb ) { - cb->addItem( it.key(), it.value() ); - } + for ( QMap::const_iterator it = map.begin(); it != map.end(); it++ ) + { + cb->addItem( it.key(), it.value() ); + } - myWidget = cb; + myWidget = cb; + } } break; @@ -133,13 +155,16 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QgsVectorLa } } - QComboBox *cb = new QComboBox( parent ); - for ( QMap::const_iterator it = classes.begin(); it != classes.end(); it++ ) + QComboBox *cb = comboBox( editor, parent ); + if ( cb ) { - cb->addItem( it.value(), it.key() ); - } + for ( QMap::const_iterator it = classes.begin(); it != classes.end(); it++ ) + { + cb->addItem( it.value(), it.key() ); + } - myWidget = cb; + myWidget = cb; + } } break; @@ -154,35 +179,74 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QgsVectorLa if ( editType == QgsVectorLayer::EditRange ) { - QSpinBox *sb = new QSpinBox( parent ); + QSpinBox *sb = NULL; - sb->setRange( min, max ); - sb->setSingleStep( step ); + if ( editor ) + sb = qobject_cast( editor ); + else + sb = new QSpinBox( parent ); - myWidget = sb; + if ( sb ) + { + sb->setRange( min, max ); + sb->setSingleStep( step ); + + myWidget = sb; + } } else { - QSlider *sl = new QSlider( Qt::Horizontal, parent ); + QSlider *sl = NULL; - sl->setRange( min, max ); - sl->setSingleStep( step ); + if ( editor ) + sl = qobject_cast( editor ); + else + sl = new QSlider( Qt::Horizontal, parent ); - myWidget = sl; + if ( sl ) + { + sl->setRange( min, max ); + sl->setSingleStep( step ); + + myWidget = sl; + } } break; } else if ( myFieldType == QVariant::Double ) { - double min = vl->range( idx ).mMin.toDouble(); - double max = vl->range( idx ).mMax.toDouble(); - double step = vl->range( idx ).mStep.toDouble(); - QDoubleSpinBox *dsb = new QDoubleSpinBox( parent ); + QDoubleSpinBox *dsb = NULL; + if ( editor ) + dsb = qobject_cast( editor ); + else + dsb = new QDoubleSpinBox( parent ); - dsb->setRange( min, max ); - dsb->setSingleStep( step ); + if ( dsb ) + { + double min = vl->range( idx ).mMin.toDouble(); + double max = vl->range( idx ).mMax.toDouble(); + double step = vl->range( idx ).mStep.toDouble(); - myWidget = dsb; + dsb->setRange( min, max ); + dsb->setSingleStep( step ); + + myWidget = dsb; + } + break; + } + } + + case QgsVectorLayer::CheckBox: + { + QCheckBox *cb = NULL; + if ( editor ) + cb = qobject_cast( editor ); + else + cb = new QCheckBox(); + + if ( cb ) + { + myWidget = cb; break; } } @@ -191,40 +255,62 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QgsVectorLa case QgsVectorLayer::LineEdit: case QgsVectorLayer::UniqueValuesEditable: - case QgsVectorLayer::Immutable: default: { - QLineEdit *le = new QLineEdit( parent ); + QLineEdit *le = NULL; + QTextEdit *te = NULL; + QPlainTextEdit *pte = NULL; - if ( editType == QgsVectorLayer::Immutable ) + if ( editor ) { - le->setEnabled( false ); + le = qobject_cast( editor ); + te = qobject_cast( editor ); + pte = qobject_cast( editor ); + } + else + { + le = new QLineEdit( parent ); } - if ( editType == QgsVectorLayer::UniqueValuesEditable ) + if ( le ) { - QList values; - vl->dataProvider()->uniqueValues( idx, values ); - QStringList svalues; - for ( QList::const_iterator it = values.begin(); it != values.end(); it++ ) - svalues << it->toString(); + if ( editType == QgsVectorLayer::UniqueValuesEditable ) + { + QList values; + vl->dataProvider()->uniqueValues( idx, values ); - QCompleter *c = new QCompleter( svalues ); - c->setCompletionMode( QCompleter::PopupCompletion ); - le->setCompleter( c ); + QStringList svalues; + for ( QList::const_iterator it = values.begin(); it != values.end(); it++ ) + svalues << it->toString(); + + QCompleter *c = new QCompleter( svalues ); + c->setCompletionMode( QCompleter::PopupCompletion ); + le->setCompleter( c ); + } + + if ( myFieldType == QVariant::Int ) + { + le->setValidator( new QIntValidator( le ) ); + } + else if ( myFieldType == QVariant::Double ) + { + le->setValidator( new QDoubleValidator( le ) ); + } + + myWidget = le; + } + + if( te ) + { + te->setAcceptRichText(true); + myWidget = te; } - if ( myFieldType == QVariant::Int ) + if( pte ) { - le->setValidator( new QIntValidator( le ) ); + myWidget = pte; } - else if ( myFieldType == QVariant::Double ) - { - le->setValidator( new QDoubleValidator( le ) ); - } - - myWidget = le; } break; @@ -234,21 +320,43 @@ QWidget *QgsAttributeEditor::createAttributeEditor( QWidget *parent, QgsVectorLa case QgsVectorLayer::FileName: { - QLineEdit *le = new QLineEdit(); + QPushButton *pb = NULL; + QLineEdit *le = qobject_cast( editor ); + if ( le ) + { + if ( le ) + myWidget = le; - QPushButton *pb = new QPushButton( tr( "..." ) ); - connect( pb, SIGNAL( clicked() ), new QgsAttributeEditor( pb ), SLOT( selectFileName() ) ); + if( editor->parent() ) + { + pb = editor->parent()->findChild(); + } + } + else + { + le = new QLineEdit(); - QHBoxLayout *hbl = new QHBoxLayout(); - hbl->addWidget( le ); - hbl->addWidget( pb ); + QPushButton *pb = new QPushButton( tr( "..." ) ); - myWidget = new QWidget( parent ); - myWidget->setLayout( hbl ); + QHBoxLayout *hbl = new QHBoxLayout(); + hbl->addWidget( le ); + hbl->addWidget( pb ); + + myWidget = new QWidget( parent ); + myWidget->setLayout( hbl ); + } + + if ( pb ) + connect( pb, SIGNAL( clicked() ), new QgsAttributeEditor( pb ), SLOT( selectFileName() ) ); } break; } + if ( editType == QgsVectorLayer::Immutable ) + { + myWidget->setEnabled( false ); + } + setValue( myWidget, vl, idx, value ); return myWidget; @@ -275,6 +383,28 @@ bool QgsAttributeEditor::retrieveValue( QWidget *widget, QgsVectorLayer *vl, int } } + QTextEdit *te = qobject_cast( widget ); + if ( te ) + { + text = te->toHtml(); + modified = te->document()->isModified(); + if( text == "NULL" ) + { + text = QString::null; + } + } + + QPlainTextEdit *pte = qobject_cast( widget ); + if ( pte ) + { + text = pte->toPlainText(); + modified = pte->document()->isModified(); + if( text == "NULL" ) + { + text = QString::null; + } + } + QComboBox *cb = qobject_cast( widget ); if ( cb ) { @@ -301,12 +431,20 @@ bool QgsAttributeEditor::retrieveValue( QWidget *widget, QgsVectorLayer *vl, int { text = QString::number( slider->value() ); } + QDoubleSpinBox *dsb = qobject_cast( widget ); if ( dsb ) { text = QString::number( dsb->value() ); } + QCheckBox *ckb = qobject_cast( widget ); + if ( ckb ) + { + QPair states = vl->checkedState( idx ); + text = ckb->isChecked() ? states.first : states.second; + } + le = widget->findChild(); if ( le ) { @@ -411,6 +549,17 @@ bool QgsAttributeEditor::setValue( QWidget *editor, QgsVectorLayer *vl, int idx, } } + case QgsVectorLayer::CheckBox: + { + QCheckBox *cb = qobject_cast( editor ); + if( cb ) + { + QPair states = vl->checkedState( idx ); + cb->setChecked( value == states.first ); + break; + } + } + // fall-through case QgsVectorLayer::LineEdit: @@ -419,7 +568,9 @@ bool QgsAttributeEditor::setValue( QWidget *editor, QgsVectorLayer *vl, int idx, default: { QLineEdit *le = qobject_cast( editor ); - if ( le == NULL ) + QTextEdit *te = qobject_cast( editor ); + QPlainTextEdit *pte = qobject_cast( editor ); + if ( !le && !te && !pte ) return false; QString text; @@ -431,7 +582,12 @@ bool QgsAttributeEditor::setValue( QWidget *editor, QgsVectorLayer *vl, int idx, else text = value.toString(); - le->setText( text ); + if( le ) + le->setText( text ); + if( te ) + te->setHtml( text ); + if( pte ) + pte->setPlainText( text ); } break; diff --git a/src/app/qgsattributeeditor.h b/src/app/qgsattributeeditor.h index ffe9ccb72dc..22e6130e459 100644 --- a/src/app/qgsattributeeditor.h +++ b/src/app/qgsattributeeditor.h @@ -23,6 +23,7 @@ class QObject; class QWidget; class QgsVectorLayer; +class QComboBox; class QgsAttributeEditor : public QObject { @@ -30,10 +31,13 @@ class QgsAttributeEditor : public QObject public: QgsAttributeEditor( QObject *parent ) : QObject( parent ) {} - static QWidget *createAttributeEditor( QWidget *parent, QgsVectorLayer *vl, int idx, const QVariant &value ); + static QWidget *createAttributeEditor( QWidget *parent, QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value ); 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 ); + public slots: void selectFileName( void ); }; diff --git a/src/app/qgsattributetypedialog.cpp b/src/app/qgsattributetypedialog.cpp index 137218c7087..0e3b1bb9850 100644 --- a/src/app/qgsattributetypedialog.cpp +++ b/src/app/qgsattributetypedialog.cpp @@ -66,6 +66,16 @@ QMap &QgsAttributeTypeDialog::valueMap() return mValueMap; } +QPair QgsAttributeTypeDialog::checkedState() +{ + return QPair( leCheckedState->text(), leUncheckedState->text() ); +} + +void QgsAttributeTypeDialog::setCheckedState( QString checked, QString unchecked ) +{ + leCheckedState->setText( checked ); + leUncheckedState->setText( unchecked ); +} void QgsAttributeTypeDialog::vCellChanged( int row, int column ) { @@ -235,6 +245,10 @@ void QgsAttributeTypeDialog::setPageForEditType( QgsVectorLayer::EditType editTy setPage( 8 ); break; + case QgsVectorLayer::CheckBox: + setPage( 9 ); + break; + case QgsVectorLayer::LineEdit: setPage( 0 ); break; @@ -513,6 +527,9 @@ void QgsAttributeTypeDialog::accept() case 8: mEditType = QgsVectorLayer::Hidden; break; + case 9: + mEditType = QgsVectorLayer::CheckBox; + break; default: mEditType = QgsVectorLayer::LineEdit; } diff --git a/src/app/qgsattributetypedialog.h b/src/app/qgsattributetypedialog.h index 70a01da7dc9..a9a0c433c6a 100644 --- a/src/app/qgsattributetypedialog.h +++ b/src/app/qgsattributetypedialog.h @@ -66,11 +66,23 @@ class QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttributeTypeDialog void setValueMap( QMap valueMap ); /** - * Setter to range for to be displayed and edited in this dialog - * @param rangeData rande data which is to be displayed + * Setter to range to be displayed and edited in this dialog + * @param rangeData range data which is to be displayed */ void setRange( QgsVectorLayer::RangeData rangeData ); + /** + * Setter to checked state to be displayed and edited in this dialog + * @param checked string that represents the checked state + */ + void setCheckedState( QString checked, QString unchecked ); + + /** + * Getter for checked state after editing + * @return string representing the checked + */ + QPair checkedState(); + /** * Getter for value map after editing * @return map which is to be returned diff --git a/src/app/qgsidentifyresults.cpp b/src/app/qgsidentifyresults.cpp index f6b7bea8ee2..9409c0fcaf0 100644 --- a/src/app/qgsidentifyresults.cpp +++ b/src/app/qgsidentifyresults.cpp @@ -147,8 +147,8 @@ void QgsIdentifyResults::addFeature( QgsMapLayer *layer, int fid, { connect( vlayer, SIGNAL( layerDeleted() ), this, SLOT( layerDestroyed() ) ); connect( vlayer, SIGNAL( featureDeleted( int ) ), this, SLOT( featureDeleted( int ) ) ); - connect( vlayer, SIGNAL( editingStarted() ), this, SLOT( addEditAction() ) ); - connect( vlayer, SIGNAL( editingStopped() ), this, SLOT( removeEditAction() ) ); + connect( vlayer, SIGNAL( editingStarted() ), this, SLOT( editingToggled() ) ); + connect( vlayer, SIGNAL( editingStopped() ), this, SLOT( editingToggled() ) ); } else { @@ -176,24 +176,22 @@ void QgsIdentifyResults::addFeature( QgsMapLayer *layer, int fid, } } - if ( vlayer && ( vlayer->actions()->size() > 0 || vlayer->isEditable() ) ) + if ( vlayer ) { QTreeWidgetItem *actionItem = new QTreeWidgetItem( QStringList() << tr( "(Actions)" ) ); actionItem->setData( 0, Qt::UserRole, "actions" ); featItem->addChild( actionItem ); - QTreeWidgetItem *twi; - - if ( vlayer->isEditable() ) - { - addEditAction( actionItem ); - } + QTreeWidgetItem *editItem = new QTreeWidgetItem( QStringList() << "" << (vlayer->isEditable() ? tr( "Edit feature form" ) : tr( "View feature form" ) ) ); + editItem->setIcon( 0, QgisApp::getThemeIcon( vlayer->isEditable() ? "/mIconEditable.png" : "/mIconEditable.png" ) ); + editItem->setData( 0, Qt::UserRole, "edit" ); + actionItem->addChild( editItem ); for ( int i = 0; i < vlayer->actions()->size(); i++ ) { QgsAttributeAction::aIter iter = vlayer->actions()->retrieveAction( i ); - twi = new QTreeWidgetItem( QStringList() << "" << iter->name() ); + QTreeWidgetItem *twi = new QTreeWidgetItem( QStringList() << "" << iter->name() ); twi->setIcon( 0, QgisApp::getThemeIcon( "/mAction.png" ) ); twi->setData( 0, Qt::UserRole, "action" ); twi->setData( 0, Qt::UserRole + 1, QVariant::fromValue( i ) ); @@ -204,6 +202,40 @@ void QgsIdentifyResults::addFeature( QgsMapLayer *layer, int fid, layItem->addChild( featItem ); } +void QgsIdentifyResults::editingToggled() +{ + QTreeWidgetItem *layItem = layerItem( sender() ); + QgsVectorLayer *vlayer = vectorLayer( layItem ); + if( !layItem || !vlayer ) + return; + + // iterate features + int i; + for( i=0; ichildCount(); i++ ) + { + QTreeWidgetItem *featItem = layItem->child(i); + + int j; + for( j=0; jchildCount() && featItem->child(j)->data( 0, Qt::UserRole ).toString() != "actions"; j++ ) + QgsDebugMsg( QString("%1: skipped %2").arg( featItem->child(j)->data( 0, Qt::UserRole ).toString() ) ); + + if( j==featItem->childCount() || featItem->child(j)->childCount()<1 ) + continue; + + QTreeWidgetItem *actions = featItem->child(j); + + for( j=0; ichildCount() && actions->child(j)->data( 0, Qt::UserRole ).toString() != "edit"; j++ ) + ; + + if( j==actions->childCount() ) + continue; + + QTreeWidgetItem *editItem = actions->child(j); + editItem->setIcon( 0, QgisApp::getThemeIcon( vlayer->isEditable() ? "/mIconEditable.png" : "/mIconEditable.png" ) ); + editItem->setText( 1, vlayer->isEditable() ? tr( "Edit feature form" ) : tr( "View feature form" ) ); + } +} + // Call to show the dialog box. void QgsIdentifyResults::show() { @@ -223,13 +255,10 @@ void QgsIdentifyResults::show() { highlightFeature( featItem ); - if ( layer->isEditable() ) - { - // if this is the only feature, it's on a vector layer and that layer is editable: - // don't show the edit dialog instead of the results window - editFeature( featItem ); - return; - } + // if this is the only feature and it's on a vector layer + // don't show the form dialog instead of the results window + featureForm( featItem ); + return; } } @@ -240,6 +269,7 @@ void QgsIdentifyResults::show() QDialog::show(); } + // Slot called when user clicks the Close button // (saves the current window size/position) void QgsIdentifyResults::close() @@ -247,6 +277,7 @@ void QgsIdentifyResults::close() saveWindowLocation(); done( 0 ); } + // Save the current window size/position before closing // from window menu or X in titlebar void QgsIdentifyResults::closeEvent( QCloseEvent *e ) @@ -256,83 +287,11 @@ void QgsIdentifyResults::closeEvent( QCloseEvent *e ) close(); } -void QgsIdentifyResults::addEditAction( QTreeWidgetItem *item ) -{ - QTreeWidgetItem *editItem = new QTreeWidgetItem( QStringList() << "" << tr( "Edit feature" ) ); - editItem->setIcon( 0, QgisApp::getThemeIcon( "/mIconEditable.png" ) ); - editItem->setData( 0, Qt::UserRole, "edit" ); - item->addChild( editItem ); -} - -void QgsIdentifyResults::addOrRemoveEditAction( bool addItem ) -{ - QTreeWidgetItem *layItem = layerItem( sender() ); - - for ( int i = 0; i < layItem->childCount(); i++ ) - { - QTreeWidgetItem *featItem = layItem->child( i ); - QTreeWidgetItem *actionsItem = 0; - - for ( int j = 0; j < featItem->childCount(); j++ ) - { - QTreeWidgetItem *attrItem = featItem->child( j ); - - if ( attrItem->childCount() == 0 || attrItem->data( 0, Qt::UserRole ).toString() != "actions" ) - continue; - - actionsItem = attrItem; - break; - } - - if ( addItem ) - { - if ( !actionsItem ) - { - actionsItem = new QTreeWidgetItem( QStringList() << tr( "(Actions)" ) ); - actionsItem->setData( 0, Qt::UserRole, "actions" ); - featItem->addChild( actionsItem ); - } - - addEditAction( actionsItem ); - } - else if ( actionsItem ) - { - for ( int k = 0; k < actionsItem->childCount(); k++ ) - { - QTreeWidgetItem *editItem = actionsItem->child( k ); - if ( editItem->data( 0, Qt::UserRole ).toString() != "edit" ) - continue; - - delete editItem; - - if ( actionsItem->childCount() == 0 ) - delete actionsItem; - - break; - } - } - else - { - QgsDebugMsg( "actions item not found" ); - } - } -} - -void QgsIdentifyResults::addEditAction() -{ - addOrRemoveEditAction( true ); -} - -void QgsIdentifyResults::removeEditAction() -{ - addOrRemoveEditAction( false ); -} - void QgsIdentifyResults::itemClicked( QTreeWidgetItem *item, int column ) { if ( item->data( 0, Qt::UserRole ).toString() == "edit" ) { - editFeature( item ); + featureForm( item ); } else if ( item->data( 0, Qt::UserRole ).toString() == "action" ) { @@ -362,12 +321,9 @@ void QgsIdentifyResults::contextMenuEvent( QContextMenuEvent* event ) QAction *a; - if ( vlayer->isEditable() ) - { - a = mActionPopup->addAction( tr( "Edit feature" ) ); - a->setEnabled( true ); - a->setData( QVariant::fromValue( -6 ) ); - } + a = mActionPopup->addAction( vlayer->isEditable() ? tr( "Edit feature form" ) : tr( "View feature form" ) ); + a->setEnabled( true ); + a->setData( QVariant::fromValue( -6 ) ); a = mActionPopup->addAction( tr( "Zoom to feature" ) ); a->setEnabled( true ); @@ -454,7 +410,7 @@ void QgsIdentifyResults::popupItemSelected( QAction* menuAction ) switch ( action ) { case -6: - editFeature( item ); + featureForm( item ); break; case -5: @@ -694,8 +650,8 @@ void QgsIdentifyResults::disconnectLayer( QObject *layer ) { disconnect( vlayer, SIGNAL( layerDeleted() ), this, SLOT( layerDestroyed() ) ); disconnect( vlayer, SIGNAL( featureDeleted( int ) ), this, SLOT( featureDeleted( int ) ) ); - disconnect( vlayer, SIGNAL( editingStarted() ), this, SLOT( addEditAction() ) ); - disconnect( vlayer, SIGNAL( editingStopped() ), this, SLOT( removeEditAction() ) ); + disconnect( vlayer, SIGNAL( editingStarted() ), this, SLOT( changeEditAction() ) ); + disconnect( vlayer, SIGNAL( editingStopped() ), this, SLOT( changeEditAction() ) ); } else { @@ -810,10 +766,10 @@ void QgsIdentifyResults::zoomToFeature( QTreeWidgetItem *item ) } -void QgsIdentifyResults::editFeature( QTreeWidgetItem *item ) +void QgsIdentifyResults::featureForm( QTreeWidgetItem *item ) { QgsVectorLayer *layer = vectorLayer( item ); - if ( !layer || !layer->isEditable() ) + if ( !layer ) return; QTreeWidgetItem *featItem = featureItem( item ); diff --git a/src/app/qgsidentifyresults.h b/src/app/qgsidentifyresults.h index 3b0d0ce90ca..f558361089a 100644 --- a/src/app/qgsidentifyresults.h +++ b/src/app/qgsidentifyresults.h @@ -80,7 +80,7 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase void popupItemSelected( QAction* menuAction ); void layerDestroyed(); - + void editingToggled(); void featureDeleted( int fid ); //! Context help @@ -96,9 +96,6 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase /* Item in tree was clicked */ void itemClicked( QTreeWidgetItem *lvi, int column ); - void addEditAction(); - void removeEditAction(); - private: QMenu *mActionPopup; QgsVectorLayer *mRubberBandLayer; @@ -113,8 +110,6 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase QTreeWidgetItem *layerItem( QObject *layer ); QTreeWidgetItem *retrieveAttributes( QTreeWidgetItem *item, std::vector< std::pair > &attributes ); void clearRubberBand(); - void addEditAction( QTreeWidgetItem * ); - void addOrRemoveEditAction( bool addItem ); void disconnectLayer( QObject *object ); void setColumnText( int column, const QString & label ); @@ -124,7 +119,7 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase void highlightFeature( QTreeWidgetItem *item ); void zoomToFeature( QTreeWidgetItem *item ); - void editFeature( QTreeWidgetItem *item ); + void featureForm( QTreeWidgetItem *item ); void doAction( QTreeWidgetItem *item, int action ); diff --git a/src/app/qgsmaptooladdfeature.cpp b/src/app/qgsmaptooladdfeature.cpp index 9f76291ba0d..17b5fe8748d 100644 --- a/src/app/qgsmaptooladdfeature.cpp +++ b/src/app/qgsmaptooladdfeature.cpp @@ -189,7 +189,7 @@ void QgsMapToolAddFeature::canvasReleaseEvent( QMouseEvent * e ) } else { - QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f ); + QgsAttributeDialog *mypDialog = new QgsAttributeDialog( vlayer, f ); if ( mypDialog->exec() ) { QgsDebugMsg( "Adding feature to layer" ); diff --git a/src/app/qgsvectorlayerproperties.cpp b/src/app/qgsvectorlayerproperties.cpp index 2c1719bc263..7e59a58f536 100644 --- a/src/app/qgsvectorlayerproperties.cpp +++ b/src/app/qgsvectorlayerproperties.cpp @@ -125,6 +125,8 @@ QgsVectorLayerProperties::QgsVectorLayerProperties( leSpatialRefSys->setText( layer->srs().toProj4() ); leSpatialRefSys->setCursorPosition( 0 ); + leEditForm->setText( layer->editForm() ); + connect( sliderTransparency, SIGNAL( valueChanged( int ) ), this, SLOT( sliderTransparency_valueChanged( int ) ) ); //for each overlay plugin create a new tab @@ -236,6 +238,11 @@ void QgsVectorLayerProperties::attributeTypeDialog( ) attributeTypeDialog.setIndex( index ); } + if ( mCheckedStates.contains( index ) ) + { + attributeTypeDialog.setCheckedState( mCheckedStates[index].first, mCheckedStates[index].second ); + } + if ( !attributeTypeDialog.exec() ) return; @@ -253,6 +260,8 @@ void QgsVectorLayerProperties::attributeTypeDialog( ) case QgsVectorLayer::SliderRange: mRanges.insert( index, attributeTypeDialog.rangeData() ); break; + case QgsVectorLayer::CheckBox: + mCheckedStates.insert( index, attributeTypeDialog.checkedState() ); default: break; } @@ -550,6 +559,7 @@ void QgsVectorLayerProperties::setupEditTypes() editTypeMap.insert( QgsVectorLayer::Enumeration, tr( "Enumeration" ) ); editTypeMap.insert( QgsVectorLayer::Immutable, tr( "Immutable" ) ); editTypeMap.insert( QgsVectorLayer::Hidden, tr( "Hidden" ) ); + editTypeMap.insert( QgsVectorLayer::CheckBox, tr( "Checkbox" ) ); } QString QgsVectorLayerProperties::editTypeButtonText( QgsVectorLayer::EditType type ) @@ -586,6 +596,8 @@ void QgsVectorLayerProperties::apply() // update the display field layer->setDisplayField( displayFieldComboBox->currentText() ); + layer->setEditForm( leEditForm->text() ); + actionDialog->apply(); labelDialog->apply(); @@ -620,6 +632,13 @@ void QgsVectorLayerProperties::apply() layer->range( idx ) = mRanges[idx]; } } + else if ( editType == QgsVectorLayer::CheckBox ) + { + if ( mCheckedStates.contains( idx ) ) + { + layer->setCheckedState( idx, mCheckedStates[idx].first, mCheckedStates[idx].second ); + } + } } QgsSingleSymbolDialog *sdialog = @@ -1053,6 +1072,18 @@ void QgsVectorLayerProperties::on_mCalculateFieldButton_clicked() calc.exec(); } +void QgsVectorLayerProperties::on_pbnSelectEditForm_clicked() +{ + QSettings myQSettings; + QString lastUsedDir = myQSettings.value( "style/lastUIDir", "." ).toString(); + QString uifilename = QFileDialog::getOpenFileName( this, tr( "Select edit form" ), lastUsedDir, tr( "UI file (*.ui)" ) ); + + if ( uifilename.isNull() ) + return; + + leEditForm->setText( uifilename ); +} + QList QgsVectorLayerProperties::overlayPlugins() const { QList pluginList; diff --git a/src/app/qgsvectorlayerproperties.h b/src/app/qgsvectorlayerproperties.h index 2eaeeac6125..7fe0a61637b 100644 --- a/src/app/qgsvectorlayerproperties.h +++ b/src/app/qgsvectorlayerproperties.h @@ -102,6 +102,7 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope void on_pbnSaveStyleAs_clicked(); void on_tblAttributes_cellChanged( int row, int column ); void on_mCalculateFieldButton_clicked(); + void on_pbnSelectEditForm_clicked(); void addAttribute(); void deleteAttribute(); @@ -145,6 +146,7 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope QMap mEditTypeMap; QMap > mValueMaps; QMap mRanges; + QMap > mCheckedStates; void updateButtons(); void loadRows(); diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index 0716c61739c..63e1e087a21 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -1128,7 +1128,7 @@ bool QgsVectorLayer::setSubsetString( QString subset ) void QgsVectorLayer::updateFeatureAttributes( QgsFeature &f ) { // do not update when we aren't in editing mode - if ( ! mEditable ) + if ( !mEditable ) return; if ( mChangedAttributeValues.contains( f.id() ) ) @@ -2357,9 +2357,20 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage mRanges[ name ] = RangeData( min, max, step ); } + else if( editType == CheckBox ) + { + mCheckedStates[ name ] = QPair( editTypeElement.attribute( "checked" ), editTypeElement.attribute( "unchecked" ) ); + } } } + QDomNode editFormNode = node.namedItem( "editform" ); + if ( !editFormNode.isNull() ) + { + QDomElement e = editFormNode.toElement(); + mEditForm = e.text(); + } + mAttributeAliasMap.clear(); QDomNode aliasesNode = node.namedItem( "aliases" ); if ( !aliasesNode.isNull() ) @@ -2504,6 +2515,14 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString& editTypeElement.setAttribute( "step", mRanges[ it.key()].mStep.toString() ); } } + else if ( it.value() == CheckBox ) + { + if ( mCheckedStates.contains( it.key() ) ) + { + editTypeElement.setAttribute( "checked", mCheckedStates[ it.key()].first ); + editTypeElement.setAttribute( "unchecked", mCheckedStates[ it.key()].second ); + } + } editTypesElement.appendChild( editTypeElement ); } @@ -2511,6 +2530,11 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString& node.appendChild( editTypesElement ); } + QDomElement efField = doc.createElement( "editform" ); + QDomText efText = doc.createTextNode( mEditForm ); + efField.appendChild( efText ); + node.appendChild( efField ); + //attribute aliases if ( mAttributeAliasMap.size() > 0 ) { @@ -3708,6 +3732,16 @@ void QgsVectorLayer::setEditType( int idx, EditType type ) mEditTypes[ fields[idx].name()] = type; } +QString QgsVectorLayer::editForm() +{ + return mEditForm; +} + +void QgsVectorLayer::setEditForm( QString ui ) +{ + mEditForm = ui; +} + QMap< QString, QVariant > &QgsVectorLayer::valueMap( int idx ) { const QgsFieldMap &fields = pendingFields(); @@ -4091,3 +4125,19 @@ void QgsVectorLayer::undoEditCommand( QgsUndoCommand* cmd ) // it's not ideal to trigger refresh from here triggerRepaint(); } + +void QgsVectorLayer::setCheckedState( int idx, QString checked, QString unchecked ) +{ + const QgsFieldMap &fields = pendingFields(); + if ( fields.contains( idx ) ) + mCheckedStates[ fields[idx].name() ] = QPair( checked, unchecked ); +} + +QPair QgsVectorLayer::checkedState( int idx ) +{ + const QgsFieldMap &fields = pendingFields(); + if ( fields.contains( idx ) && mCheckedStates.contains( fields[idx].name() ) ) + return mCheckedStates[ fields[idx].name() ]; + else + return QPair( "1", "0" ); +} diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index 937811b65b7..e027b2dcc7b 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -53,9 +53,6 @@ typedef QSet QgsFeatureIds; typedef QSet QgsAttributeIds; - - - /** \ingroup core * Vector layer backed by a data source provider. */ @@ -73,6 +70,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer Classification, EditRange, SliderRange, + CheckBox, /* added in 1.4 */ FileName, Enumeration, Immutable, /*The attribute value should not be changed in the attribute form*/ @@ -450,6 +448,18 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer /**set edit type*/ void setEditType( int idx, EditType edit ); + + /** set string representing 'true' for a checkbox (added in 1.4) */ + void setCheckedState( int idx, QString checked, QString notChecked ); + + /** return string representing 'true' for a checkbox (added in 1.4) */ + QPair checkedState( int idx ); + + /** get edit form (added in 1.4) */ + QString editForm(); + + /** set edit form (added in 1.4) */ + void setEditForm( QString ui ); /**access value map*/ QMap &valueMap( int idx ); @@ -719,6 +729,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer QMap< QString, EditType > mEditTypes; QMap< QString, QMap > mValueMaps; QMap< QString, RangeData > mRanges; + QMap< QString, QPair > mCheckedStates; + QString mEditForm; bool mFetching; QgsRectangle mFetchRect; diff --git a/src/ui/qgsattributedialogbase.ui b/src/ui/qgsattributedialogbase.ui deleted file mode 100644 index d8bf52d8a9d..00000000000 --- a/src/ui/qgsattributedialogbase.ui +++ /dev/null @@ -1,71 +0,0 @@ - - QgsAttributeDialogBase - - - - 0 - 0 - 447 - 343 - - - - Enter Attribute Values - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok - - - - - - - - - - buttonBox - accepted() - QgsAttributeDialogBase - accept() - - - 277 - 318 - - - 325 - 279 - - - - - buttonBox - rejected() - QgsAttributeDialogBase - reject() - - - 208 - 308 - - - 163 - 284 - - - - - diff --git a/src/ui/qgsattributetypeedit.ui b/src/ui/qgsattributetypeedit.ui index e3c42362223..0028382e1bc 100644 --- a/src/ui/qgsattributetypeedit.ui +++ b/src/ui/qgsattributetypeedit.ui @@ -6,7 +6,7 @@ 0 0 - 401 + 471 428 @@ -61,12 +61,23 @@ Hidden + + + Checkbox + + + + + 0 + 0 + + - 0 + 9 @@ -486,6 +497,53 @@ + + + + 453 + 333 + + + + + + + + + + + + Representation for checked state + + + + + + + Representation for unchecked state + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + diff --git a/src/ui/qgsvectorlayerpropertiesbase.ui b/src/ui/qgsvectorlayerpropertiesbase.ui index 8df14d432b2..87e8323dbf6 100644 --- a/src/ui/qgsvectorlayerpropertiesbase.ui +++ b/src/ui/qgsvectorlayerpropertiesbase.ui @@ -94,7 +94,7 @@ QTabWidget::Rounded - 0 + 3 @@ -410,21 +410,21 @@ - + true - + Create Spatial Index - + Specify the coordinate reference system of the layer's geometry. @@ -437,6 +437,23 @@ + + + + Edit UI + + + + + + + + + + ... + + +