|
114 | 114 | #include "qgsmapoverviewcanvas.h"
|
115 | 115 | #include "qgsmaprenderer.h"
|
116 | 116 | #include "qgsmaptip.h"
|
| 117 | +#include "qgsmergeattributesdialog.h" |
117 | 118 | #include "qgsmessageviewer.h"
|
118 | 119 | #include "qgsoptions.h"
|
119 | 120 | #include "qgspastetransformations.h"
|
@@ -703,6 +704,12 @@ void QgisApp::createActions()
|
703 | 704 | connect( mActionDeletePart, SIGNAL( triggered() ), this, SLOT( deletePart() ) );
|
704 | 705 | mActionDeletePart->setEnabled( false );
|
705 | 706 |
|
| 707 | + mActionMergeFeatures = new QAction( getThemeIcon("mActionMergeFeatures.png"), tr("Merge selected features"), this); |
| 708 | + shortcuts->registerAction(mActionMergeFeatures); |
| 709 | + mActionMergeFeatures->setStatusTip( tr("Merge selected features")); |
| 710 | + connect( mActionMergeFeatures, SIGNAL(triggered()), this, SLOT(mergeSelectedFeatures())); |
| 711 | + mActionMergeFeatures->setEnabled(false); |
| 712 | + |
706 | 713 |
|
707 | 714 | // View Menu Items
|
708 | 715 |
|
@@ -1053,6 +1060,7 @@ void QgisApp::createActionGroups()
|
1053 | 1060 | mMapToolGroup->addAction( mActionDeleteRing );
|
1054 | 1061 | mActionDeletePart->setCheckable( true );
|
1055 | 1062 | mMapToolGroup->addAction( mActionDeletePart );
|
| 1063 | + mMapToolGroup->addAction( mActionMergeFeatures); |
1056 | 1064 | }
|
1057 | 1065 |
|
1058 | 1066 | void QgisApp::createMenus()
|
@@ -1141,6 +1149,7 @@ void QgisApp::createMenus()
|
1141 | 1149 | mEditMenu->addAction( mActionAddIsland );
|
1142 | 1150 | mEditMenu->addAction( mActionDeleteRing );
|
1143 | 1151 | mEditMenu->addAction( mActionDeletePart );
|
| 1152 | + mEditMenu->addAction( mActionMergeFeatures ); |
1144 | 1153 |
|
1145 | 1154 | if ( layout == QDialogButtonBox::GnomeLayout || layout == QDialogButtonBox::MacLayout )
|
1146 | 1155 | {
|
@@ -1345,6 +1354,7 @@ void QgisApp::createToolBars()
|
1345 | 1354 | mAdvancedDigitizeToolBar->addAction( mActionAddIsland );
|
1346 | 1355 | mAdvancedDigitizeToolBar->addAction( mActionDeleteRing );
|
1347 | 1356 | mAdvancedDigitizeToolBar->addAction( mActionDeletePart );
|
| 1357 | + mAdvancedDigitizeToolBar->addAction( mActionMergeFeatures ); |
1348 | 1358 | mToolbarMenu->addAction( mAdvancedDigitizeToolBar->toggleViewAction() );
|
1349 | 1359 |
|
1350 | 1360 |
|
@@ -4085,6 +4095,139 @@ void QgisApp::deletePart()
|
4085 | 4095 | mMapCanvas->setMapTool( mMapTools.mDeletePart );
|
4086 | 4096 | }
|
4087 | 4097 |
|
| 4098 | +QgsGeometry* QgisApp::unionGeometries(const QgsVectorLayer* vl, QgsFeatureList& featureList) const |
| 4099 | +{ |
| 4100 | + if(!vl || featureList.size() < 2) |
| 4101 | + { |
| 4102 | + return 0; |
| 4103 | + } |
| 4104 | + |
| 4105 | + QgsGeometry* unionGeom = featureList[0].geometry(); |
| 4106 | + QgsGeometry* backupPtr = 0; //pointer to delete intermediate results |
| 4107 | + if(!unionGeom) |
| 4108 | + { |
| 4109 | + return 0; |
| 4110 | + } |
| 4111 | + |
| 4112 | + for(int i = 1; i < featureList.size(); ++i) |
| 4113 | + { |
| 4114 | + QgsGeometry* currentGeom = featureList[i].geometry(); |
| 4115 | + if(currentGeom) |
| 4116 | + { |
| 4117 | + backupPtr = unionGeom; |
| 4118 | + unionGeom = unionGeom->combine(currentGeom); |
| 4119 | + if(i > 1) //delete previous intermediate results |
| 4120 | + { |
| 4121 | + delete backupPtr; |
| 4122 | + backupPtr = 0; |
| 4123 | + } |
| 4124 | + } |
| 4125 | + } |
| 4126 | + return unionGeom; |
| 4127 | +} |
| 4128 | + |
| 4129 | +void QgisApp::mergeSelectedFeatures() |
| 4130 | +{ |
| 4131 | + //get active layer (hopefully vector) |
| 4132 | + QgsMapLayer* activeMapLayer = activeLayer(); |
| 4133 | + if(!activeMapLayer) |
| 4134 | + { |
| 4135 | + QMessageBox::information(0, tr("No active layer"), tr("No active layer found. Please select a layer in the layer list")); |
| 4136 | + return; |
| 4137 | + } |
| 4138 | + QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>(activeMapLayer); |
| 4139 | + if(!vl) |
| 4140 | + { |
| 4141 | + 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")); |
| 4142 | + return; |
| 4143 | + } |
| 4144 | + if(!vl->isEditable()) |
| 4145 | + { |
| 4146 | + 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")); |
| 4147 | + return; |
| 4148 | + } |
| 4149 | + |
| 4150 | + //get selected feature ids (as a QSet<int> ) |
| 4151 | + const QgsFeatureIds& featureIdSet = vl->selectedFeaturesIds(); |
| 4152 | + if(featureIdSet.size() < 2) |
| 4153 | + { |
| 4154 | + QMessageBox::information(0, "Not enough features selected", tr("The merge tool requires at least two selected features")); |
| 4155 | + return; |
| 4156 | + } |
| 4157 | + |
| 4158 | + //get initial selection (may be altered by attribute merge dialog later) |
| 4159 | + QgsFeatureList featureList = vl->selectedFeatures(); //get QList<QgsFeature> |
| 4160 | + QgsGeometry* unionGeom = unionGeometries(vl, featureList); |
| 4161 | + if(!unionGeom) |
| 4162 | + { |
| 4163 | + return; |
| 4164 | + } |
| 4165 | + |
| 4166 | + //make a first geometry union and notify the user straight away if the union geometry type does not match the layer one |
| 4167 | + QGis::WkbType originalType = vl->wkbType(); |
| 4168 | + QGis::WkbType newType = unionGeom->wkbType(); |
| 4169 | + if(unionGeom->wkbType() != vl->wkbType()) |
| 4170 | + { |
| 4171 | + 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")); |
| 4172 | + delete unionGeom; |
| 4173 | + return; |
| 4174 | + } |
| 4175 | + |
| 4176 | + //merge the attributes together |
| 4177 | + QgsMergeAttributesDialog d(featureList, vl, mapCanvas()); |
| 4178 | + if(d.exec() == QDialog::Rejected) |
| 4179 | + { |
| 4180 | + return; |
| 4181 | + } |
| 4182 | + |
| 4183 | + QgsFeatureList featureListAfter = vl->selectedFeatures(); |
| 4184 | + |
| 4185 | + if(featureListAfter.size() < 2) |
| 4186 | + { |
| 4187 | + QMessageBox::information(0, "Not enough features selected", tr("The merge tool requires at least two selected features")); |
| 4188 | + delete unionGeom; |
| 4189 | + return; |
| 4190 | + } |
| 4191 | + |
| 4192 | + //if the user changed the feature selection in the merge dialog, we need to repead the union and check the type |
| 4193 | + if(featureList.size() != featureListAfter.size()) |
| 4194 | + { |
| 4195 | + delete unionGeom; |
| 4196 | + unionGeom = unionGeometries(vl, featureListAfter); |
| 4197 | + if(!unionGeom) |
| 4198 | + { |
| 4199 | + return; |
| 4200 | + } |
| 4201 | + |
| 4202 | + originalType = vl->wkbType(); |
| 4203 | + newType = unionGeom->wkbType(); |
| 4204 | + if(unionGeom->wkbType() != vl->wkbType()) |
| 4205 | + { |
| 4206 | + 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")); |
| 4207 | + delete unionGeom; |
| 4208 | + return; |
| 4209 | + } |
| 4210 | + } |
| 4211 | + |
| 4212 | + //create new feature |
| 4213 | + QgsFeature newFeature; |
| 4214 | + newFeature.setGeometry(unionGeom); |
| 4215 | + newFeature.setAttributeMap(d.mergedAttributesMap()); |
| 4216 | + |
| 4217 | + QgsFeatureList::const_iterator feature_it = featureListAfter.constBegin(); |
| 4218 | + for(; feature_it != featureListAfter.constEnd(); ++feature_it) |
| 4219 | + { |
| 4220 | + vl->deleteFeature(feature_it->id()); |
| 4221 | + } |
| 4222 | + |
| 4223 | + vl->addFeature(newFeature, false); |
| 4224 | + |
| 4225 | + if(mapCanvas()) |
| 4226 | + { |
| 4227 | + mapCanvas()->refresh(); |
| 4228 | + } |
| 4229 | +} |
| 4230 | + |
4088 | 4231 | void QgisApp::splitFeatures()
|
4089 | 4232 | {
|
4090 | 4233 | mMapCanvas->setMapTool( mMapTools.mSplitFeatures );
|
@@ -5314,6 +5457,17 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
|
5314 | 5457 | mActionCutFeatures->setEnabled( false );
|
5315 | 5458 | }
|
5316 | 5459 |
|
| 5460 | + //merge tool needs editable layer and provider with the capability of adding and deleting features |
| 5461 | + if ( vlayer->isEditable() && (dprovider->capabilities() & QgsVectorDataProvider::DeleteFeatures) \ |
| 5462 | + && QgsVectorDataProvider::AddFeatures) |
| 5463 | + { |
| 5464 | + mActionMergeFeatures->setEnabled(layerHasSelection); |
| 5465 | + } |
| 5466 | + else |
| 5467 | + { |
| 5468 | + mActionMergeFeatures->setEnabled( false ); |
| 5469 | + } |
| 5470 | + |
5317 | 5471 | // moving enabled if geometry changes are supported
|
5318 | 5472 | if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeGeometries )
|
5319 | 5473 | {
|
@@ -5366,6 +5520,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
|
5366 | 5520 | mActionSplitFeatures->setEnabled( true );
|
5367 | 5521 | mActionSimplifyFeature->setEnabled( true );
|
5368 | 5522 | mActionDeletePart->setEnabled( true );
|
| 5523 | + |
5369 | 5524 | }
|
5370 | 5525 | else
|
5371 | 5526 | {
|
|
0 commit comments