New functionality for merging features

git-svn-id: http://svn.osgeo.org/qgis/trunk@10879 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
mhugent 2009-06-03 11:33:58 +00:00
parent aa18385d53
commit dbaf7bd454
9 changed files with 909 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -41,6 +41,7 @@ SET(QGIS_APP_SRCS
qgsmaptoolvertexedit.cpp
qgsmeasuredialog.cpp
qgsmeasuretool.cpp
qgsmergeattributesdialog.cpp
qgsnewhttpconnection.cpp
qgsnumericsortlistviewitem.cpp
qgsogrsublayersdialog.cpp
@ -129,6 +130,7 @@ SET (QGIS_APP_MOC_HDRS
qgsmeasuretool.h
qgsmeasuredialog.h
qgsmergeattributesdialog.h
qgsnewhttpconnection.h
qgsoptions.h
qgsogrsublayersdialog.h

View File

@ -114,6 +114,7 @@
#include "qgsmapoverviewcanvas.h"
#include "qgsmaprenderer.h"
#include "qgsmaptip.h"
#include "qgsmergeattributesdialog.h"
#include "qgsmessageviewer.h"
#include "qgsoptions.h"
#include "qgspastetransformations.h"
@ -703,6 +704,12 @@ void QgisApp::createActions()
connect( mActionDeletePart, SIGNAL( triggered() ), this, SLOT( deletePart() ) );
mActionDeletePart->setEnabled( false );
mActionMergeFeatures = new QAction( getThemeIcon("mActionMergeFeatures.png"), tr("Merge selected features"), this);
shortcuts->registerAction(mActionMergeFeatures);
mActionMergeFeatures->setStatusTip( tr("Merge selected features"));
connect( mActionMergeFeatures, SIGNAL(triggered()), this, SLOT(mergeSelectedFeatures()));
mActionMergeFeatures->setEnabled(false);
// View Menu Items
@ -1053,6 +1060,7 @@ void QgisApp::createActionGroups()
mMapToolGroup->addAction( mActionDeleteRing );
mActionDeletePart->setCheckable( true );
mMapToolGroup->addAction( mActionDeletePart );
mMapToolGroup->addAction( mActionMergeFeatures);
}
void QgisApp::createMenus()
@ -1141,6 +1149,7 @@ void QgisApp::createMenus()
mEditMenu->addAction( mActionAddIsland );
mEditMenu->addAction( mActionDeleteRing );
mEditMenu->addAction( mActionDeletePart );
mEditMenu->addAction( mActionMergeFeatures );
if ( layout == QDialogButtonBox::GnomeLayout || layout == QDialogButtonBox::MacLayout )
{
@ -1345,6 +1354,7 @@ void QgisApp::createToolBars()
mAdvancedDigitizeToolBar->addAction( mActionAddIsland );
mAdvancedDigitizeToolBar->addAction( mActionDeleteRing );
mAdvancedDigitizeToolBar->addAction( mActionDeletePart );
mAdvancedDigitizeToolBar->addAction( mActionMergeFeatures );
mToolbarMenu->addAction( mAdvancedDigitizeToolBar->toggleViewAction() );
@ -4085,6 +4095,139 @@ void QgisApp::deletePart()
mMapCanvas->setMapTool( mMapTools.mDeletePart );
}
QgsGeometry* QgisApp::unionGeometries(const QgsVectorLayer* vl, QgsFeatureList& featureList) const
{
if(!vl || featureList.size() < 2)
{
return 0;
}
QgsGeometry* unionGeom = featureList[0].geometry();
QgsGeometry* backupPtr = 0; //pointer to delete intermediate results
if(!unionGeom)
{
return 0;
}
for(int i = 1; i < featureList.size(); ++i)
{
QgsGeometry* currentGeom = featureList[i].geometry();
if(currentGeom)
{
backupPtr = unionGeom;
unionGeom = unionGeom->combine(currentGeom);
if(i > 1) //delete previous intermediate results
{
delete backupPtr;
backupPtr = 0;
}
}
}
return unionGeom;
}
void QgisApp::mergeSelectedFeatures()
{
//get active layer (hopefully vector)
QgsMapLayer* activeMapLayer = activeLayer();
if(!activeMapLayer)
{
QMessageBox::information(0, tr("No active layer"), tr("No active layer found. Please select a layer in the layer list"));
return;
}
QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>(activeMapLayer);
if(!vl)
{
QMessageBox::information(0, tr("Active layer is not vector"), tr("The merge features tool only works on vector layers. Please select a vector layer from the layer list"));
return;
}
if(!vl->isEditable())
{
QMessageBox::information(0, tr("Layer not editable"), tr("Merging features can only be done for layers in editing mode. To use the merge tool, go to Layer->Toggle editing"));
return;
}
//get selected feature ids (as a QSet<int> )
const QgsFeatureIds& featureIdSet = vl->selectedFeaturesIds();
if(featureIdSet.size() < 2)
{
QMessageBox::information(0, "Not enough features selected", tr("The merge tool requires at least two selected features"));
return;
}
//get initial selection (may be altered by attribute merge dialog later)
QgsFeatureList featureList = vl->selectedFeatures(); //get QList<QgsFeature>
QgsGeometry* unionGeom = unionGeometries(vl, featureList);
if(!unionGeom)
{
return;
}
//make a first geometry union and notify the user straight away if the union geometry type does not match the layer one
QGis::WkbType originalType = vl->wkbType();
QGis::WkbType newType = unionGeom->wkbType();
if(unionGeom->wkbType() != vl->wkbType())
{
QMessageBox::critical(0, "Union operation canceled", tr("The union operation would result in a geometry type that is not compatible with the current layer and therefore is canceled"));
delete unionGeom;
return;
}
//merge the attributes together
QgsMergeAttributesDialog d(featureList, vl, mapCanvas());
if(d.exec() == QDialog::Rejected)
{
return;
}
QgsFeatureList featureListAfter = vl->selectedFeatures();
if(featureListAfter.size() < 2)
{
QMessageBox::information(0, "Not enough features selected", tr("The merge tool requires at least two selected features"));
delete unionGeom;
return;
}
//if the user changed the feature selection in the merge dialog, we need to repead the union and check the type
if(featureList.size() != featureListAfter.size())
{
delete unionGeom;
unionGeom = unionGeometries(vl, featureListAfter);
if(!unionGeom)
{
return;
}
originalType = vl->wkbType();
newType = unionGeom->wkbType();
if(unionGeom->wkbType() != vl->wkbType())
{
QMessageBox::critical(0, "Union operation canceled", tr("The union operation would result in a geometry type that is not compatible with the current layer and therefore is canceled"));
delete unionGeom;
return;
}
}
//create new feature
QgsFeature newFeature;
newFeature.setGeometry(unionGeom);
newFeature.setAttributeMap(d.mergedAttributesMap());
QgsFeatureList::const_iterator feature_it = featureListAfter.constBegin();
for(; feature_it != featureListAfter.constEnd(); ++feature_it)
{
vl->deleteFeature(feature_it->id());
}
vl->addFeature(newFeature, false);
if(mapCanvas())
{
mapCanvas()->refresh();
}
}
void QgisApp::splitFeatures()
{
mMapCanvas->setMapTool( mMapTools.mSplitFeatures );
@ -5314,6 +5457,17 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionCutFeatures->setEnabled( false );
}
//merge tool needs editable layer and provider with the capability of adding and deleting features
if ( vlayer->isEditable() && (dprovider->capabilities() & QgsVectorDataProvider::DeleteFeatures) \
&& QgsVectorDataProvider::AddFeatures)
{
mActionMergeFeatures->setEnabled(layerHasSelection);
}
else
{
mActionMergeFeatures->setEnabled( false );
}
// moving enabled if geometry changes are supported
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeGeometries )
{
@ -5366,6 +5520,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionSplitFeatures->setEnabled( true );
mActionSimplifyFeature->setEnabled( true );
mActionDeletePart->setEnabled( true );
}
else
{

View File

@ -41,6 +41,7 @@ class QValidator;
class QgisAppInterface;
class QgsClipboard;
class QgsComposer;
class QgsGeometry;
class QgsHelpViewer;
class QgsFeature;
@ -63,6 +64,7 @@ class QgsVectorLayer;
#include <QPointer>
#include "qgsconfig.h"
#include "qgsfeature.h"
#include "qgspoint.h"
/*! \class QgisApp
@ -509,6 +511,8 @@ class QgisApp : public QMainWindow
void deleteRing();
//! deletes part of polygon
void deletePart();
//! merges the selected features together
void mergeSelectedFeatures();
//! activates the selection tool
void select();
@ -655,6 +659,9 @@ class QgisApp : public QMainWindow
void pasteTransformations();
//! check to see if file is dirty and if so, prompt the user th save it
bool saveDirty();
/** Helper function to union several geometries together (used in function mergeSelectedFeatures)
@return 0 in case of error*/
QgsGeometry* unionGeometries(const QgsVectorLayer* vl, QgsFeatureList& featureList) const;
/// QgisApp aren't copyable
QgisApp( QgisApp const & );
@ -719,6 +726,7 @@ class QgisApp : public QMainWindow
QAction *mActionSimplifyFeature;
QAction *mActionDeleteRing;
QAction *mActionDeletePart;
QAction *mActionMergeFeatures;
QAction *mActionEditSeparator3;
QAction *mActionPan;

View File

@ -0,0 +1,532 @@
/***************************************************************************
qgsmergeattributesdialog.cpp
----------------------------
begin : May 2009
copyright : (C) 2009 by Marco Hugentobler
email : marco dot hugentobler at karto dot baug dot ethz 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 "qgsmergeattributesdialog.h"
#include "qgisapp.h"
#include "qgsfield.h"
#include "qgsmapcanvas.h"
#include "qgsrubberband.h"
#include "qgsvectorlayer.h"
#include <limits>
#include <QComboBox>
QgsMergeAttributesDialog::QgsMergeAttributesDialog(const QgsFeatureList& features, QgsVectorLayer* vl, QgsMapCanvas* canvas, QWidget * parent, Qt::WindowFlags f): QDialog(parent, f), mFeatureList(features), mVectorLayer(vl), mMapCanvas(canvas), mSelectionRubberBand(0)
{
setupUi(this);
createTableWidgetContents();
QHeaderView* verticalHeader = mTableWidget->verticalHeader();
if(verticalHeader)
{
QObject::connect(mTableWidget, SIGNAL(itemSelectionChanged ()), this, SLOT(selectedRowChanged()));
}
mTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
mTableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
mFromSelectedPushButton->setIcon(QgisApp::getThemeIcon("mActionFromSelectedFeature.png"));
mRemoveFeatureFromSelectionButton->setIcon(QgisApp::getThemeIcon("mActionRemoveSelectedFeature.png"));
}
QgsMergeAttributesDialog::QgsMergeAttributesDialog(): QDialog()
{
setupUi(this);
}
QgsMergeAttributesDialog::~QgsMergeAttributesDialog()
{
delete mSelectionRubberBand;
}
void QgsMergeAttributesDialog::createTableWidgetContents()
{
//get information about attributes from vector layer
if(!mVectorLayer)
{
return;
}
const QgsFieldMap& fieldMap = mVectorLayer->pendingFields();
//combo box row, attributes titles, feature values and current merge results
mTableWidget->setRowCount(mFeatureList.size() + 2);
mTableWidget->setColumnCount(fieldMap.size());
//create combo boxes
for(int i = 0; i < fieldMap.size(); ++i)
{
mTableWidget->setCellWidget(0, i, createMergeComboBox(fieldMap[i].type()));
}
QgsFieldMap::const_iterator fieldIt = fieldMap.constBegin();
//insert attribute names
QStringList horizontalHeaderLabels;
for(; fieldIt != fieldMap.constEnd(); ++fieldIt)
{
horizontalHeaderLabels << fieldIt.value().name();
}
mTableWidget->setHorizontalHeaderLabels(horizontalHeaderLabels);
//insert the attribute values
int currentRow = 1;
QStringList verticalHeaderLabels; //the id column is in the
verticalHeaderLabels << tr("Id");
for(int i = 0; i < mFeatureList.size(); ++i)
{
verticalHeaderLabels << QString::number(mFeatureList[i].id());
QgsAttributeMap currentAttributeMap = mFeatureList[i].attributeMap();
QgsAttributeMap::const_iterator currentMapIt = currentAttributeMap.constBegin();
int col = 0;
for(; currentMapIt != currentAttributeMap.constEnd(); ++currentMapIt)
{
QTableWidgetItem* attributeValItem = new QTableWidgetItem(currentMapIt.value().toString());
attributeValItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
mTableWidget->setItem(currentRow, col, attributeValItem);
++col;
}
++currentRow;
}
//merge
verticalHeaderLabels << tr("Merge");
mTableWidget->setVerticalHeaderLabels(verticalHeaderLabels);
//insert currently merged values
for(int i = 0; i < fieldMap.size(); ++i)
{
refreshMergedValue(i);
}
}
QComboBox* QgsMergeAttributesDialog::createMergeComboBox(QVariant::Type columnType) const
{
QComboBox* newComboBox = new QComboBox();
//add items for feature
QgsFeatureList::const_iterator f_it = mFeatureList.constBegin();
for(; f_it != mFeatureList.constEnd(); ++f_it)
{
newComboBox->addItem(tr("feature %1").arg(f_it->id()));
}
if(columnType == QVariant::Double || columnType == QVariant::Int)
{
newComboBox->addItem(tr("Minimum"));
newComboBox->addItem(tr("Maximum"));
newComboBox->addItem(tr("Median"));
}
else if(columnType == QVariant::String)
{
newComboBox->addItem(tr("Concatenation"));
}
if(columnType == QVariant::Double)
{
newComboBox->addItem(tr("Mean"));
}
QObject::connect(newComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(comboValueChanged(const QString&)));
return newComboBox;
}
int QgsMergeAttributesDialog::findComboColumn(QComboBox* c) const
{
for(int i = 0; i < mTableWidget->columnCount(); ++i)
{
if(mTableWidget->cellWidget(0, i) == c)
{
return i;
}
}
return -1;
}
void QgsMergeAttributesDialog::comboValueChanged(const QString & text)
{
QComboBox* senderComboBox = dynamic_cast<QComboBox*>(sender());
if(!senderComboBox)
{
return;
}
int column = findComboColumn(senderComboBox);
refreshMergedValue(column);
}
void QgsMergeAttributesDialog::selectedRowChanged()
{
//find out selected row
QList<QTableWidgetItem *> selectionList = mTableWidget->selectedItems();
if(selectionList.size() < 1)
{
delete mSelectionRubberBand;
mSelectionRubberBand = 0;
return;
}
int row = selectionList[0]->row();
if(!mTableWidget || !mMapCanvas || !mVectorLayer || row < 1 || row >= (mTableWidget->rowCount()))
{
return;
}
//read the feature id
QTableWidgetItem* idItem = mTableWidget->verticalHeaderItem(row);
if(!idItem)
{
return;
}
bool conversionSuccess = false;
int featureIdToSelect = idItem->text().toInt(&conversionSuccess);
if(!conversionSuccess)
{
//the merge result row was selected
delete mSelectionRubberBand;
mSelectionRubberBand = 0;
return;
}
createRubberBandForFeature(featureIdToSelect);
}
void QgsMergeAttributesDialog::refreshMergedValue(int col)
{
//get QComboBox
QWidget* cellWidget = mTableWidget->cellWidget(0, col);
if(!cellWidget)
{
return;
}
QComboBox* comboBox = dynamic_cast<QComboBox*>(cellWidget);
if(!comboBox)
{
return;
}
//evaluate behaviour (feature value or min / max / mean )
QString mergeBehaviourString = comboBox->currentText();
QString evalText; //text that has to be inserted into merge result field
if(mergeBehaviourString == tr("Minimum"))
{
evalText = minimumAttributeString(col);
}
else if(mergeBehaviourString == tr("Maximum"))
{
evalText = maximumAttributeString(col);
}
else if(mergeBehaviourString == tr("Mean"))
{
evalText = meanAttributeString(col);
}
else if(mergeBehaviourString == tr("Median"))
{
evalText = medianAttributeString(col);
}
else if(mergeBehaviourString == tr("Concatenation"))
{
evalText = concatenationAttributeString(col);
}
else //an existing feature value
{
int featureId = mergeBehaviourString.split(" ").at(1).toInt(); //probably not very robust for translations...
evalText = featureAttributeString(featureId, col);
}
//insert string into table widget
QTableWidgetItem* newTotalItem = new QTableWidgetItem(evalText);
newTotalItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
mTableWidget->setItem(mTableWidget->rowCount() - 1, col, newTotalItem);
}
QString QgsMergeAttributesDialog::featureAttributeString(int featureId, int col)
{
QString resultText;
for(int i = 0; i < mFeatureList.size(); ++i)
{
int currentFid = mFeatureList[i].id();
if(currentFid == featureId)
{
QTableWidgetItem* currentItem = mTableWidget->item(i+1, col);
if(!currentItem)
{
continue;
}
resultText = currentItem->text();
}
}
return resultText;
}
QString QgsMergeAttributesDialog::minimumAttributeString(int col)
{
double minimumValue = std::numeric_limits<double>::max();
double currentValue;
bool conversion = false;
int numberOfConsideredFeatures = 0;
for(int i = 0; i < mFeatureList.size(); ++i)
{
currentValue = mTableWidget->item(i+1, col)->text().toDouble(&conversion);
if(conversion)
{
if(currentValue < minimumValue)
{
minimumValue = currentValue;
++numberOfConsideredFeatures;
}
}
}
if(numberOfConsideredFeatures < 1)
{
return QString();
}
return QString::number(minimumValue, 'f');
}
QString QgsMergeAttributesDialog::maximumAttributeString(int col)
{
double maximumValue = -std::numeric_limits<double>::max();
double currentValue;
bool conversion = false;
int numberOfConsideredFeatures = 0;
for(int i = 0; i < mFeatureList.size(); ++i)
{
currentValue = mTableWidget->item(i+1, col)->text().toDouble(&conversion);
if(conversion)
{
if(currentValue > maximumValue)
{
maximumValue = currentValue;
++numberOfConsideredFeatures;
}
}
}
if(numberOfConsideredFeatures < 1)
{
return QString();
}
return QString::number(maximumValue, 'f');
}
QString QgsMergeAttributesDialog::meanAttributeString(int col)
{
int numberOfConsideredFeatures = 0;
double currentValue;
double sum = 0;
bool conversion = false;
for(int i = 0; i < mFeatureList.size(); ++i)
{
currentValue = mTableWidget->item(i+1, col)->text().toDouble(&conversion);
if(conversion)
{
sum += currentValue;
++numberOfConsideredFeatures;
}
}
double mean = sum / numberOfConsideredFeatures;
return QString::number(mean, 'f');
}
QString QgsMergeAttributesDialog::medianAttributeString(int col)
{
//bring all values into a list and sort
QList<double> valueList;
double currentValue;
bool conversionSuccess;
for(int i = 0; i < mFeatureList.size(); ++i)
{
currentValue = mTableWidget->item(i+1, col)->text().toDouble(&conversionSuccess);
if(!conversionSuccess)
{
continue;
}
valueList.push_back(currentValue);
}
qSort(valueList);
double medianValue;
int size = valueList.size();
bool even = (size % 2) < 1;
if(even)
{
medianValue = (valueList[size / 2 - 1] + valueList[size / 2]) / 2;
}
else //odd
{
medianValue = valueList[(size + 1) / 2 - 1];
}
return QString::number(medianValue, 'f');
}
QString QgsMergeAttributesDialog::concatenationAttributeString(int col)
{
QStringList concatString;
for(int i = 0; i < mFeatureList.size(); ++i)
{
concatString << mTableWidget->item(i+1, col)->text();
}
return concatString.join(","); //todo: make separator user configurable
}
void QgsMergeAttributesDialog::on_mFromSelectedPushButton_clicked()
{
//find the selected feature
if(!mVectorLayer)
{
return;
}
//find out feature id of selected row
QList<QTableWidgetItem *> selectionList = mTableWidget->selectedItems();
if(selectionList.size() < 1)
{
return;
}
//assume all selected items to be in the same row
QTableWidgetItem* selectedItem = selectionList[0];
int selectedRow = selectedItem->row();
QTableWidgetItem* selectedHeaderItem = mTableWidget->verticalHeaderItem(selectedRow);
if(!selectedHeaderItem)
{
return;
}
bool conversionSuccess;
int featureId = selectedHeaderItem->text().toInt(&conversionSuccess);
if(!conversionSuccess)
{
return;
}
for(int i = 0; i < mTableWidget->columnCount(); ++i)
{
QComboBox* currentComboBox = dynamic_cast<QComboBox*>(mTableWidget->cellWidget(0, i));
if(currentComboBox)
{
currentComboBox->setCurrentIndex(currentComboBox->findText(tr("feature %1").arg(featureId)));
}
}
}
void QgsMergeAttributesDialog::on_mRemoveFeatureFromSelectionButton_clicked()
{
if(!mVectorLayer)
{
return;
}
//find out feature id of selected row
QList<QTableWidgetItem *> selectionList = mTableWidget->selectedItems();
if(selectionList.size() < 1)
{
return;
}
//assume all selected items to be in the same row
QTableWidgetItem* selectedItem = selectionList[0];
int selectedRow = selectedItem->row();
QTableWidgetItem* selectedHeaderItem = mTableWidget->verticalHeaderItem(selectedRow);
if(!selectedHeaderItem)
{
return;
}
bool conversionSuccess;
int featureId = selectedHeaderItem->text().toInt(&conversionSuccess);
if(!conversionSuccess)
{
selectedRowChanged();
return;
}
mTableWidget->removeRow(selectedRow);
selectedRowChanged();
//remove feature from the vector layer selection
QgsFeatureIds selectedIds = mVectorLayer->selectedFeaturesIds();
selectedIds.remove(featureId);
mVectorLayer->setSelectedFeatures(selectedIds);
mMapCanvas->repaint();
//remove feature option from the combo box (without altering the current merge values)
for(int i = 0; i < mTableWidget->columnCount(); ++i)
{
QComboBox* currentComboBox = dynamic_cast<QComboBox*>(mTableWidget->cellWidget(0, i));
if(currentComboBox)
{
currentComboBox->blockSignals(true);
currentComboBox->removeItem(currentComboBox->findText(tr("feature %1").arg(featureId)));
currentComboBox->blockSignals(false);
}
}
//finally remove the feature from mFeatureList
QgsFeatureList::iterator f_it = mFeatureList.begin();
for(; f_it != mFeatureList.end(); ++f_it)
{
if(f_it->id() == featureId)
{
mFeatureList.erase(f_it);
break;
}
}
}
void QgsMergeAttributesDialog::createRubberBandForFeature(int featureId)
{
//create rubber band to highlight the feature
delete mSelectionRubberBand;
mSelectionRubberBand = new QgsRubberBand(mMapCanvas, mVectorLayer->geometryType() == QGis::Polygon);
mSelectionRubberBand->setColor(QColor(255, 0, 0));
QgsFeature featureToSelect;
mVectorLayer->featureAtId(featureId, featureToSelect, true, false);
mSelectionRubberBand->setToGeometry( featureToSelect.geometry(), mVectorLayer );
}
QgsAttributeMap QgsMergeAttributesDialog::mergedAttributesMap() const
{
QgsAttributeMap resultMap;
if(mFeatureList.size() < 1)
{
return resultMap; //return empty map
}
resultMap = mFeatureList[0].attributeMap();
//go through all the items and replace the values in the attribute map
for(int i = 0; i < resultMap.size(); ++i)
{
QTableWidgetItem* currentItem = mTableWidget->item(mFeatureList.size() + 1, i);
if(!currentItem)
{
continue;
}
QString mergedString = currentItem->text();
QVariant newValue(mergedString);
resultMap.insert(i, newValue);
}
return resultMap;
}

View File

@ -0,0 +1,78 @@
/***************************************************************************
qgsmergeattributesdialog.h
--------------------------
begin : May 2009
copyright : (C) 2009 by Marco Hugentobler
email : marco dot hugentobler at karto dot baug dot ethz 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 QGSMERGEATTRIBUTESDIALOG_H
#define QGSMERGEATTRIBUTESDIALOG_H
#include "ui_qgsmergeattributesdialogbase.h"
#include "qgsfeature.h"
class QgsMapCanvas;
class QgsRubberBand;
class QgsVectorLayer;
class QComboBox;
/**A dialog to insert the merge behaviour for attributes (e.g. for the union features editing tool)*/
class QgsMergeAttributesDialog: public QDialog, private Ui::QgsMergeAttributesDialogBase
{
Q_OBJECT
public:
QgsMergeAttributesDialog(const QgsFeatureList& features, QgsVectorLayer* vl, QgsMapCanvas* canvas, QWidget * parent = 0, Qt::WindowFlags f = 0);
~QgsMergeAttributesDialog();
QgsAttributeMap mergedAttributesMap() const;
private slots:
void comboValueChanged(const QString & text);
void selectedRowChanged();
void on_mFromSelectedPushButton_clicked();
void on_mRemoveFeatureFromSelectionButton_clicked();
private:
QgsMergeAttributesDialog(); //default constructor forbidden
void createTableWidgetContents();
/**Create new combo box with the options for featureXX / mean / min / max */
QComboBox* createMergeComboBox(QVariant::Type columnType) const;
/**Returns the table widget column index of a combo box
@return the column index or -1 in case of error*/
int findComboColumn(QComboBox* c) const;
/**Calculates the merged value of a column (depending on the selected merge behaviour) and inserts the value in the corresponding cell*/
void refreshMergedValue(int col);
/**Inserts the attribute value of a specific feature into the row of merged attributes*/
QString featureAttributeString(int featureId, int col);
/**Calculates and inserts the minimum attribute value of a column*/
QString minimumAttributeString(int col);
/**Calculates and inserts the maximum value of a column*/
QString maximumAttributeString(int col);
/**Calculates and inserts the mean value of a column*/
QString meanAttributeString(int col);
/**Calculates and inserts the median value of a column*/
QString medianAttributeString(int col);
/**Appends the values of the features for the final value*/
QString concatenationAttributeString(int col);
/**Sets mSelectionRubberBand to a new feature*/
void createRubberBandForFeature(int featureId);
QgsFeatureList mFeatureList;
QgsVectorLayer* mVectorLayer;
QgsMapCanvas* mMapCanvas;
/**Item that highlights the selected feature in the merge table*/
QgsRubberBand* mSelectionRubberBand;
};
#endif // QGSMERGEATTRIBUTESDIALOG_H

View File

@ -0,0 +1,134 @@
<ui version="4.0" >
<class>QgsMergeAttributesDialogBase</class>
<widget class="QDialog" name="QgsMergeAttributesDialogBase" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>382</height>
</rect>
</property>
<property name="windowTitle" >
<string>Merge feature attributes</string>
</property>
<layout class="QGridLayout" name="gridLayout" >
<item row="0" column="0" >
<widget class="QTableWidget" name="mTableWidget" />
</item>
<item row="1" column="0" >
<layout class="QHBoxLayout" name="horizontalLayout" >
<item>
<widget class="QPushButton" name="mFromSelectedPushButton" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="mTakeSelectedAttributesLabel" >
<property name="text" >
<string>Take attributes from selected feature</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>58</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="2" column="0" >
<layout class="QHBoxLayout" name="horizontalLayout_2" >
<item>
<widget class="QPushButton" name="mRemoveFeatureFromSelectionButton" >
<property name="text" >
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="mRemoveFeatureFromSelectionLabel" >
<property name="text" >
<string>Remove feature from selection</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>98</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="3" column="0" >
<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>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QgsMergeAttributesDialogBase</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>QgsMergeAttributesDialogBase</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>