Skip to content

Commit 24e259b

Browse files
committedNov 26, 2012
[FEATURE] Possibility to save error messages as shapefile from check
geometry validity tool. Contributed by Salvatore Larosa
1 parent 677c9ca commit 24e259b

File tree

4 files changed

+216
-79
lines changed

4 files changed

+216
-79
lines changed
 

‎i18n/qgis_it.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,11 @@ sono stati ridotti a %2 dopo la semplificazione</translation>
830830
<source>Press Ctrl+C to copy results to the clipboard</source>
831831
<translation>Premi Ctrl+C per copiare i risultati negli appunti</translation>
832832
</message>
833+
<message>
834+
<location filename="../python/plugins/fTools/tools/frmVisual.ui" line="120"/>
835+
<source>Save errors location</source>
836+
<translation>Salva posizione errori</translation>
837+
</message>
833838
<message>
834839
<source>Sum line lengths</source>
835840
<translation>Somma lunghezza linee</translation>

‎python/plugins/fTools/tools/doValidate.py

Lines changed: 115 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def setGeom(self, p):
6060

6161
def reset(self):
6262
if not self.__marker is None:
63-
self.__canvas.scene().removeItem(self.__marker)
63+
self.__canvas.scene().removeItem(self.__marker)
6464
del self.__marker
6565
self.__marker = None
6666

