[QGIS Commit] r15155 - in trunk/qgis: . images
images/themes/default/propertyicons src/app
src/app/attributetable src/core src/core/symbology-ng
src/providers/ogr src/providers/postgres
src/providers/spatialite src/ui
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Fri Feb 11 11:23:17 EST 2011
Author: mhugent
Date: 2011-02-11 08:23:17 -0800 (Fri, 11 Feb 2011)
New Revision: 15155
Added:
trunk/qgis/images/themes/default/propertyicons/join.png
trunk/qgis/src/app/qgsaddjoindialog.cpp
trunk/qgis/src/app/qgsaddjoindialog.h
trunk/qgis/src/core/qgsvectorlayerjoinbuffer.cpp
trunk/qgis/src/core/qgsvectorlayerjoinbuffer.h
trunk/qgis/src/ui/qgsaddjoindialogbase.ui
Modified:
trunk/qgis/
trunk/qgis/images/images.qrc
trunk/qgis/src/app/CMakeLists.txt
trunk/qgis/src/app/attributetable/qgsattributetablemodel.cpp
trunk/qgis/src/app/qgsvectorlayerproperties.cpp
trunk/qgis/src/app/qgsvectorlayerproperties.h
trunk/qgis/src/core/CMakeLists.txt
trunk/qgis/src/core/qgsdataprovider.h
trunk/qgis/src/core/qgsproject.cpp
trunk/qgis/src/core/qgsvectordataprovider.cpp
trunk/qgis/src/core/qgsvectordataprovider.h
trunk/qgis/src/core/qgsvectorlayer.cpp
trunk/qgis/src/core/qgsvectorlayer.h
trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
trunk/qgis/src/providers/ogr/qgsogrprovider.cpp
trunk/qgis/src/providers/ogr/qgsogrprovider.h
trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
trunk/qgis/src/providers/postgres/qgspostgresprovider.h
trunk/qgis/src/providers/spatialite/qgsspatialiteprovider.cpp
trunk/qgis/src/providers/spatialite/qgsspatialiteprovider.h
trunk/qgis/src/ui/qgsvectorlayerpropertiesbase.ui
Log:
[FEATURE]: experimental table join support refactored and ported from branch to trunk
Property changes on: trunk/qgis
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/symbology-ng-branch:10769-12136
+ /branches/symbology-ng-branch:10769-12136
/branches/table_join_branch:13934-14132
Modified: trunk/qgis/images/images.qrc
===================================================================
--- trunk/qgis/images/images.qrc 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/images/images.qrc 2011-02-11 16:23:17 UTC (rev 15155)
@@ -269,6 +269,7 @@
<file>themes/default/propertyicons/digitising.png</file>
<file>themes/default/propertyicons/general.png</file>
<file>themes/default/propertyicons/histogram.png</file>
+ <file>themes/default/propertyicons/join.png</file>
<file>themes/default/propertyicons/labels.png</file>
<file>themes/default/propertyicons/locale.png</file>
<file>themes/default/propertyicons/map_tools.png</file>
Copied: trunk/qgis/images/themes/default/propertyicons/join.png (from rev 14132, branches/table_join_branch/images/themes/default/propertyicons/join.png)
===================================================================
(Binary files differ)
Modified: trunk/qgis/src/app/CMakeLists.txt
===================================================================
--- trunk/qgis/src/app/CMakeLists.txt 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/app/CMakeLists.txt 2011-02-11 16:23:17 UTC (rev 15155)
@@ -4,6 +4,7 @@
qgisappinterface.cpp
qgsabout.cpp
qgsaddattrdialog.cpp
+ qgsaddjoindialog.cpp
qgsannotationwidget.cpp
qgsattributeactiondialog.cpp
qgsattributedialog.cpp
@@ -144,6 +145,7 @@
qgsabout.h
qgsaddattrdialog.h
qgsdisplayangle.h
+ qgsaddjoindialog.h
qgsannotationwidget.h
qgsattributeactiondialog.h
qgsattributedialog.h
Modified: trunk/qgis/src/app/attributetable/qgsattributetablemodel.cpp
===================================================================
--- trunk/qgis/src/app/attributetable/qgsattributetablemodel.cpp 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/app/attributetable/qgsattributetablemodel.cpp 2011-02-11 16:23:17 UTC (rev 15155)
@@ -234,7 +234,7 @@
rect = QgisApp::instance()->mapCanvas()->extent();
}
- mLayer->select( mAttributes, rect, false );
+ mLayer->select( QgsAttributeList(), rect, false );
QgsFeature f;
for ( int i = 0; mLayer->nextFeature( f ); ++i )
Copied: trunk/qgis/src/app/qgsaddjoindialog.cpp (from rev 14132, branches/table_join_branch/src/app/qgsaddjoindialog.cpp)
===================================================================
--- trunk/qgis/src/app/qgsaddjoindialog.cpp (rev 0)
+++ trunk/qgis/src/app/qgsaddjoindialog.cpp 2011-02-11 16:23:17 UTC (rev 15155)
@@ -0,0 +1,137 @@
+/***************************************************************************
+ qgsaddjoindialog.cpp
+ --------------------
+ begin : July 10, 2010
+ copyright : (C) 2010 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole 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 "qgsaddjoindialog.h"
+#include "qgsmaplayer.h"
+#include "qgsmaplayerregistry.h"
+#include "qgsvectordataprovider.h"
+#include "qgsvectorlayer.h"
+
+QgsAddJoinDialog::QgsAddJoinDialog( QgsVectorLayer* layer, QWidget * parent, Qt::WindowFlags f ): QDialog( parent, f ), mLayer( layer )
+{
+ setupUi( this );
+
+ if ( !mLayer )
+ {
+ return;
+ }
+
+ //insert possible vector layers into mJoinLayerComboBox
+
+ mJoinLayerComboBox->blockSignals( true );
+ const QMap<QString, QgsMapLayer*>& layerList = QgsMapLayerRegistry::instance()->mapLayers();
+ QMap<QString, QgsMapLayer*>::const_iterator layerIt = layerList.constBegin();
+ for ( ; layerIt != layerList.constEnd(); ++layerIt )
+ {
+ QgsMapLayer* currentLayer = layerIt.value();
+ if ( currentLayer->type() == QgsMapLayer::VectorLayer )
+ {
+ QgsVectorLayer* currentVectorLayer = dynamic_cast<QgsVectorLayer*>( currentLayer );
+ if ( currentVectorLayer && currentVectorLayer != mLayer )
+ {
+ if ( currentVectorLayer->dataProvider() && currentVectorLayer->dataProvider()->supportsSubsetString() )
+ mJoinLayerComboBox->addItem( currentLayer->name(), QVariant( currentLayer->getLayerID() ) );
+ }
+ }
+ }
+ mJoinLayerComboBox->blockSignals( false );
+ on_mJoinLayerComboBox_currentIndexChanged( mJoinLayerComboBox->currentIndex() );
+
+ //insert possible target fields
+ const QgsFieldMap& layerFieldMap = mLayer->pendingFields();
+ QgsFieldMap::const_iterator fieldIt = layerFieldMap.constBegin();
+ for ( ; fieldIt != layerFieldMap.constEnd(); ++fieldIt )
+ {
+ mTargetFieldComboBox->addItem( fieldIt.value().name(), fieldIt.key() );
+ }
+
+ mCacheInMemoryCheckBox->setChecked( true );
+}
+
+QgsAddJoinDialog::~QgsAddJoinDialog()
+{
+}
+
+QString QgsAddJoinDialog::joinedLayerId() const
+{
+ return mJoinLayerComboBox->itemData( mJoinLayerComboBox->currentIndex() ).toString();
+}
+
+int QgsAddJoinDialog::joinField() const
+{
+ return mJoinFieldComboBox->itemData( mJoinFieldComboBox->currentIndex() ).toInt();
+}
+
+QString QgsAddJoinDialog::joinFieldName() const
+{
+ return mJoinFieldComboBox->itemText( mJoinFieldComboBox->currentIndex() );
+}
+
+int QgsAddJoinDialog::targetField() const
+{
+ return mTargetFieldComboBox->itemData( mTargetFieldComboBox->currentIndex() ).toInt();
+}
+
+QString QgsAddJoinDialog::targetFieldName() const
+{
+ return mTargetFieldComboBox->itemText( mTargetFieldComboBox->currentIndex() );
+}
+
+bool QgsAddJoinDialog::cacheInMemory() const
+{
+ return mCacheInMemoryCheckBox->isChecked();
+}
+
+bool QgsAddJoinDialog::createAttributeIndex() const
+{
+ return mCreateIndexCheckBox->isChecked();
+}
+
+void QgsAddJoinDialog::on_mJoinLayerComboBox_currentIndexChanged( int index )
+{
+ mJoinFieldComboBox->clear();
+ QString layerId = mJoinLayerComboBox->itemData( index ).toString();
+ QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerId );
+ if ( !layer )
+ {
+ return;
+ }
+ QgsVectorLayer* vLayer = dynamic_cast<QgsVectorLayer*>( layer );
+ if ( !vLayer )
+ {
+ return;
+ }
+
+ const QgsFieldMap& layerFieldMap = vLayer->pendingFields();
+ QgsFieldMap::const_iterator fieldIt = layerFieldMap.constBegin();
+ for ( ; fieldIt != layerFieldMap.constEnd(); ++fieldIt )
+ {
+ mJoinFieldComboBox->addItem( fieldIt.value().name(), fieldIt.key() );
+ }
+
+ //does provider support creation of attribute indices?
+ QgsVectorDataProvider* dp = vLayer->dataProvider();
+ if ( dp && ( dp->capabilities() & QgsVectorDataProvider::CreateAttributeIndex ) )
+ {
+ mCreateIndexCheckBox->setEnabled( true );
+ }
+ else
+ {
+ mCreateIndexCheckBox->setEnabled( false );
+ mCreateIndexCheckBox->setChecked( false );
+ }
+}
Copied: trunk/qgis/src/app/qgsaddjoindialog.h (from rev 14132, branches/table_join_branch/src/app/qgsaddjoindialog.h)
===================================================================
--- trunk/qgis/src/app/qgsaddjoindialog.h (rev 0)
+++ trunk/qgis/src/app/qgsaddjoindialog.h 2011-02-11 16:23:17 UTC (rev 15155)
@@ -0,0 +1,57 @@
+/***************************************************************************
+ qgsaddjoindialog.h
+ ------------------
+ begin : July 10, 2010
+ copyright : (C) 2010 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole 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 QGSADDJOINDIALOG_H
+#define QGSADDJOINDIALOG_H
+
+#include "ui_qgsaddjoindialogbase.h"
+class QgsVectorLayer;
+
+class QgsAddJoinDialog: public QDialog, private Ui::QgsAddJoinDialogBase
+{
+ Q_OBJECT
+ public:
+ QgsAddJoinDialog( QgsVectorLayer* layer, QWidget * parent = 0, Qt::WindowFlags f = 0 );
+ ~QgsAddJoinDialog();
+
+ //retrieve results
+
+ /**Get the id of the layer to join*/
+ QString joinedLayerId() const;
+ /**Returns the index of the join field*/
+ int joinField() const;
+ /**Returns the name of the join field*/
+ QString joinFieldName() const;
+ /**Returns the index of the target field (join-to field)*/
+ int targetField() const;
+ /**Returns the name of the target field (join-to field)*/
+ QString targetFieldName() const;
+ /**True if joined layer should be cached in virtual memory*/
+ bool cacheInMemory() const;
+ /**Returns true if user wants to create an attribute index on the join field*/
+ bool createAttributeIndex() const;
+
+ private slots:
+ void on_mJoinLayerComboBox_currentIndexChanged( int index );
+
+ private:
+ /**Target layer*/
+ QgsVectorLayer* mLayer;
+};
+
+
+#endif // QGSADDJOINDIALOG_H
Modified: trunk/qgis/src/app/qgsvectorlayerproperties.cpp
===================================================================
--- trunk/qgis/src/app/qgsvectorlayerproperties.cpp 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/app/qgsvectorlayerproperties.cpp 2011-02-11 16:23:17 UTC (rev 15155)
@@ -21,6 +21,7 @@
#include <limits>
#include "qgisapp.h"
+#include "qgsaddjoindialog.h"
#include "qgsapplication.h"
#include "qgsattributeactiondialog.h"
#include "qgsapplydialog.h"
@@ -33,6 +34,7 @@
#include "qgslabel.h"
#include "qgsgenericprojectionselector.h"
#include "qgslogger.h"
+#include "qgsmaplayerregistry.h"
#include "qgspluginmetadata.h"
#include "qgspluginregistry.h"
#include "qgsproject.h"
@@ -133,6 +135,13 @@
connect( sliderTransparency, SIGNAL( valueChanged( int ) ), this, SLOT( sliderTransparency_valueChanged( int ) ) );
+ //insert existing join info
+ const QList< QgsVectorJoinInfo >& joins = layer->vectorJoins();
+ for ( int i = 0; i < joins.size(); ++i )
+ {
+ addJoinToTreeWidget( joins[i] );
+ }
+
//for each overlay plugin create a new tab
int position;
QList<QgsVectorOverlayPlugin*> overlayPluginList = overlayPlugins();
@@ -813,7 +822,6 @@
{
xMin = QString( "%1" ).arg( myExtent.xMinimum() );
}
-
if ( qAbs( myExtent.yMinimum() ) > changeoverValue )
{
yMin = QString( "%1" ).arg( myExtent.yMinimum(), 0, 'f', 2 );
@@ -822,7 +830,6 @@
{
yMin = QString( "%1" ).arg( myExtent.yMinimum() );
}
-
if ( qAbs( myExtent.xMaximum() ) > changeoverValue )
{
xMax = QString( "%1" ).arg( myExtent.xMaximum(), 0, 'f', 2 );
@@ -831,7 +838,6 @@
{
xMax = QString( "%1" ).arg( myExtent.xMaximum() );
}
-
if ( qAbs( myExtent.yMaximum() ) > changeoverValue )
{
yMax = QString( "%1" ).arg( myExtent.yMaximum(), 0, 'f', 2 );
@@ -1171,6 +1177,70 @@
updateSymbologyPage();
}
+void QgsVectorLayerProperties::on_mButtonAddJoin_clicked()
+{
+ QgsAddJoinDialog d( layer );
+ if ( d.exec() == QDialog::Accepted )
+ {
+ QgsVectorJoinInfo info;
+ info.targetField = d.targetField();
+ info.joinLayerId = d.joinedLayerId();
+ info.joinField = d.joinField();
+ info.memoryCache = d.cacheInMemory();
+ if ( layer )
+ {
+ //create attribute index if possible. Todo: ask user if this should be done (e.g. in QgsAddJoinDialog)
+ if ( d.createAttributeIndex() )
+ {
+ QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( info.joinLayerId ) );
+ if ( joinLayer )
+ {
+ joinLayer->dataProvider()->createAttributeIndex( info.joinField );
+ }
+ }
+
+ layer->addJoin( info );
+ loadRows(); //update attribute tab
+ addJoinToTreeWidget( info );
+ }
+ }
+}
+
+void QgsVectorLayerProperties::addJoinToTreeWidget( const QgsVectorJoinInfo& join )
+{
+ QTreeWidgetItem* joinItem = new QTreeWidgetItem();
+
+ QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join.joinLayerId ) );
+ if ( !joinLayer )
+ {
+ return;
+ }
+
+ joinItem->setText( 0, joinLayer->name() );
+ joinItem->setData( 0, Qt::UserRole, join.joinLayerId );
+ QString joinFieldName = joinLayer->pendingFields().value( join.joinField ).name();
+ QString targetFieldName = layer->pendingFields().value( join.targetField ).name();
+ joinItem->setText( 1, joinFieldName );
+ joinItem->setData( 1, Qt::UserRole, join.joinField );
+ joinItem->setText( 2, targetFieldName );
+ joinItem->setData( 2, Qt::UserRole, join.targetField );
+
+ mJoinTreeWidget->addTopLevelItem( joinItem );
+}
+
+void QgsVectorLayerProperties::on_mButtonRemoveJoin_clicked()
+{
+ QTreeWidgetItem* currentJoinItem = mJoinTreeWidget->currentItem();
+ if ( !layer || !currentJoinItem )
+ {
+ return;
+ }
+
+ layer->removeJoin( currentJoinItem->data( 0, Qt::UserRole ).toString() );
+ loadRows();
+ mJoinTreeWidget->takeTopLevelItem( mJoinTreeWidget->indexOfTopLevelItem( currentJoinItem ) );
+}
+
void QgsVectorLayerProperties::useNewSymbology()
{
int res = QMessageBox::question( this, tr( "Symbology" ),
Modified: trunk/qgis/src/app/qgsvectorlayerproperties.h
===================================================================
--- trunk/qgis/src/app/qgsvectorlayerproperties.h 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/app/qgsvectorlayerproperties.h 2011-02-11 16:23:17 UTC (rev 15155)
@@ -117,6 +117,9 @@
void useNewSymbology();
void setUsingNewSymbology( bool useNewSymbology );
+ void on_mButtonAddJoin_clicked();
+ void on_mButtonRemoveJoin_clicked();
+
signals:
/** emitted when changes to layer were saved to update legend */
@@ -171,6 +174,9 @@
/**Buffer pixmap which takes the picture of renderers before they are assigned to the vector layer*/
//QPixmap bufferPixmap;
+ /**Adds a new join to mJoinTreeWidget*/
+ void addJoinToTreeWidget( const QgsVectorJoinInfo& join );
+
static QMap< QgsVectorLayer::EditType, QString > editTypeMap;
static void setupEditTypes();
static QString editTypeButtonText( QgsVectorLayer::EditType type );
Modified: trunk/qgis/src/core/CMakeLists.txt
===================================================================
--- trunk/qgis/src/core/CMakeLists.txt 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/core/CMakeLists.txt 2011-02-11 16:23:17 UTC (rev 15155)
@@ -89,6 +89,7 @@
qgsvectordataprovider.cpp
qgsvectorfilewriter.cpp
qgsvectorlayer.cpp
+ qgsvectorlayerjoinbuffer.cpp
qgsvectorlayerundocommand.cpp
qgsvectoroverlay.cpp
Modified: trunk/qgis/src/core/qgsdataprovider.h
===================================================================
--- trunk/qgis/src/core/qgsdataprovider.h 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/core/qgsdataprovider.h 2011-02-11 16:23:17 UTC (rev 15155)
@@ -113,7 +113,7 @@
* that can be used by the data provider to create a subset.
* Must be implemented in the dataprovider.
*/
- virtual bool setSubsetString( QString subset )
+ virtual bool setSubsetString( QString subset, bool updateFeatureCount = true )
{
// NOP by default
Q_UNUSED( subset );
Modified: trunk/qgis/src/core/qgsproject.cpp
===================================================================
--- trunk/qgis/src/core/qgsproject.cpp 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/core/qgsproject.cpp 2011-02-11 16:23:17 UTC (rev 15155)
@@ -675,6 +675,7 @@
bool returnStatus = true;
emit layerLoaded( 0, nl.count() );
+ QList<QgsVectorLayer*> vLayerList; //collect
for ( int i = 0; i < nl.count(); i++ )
{
@@ -714,6 +715,11 @@
if ( mapLayer->readXML( node ) )
{
mapLayer = QgsMapLayerRegistry::instance()->addMapLayer( mapLayer );
+ QgsVectorLayer* vLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
+ if ( vLayer )
+ {
+ vLayerList.push_back( vLayer );
+ }
}
else
{
@@ -725,10 +731,18 @@
brokenNodes.push_back( node );
}
-
emit layerLoaded( i + 1, nl.count() );
}
+ //Update field map of layers with joins and create join caches if necessary
+ //Needs to be done here once all dependent layers are loaded
+ QList<QgsVectorLayer*>::iterator vIt = vLayerList.begin();
+ for ( ; vIt != vLayerList.end(); ++vIt )
+ {
+ ( *vIt )->createJoinCaches();
+ ( *vIt )->updateFieldMap();
+ }
+
return qMakePair( returnStatus, brokenNodes );
} // _getMapLayers
Modified: trunk/qgis/src/core/qgsvectordataprovider.cpp
===================================================================
--- trunk/qgis/src/core/qgsvectordataprovider.cpp 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/core/qgsvectordataprovider.cpp 2011-02-11 16:23:17 UTC (rev 15155)
@@ -126,6 +126,11 @@
return false;
}
+bool QgsVectorDataProvider::createAttributeIndex( int field )
+{
+ return true;
+}
+
int QgsVectorDataProvider::capabilities() const
{
return QgsVectorDataProvider::NoCapabilities;
Modified: trunk/qgis/src/core/qgsvectordataprovider.h
===================================================================
--- trunk/qgis/src/core/qgsvectordataprovider.h 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/core/qgsvectordataprovider.h 2011-02-11 16:23:17 UTC (rev 15155)
@@ -74,6 +74,7 @@
RandomSelectGeometryAtId = 1 << 10,
/** DEPRECATED - do not use */
SequentialSelectGeometryAtId = 1 << 11,
+ CreateAttributeIndex = 1 << 12
};
/** bitmask of all provider's editing capabilities */
@@ -272,6 +273,9 @@
*/
virtual bool createSpatialIndex();
+ /**Create an attribute index on the datasource*/
+ virtual bool createAttributeIndex( int field );
+
/** Returns a bitmask containing the supported capabilities
Note, some capabilities may change depending on whether
a spatial filter is active on this provider, so it may
Modified: trunk/qgis/src/core/qgsvectorlayer.cpp
===================================================================
--- trunk/qgis/src/core/qgsvectorlayer.cpp 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/core/qgsvectorlayer.cpp 2011-02-11 16:23:17 UTC (rev 15155)
@@ -68,6 +68,7 @@
#include "qgssinglesymbolrenderer.h"
#include "qgscoordinatereferencesystem.h"
#include "qgsvectordataprovider.h"
+#include "qgsvectorlayerjoinbuffer.h"
#include "qgsvectorlayerundocommand.h"
#include "qgsvectoroverlay.h"
#include "qgsmaplayerregistry.h"
@@ -110,7 +111,8 @@
mLabel( 0 ),
mLabelOn( false ),
mVertexMarkerOnlyForSelection( false ),
- mFetching( false )
+ mFetching( false ),
+ mJoinBuffer( 0 )
{
mActions = new QgsAttributeAction( this );
@@ -154,6 +156,11 @@
}
}
+ mJoinBuffer = new QgsVectorLayerJoinBuffer();
+
+ connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( checkJoinLayerRemove( QString ) ) );
+ updateFieldMap();
+
// Get the update threshold from user settings. We
// do this only on construction to avoid the penality of
// fetching this each time the layer is drawn. If the user
@@ -175,13 +182,9 @@
mValid = false;
- if ( mRenderer )
- {
- delete mRenderer;
- }
- // delete the provider object
+ delete mRenderer;
delete mDataProvider;
-
+ delete mJoinBuffer;
delete mLabel;
// Destroy any cached geometries and clear the references to them
@@ -1500,6 +1503,14 @@
void QgsVectorLayer::updateFeatureAttributes( QgsFeature &f, bool all )
{
+ if ( mDataProvider && ( all || ( mFetchAttributes.size() > 0 && mJoinBuffer->containsFetchJoins() ) ) )
+ {
+ int index = 0;
+ maxIndex( mDataProvider->fields(), index );
+ mJoinBuffer->updateFeatureAttributes( f, index, all );
+ }
+
+
// do not update when we aren't in editing mode
if ( !mEditable )
return;
@@ -1523,6 +1534,73 @@
f.changeAttribute( it.key(), QVariant( QString::null ) );
}
+void QgsVectorLayer::addJoinedFeatureAttributes( QgsFeature& f, const QgsVectorJoinInfo& joinInfo, const QString& joinFieldName,
+ const QVariant& joinValue, const QgsAttributeList& attributes, int attributeIndexOffset )
+{
+ const QHash< QString, QgsAttributeMap>& memoryCache = joinInfo.cachedAttributes;
+ if ( !memoryCache.isEmpty() ) //use join memory cache
+ {
+ QgsAttributeMap featureAttributes = memoryCache.value( joinValue.toString() );
+ bool found = !featureAttributes.isEmpty();
+ QgsAttributeList::const_iterator attIt = attributes.constBegin();
+ for ( ; attIt != attributes.constEnd(); ++attIt )
+ {
+ if ( found )
+ {
+ f.addAttribute( *attIt + attributeIndexOffset, featureAttributes.value( *attIt ) );
+ }
+ else
+ {
+ f.addAttribute( *attIt + attributeIndexOffset, QVariant() );
+ }
+ }
+ }
+ else //work with subset string
+ {
+ QgsVectorLayer* joinLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo.joinLayerId ) );
+ if ( !joinLayer )
+ {
+ return;
+ }
+
+ //no memory cache, query the joined values by setting substring
+ QString subsetString = joinLayer->dataProvider()->subsetString(); //provider might already have a subset string
+ QString bkSubsetString = subsetString;
+ if ( !subsetString.isEmpty() )
+ {
+ subsetString.append( " AND " );
+ }
+
+ subsetString.append( "\"" + joinFieldName + "\"" + " = " + "\"" + joinValue.toString() + "\"" );
+ joinLayer->dataProvider()->setSubsetString( subsetString, false );
+
+ //select (no geometry)
+ joinLayer->select( attributes, QgsRectangle(), false, false );
+
+ //get first feature
+ QgsFeature fet;
+ if ( joinLayer->nextFeature( fet ) )
+ {
+ QgsAttributeMap attMap = fet.attributeMap();
+ QgsAttributeMap::const_iterator attIt = attMap.constBegin();
+ for ( ; attIt != attMap.constEnd(); ++attIt )
+ {
+ f.addAttribute( attIt.key() + attributeIndexOffset, attIt.value() );
+ }
+ }
+ else //no suitable join feature found, insert invalid variants
+ {
+ QgsAttributeList::const_iterator attIt = attributes.constBegin();
+ for ( ; attIt != attributes.constEnd(); ++attIt )
+ {
+ f.addAttribute( *attIt + attributeIndexOffset, QVariant() );
+ }
+ }
+
+ joinLayer->dataProvider()->setSubsetString( bkSubsetString, false );
+ }
+}
+
void QgsVectorLayer::updateFeatureGeometry( QgsFeature &f )
{
if ( mChangedGeometries.contains( f.id() ) )
@@ -1539,8 +1617,8 @@
mFetchRect = rect;
mFetchAttributes = attributes;
mFetchGeometry = fetchGeometries;
-
mFetchConsidered = mDeletedFeatureIds;
+ QgsAttributeList targetJoinFieldList;
if ( mEditable )
{
@@ -1551,24 +1629,44 @@
//look in the normal features of the provider
if ( mFetchAttributes.size() > 0 )
{
- if ( mEditable )
+ if ( mEditable || mJoinBuffer->containsJoins() )
{
- // fetch only available field from provider
+ QgsAttributeList joinFields;
+
+ int maxProviderIndex = 0;
+ if ( mDataProvider )
+ {
+ maxIndex( mDataProvider->fields(), maxProviderIndex );
+ }
+
+ mJoinBuffer->select( mFetchAttributes, joinFields, maxProviderIndex );
+ QgsAttributeList::const_iterator joinFieldIt = joinFields.constBegin();
+ for ( ; joinFieldIt != joinFields.constEnd(); ++joinFieldIt )
+ {
+ if ( !mFetchAttributes.contains( *joinFieldIt ) )
+ {
+ mFetchAttributes.append( *joinFieldIt );
+ }
+ }
+
+ //detect which fields are from the provider
mFetchProvAttributes.clear();
for ( QgsAttributeList::iterator it = mFetchAttributes.begin(); it != mFetchAttributes.end(); it++ )
{
- if ( !mUpdatedFields.contains( *it ) || mAddedAttributeIds.contains( *it ) )
- continue;
-
- mFetchProvAttributes << *it;
+ if ( mDataProvider->fields().contains( *it ) )
+ {
+ mFetchProvAttributes << *it;
+ }
}
mDataProvider->select( mFetchProvAttributes, rect, fetchGeometries, useIntersect );
}
else
+ {
mDataProvider->select( mFetchAttributes, rect, fetchGeometries, useIntersect );
+ }
}
- else
+ else //we don't need any attributes at all
{
mDataProvider->select( QgsAttributeList(), rect, fetchGeometries, useIntersect );
}
@@ -1617,6 +1715,7 @@
{
found = true;
f.setAttributeMap( it->attributeMap() );
+ updateFeatureAttributes( f );
break;
}
}
@@ -1678,12 +1777,13 @@
while ( dataProvider()->nextFeature( f ) )
{
if ( mFetchConsidered.contains( f.id() ) )
+ {
continue;
-
- if ( mEditable )
- updateFeatureAttributes( f );
-
- // found it
+ }
+ if ( mFetchAttributes.size() > 0 )
+ {
+ updateFeatureAttributes( f ); //check joined attributes / changed attributes
+ }
return true;
}
@@ -2501,10 +2601,10 @@
mEditable = true;
- mUpdatedFields = mDataProvider->fields();
+ mAddedAttributeIds.clear();
+ mDeletedAttributeIds.clear();
+ updateFieldMap();
- mMaxUpdatedIndex = -1;
-
for ( QgsFieldMap::const_iterator it = mUpdatedFields.begin(); it != mUpdatedFields.end(); it++ )
if ( it.key() > mMaxUpdatedIndex )
mMaxUpdatedIndex = it.key();
@@ -2561,12 +2661,21 @@
}
}
+ //load vector joins
+ if ( !mJoinBuffer )
+ {
+ mJoinBuffer = new QgsVectorLayerJoinBuffer();
+ }
+ mJoinBuffer->readXml( layer_node );
+
QString errorMsg;
if ( !readSymbology( layer_node, errorMsg ) )
{
return false;
}
+ updateFieldMap();
+
return mValid; // should be true if read successfully
} // void QgsVectorLayer::readXml
@@ -2706,6 +2815,9 @@
layer_node.appendChild( provider );
}
+ //save joins
+ mJoinBuffer->writeXml( layer_node, document );
+
// renderer specific settings
QString errorMsg;
return writeSymbology( layer_node, document, errorMsg );
@@ -3236,12 +3348,12 @@
const QgsFieldMap &QgsVectorLayer::pendingFields() const
{
- return isEditable() ? mUpdatedFields : mDataProvider->fields();
+ return mUpdatedFields;
}
QgsAttributeList QgsVectorLayer::pendingAllAttributesList()
{
- return isEditable() ? mUpdatedFields.keys() : mDataProvider->attributeIndexes();
+ return mUpdatedFields.keys();
}
int QgsVectorLayer::pendingFeatureCount()
@@ -3302,9 +3414,12 @@
if ( mAddedAttributeIds.size() > 0 )
{
QList<QgsField> addedAttributes;
- for ( QgsAttributeIds::const_iterator it = mAddedAttributeIds.begin(); it != mAddedAttributeIds.end(); it++ )
- addedAttributes << mUpdatedFields[ *it ];
+ for ( QgsAttributeIds::const_iterator it = mAddedAttributeIds.constBegin(); it != mAddedAttributeIds.constEnd(); it++ )
+ {
+ addedAttributes << mUpdatedFields[*it];
+ }
+
if (( cap & QgsVectorDataProvider::AddAttributes ) && mDataProvider->addAttributes( addedAttributes ) )
{
mCommitErrors << tr( "SUCCESS: %n attribute(s) added.", "added attributes count", mAddedAttributeIds.size() );
@@ -3350,7 +3465,7 @@
// (otherwise we'll loose updates when doing the remapping)
if ( mAddedAttributeIds.size() > 0 )
{
- for ( QgsAttributeIds::const_iterator it = mAddedAttributeIds.begin(); it != mAddedAttributeIds.end(); it++ )
+ for ( QgsAttributeIds::const_iterator it = mAddedAttributeIds.constBegin(); it != mAddedAttributeIds.constEnd(); it++ )
{
QString name = mUpdatedFields[ *it ].name();
if ( dst.contains( name ) )
@@ -3532,13 +3647,11 @@
{
mEditable = false;
setModified( false );
-
- mUpdatedFields.clear();
- mMaxUpdatedIndex = -1;
undoStack()->clear();
emit editingStopped();
}
+ updateFieldMap();
mDataProvider->updateExtents();
triggerRepaint();
@@ -3590,9 +3703,7 @@
// Roll back deleted features
mDeletedFeatureIds.clear();
- // clear private field map
- mUpdatedFields.clear();
- mMaxUpdatedIndex = -1;
+ updateFieldMap();
}
deleteCachedGeometries();
@@ -3643,6 +3754,7 @@
QgsFeatureList features;
QgsAttributeList allAttrs = mDataProvider->attributeIndexes();
+ mFetchAttributes = pendingAllAttributesList();
for ( QgsFeatureIds::iterator it = mSelectedFeatureIds.begin(); it != mSelectedFeatureIds.end(); ++it )
{
@@ -4728,6 +4840,99 @@
return -1;
}
+void QgsVectorLayer::addJoin( QgsVectorJoinInfo joinInfo )
+{
+ mJoinBuffer->addJoin( joinInfo );
+ updateFieldMap();
+}
+
+void QgsVectorLayer::checkJoinLayerRemove( QString theLayerId )
+{
+ removeJoin( theLayerId );
+}
+
+void QgsVectorLayer::removeJoin( const QString& joinLayerId )
+{
+ mJoinBuffer->removeJoin( joinLayerId );
+ updateFieldMap();
+}
+
+const QList< QgsVectorJoinInfo >& QgsVectorLayer::vectorJoins() const
+{
+ return mJoinBuffer->vectorJoins();
+}
+
+void QgsVectorLayer::updateFieldMap()
+{
+ //first backup mAddedAttributes
+ QgsFieldMap bkAddedAttributes;
+ QgsAttributeIds::const_iterator attIdIt = mAddedAttributeIds.constBegin();
+ for ( ; attIdIt != mAddedAttributeIds.constEnd(); ++attIdIt )
+ {
+ bkAddedAttributes.insert( *attIdIt, mUpdatedFields.value( *attIdIt ) );
+ }
+
+ mUpdatedFields = QgsFieldMap();
+ if ( mDataProvider )
+ {
+ mUpdatedFields = mDataProvider->fields();
+ }
+
+ int currentMaxIndex = 0; //maximum index of current layer
+ if ( !maxIndex( mUpdatedFields, currentMaxIndex ) )
+ {
+ return;
+ }
+
+ mMaxUpdatedIndex = currentMaxIndex;
+
+ //joined fields
+ if ( mJoinBuffer->containsJoins() )
+ {
+ mJoinBuffer->updateFieldMap( mUpdatedFields, mMaxUpdatedIndex );
+ }
+
+ //insert added attributes after provider fields and joined fields
+ mAddedAttributeIds.clear();
+ QgsFieldMap::const_iterator fieldIt = bkAddedAttributes.constBegin();
+ for ( ; fieldIt != bkAddedAttributes.constEnd(); ++fieldIt )
+ {
+ ++mMaxUpdatedIndex;
+ mUpdatedFields.insert( mMaxUpdatedIndex, fieldIt.value() );
+ mAddedAttributeIds.insert( mMaxUpdatedIndex );
+
+ //go through the changed attributes map and adapt indices of added attributes
+ for ( int i = 0; i < mChangedAttributeValues.size(); ++i )
+ {
+ updateAttributeMapIndex( mChangedAttributeValues[i], fieldIt.key(), mMaxUpdatedIndex );
+ }
+
+ //go through added features and adapt attribute maps
+ QgsFeatureList::iterator featureIt = mAddedFeatures.begin();
+ for ( ; featureIt != mAddedFeatures.end(); ++featureIt )
+ {
+ QgsAttributeMap attMap = featureIt->attributeMap();
+ updateAttributeMapIndex( attMap, fieldIt.key(), mMaxUpdatedIndex );
+ featureIt->setAttributeMap( attMap );
+ }
+ }
+
+ //remove deleted attributes
+ QgsAttributeIds::const_iterator deletedIt = mDeletedAttributeIds.constBegin();
+ for ( ; deletedIt != mDeletedAttributeIds.constEnd(); ++deletedIt )
+ {
+ mUpdatedFields.remove( *deletedIt );
+ }
+}
+
+void QgsVectorLayer::createJoinCaches()
+{
+ if ( mJoinBuffer->containsJoins() )
+ {
+ mJoinBuffer->createJoinCaches();
+ }
+}
+
void QgsVectorLayer::stopRendererV2( QgsRenderContext& rendererContext, QgsSingleSymbolRendererV2* selRenderer )
{
mRendererV2->stopRender( rendererContext );
@@ -4737,3 +4942,27 @@
delete selRenderer;
}
}
+
+bool QgsVectorLayer::maxIndex( const QgsFieldMap& fMap, int& index ) const
+{
+ if ( fMap.size() < 1 )
+ {
+ return false;
+ }
+ QgsFieldMap::const_iterator endIt = fMap.constEnd();
+ --endIt;
+ index = endIt.key();
+ return true;
+}
+
+void QgsVectorLayer::updateAttributeMapIndex( QgsAttributeMap& map, int oldIndex, int newIndex ) const
+{
+ QgsAttributeMap::const_iterator it = map.find( oldIndex );
+ if ( it == map.constEnd() )
+ {
+ return;
+ }
+
+ map.insert( newIndex, it.value() );
+ map.remove( oldIndex );
+}
Modified: trunk/qgis/src/core/qgsvectorlayer.h
===================================================================
--- trunk/qgis/src/core/qgsvectorlayer.h 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/core/qgsvectorlayer.h 2011-02-11 16:23:17 UTC (rev 15155)
@@ -30,6 +30,7 @@
#include "qgssnapper.h"
#include "qgsfield.h"
+
class QPainter;
class QImage;
@@ -45,8 +46,8 @@
class QgsVectorDataProvider;
class QgsVectorOverlay;
class QgsSingleSymbolRendererV2;
-
class QgsRectangle;
+class QgsVectorLayerJoinBuffer;
class QgsFeatureRendererV2;
@@ -54,7 +55,29 @@
typedef QSet<int> QgsFeatureIds;
typedef QSet<int> QgsAttributeIds;
+struct CORE_EXPORT QgsVectorJoinInfo
+{
+ /**Join field in the target layer*/
+ int targetField;
+ /**Source layer*/
+ QString joinLayerId;
+ /**Join field in the source layer*/
+ int joinField;
+ /**True if the join is cached in virtual memory*/
+ bool memoryCache;
+ /**Cache for joined attributes to provide fast lookup (size is 0 if no memory caching)*/
+ QHash< QString, QgsAttributeMap> cachedAttributes;
+};
+/**Join information prepared for fast attribute id mapping in QgsVectorLayerJoinBuffer::updateFeatureAttributes().
+ Created in the select() method of QgsVectorLayerJoinBuffer for the joins that contain fetched attributes*/
+struct CORE_EXPORT QgsFetchJoinInfo
+{
+ const QgsVectorJoinInfo* joinInfo;
+ QgsAttributeList attributes; //attributes to fetch
+ int indexOffset; //index offset between this layer and join layer
+};
+
/** \ingroup core
* Vector layer backed by a data source provider.
*/
@@ -127,6 +150,16 @@
/** Setup the coordinate system tranformation for the layer */
void setCoordinateSystem();
+ /**Joins another vector layer to this layer
+ @param joinInfo join object containing join layer id, target and source field
+ @param cacheInMemory if true: caches the content of the join layer in virtual memory*/
+ void addJoin( QgsVectorJoinInfo joinInfo );
+
+ /**Removes a vector layer join*/
+ void removeJoin( const QString& joinLayerId );
+
+ const QList< QgsVectorJoinInfo >& vectorJoins() const;
+
/** Get the label object associated with this layer */
QgsLabel *label();
@@ -594,6 +627,14 @@
@note public and static from version 1.4 */
static void drawVertexMarker( double x, double y, QPainter& p, QgsVectorLayer::VertexMarkerType type, int vertexSize );
+ /**Assembles mUpdatedFields considering provider fields, joined fields and added fields
+ @note added in version 1.6*/
+ void updateFieldMap();
+
+ /**Caches joined attributes if required (and not already done)*/
+ void createJoinCaches();
+
+
public slots:
/** Select feature by its ID, optionally emit signal selectionChanged() */
void select( int featureId, bool emitSignal = true );
@@ -611,6 +652,9 @@
*/
virtual void updateExtents();
+ /**Check if there is a join with a layer that will be removed*/
+ void checkJoinLayerRemove( QString theLayerId );
+
signals:
/** This signal is emited when selection was changed */
@@ -701,9 +745,19 @@
/**Reads vertex marker size from settings*/
static int currentVertexMarkerSize();
- /**Update feature with uncommited attribute updates*/
+ /**Update feature with uncommited attribute updates and joined attributes*/
void updateFeatureAttributes( QgsFeature &f, bool all = false );
+ /**Adds joined attributes to a feature
+ @param f the feature to add the attributes
+ @param joinInfo vector join
+ @param joinFieldName name of the (source) join Field
+ @param joinValue lookup value for join
+ @param attributes (join layer) attribute indices to add
+ @param attributeOffset index offset to get from join layer attribute index to layer index*/
+ void addJoinedFeatureAttributes( QgsFeature& f, const QgsVectorJoinInfo& joinInfo, const QString& joinFieldName, const QVariant& joinValue,
+ const QgsAttributeList& attributes, int attributeIndexOffset );
+
/**Update feature with uncommited geometry updates*/
void updateFeatureGeometry( QgsFeature &f );
@@ -722,6 +776,13 @@
/** Stop version 2 renderer and selected renderer (if required) */
void stopRendererV2( QgsRenderContext& rendererContext, QgsSingleSymbolRendererV2* selRenderer );
+ /** Helper function to find out the maximum index of a field map
+ @return true in case of success, otherwise false (e.g. empty map)*/
+ bool maxIndex( const QgsFieldMap& fMap, int& index ) const;
+
+ /**Updates an index in an attribute map to a new value (usually necessary because of a join operation)*/
+ void updateAttributeMapIndex( QgsAttributeMap& map, int oldIndex, int newIndex ) const;
+
private: // Private attributes
/** Update threshold for drawing features as they are read. A value of zero indicates
@@ -846,6 +907,9 @@
QSet<int> mFetchConsidered;
QgsGeometryMap::iterator mFetchChangedGeomIt;
QgsFeatureList::iterator mFetchAddedFeaturesIt;
+
+ //stores information about joined layers
+ QgsVectorLayerJoinBuffer* mJoinBuffer;
};
#endif
Added: trunk/qgis/src/core/qgsvectorlayerjoinbuffer.cpp
===================================================================
--- trunk/qgis/src/core/qgsvectorlayerjoinbuffer.cpp (rev 0)
+++ trunk/qgis/src/core/qgsvectorlayerjoinbuffer.cpp 2011-02-11 16:23:17 UTC (rev 15155)
@@ -0,0 +1,346 @@
+/***************************************************************************
+ qgsvectorlayerjoinbuffer.cpp
+ ----------------------------
+ begin : Feb 09, 2011
+ copyright : (C) 2011 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole 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 "qgsvectorlayerjoinbuffer.h"
+#include "qgsmaplayerregistry.h"
+#include "qgsvectordataprovider.h"
+
+#include <QDomElement>
+
+QgsVectorLayerJoinBuffer::QgsVectorLayerJoinBuffer()
+{
+}
+
+QgsVectorLayerJoinBuffer::~QgsVectorLayerJoinBuffer()
+{
+}
+
+void QgsVectorLayerJoinBuffer::addJoin( QgsVectorJoinInfo joinInfo )
+{
+ mVectorJoins.push_back( joinInfo );
+
+ //cache joined layer to virtual memory if specified by user
+ if ( joinInfo.memoryCache )
+ {
+ cacheJoinLayer( mVectorJoins.last() );
+ }
+}
+
+void QgsVectorLayerJoinBuffer::removeJoin( const QString& joinLayerId )
+{
+ for ( int i = 0; i < mVectorJoins.size(); ++i )
+ {
+ if ( mVectorJoins.at( i ).joinLayerId == joinLayerId )
+ {
+ mVectorJoins.removeAt( i );
+ return;
+ }
+ }
+}
+
+void QgsVectorLayerJoinBuffer::cacheJoinLayer( QgsVectorJoinInfo& joinInfo )
+{
+ //memory cache not required or already done
+ if ( !joinInfo.memoryCache || joinInfo.cachedAttributes.size() > 0 )
+ {
+ return;
+ }
+
+ QgsVectorLayer* cacheLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo.joinLayerId ) );
+ if ( cacheLayer )
+ {
+ joinInfo.cachedAttributes.clear();
+ cacheLayer->select( cacheLayer->pendingAllAttributesList(), QgsRectangle(), false, false );
+ QgsFeature f;
+ while ( cacheLayer->nextFeature( f ) )
+ {
+ const QgsAttributeMap& map = f.attributeMap();
+ joinInfo.cachedAttributes.insert( map.value( joinInfo.joinField ).toString(), map );
+ }
+ }
+}
+
+void QgsVectorLayerJoinBuffer::updateFieldMap( QgsFieldMap& fields, int& maxIndex )
+{
+ int currentMaxIndex = 0; //maximum index of the current join layer
+
+ QList< QgsVectorJoinInfo>::const_iterator joinIt = mVectorJoins.constBegin();
+ for ( ; joinIt != mVectorJoins.constEnd(); ++joinIt )
+ {
+ QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinIt->joinLayerId ) );
+ if ( !joinLayer )
+ {
+ continue;
+ }
+
+ const QgsFieldMap& joinFields = joinLayer->pendingFields();
+ QgsFieldMap::const_iterator fieldIt = joinFields.constBegin();
+ for ( ; fieldIt != joinFields.constEnd(); ++fieldIt )
+ {
+ fields.insert( maxIndex + 1 + fieldIt.key(), fieldIt.value() );
+ }
+
+ if ( maximumIndex( joinFields, currentMaxIndex ) )
+ {
+ maxIndex += ( currentMaxIndex + 1 ); //+1 because there are fields with index 0
+ }
+ }
+}
+
+void QgsVectorLayerJoinBuffer::createJoinCaches()
+{
+ QList< QgsVectorJoinInfo >::iterator joinIt = mVectorJoins.begin();
+ for ( ; joinIt != mVectorJoins.end(); ++joinIt )
+ {
+ cacheJoinLayer( *joinIt );
+ }
+}
+
+void QgsVectorLayerJoinBuffer::select( const QgsAttributeList& fetchAttributes,
+ QgsAttributeList& sourceJoinFields, int maxProviderIndex )
+{
+ mFetchJoinInfos.clear();
+ sourceJoinFields.clear();
+
+ QgsAttributeList::const_iterator attIt = fetchAttributes.constBegin();
+ for ( ; attIt != fetchAttributes.constEnd(); ++attIt )
+ {
+ int indexOffset;
+ const QgsVectorJoinInfo* joinInfo = joinForFieldIndex( *attIt, maxProviderIndex, indexOffset );
+ if ( joinInfo )
+ {
+ QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo->joinLayerId ) );
+ if ( joinLayer )
+ {
+ mFetchJoinInfos[ joinLayer ].joinInfo = joinInfo;
+ mFetchJoinInfos[ joinLayer].attributes.push_back( *attIt - indexOffset ); //store provider index
+ mFetchJoinInfos[ joinLayer ].indexOffset = indexOffset;
+ //for joined fields, we always need to request the targetField from the provider too
+ if ( !fetchAttributes.contains( joinInfo->targetField ) )
+ {
+ sourceJoinFields << joinInfo->targetField;
+ }
+ }
+ }
+ }
+}
+
+void QgsVectorLayerJoinBuffer::updateFeatureAttributes( QgsFeature &f, int maxProviderIndex, bool all )
+{
+ if ( all )
+ {
+ int index = maxProviderIndex + 1;
+ int currentMaxIndex;
+
+ QList< QgsVectorJoinInfo >::const_iterator joinIt = mVectorJoins.constBegin();
+ for ( ; joinIt != mVectorJoins.constEnd(); ++joinIt )
+ {
+ QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinIt->joinLayerId ) );
+ if ( !joinLayer )
+ {
+ continue;
+ }
+
+ QString joinFieldName = joinLayer->pendingFields().value( joinIt->joinField ).name();
+ if ( joinFieldName.isEmpty() )
+ {
+ continue;
+ }
+
+ QVariant targetFieldValue = f.attributeMap().value( joinIt->targetField );
+ if ( !targetFieldValue.isValid() )
+ {
+ continue;
+ }
+
+ addJoinedFeatureAttributes( f, *joinIt, joinFieldName, targetFieldValue, joinLayer->pendingAllAttributesList(), index );
+
+ maximumIndex( joinLayer->pendingFields(), currentMaxIndex );
+ index += ( currentMaxIndex + 1 );
+ }
+ }
+ else
+ {
+ QMap<QgsVectorLayer*, QgsFetchJoinInfo>::const_iterator joinIt = mFetchJoinInfos.constBegin();
+ for ( ; joinIt != mFetchJoinInfos.constEnd(); ++joinIt )
+ {
+ QgsVectorLayer* joinLayer = joinIt.key();
+ if ( !joinLayer )
+ {
+ continue;
+ }
+
+ QString joinFieldName = joinLayer->pendingFields().value( joinIt.value().joinInfo->joinField ).name();
+ if ( joinFieldName.isEmpty() )
+ {
+ continue;
+ }
+
+ QVariant targetFieldValue = f.attributeMap().value( joinIt->joinInfo->targetField );
+ if ( !targetFieldValue.isValid() )
+ {
+ continue;
+ }
+
+ addJoinedFeatureAttributes( f, *( joinIt.value().joinInfo ), joinFieldName, targetFieldValue, joinIt.value().attributes, joinIt.value().indexOffset );
+ }
+ }
+}
+
+void QgsVectorLayerJoinBuffer::addJoinedFeatureAttributes( QgsFeature& f, const QgsVectorJoinInfo& joinInfo, const QString& joinFieldName,
+ const QVariant& joinValue, const QgsAttributeList& attributes, int attributeIndexOffset )
+{
+ const QHash< QString, QgsAttributeMap>& memoryCache = joinInfo.cachedAttributes;
+ if ( !memoryCache.isEmpty() ) //use join memory cache
+ {
+ QgsAttributeMap featureAttributes = memoryCache.value( joinValue.toString() );
+ bool found = !featureAttributes.isEmpty();
+ QgsAttributeList::const_iterator attIt = attributes.constBegin();
+ for ( ; attIt != attributes.constEnd(); ++attIt )
+ {
+ if ( found )
+ {
+ f.addAttribute( *attIt + attributeIndexOffset, featureAttributes.value( *attIt ) );
+ }
+ else
+ {
+ f.addAttribute( *attIt + attributeIndexOffset, QVariant() );
+ }
+ }
+ }
+ else //work with subset string
+ {
+ QgsVectorLayer* joinLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinInfo.joinLayerId ) );
+ if ( !joinLayer )
+ {
+ return;
+ }
+
+ //no memory cache, query the joined values by setting substring
+ QString subsetString = joinLayer->dataProvider()->subsetString(); //provider might already have a subset string
+ QString bkSubsetString = subsetString;
+ if ( !subsetString.isEmpty() )
+ {
+ subsetString.append( " AND " );
+ }
+
+ subsetString.append( "\"" + joinFieldName + "\"" + " = " + "\"" + joinValue.toString() + "\"" );
+ joinLayer->dataProvider()->setSubsetString( subsetString, false );
+
+ //select (no geometry)
+ joinLayer->select( attributes, QgsRectangle(), false, false );
+
+ //get first feature
+ QgsFeature fet;
+ if ( joinLayer->nextFeature( fet ) )
+ {
+ QgsAttributeMap attMap = fet.attributeMap();
+ QgsAttributeMap::const_iterator attIt = attMap.constBegin();
+ for ( ; attIt != attMap.constEnd(); ++attIt )
+ {
+ f.addAttribute( attIt.key() + attributeIndexOffset, attIt.value() );
+ }
+ }
+ else //no suitable join feature found, insert invalid variants
+ {
+ QgsAttributeList::const_iterator attIt = attributes.constBegin();
+ for ( ; attIt != attributes.constEnd(); ++attIt )
+ {
+ f.addAttribute( *attIt + attributeIndexOffset, QVariant() );
+ }
+ }
+
+ joinLayer->dataProvider()->setSubsetString( bkSubsetString, false );
+ }
+}
+
+void QgsVectorLayerJoinBuffer::writeXml( QDomNode& layer_node, QDomDocument& document ) const
+{
+ QDomElement vectorJoinsElem = document.createElement( "vectorjoins" );
+ layer_node.appendChild( vectorJoinsElem );
+ QList< QgsVectorJoinInfo >::const_iterator joinIt = mVectorJoins.constBegin();
+ for ( ; joinIt != mVectorJoins.constEnd(); ++joinIt )
+ {
+ QDomElement joinElem = document.createElement( "join" );
+ joinElem.setAttribute( "targetField", joinIt->targetField );
+ joinElem.setAttribute( "joinLayerId", joinIt->joinLayerId );
+ joinElem.setAttribute( "joinField", joinIt->joinField );
+ joinElem.setAttribute( "memoryCache", !joinIt->cachedAttributes.isEmpty() );
+ vectorJoinsElem.appendChild( joinElem );
+ }
+}
+
+void QgsVectorLayerJoinBuffer::readXml( QDomNode& layer_node )
+{
+ mVectorJoins.clear();
+ QDomElement vectorJoinsElem = layer_node.firstChildElement( "vectorjoins" );
+ if ( !vectorJoinsElem.isNull() )
+ {
+ QDomNodeList joinList = vectorJoinsElem.elementsByTagName( "join" );
+ for ( int i = 0; i < joinList.size(); ++i )
+ {
+ QDomElement infoElem = joinList.at( i ).toElement();
+ QgsVectorJoinInfo info;
+ info.joinField = infoElem.attribute( "joinField" ).toInt();
+ info.joinLayerId = infoElem.attribute( "joinLayerId" );
+ info.targetField = infoElem.attribute( "targetField" ).toInt();
+ info.memoryCache = infoElem.attribute( "memoryCache" ).toInt();
+ addJoin( info );
+ }
+ }
+}
+
+const QgsVectorJoinInfo* QgsVectorLayerJoinBuffer::joinForFieldIndex( int index, int maxProviderIndex, int& indexOffset ) const
+{
+ int currentMaxIndex = 0;
+ int totIndex = maxProviderIndex + 1;
+
+ //go through all the joins to search the index
+ QList< QgsVectorJoinInfo>::const_iterator joinIt = mVectorJoins.constBegin();
+ for ( ; joinIt != mVectorJoins.constEnd(); ++joinIt )
+ {
+ QgsVectorLayer* joinLayer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( joinIt->joinLayerId ) );
+ if ( !joinLayer )
+ {
+ continue;
+ }
+
+ if ( joinLayer->pendingFields().contains( index - totIndex ) )
+ {
+ indexOffset = totIndex;
+ return &( *joinIt );
+ }
+
+ maximumIndex( joinLayer->pendingFields(), currentMaxIndex );
+ totIndex += ( currentMaxIndex + 1 );
+ }
+
+ //an added field or a provider field
+ return 0;
+}
+
+bool QgsVectorLayerJoinBuffer::maximumIndex( const QgsFieldMap& fMap, int& index )
+{
+ if ( fMap.size() < 1 )
+ {
+ return false;
+ }
+ QgsFieldMap::const_iterator endIt = fMap.constEnd();
+ --endIt;
+ index = endIt.key();
+ return true;
+}
Added: trunk/qgis/src/core/qgsvectorlayerjoinbuffer.h
===================================================================
--- trunk/qgis/src/core/qgsvectorlayerjoinbuffer.h (rev 0)
+++ trunk/qgis/src/core/qgsvectorlayerjoinbuffer.h 2011-02-11 16:23:17 UTC (rev 15155)
@@ -0,0 +1,104 @@
+/***************************************************************************
+ qgsvectorlayerjoinbuffer.h
+ ---------------------------
+ begin : Feb 09, 2011
+ copyright : (C) 2011 by Marco Hugentobler
+ email : marco dot hugentobler at sourcepole 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 QGSVECTORLAYERJOINBUFFER_H
+#define QGSVECTORLAYERJOINBUFFER_H
+
+#include "qgsfeature.h"
+#include "qgsvectorlayer.h"
+
+#include <QHash>
+#include <QString>
+
+/**Manages joined field for a vector layer*/
+class CORE_EXPORT QgsVectorLayerJoinBuffer
+{
+ public:
+ QgsVectorLayerJoinBuffer();
+ ~QgsVectorLayerJoinBuffer();
+
+ /**Joins another vector layer to this layer
+ @param joinInfo join object containing join layer id, target and source field
+ @param cacheInMemory if true: caches the content of the join layer in virtual memory*/
+ void addJoin( QgsVectorJoinInfo joinInfo );
+
+ /**Removes a vector layer join*/
+ void removeJoin( const QString& joinLayerId );
+
+ /**Creates QgsVectorLayerJoinBuffer for the joins containing attributes to fetch*/
+ void select( const QgsAttributeList& fetchAttributes,
+ QgsAttributeList& sourceJoinFields, int maxProviderIndex );
+
+ /**Updates field map with joined attributes
+ @param fields map to append joined attributes
+ @param maxIndex in/out: maximum attribute index*/
+ void updateFieldMap( QgsFieldMap& fields, int& maxIndex );
+
+ /**Update feature with uncommited attribute updates and joined attributes*/
+ void updateFeatureAttributes( QgsFeature &f, int maxProviderIndex, bool all = false );
+
+ /**Calls cacheJoinLayer() for all vector joins*/
+ void createJoinCaches();
+
+ /**Saves mVectorJoins to xml under the layer node*/
+ void writeXml( QDomNode& layer_node, QDomDocument& document ) const;
+
+ /**Reads joins from project file*/
+ void readXml( QDomNode& layer_node );
+
+ /**Quick way to test if there is any join at all*/
+ bool containsJoins() const { return ( mVectorJoins.size() > 0 ); }
+ /**Quick way to test if there is a join to be fetched*/
+ bool containsFetchJoins() const { return ( mFetchJoinInfos.size() > 0 ); }
+
+ const QList< QgsVectorJoinInfo >& vectorJoins() const { return mVectorJoins; }
+
+ /** Helper function to find out the maximum index of a field map
+ @return true in case of success, otherwise false (e.g. empty map)*/
+ static bool maximumIndex( const QgsFieldMap& fMap, int& index );
+
+ private:
+
+ /**Joined vector layers*/
+ QList< QgsVectorJoinInfo > mVectorJoins;
+
+ /**Informations about joins used in the current select() statement.
+ Allows faster mapping of attribute ids compared to mVectorJoins*/
+ QMap<QgsVectorLayer*, QgsFetchJoinInfo> mFetchJoinInfos;
+
+ /**Caches attributes of join layer in memory if QgsVectorJoinInfo.memoryCache is true (and the cache is not already there)*/
+ void cacheJoinLayer( QgsVectorJoinInfo& joinInfo );
+
+ /**Adds joined attributes to a feature
+ @param f the feature to add the attributes
+ @param joinInfo vector join
+ @param joinFieldName name of the (source) join Field
+ @param joinValue lookup value for join
+ @param attributes (join layer) attribute indices to add
+ @param attributeOffset index offset to get from join layer attribute index to layer index*/
+ void addJoinedFeatureAttributes( QgsFeature& f, const QgsVectorJoinInfo& joinInfo, const QString& joinFieldName, const QVariant& joinValue,
+ const QgsAttributeList& attributes, int attributeIndexOffset );
+
+ /**Finds the vector join for a layer field index.
+ @param index this layers attribute index
+ @param maxProviderIndex maximum attribute index of the vectorlayer provider
+ @param indexOffset out: offset between layer index and original provider index
+ @return pointer to the join if the index belongs to a joined field, otherwise 0 (possibily provider field or added field)*/
+ const QgsVectorJoinInfo* joinForFieldIndex( int index, int maxProviderIndex, int& indexOffset ) const;
+};
+
+#endif // QGSVECTORLAYERJOINBUFFER_H
Modified: trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp 2011-02-11 16:23:17 UTC (rev 15155)
@@ -65,6 +65,10 @@
void QgsSingleSymbolRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
{
+ if ( !mSymbol )
+ {
+ return;
+ }
mRotationFieldIdx = mRotationField.isEmpty() ? -1 : vlayer->fieldNameIndex( mRotationField );
mSizeScaleFieldIdx = mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField );
@@ -99,6 +103,10 @@
void QgsSingleSymbolRendererV2::stopRender( QgsRenderContext& context )
{
+ if ( !mSymbol )
+ {
+ return;
+ }
mSymbol->stopRender( context );
if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
@@ -134,7 +142,14 @@
QString QgsSingleSymbolRendererV2::dump()
{
- return QString( "SINGLE: %1" ).arg( mSymbol->dump() );
+ if ( mSymbol )
+ {
+ return QString( "SINGLE: %1" ).arg( mSymbol->dump() );
+ }
+ else
+ {
+ return "";
+ }
}
QgsFeatureRendererV2* QgsSingleSymbolRendererV2::clone()
@@ -205,10 +220,12 @@
QgsLegendSymbologyList QgsSingleSymbolRendererV2::legendSymbologyItems( QSize iconSize )
{
- QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mSymbol, iconSize );
-
QgsLegendSymbologyList lst;
- lst << qMakePair( QString(), pix );
+ if ( mSymbol )
+ {
+ QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mSymbol, iconSize );
+ lst << qMakePair( QString(), pix );
+ }
return lst;
}
Modified: trunk/qgis/src/providers/ogr/qgsogrprovider.cpp
===================================================================
--- trunk/qgis/src/providers/ogr/qgsogrprovider.cpp 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/providers/ogr/qgsogrprovider.cpp 2011-02-11 16:23:17 UTC (rev 15155)
@@ -229,7 +229,7 @@
}
}
-bool QgsOgrProvider::setSubsetString( QString theSQL )
+bool QgsOgrProvider::setSubsetString( QString theSQL, bool updateFeatureCount )
{
QgsCPLErrorHandler handler;
@@ -287,7 +287,10 @@
// getting the total number of features in the layer
// TODO: This can be expensive, do we really need it!
- recalculateFeatureCount();
+ if ( updateFeatureCount )
+ {
+ recalculateFeatureCount();
+ }
// check the validity of the layer
QgsDebugMsg( "checking validity" );
@@ -1046,6 +1049,20 @@
return indexfile.exists();
}
+bool QgsOgrProvider::createAttributeIndex( int field )
+{
+ QString layerName = OGR_FD_GetName( OGR_L_GetLayerDefn( ogrOrigLayer ) );
+ QString dropSql = QString( "DROP INDEX ON %1" ).arg( quotedIdentifier( layerName ) );
+ QString createSql = QString( "CREATE INDEX ON %1 USING %2" ).arg( quotedIdentifier( layerName ) ).arg( fields()[field].name() );
+ OGR_DS_ExecuteSQL( ogrDataSource, mEncoding->fromUnicode( dropSql ).data(), OGR_L_GetSpatialFilter( ogrOrigLayer ), "SQL" );
+ OGR_DS_ExecuteSQL( ogrDataSource, mEncoding->fromUnicode( createSql ).data(), OGR_L_GetSpatialFilter( ogrOrigLayer ), "SQL" );
+
+ QFileInfo fi( mFilePath ); // to get the base name
+ //find out, if the .idm file is there
+ QFile indexfile( fi.path().append( "/" ).append( fi.completeBaseName() ).append( ".idm" ) );
+ return indexfile.exists();
+}
+
bool QgsOgrProvider::deleteFeatures( const QgsFeatureIds & id )
{
QgsCPLErrorHandler handler;
@@ -1182,6 +1199,7 @@
// adding attributes was added in GDAL 1.6
ability |= AddAttributes;
#endif
+ ability |= CreateAttributeIndex;
if ( mAttributeFields.size() == 0 )
{
@@ -1816,7 +1834,14 @@
void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit )
{
- QgsField fld = mAttributeFields[index];
+ uniqueValues.clear();
+
+ QgsField fld = mAttributeFields.value( index );
+ if ( fld.name().isNull() )
+ {
+ return; //not a provider field
+ }
+
QString theLayerName = OGR_FD_GetName( OGR_L_GetLayerDefn( ogrLayer ) );
QString sql = QString( "SELECT DISTINCT %1 FROM %2" )
@@ -1830,8 +1855,6 @@
sql += QString( " ORDER BY %1" ).arg( fld.name() );
- uniqueValues.clear();
-
QgsDebugMsg( QString( "SQL: %1" ).arg( sql ) );
OGRLayerH l = OGR_DS_ExecuteSQL( ogrDataSource, mEncoding->fromUnicode( sql ).data(), NULL, "SQL" );
if ( l == 0 )
Modified: trunk/qgis/src/providers/ogr/qgsogrprovider.h
===================================================================
--- trunk/qgis/src/providers/ogr/qgsogrprovider.h 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/providers/ogr/qgsogrprovider.h 2011-02-11 16:23:17 UTC (rev 15155)
@@ -98,7 +98,7 @@
virtual bool supportsSubsetString() { return true; }
/** mutator for sql where clause used to limit dataset size */
- virtual bool setSubsetString( QString theSQL );
+ virtual bool setSubsetString( QString theSQL, bool updateFeatureCount = true );
/**
* Get feature type.
@@ -155,6 +155,9 @@
@return true in case of success*/
virtual bool createSpatialIndex();
+ /**Create an attribute index on the datasource*/
+ virtual bool createAttributeIndex( int field );
+
/** Returns a bitmask containing the supported capabilities
Note, some capabilities may change depending on whether
a spatial filter is active on this provider, so it may
Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp 2011-02-11 16:23:17 UTC (rev 15155)
@@ -2793,7 +2793,7 @@
return enabledCapabilities;
}
-bool QgsPostgresProvider::setSubsetString( QString theSQL )
+bool QgsPostgresProvider::setSubsetString( QString theSQL, bool updateFeatureCount )
{
QString prevWhere = sqlWhereClause;
@@ -2828,7 +2828,10 @@
// uri? Perhaps this needs some rationalisation.....
setDataSourceUri( mUri.uri() );
- featuresCounted = -1;
+ if ( updateFeatureCount )
+ {
+ featuresCounted = -1;
+ }
layerExtent.setMinimal();
return true;
Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.h
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.h 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.h 2011-02-11 16:23:17 UTC (rev 15155)
@@ -250,7 +250,7 @@
QString subsetString();
/** mutator for sql where clause used to limit dataset size */
- bool setSubsetString( QString theSQL );
+ bool setSubsetString( QString theSQL, bool updateFeatureCount = true );
virtual bool supportsSubsetString() { return true; }
Modified: trunk/qgis/src/providers/spatialite/qgsspatialiteprovider.cpp
===================================================================
--- trunk/qgis/src/providers/spatialite/qgsspatialiteprovider.cpp 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/providers/spatialite/qgsspatialiteprovider.cpp 2011-02-11 16:23:17 UTC (rev 15155)
@@ -560,7 +560,7 @@
return mSubsetString;
}
-bool QgsSpatiaLiteProvider::setSubsetString( QString theSQL )
+bool QgsSpatiaLiteProvider::setSubsetString( QString theSQL, bool updateFeatureCount )
{
QString prevSubsetString = mSubsetString;
mSubsetString = theSQL;
@@ -571,8 +571,10 @@
setDataSourceUri( uri.uri() );
// update feature count and extents
- if ( getTableSummary() )
+ if ( updateFeatureCount && getTableSummary() )
+ {
return true;
+ }
mSubsetString = prevSubsetString;
Modified: trunk/qgis/src/providers/spatialite/qgsspatialiteprovider.h
===================================================================
--- trunk/qgis/src/providers/spatialite/qgsspatialiteprovider.h 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/providers/spatialite/qgsspatialiteprovider.h 2011-02-11 16:23:17 UTC (rev 15155)
@@ -80,7 +80,7 @@
virtual QString subsetString();
/** mutator for sql where clause used to limit dataset size */
- virtual bool setSubsetString( QString theSQL );
+ virtual bool setSubsetString( QString theSQL, bool updateFeatureCount = true );
virtual bool supportsSubsetString() { return true; }
Copied: trunk/qgis/src/ui/qgsaddjoindialogbase.ui (from rev 14132, branches/table_join_branch/src/ui/qgsaddjoindialogbase.ui)
===================================================================
--- trunk/qgis/src/ui/qgsaddjoindialogbase.ui (rev 0)
+++ trunk/qgis/src/ui/qgsaddjoindialogbase.ui 2011-02-11 16:23:17 UTC (rev 15155)
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QgsAddJoinDialogBase</class>
+ <widget class="QDialog" name="QgsAddJoinDialogBase">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>281</width>
+ <height>160</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Add vector join</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="mJoinLayerLabel">
+ <property name="text">
+ <string>Join layer: </string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="mJoinLayerComboBox"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="mJoinFieldLabel">
+ <property name="text">
+ <string>Join field:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="mJoinFieldComboBox"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="mTargetFieldLabel">
+ <property name="text">
+ <string>Target field:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QComboBox" name="mTargetFieldComboBox"/>
+ </item>
+ <item row="5" column="0" colspan="2">
+ <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="4" column="0" colspan="2">
+ <widget class="QCheckBox" name="mCreateIndexCheckBox">
+ <property name="text">
+ <string>Create attribute index on join field</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QCheckBox" name="mCacheInMemoryCheckBox">
+ <property name="text">
+ <string>Cache join layer in virtual memory</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>QgsAddJoinDialogBase</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>QgsAddJoinDialogBase</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
Modified: trunk/qgis/src/ui/qgsvectorlayerpropertiesbase.ui
===================================================================
--- trunk/qgis/src/ui/qgsvectorlayerpropertiesbase.ui 2011-02-10 21:46:31 UTC (rev 15154)
+++ trunk/qgis/src/ui/qgsvectorlayerpropertiesbase.ui 2011-02-11 16:23:17 UTC (rev 15155)
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>668</width>
+ <width>591</width>
<height>426</height>
</rect>
</property>
@@ -372,8 +372,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>384</width>
- <height>408</height>
+ <width>432</width>
+ <height>419</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_3">
@@ -611,6 +611,74 @@
</item>
</layout>
</widget>
+ <widget class="QWidget" name="mJoinPage">
+ <attribute name="icon">
+ <iconset resource="../../images/images.qrc">
+ <normaloff>:/images/themes/default/propertyicons/join.png</normaloff>:/images/themes/default/propertyicons/join.png</iconset>
+ </attribute>
+ <attribute name="title">
+ <string>Joins</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_10">
+ <item row="0" column="0">
+ <widget class="QPushButton" name="mButtonAddJoin">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../../images/images.qrc">
+ <normaloff>:/images/themes/default/symbologyAdd.png</normaloff>:/images/themes/default/symbologyAdd.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QPushButton" name="mButtonRemoveJoin">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../../images/images.qrc">
+ <normaloff>:/images/themes/default/symbologyRemove.png</normaloff>:/images/themes/default/symbologyRemove.png</iconset>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>354</width>
+ <height>23</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0" colspan="3">
+ <widget class="QTreeWidget" name="mJoinTreeWidget">
+ <property name="columnCount">
+ <number>3</number>
+ </property>
+ <column>
+ <property name="text">
+ <string>Join layer</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Join field</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Target field</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
</widget>
</item>
</layout>
More information about the QGIS-commit
mailing list