1
|
|
2
|
|
3
|
from PyQt4.QtCore import *
|
4
|
from PyQt4.QtGui import *
|
5
|
|
6
|
from qgis.core import *
|
7
|
from qgis.gui import *
|
8
|
|
9
|
import ftools_utils
|
10
|
|
11
|
from ui_frmMergeShapes import Ui_Dialog
|
12
|
|
13
|
class Dialog( QDialog, Ui_Dialog ):
|
14
|
def __init__( self, iface ):
|
15
|
QDialog.__init__( self )
|
16
|
self.setupUi( self )
|
17
|
self.iface = iface
|
18
|
|
19
|
self.mergeThread = None
|
20
|
self.inputFiles = None
|
21
|
|
22
|
self.btnOk = self.buttonBox.button( QDialogButtonBox.Ok )
|
23
|
self.btnClose = self.buttonBox.button( QDialogButtonBox.Close )
|
24
|
|
25
|
QObject.connect( self.btnSelectDir, SIGNAL( "clicked()" ), self.inputDir )
|
26
|
QObject.connect( self.btnSelectFile, SIGNAL( "clicked()" ), self.outFile )
|
27
|
|
28
|
QObject.connect( self.btnUpdate, SIGNAL( "clicked()" ), self.updateList )
|
29
|
|
30
|
def inputDir( self ):
|
31
|
inDir = QFileDialog.getExistingDirectory( self,
|
32
|
self.tr( "Select directory with shapefiles to merge" ),
|
33
|
"." )
|
34
|
|
35
|
if inDir.isEmpty():
|
36
|
return
|
37
|
|
38
|
|
39
|
|
40
|
|
41
|
|
42
|
|
43
|
|
44
|
|
45
|
|
46
|
|
47
|
|
48
|
|
49
|
|
50
|
self.leInputDir.setText( inDir )
|
51
|
|
52
|
def outFile( self ):
|
53
|
( self.outFileName, self.encoding ) = ftools_utils.saveDialog( self )
|
54
|
if self.outFileName is None or self.encoding is None:
|
55
|
return
|
56
|
self.leOutShape.setText( self.outFileName )
|
57
|
|
58
|
def reject( self ):
|
59
|
QDialog.reject( self )
|
60
|
|
61
|
|
62
|
|
63
|
def updateList( self ):
|
64
|
workDir = QDir( self.leInputDir.text() )
|
65
|
workDir.setFilter( QDir.Files | QDir.NoSymLinks | QDir.NoDotAndDotDot )
|
66
|
nameFilter = QStringList() << "*.shp" << "*.SHP"
|
67
|
workDir.setNameFilters( nameFilter )
|
68
|
self.inputFiles = workDir.entryList()
|
69
|
if self.inputFiles.count() == 0:
|
70
|
QMessageBox.warning( self, self.tr( "No shapefiles found" ),
|
71
|
self.tr( "There are no shapefiles in this directory. Please select another one." ) )
|
72
|
self.inputFiles = None
|
73
|
return
|
74
|
|
75
|
self.comboSelectAttribSrc.clear()
|
76
|
for inFile in self.inputFiles:
|
77
|
self.comboSelectAttribSrc.addItem(unicode(inFile))
|
78
|
|
79
|
self.progressFiles.setRange( 0, self.inputFiles.count() )
|
80
|
|
81
|
def accept( self ):
|
82
|
if self.inputFiles is None:
|
83
|
workDir = QDir( self.leInputDir.text() )
|
84
|
workDir.setFilter( QDir.Files | QDir.NoSymLinks | QDir.NoDotAndDotDot )
|
85
|
nameFilter = QStringList() << "*.shp" << "*.SHP"
|
86
|
workDir.setNameFilters( nameFilter )
|
87
|
self.inputFiles = workDir.entryList()
|
88
|
if self.inputFiles.count() == 0:
|
89
|
QMessageBox.warning( self, self.tr( "No shapefiles found" ),
|
90
|
self.tr( "There are no shapefiles in this directory. Please select another one." ) )
|
91
|
self.inputFiles = None
|
92
|
return
|
93
|
self.progressFiles.setRange( 0, self.inputFiles.count() )
|
94
|
|
95
|
outFile = QFile( self.outFileName )
|
96
|
if outFile.exists():
|
97
|
if not QgsVectorFileWriter.deleteShapeFile( self.outFileName ):
|
98
|
QMessageBox.warning( self, self.tr( "Delete error" ), self.tr( "Can't delete file %1" ).arg( outFileName ) )
|
99
|
return
|
100
|
|
101
|
baseDir = self.leInputDir.text()
|
102
|
|
103
|
QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) )
|
104
|
self.btnOk.setEnabled( False )
|
105
|
|
106
|
|
107
|
self.attributesShapeIndex = self.inputFiles.indexOf(self.comboSelectAttribSrc.currentText())
|
108
|
|
109
|
|
110
|
self.mergeThread = ShapeMergeThread( baseDir, self.inputFiles, self.outFileName, self.encoding, self.attributesShapeIndex)
|
111
|
QObject.connect( self.mergeThread, SIGNAL( "rangeChanged( PyQt_PyObject )" ), self.setProgressRange )
|
112
|
QObject.connect( self.mergeThread, SIGNAL( "featureProcessed()" ), self.featureProcessed )
|
113
|
QObject.connect( self.mergeThread, SIGNAL( "shapeProcessed()" ), self.shapeProcessed )
|
114
|
QObject.connect( self.mergeThread, SIGNAL( "processingFinished()" ), self.processingFinished )
|
115
|
QObject.connect( self.mergeThread, SIGNAL( "processingInterrupted()" ), self.processingInterrupted )
|
116
|
|
117
|
self.btnClose.setText( self.tr( "Cancel" ) )
|
118
|
QObject.disconnect( self.buttonBox, SIGNAL( "rejected()" ), self.reject )
|
119
|
QObject.connect( self.btnClose, SIGNAL( "clicked()" ), self.stopProcessing )
|
120
|
|
121
|
self.mergeThread.start()
|
122
|
|
123
|
def setProgressRange( self, max ):
|
124
|
self.progressFeatures.setRange( 0, max )
|
125
|
|
126
|
def featureProcessed( self ):
|
127
|
self.progressFeatures.setValue( self.progressFeatures.value() + 1 )
|
128
|
|
129
|
def shapeProcessed( self ):
|
130
|
self.progressFiles.setValue( self.progressFiles.value() + 1 )
|
131
|
|
132
|
def processingFinished( self ):
|
133
|
self.stopProcessing()
|
134
|
|
135
|
if self.chkAddToCanvas.isChecked():
|
136
|
if not ftools_utils.addShapeToCanvas( unicode( self.outFileName ) ):
|
137
|
QMessageBox.warning( self, self.tr( "Merging" ), self.tr( "Error loading output shapefile:\n%1" ).arg( unicode( self.outFileName ) ) )
|
138
|
|
139
|
self.restoreGui()
|
140
|
|
141
|
def processingInterrupted( self ):
|
142
|
self.restoreGui()
|
143
|
|
144
|
def stopProcessing( self ):
|
145
|
if self.mergeThread != None:
|
146
|
self.mergeThread.stop()
|
147
|
self.mergeThread = None
|
148
|
|
149
|
def restoreGui( self ):
|
150
|
self.progressFeatures.setValue( 0 )
|
151
|
self.progressFiles.setValue( 0 )
|
152
|
QApplication.restoreOverrideCursor()
|
153
|
QObject.connect( self.buttonBox, SIGNAL( "rejected()" ), self.reject )
|
154
|
self.btnClose.setText( self.tr( "Close" ) )
|
155
|
self.btnOk.setEnabled( True )
|
156
|
|
157
|
class ShapeMergeThread( QThread ):
|
158
|
|
159
|
def __init__( self, dir, shapes, outputFileName, outputEncoding, attributesShapeIndex ):
|
160
|
QThread.__init__( self, QThread.currentThread() )
|
161
|
self.baseDir = dir
|
162
|
self.shapes = shapes
|
163
|
self.outputFileName = outputFileName
|
164
|
self.outputEncoding = outputEncoding
|
165
|
self.attributesShapeIndex = attributesShapeIndex
|
166
|
|
167
|
|
168
|
self.mutex = QMutex()
|
169
|
self.stopMe = 0
|
170
|
|
171
|
def run( self ):
|
172
|
self.mutex.lock()
|
173
|
self.stopMe = 0
|
174
|
self.mutex.unlock()
|
175
|
|
176
|
interrupted = False
|
177
|
|
178
|
|
179
|
|
180
|
layerPath = QFileInfo( self.baseDir + "/" + self.shapes[ self.attributesShapeIndex ] ).absoluteFilePath()
|
181
|
newLayer = QgsVectorLayer( layerPath, QFileInfo( layerPath ).baseName(), "ogr" )
|
182
|
self.crs = newLayer.srs()
|
183
|
self.geom = newLayer.wkbType()
|
184
|
vprovider = newLayer.dataProvider()
|
185
|
self.fields = vprovider.fields()
|
186
|
|
187
|
myfieldnames = ftools_utils.getFieldList(newLayer)
|
188
|
|
189
|
writer = QgsVectorFileWriter( self.outputFileName, self.outputEncoding,
|
190
|
self.fields, self.geom, self.crs )
|
191
|
|
192
|
for fileName in self.shapes:
|
193
|
layerPath = QFileInfo( self.baseDir + "/" + fileName ).absoluteFilePath()
|
194
|
newLayer = QgsVectorLayer( layerPath, QFileInfo( layerPath ).baseName(), "ogr" )
|
195
|
newFieldList = ftools_utils.getFieldList(newLayer)
|
196
|
vprovider = newLayer.dataProvider()
|
197
|
allAttrs = vprovider.attributeIndexes()
|
198
|
vprovider.select( allAttrs )
|
199
|
nFeat = vprovider.featureCount()
|
200
|
self.emit( SIGNAL( "rangeChanged( PyQt_PyObject )" ), nFeat )
|
201
|
inFeat = QgsFeature()
|
202
|
outFeat = QgsFeature()
|
203
|
inGeom = QgsGeometry()
|
204
|
while vprovider.nextFeature( inFeat ):
|
205
|
atMap = inFeat.attributeMap()
|
206
|
inGeom = QgsGeometry( inFeat.geometry() )
|
207
|
outFeat.setGeometry( inGeom )
|
208
|
outFeat.setAttributeMap( atMap )
|
209
|
|
210
|
for i in myfieldnames:
|
211
|
outFeat.changeAttribute (i, QVariant("-9999"))
|
212
|
for j in newFieldList:
|
213
|
if(newFieldList[j].name() == myfieldnames[i].name()):
|
214
|
outFeat.changeAttribute (i, inFeat.attributeMap()[ j ])
|
215
|
writer.addFeature( outFeat )
|
216
|
self.emit( SIGNAL( "featureProcessed()" ) )
|
217
|
|
218
|
self.emit( SIGNAL( "shapeProcessed()" ) )
|
219
|
self.mutex.lock()
|
220
|
s = self.stopMe
|
221
|
self.mutex.unlock()
|
222
|
if s == 1:
|
223
|
interrupted = True
|
224
|
break
|
225
|
|
226
|
del writer
|
227
|
|
228
|
if not interrupted:
|
229
|
self.emit( SIGNAL( "processingFinished()" ) )
|
230
|
else:
|
231
|
self.emit( SIGNAL( "processingInterrupted()" ) )
|
232
|
|
233
|
def stop( self ):
|
234
|
self.mutex.lock()
|
235
|
self.stopMe = 1
|
236
|
self.mutex.unlock()
|
237
|
|
238
|
QThread.wait( self )
|