@@ -83,9 +83,10 @@ def __init__(self, iface):
8383
self.tblUnique.setSelectionBehavior(QAbstractItemView.SelectRows)
8484
# populate list of available layers
8585
myList = ftools_utils.getLayerNames( [ QGis.Point, QGis.Line, QGis.Polygon ] )
86-
self.connect(self.tblUnique, SIGNAL("currentItemChanged(QTableWidgetItem*, QTableWidgetItem*)" ),
86+
self.connect(self.tblUnique, SIGNAL("currentItemChanged(QTableWidgetItem*, QTableWidgetItem*)" ),
8787
self.zoomToError)
8888
self.inShape.addItems( myList )
89+
self.buttonBox_2.setOrientation(Qt.Horizontal)
8990
self.cancel_close = self.buttonBox_2.button(QDialogButtonBox.Close)
9091
self.buttonOk = self.buttonBox_2.button(QDialogButtonBox.Ok)
9192
self.progressBar.setValue(0)
@@ -96,12 +97,16 @@ def __init__(self, iface):
9697
settings = QSettings()
9798
self.restoreGeometry( settings.value("/fTools/ValidateDialog/geometry").toByteArray() )
9899

100+
QObject.connect( self.browseShpError, SIGNAL( "clicked()" ), self.outFile )
101+
QObject.connect( self.ckBoxShpError, SIGNAL( "stateChanged( int )" ), self.updateGui )
102+
self.updateGui()
103+
99104
def closeEvent(self, e):
100105
settings = QSettings()
101106
settings.setValue( "/fTools/ValidateDialog/geometry", QVariant(self.saveGeometry()) )
102107
QDialog.closeEvent(self, e)
103108
del self.marker
104-
109+
105110
def keyPressEvent( self, e ):
106111
if ( e.modifiers() == Qt.ControlModifier or \
107112
e.modifiers() == Qt.MetaModifier ) and \
@@ -122,10 +127,37 @@ def accept( self ):
122127
QMessageBox.information( self, self.tr("Error!"), self.tr( "Please specify input vector layer" ) )
123128
elif self.cmbField.isVisible() and self.cmbField.currentText() == "":
124129
QMessageBox.information( self, self.tr("Error!"), self.tr( "Please specify input field" ) )
130+
elif self.ckBoxShpError.isChecked() and self.lineEditShpError.text() == "":
131+
QMessageBox.information( self, self.tr( "Error!" ), self.tr( "Please specify output shapefile" ) )
125132
else:
126133
self.vlayer = ftools_utils.getVectorLayerByName( self.inShape.currentText() )
127134
self.validate( self.useSelected.checkState() )
128-
135+
136+
def updateGui( self ):
137+
if self.ckBoxShpError.isChecked():
138+
self.lineEditShpError.setEnabled( True )
139+
self.browseShpError.setEnabled( True )
140+
self.tblUnique.setEnabled( False )
141+
self.lstCount.setEnabled( False )
142+
self.label_2.setEnabled( False )
143+
self.label_4.setEnabled( False )
144+
self.label_5.setEnabled( False )
145+
else:
146+
self.lineEditShpError.setEnabled( False )
147+
self.browseShpError.setEnabled( False )
148+
self.tblUnique.setEnabled( True )
149+
self.lstCount.setEnabled( True )
150+
self.label_2.setEnabled( True )
151+
self.label_4.setEnabled( True )
152+
self.label_5.setEnabled( True )
153+
154+
def outFile( self ):
155+
self.lineEditShpError.clear()
156+
(self.shapefileName, self.encoding) = ftools_utils.saveDialog( self )
157+
if self.shapefileName is None or self.encoding is None:
158+
return
159+
self.lineEditShpError.setText( QString( self.shapefileName ) )
160+
129161
def zoomToError(self, curr, prev):
130162
if curr is None:
131163
return
@@ -162,11 +194,16 @@ def zoomToError(self, curr, prev):
162194
mc.refresh()
163195

164196
def validate( self, mySelection ):
165-
self.tblUnique.clearContents()
166-
self.tblUnique.setRowCount( 0 )
167-
self.lstCount.clear()
197+
if not self.ckBoxShpError.isChecked():
198+
self.tblUnique.clearContents()
199+
self.tblUnique.setRowCount( 0 )
200+
self.lstCount.clear()
201+
self.shapefileName = None
202+
self.encoding = None
203+
168204
self.buttonOk.setEnabled( False )
169-
self.testThread = validateThread( self.iface.mainWindow(), self, self.vlayer, mySelection )
205+
206+
self.testThread = validateThread( self.iface.mainWindow(), self, self.vlayer, mySelection, self.shapefileName, self.encoding, self.ckBoxShpError.isChecked() )
170207
QObject.connect( self.testThread, SIGNAL( "runFinished(PyQt_PyObject)" ), self.runFinishedFromThread )
171208
QObject.connect( self.testThread, SIGNAL( "runStatus(PyQt_PyObject)" ), self.runStatusFromThread )
172209
QObject.connect( self.testThread, SIGNAL( "runRange(PyQt_PyObject)" ), self.runRangeFromThread )
@@ -180,60 +217,73 @@ def reject(self):
180217
# Remove Marker
181218
self.marker.reset()
182219
QDialog.reject(self)
183-
220+
184221
def cancelThread( self ):
185222
self.testThread.stop()
186223
QApplication.restoreOverrideCursor()
187224
self.buttonOk.setEnabled( True )
188-
189-
def runFinishedFromThread( self, output ):
225+
226+
def runFinishedFromThread( self, success ):
190227
self.testThread.stop()
191228
QApplication.restoreOverrideCursor()
192229
self.buttonOk.setEnabled( True )
193-
self.tblUnique.setColumnCount( 2 )
194-
count = 0
195-
for rec in output:
196-
if len(rec[1]) < 1:
197-
continue
198-
where = None
199-
for err in rec[1]: # for each error we find
200-
self.tblUnique.insertRow(count)
201-
fidItem = QTableWidgetItem( str(rec[0]) )
202-
self.tblUnique.setItem( count, 0, fidItem )
203-
message = err.what()
204-
errItem = QTableWidgetItem( message )
205-
if err.hasWhere(): # if there is a location associated with the error
206-
errItem.setData(Qt.UserRole, QVariant(err.where()))
207-
self.tblUnique.setItem( count, 1, errItem )
208-
count += 1
209-
self.tblUnique.setHorizontalHeaderLabels( [ self.tr("Feature"), self.tr("Error(s)") ] )
210-
self.tblUnique.horizontalHeader().setResizeMode( 0, QHeaderView.ResizeToContents )
211-
self.tblUnique.horizontalHeader().show()
212-
self.tblUnique.horizontalHeader().setResizeMode( 1, QHeaderView.Stretch )
213-
self.tblUnique.resizeRowsToContents()
214-
self.lstCount.insert(str(count))
230+
if success == "writeShape":
231+
extra = ""
232+
addToTOC = QMessageBox.question( self, self.tr("Geometry"),
233+
self.tr( "Created output shapefile:\n%1\n%2\n\nWould you like to add the new layer to the TOC?" ).arg( unicode( self.shapefileName ) ).arg( extra ),
234+
QMessageBox.Yes, QMessageBox.No, QMessageBox.NoButton )
235+
if addToTOC == QMessageBox.Yes:
236+
if not ftools_utils.addShapeToCanvas( unicode( self.shapefileName ) ):
237+
QMessageBox.warning( self, self.tr( "Geometry"),
238+
self.tr( "Error loading output shapefile:\n%1" ).arg( unicode( self.shapefileName ) ) )
239+
else:
240+
self.tblUnique.setColumnCount( 2 )
241+
count = 0
242+
for rec in success:
243+
if len(rec[1]) < 1:
244+
continue
245+
where = None
246+
for err in rec[1]: # for each error we find
247+
self.tblUnique.insertRow(count)
248+
fidItem = QTableWidgetItem( str(rec[0]) )
249+
self.tblUnique.setItem( count, 0, fidItem )
250+
message = err.what()
251+
errItem = QTableWidgetItem( message )
252+
if err.hasWhere(): # if there is a location associated with the error
253+
errItem.setData(Qt.UserRole, QVariant(err.where()))
254+
self.tblUnique.setItem( count, 1, errItem )
255+
count += 1
256+
self.tblUnique.setHorizontalHeaderLabels( [ self.tr("Feature"), self.tr("Error(s)") ] )
257+
self.tblUnique.horizontalHeader().setResizeMode( 0, QHeaderView.ResizeToContents )
258+
self.tblUnique.horizontalHeader().show()
259+
self.tblUnique.horizontalHeader().setResizeMode( 1, QHeaderView.Stretch )
260+
self.tblUnique.resizeRowsToContents()
261+
self.lstCount.insert(str(count))
215262
self.cancel_close.setText( "Close" )
216263
QObject.disconnect( self.cancel_close, SIGNAL( "clicked()" ), self.cancelThread )
217264
return True
218-
265+
219266
def runStatusFromThread( self, status ):
220267
self.progressBar.setValue( status )
221-
268+
222269
def runRangeFromThread( self, range_vals ):
223270
self.progressBar.setRange( range_vals[ 0 ], range_vals[ 1 ] )
224271

225272
class validateThread( QThread ):
226-
def __init__( self, parentThread, parentObject, vlayer, mySelection ):
273+
def __init__( self, parentThread, parentObject, vlayer, mySelection, myName, myEncoding, myNewShape ):
227274
QThread.__init__( self, parentThread )
228275
self.parent = parentObject
229276
self.running = False
230277
self.vlayer = vlayer
231278
self.mySelection = mySelection
279+
self.myName = myName
280+
self.myEncoding = myEncoding
281+
self.writeShape = myNewShape
232282

233283
def run( self ):
234284
self.running = True
235-
output = self.check_geometry( self.vlayer )
236-
self.emit( SIGNAL( "runFinished(PyQt_PyObject)" ), output )
285+
success = self.check_geometry( self.vlayer )
286+
self.emit( SIGNAL( "runFinished(PyQt_PyObject)" ), success )
237287

238288
def stop(self):
239289
self.running = False
@@ -265,4 +315,30 @@ def check_geometry( self, vlayer ):
265315
if not geom.isGeosEmpty():
266316
lstErrors.append((feat.id(), list(geom.validateGeometry())))
267317
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nFeat )
268-
return lstErrors
318+
319+
if self.writeShape:
320+
fields = { 0 : QgsField( "FEAT_ID", QVariant.Int ),
321+
1 : QgsField( "ERROR", QVariant.String ) }
322+
writer = QgsVectorFileWriter( self.myName, self.myEncoding, fields,
323+
QGis.WKBPoint, vlayer.crs() )
324+
for rec in lstErrors:
325+
if len(rec[1]) < 1:
326+
continue
327+
for err in rec[1]:
328+
fidItem = str(rec[0])
329+
message = err.what()
330+
if err.hasWhere():
331+
locErr = err.where()
332+
xP = locErr.x()
333+
yP = locErr.y()
334+
myPoint = QgsPoint( xP, yP )
335+
geometry = QgsGeometry().fromPoint( myPoint )
336+
ft = QgsFeature()
337+
ft.setGeometry( geometry )
338+
ft.setAttributeMap( { 0 : QVariant( fidItem ),
339+
1 : QVariant( message ) } )
340+
writer.addFeature( ft )
341+
del writer
342+
return "writeShape"
343+
else:
344+
return lstErrors

