doMergeShapes.py

Rui Pedro Henriques, 2010-09-15 08:05 AM

Download (8.38 KB)

 
1
# -*- coding: utf-8 -*-
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
  #[RPH] changed 1 line below
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
    #workDir = QDir( inDir )
39
    #workDir.setFilter( QDir.Files | QDir.NoSymLinks | QDir.NoDotAndDotDot )
40
    #nameFilter = QStringList() << "*.shp" << "*.SHP"
41
    #workDir.setNameFilters( nameFilter )
42
    #self.inputFiles = workDir.entryList()
43
    #if self.inputFiles.count() == 0:
44
    #  QMessageBox.warning( self, self.tr( "No shapefiles found" ),
45
    #    self.tr( "There are no shapefiles in this directory. Please select another one." ) )
46
    #  self.inputFiles = None
47
    #  return
48

    
49
    #self.progressFiles.setRange( 0, self.inputFiles.count() )
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
  #[RPH] changed 17 lines below 
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
  #[RPH] changed 1 line below 
107
    self.attributesShapeIndex = self.inputFiles.indexOf(self.comboSelectAttribSrc.currentText())
108

    
109
  #[RPH] changed 1 lines below
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
  #[RPH] changed 1 line below
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
    # get information about shapefiles
179
    #[RPH] changed 1 lines below
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
        #[RPH] changed 1 lines below
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
#[RPH] changed 5 lines below
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 )