Skip to content

Commit 6327b2e

Browse files
committed
allow merging shapefiles with different attribute tables (fix #3010)
1 parent 07da493 commit 6327b2e

File tree

2 files changed

+49
-11
lines changed

2 files changed

+49
-11
lines changed

python/plugins/fTools/tools/doMergeShapes.py

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ def outFile( self ):
5858
self.leOutShape.setText( self.outFileName )
5959

6060
def inputFile( self ):
61-
files = QFileDialog.getOpenFileNames( self, self.tr( "Select files to merge" ), ".", "Shapefiles(*.shp *.SHP)" )
62-
if files.isEmpty():
61+
( files, self.inEncoding ) = ftools_utils.openDialog( self, dialogMode="ManyFiles" )
62+
if files is None or self.inEncoding is None:
6363
self.inputFiles = None
6464
return
6565

@@ -134,7 +134,7 @@ def accept( self ):
134134
self.btnOk.setEnabled( False )
135135

136136
self.mergeThread = ShapeMergeThread( baseDir, self.inputFiles, self.inEncoding, self.outFileName, self.encoding )
137-
QObject.connect( self.mergeThread, SIGNAL( "rangeChanged( PyQt_PyObject )" ), self.setProgressRange )
137+
QObject.connect( self.mergeThread, SIGNAL( "rangeChanged( PyQt_PyObject )" ), self.setFeatureProgressRange )
138138
QObject.connect( self.mergeThread, SIGNAL( "checkStarted()" ), self.setFeatureProgressFormat )
139139
QObject.connect( self.mergeThread, SIGNAL( "checkFinished()" ), self.resetFeatureProgressFormat )
140140
QObject.connect( self.mergeThread, SIGNAL( "fileNameChanged( PyQt_PyObject )" ), self.setShapeProgressFormat )
@@ -149,8 +149,8 @@ def accept( self ):
149149

150150
self.mergeThread.start()
151151

152-
def setProgressRange( self, max ):
153-
self.progressFeatures.setRange( 0, max )
152+
def setFeatureProgressRange( self, maximum ):
153+
self.progressFeatures.setRange( 0, maximum )
154154
self.progressFeatures.setValue( 0 )
155155

156156
def setFeatureProgressFormat( self ):
@@ -216,13 +216,38 @@ def run( self ):
216216

217217
interrupted = False
218218

219+
# create attribute list with uniquie fields
220+
# from all selected layers
221+
mergedFields = {}
222+
count = 0
223+
self.emit( SIGNAL( "rangeChanged( PyQt_PyObject )" ), len( self.shapes ) )
224+
self.emit( SIGNAL( "checkStarted()" ) )
225+
for fileName in self.shapes:
226+
layerPath = QFileInfo( self.baseDir + "/" + fileName ).absoluteFilePath()
227+
newLayer = QgsVectorLayer( layerPath, QFileInfo( layerPath ).baseName(), "ogr" )
228+
if not newLayer.isValid():
229+
continue
230+
vprovider = newLayer.dataProvider()
231+
layerFields = vprovider.fields()
232+
for layerIndex, layerField in layerFields.iteritems():
233+
fieldFound = False
234+
for mergedIndex, mergedField in mergedFields.iteritems():
235+
if ( mergedField.name() == layerField.name() ) and ( mergedField.type() == layerField.type() ):
236+
fieldFound = True
237+
238+
if not fieldFound:
239+
mergedFields[ count ] = layerField
240+
count += 1
241+
self.emit( SIGNAL( "featureProcessed()" ) )
242+
self.emit( SIGNAL( "checkFinished()" ) )
243+
219244
# get information about shapefiles
220245
layerPath = QFileInfo( self.baseDir + "/" + self.shapes[ 0 ] ).absoluteFilePath()
221246
newLayer = QgsVectorLayer( layerPath, QFileInfo( layerPath ).baseName(), "ogr" )
222247
self.crs = newLayer.crs()
223248
self.geom = newLayer.wkbType()
224249
vprovider = newLayer.dataProvider()
225-
self.fields = vprovider.fields()
250+
self.fields = mergedFields
226251

227252
writer = QgsVectorFileWriter( self.outputFileName, self.outputEncoding,
228253
self.fields, self.geom, self.crs )
@@ -234,6 +259,7 @@ def run( self ):
234259
continue
235260
vprovider = newLayer.dataProvider()
236261
vprovider.setEncoding( self.inputEncoding )
262+
layerFields = vprovider.fields()
237263
allAttrs = vprovider.attributeIndexes()
238264
vprovider.select( allAttrs )
239265
nFeat = vprovider.featureCount()
@@ -244,9 +270,15 @@ def run( self ):
244270
inGeom = QgsGeometry()
245271
while vprovider.nextFeature( inFeat ):
246272
atMap = inFeat.attributeMap()
273+
mergedAttrs = {}
274+
# fill available attributes with values
275+
for layerIndex, layerField in layerFields.iteritems():
276+
for mergedIndex, mergedField in self.fields.iteritems():
277+
if ( mergedField.name() == layerField.name() ) and ( mergedField.type() == layerField.type() ):
278+
mergedAttrs[ mergedIndex ] = atMap[ layerIndex ]
247279
inGeom = QgsGeometry( inFeat.geometry() )
248280
outFeat.setGeometry( inGeom )
249-
outFeat.setAttributeMap( atMap )
281+
outFeat.setAttributeMap( mergedAttrs )
250282
writer.addFeature( outFeat )
251283
self.emit( SIGNAL( "featureProcessed()" ) )
252284

python/plugins/fTools/tools/ftools_utils.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ def getUniqueValues( provider, index ):
253253
return values
254254

255255
# Generate a save file dialog with a dropdown box for choosing encoding style
256-
def saveDialog( parent, filtering="Shapefiles (*.shp)"):
256+
def saveDialog( parent, filtering="Shapefiles (*.shp *.SHP)"):
257257
settings = QSettings()
258258
dirName = settings.value( "/UI/lastShapefileDir" ).toString()
259259
encode = settings.value( "/UI/encoding" ).toString()
@@ -269,18 +269,24 @@ def saveDialog( parent, filtering="Shapefiles (*.shp)"):
269269
return ( unicode( files.first() ), unicode( fileDialog.encoding() ) )
270270

271271
# Generate a save file dialog with a dropdown box for choosing encoding style
272-
def openDialog( parent, filtering="Shapefiles (*.shp)"):
272+
# with mode="SingleFile" will allow to select only one file, in other cases - several files
273+
def openDialog( parent, filtering="Shapefiles (*.shp *.SHP)", dialogMode="SingleFile"):
273274
settings = QSettings()
274275
dirName = settings.value( "/UI/lastShapefileDir" ).toString()
275276
encode = settings.value( "/UI/encoding" ).toString()
276277
fileDialog = QgsEncodingFileDialog( parent, "Save output shapefile", dirName, QString(filtering), encode )
277-
fileDialog.setFileMode( QFileDialog.AnyFile )
278+
#fileDialog.setFileMode( QFileDialog.AnyFile )
279+
fileDialog.setFileMode( QFileDialog.ExistingFiles )
278280
fileDialog.setAcceptMode( QFileDialog.AcceptOpen )
279281
if not fileDialog.exec_() == QDialog.Accepted:
280282
return None, None
281283
files = fileDialog.selectedFiles()
282284
settings.setValue("/UI/lastShapefileDir", QVariant( QFileInfo( unicode( files.first() ) ).absolutePath() ) )
283-
return ( unicode( files.first() ), unicode( fileDialog.encoding() ) )
285+
#return ( unicode( files.first() ), unicode( fileDialog.encoding() ) )
286+
if dialogMode == "SingleFile":
287+
return ( unicode( files.first() ), unicode( fileDialog.encoding() ) )
288+
else:
289+
return ( files, unicode( fileDialog.encoding() ) )
284290

285291
# Generate a select directory dialog with a dropdown box for choosing encoding style
286292
def dirDialog( parent ):

0 commit comments

Comments
 (0)