‎python/plugins/fTools/tools/doVisual.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ def __init__( self, iface, function ):
4141
self.iface = iface
4242
self.setupUi( self )
4343
self.myFunction = function
44+
45+
## Set object visibility to False if tool is not Check geometry
46+
self.ckBoxShpError.hide()
47+
self.browseShpError.hide()
48+
self.lineEditShpError.hide()
49+
self.label_6.hide()
50+
self.line.hide()
51+
self.buttonBox_2.setOrientation(Qt.Horizontal)
52+
4453
if self.myFunction == 2 or self.myFunction == 3:
4554
QObject.connect( self.inShape, SIGNAL( "currentIndexChanged(QString)" ), self.update )
4655
self.manageGui()
@@ -289,7 +298,7 @@ def basic_statistics( self, vlayer, myField ):
289298
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), nElement )
290299
else: # there is no selection, process the whole layer
291300
nFeat = vprovider.featureCount()
292-
if nFeat > 0:
301+
if nFeat > 0:
293302
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
294303
self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
295304
vprovider.select( allAttrs )
@@ -355,7 +364,7 @@ def basic_statistics( self, vlayer, myField ):
355364
else: # there is no selection, process the whole layer
356365
nFeat = vprovider.featureCount()
357366
uniqueVal = ftools_utils.getUniqueValuesCount( vlayer, index, False )
358-
if nFeat > 0:
367+
if nFeat > 0:
359368
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
360369
self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
361370
vprovider.select( allAttrs )

‎python/plugins/fTools/tools/frmVisual.ui

Lines changed: 85 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
<rect>
1010
<x>0</x>
1111
<y>0</y>
12-
<width>404</width>
13-
<height>481</height>
12+
<width>370</width>
13+
<height>484</height>
1414
</rect>
1515
</property>
1616
<property name="windowTitle">
@@ -20,7 +20,7 @@
2020
<bool>true</bool>
2121
</property>
2222
<layout class="QGridLayout" name="gridLayout">
23-
<item row="0" column="0" colspan="2">
23+
<item row="0" column="0">
2424
<layout class="QVBoxLayout">
2525
<item>
2626
<widget class="QLabel" name="label_3">
@@ -34,18 +34,7 @@
3434
</item>
3535
</layout>
3636
</item>
37-
<item row="3" column="0">
38-
<layout class="QVBoxLayout" name="verticalLayout">
39-
<item>
40-
<widget class="QCheckBox" name="useSelected">
41-
<property name="text">
42-
<string>Use only selected features</string>
43-
</property>
44-
</widget>
45-
</item>
46-
</layout>
47-
</item>
48-
<item row="4" column="0" colspan="2">
37+
<item row="2" column="0">
4938
<layout class="QVBoxLayout">
5039
<item>
5140
<widget class="QLabel" name="label">
@@ -59,7 +48,7 @@
5948
</item>
6049
</layout>
6150
</item>
62-
<item row="5" column="0" colspan="2">
51+
<item row="3" column="0">
6352
<layout class="QVBoxLayout">
6453
<item>
6554
<widget class="QLabel" name="label_2">
@@ -107,7 +96,7 @@
10796
</item>
10897
</layout>
10998
</item>
110-
<item row="6" column="0" colspan="2">
99+
<item row="4" column="0">
111100
<layout class="QHBoxLayout">
112101
<item>
113102
<widget class="QLabel" name="label_4">
@@ -125,37 +114,95 @@
125114
</item>
126115
</layout>
127116
</item>
128-
<item row="9" column="0">
129-
<widget class="QProgressBar" name="progressBar">
130-
<property name="value">
131-
<number>24</number>
132-
</property>
133-
<property name="alignment">
134-
<set>Qt::AlignCenter</set>
117+
<item row="7" column="0">
118+
<widget class="QCheckBox" name="ckBoxShpError">
119+
<property name="text">
120+
<string>Save errors location</string>
135121
</property>
136122
</widget>
137123
</item>
138-
<item row="8" column="1" rowspan="2">
139-
<widget class="QDialogButtonBox" name="buttonBox_2">
140-
<property name="orientation">
141-
<enum>Qt::Vertical</enum>
142-
</property>
143-
<property name="standardButtons">
144-
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
124+
<item row="5" column="0">
125+
<widget class="QLabel" name="label_5">
126+
<property name="text">
127+
<string>Press Ctrl+C to copy results to the clipboard</string>
145128
</property>
146129
</widget>
147130
</item>
131+
<item row="9" column="0">
132+
<layout class="QHBoxLayout" name="horizontalLayout">
133+
<item>
134+
<widget class="QLineEdit" name="lineEditShpError">
135+
<property name="readOnly">
136+
<bool>true</bool>
137+
</property>
138+
</widget>
139+
</item>
140+
<item>
141+
<widget class="QPushButton" name="browseShpError">
142+
<property name="text">
143+
<string>Browse</string>
144+
</property>
145+
</widget>
146+
</item>
147+
</layout>
148+
</item>
148149
<item row="8" column="0">
149-
<widget class="QProgressBar" name="partProgressBar">
150-
<property name="value">
151-
<number>24</number>
150+
<widget class="QLabel" name="label_6">
151+
<property name="text">
152+
<string>Output point shapefile</string>
152153
</property>
153154
</widget>
154155
</item>
155-
<item row="7" column="0">
156-
<widget class="QLabel" name="label_5">
157-
<property name="text">
158-
<string>Press Ctrl+C to copy results to the clipboard</string>
156+
<item row="1" column="0">
157+
<layout class="QVBoxLayout" name="verticalLayout">
158+
<item>
159+
<widget class="QCheckBox" name="useSelected">
160+
<property name="text">
161+
<string>Use only selected features</string>
162+
</property>
163+
</widget>
164+
</item>
165+
</layout>
166+
</item>
167+
<item row="10" column="0">
168+
<layout class="QHBoxLayout" name="horizontalLayout_2">
169+
<item>
170+
<layout class="QVBoxLayout" name="verticalLayout_2">
171+
<item>
172+
<widget class="QProgressBar" name="partProgressBar">
173+
<property name="value">
174+
<number>24</number>
175+
</property>
176+
</widget>
177+
</item>
178+
<item>
179+
<widget class="QProgressBar" name="progressBar">
180+
<property name="value">
181+
<number>24</number>
182+
</property>
183+
<property name="alignment">
184+
<set>Qt::AlignCenter</set>
185+
</property>
186+
</widget>
187+
</item>
188+
</layout>
189+
</item>
190+
<item>
191+
<widget class="QDialogButtonBox" name="buttonBox_2">
192+
<property name="orientation">
193+
<enum>Qt::Vertical</enum>
194+
</property>
195+
<property name="standardButtons">
196+
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
197+
</property>
198+
</widget>
199+
</item>
200+
</layout>
201+
</item>
202+
<item row="6" column="0">
203+
<widget class="Line" name="line">
204+
<property name="orientation">
205+
<enum>Qt::Horizontal</enum>
159206
</property>
160207
</widget>
161208
</item>

0 commit comments

Comments
 (0)
Please sign in to comment.