mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
[FEATURE] Build spatial index tool for fTools (see #2779). Currently
without icon
This commit is contained in:
parent
55337b3bbc
commit
48112cc1bc
@ -43,7 +43,7 @@ import doGeometry, doGeoprocessing, doVisual
|
||||
import doIntersectLines, doSelectByLocation, doVectorSplit, doMeanCoords
|
||||
import doPointDistance, doPointsInPolygon, doRandom, doRandPoints, doRegPoints
|
||||
import doSpatialJoin, doSubsetSelect, doSumLines, doVectorGrid, doMergeShapes
|
||||
import doValidate, doSimplify, doDefineProj
|
||||
import doValidate, doSimplify, doDefineProj, doSpatialIndex
|
||||
|
||||
class fToolsPlugin:
|
||||
def __init__(self,iface):
|
||||
@ -113,6 +113,7 @@ class fToolsPlugin:
|
||||
self.spatJoin.setIcon(QIcon(self.getThemeIcon("join_location.png")))
|
||||
self.splitVect.setIcon(QIcon(self.getThemeIcon("split_layer.png")))
|
||||
self.mergeShapes.setIcon(QIcon(self.getThemeIcon("merge_shapes.png")))
|
||||
self.spatialIndex.setIcon(QIcon(self.getThemeIcon("spatial_index.png")))
|
||||
|
||||
def initGui(self):
|
||||
if int(self.QgisVersion) < 1:
|
||||
@ -179,7 +180,8 @@ class fToolsPlugin:
|
||||
self.spatJoin = QAction(QCoreApplication.translate("fTools", "Join attributes by location"), self.iface.mainWindow())
|
||||
self.splitVect = QAction(QCoreApplication.translate("fTools", "Split vector layer"), self.iface.mainWindow())
|
||||
self.mergeShapes = QAction(QCoreApplication.translate("fTools", "Merge shapefiles to one"), self.iface.mainWindow())
|
||||
self.dataManageMenu.addActions([self.define, self.spatJoin, self.splitVect, self.mergeShapes])
|
||||
self.spatialIndex = QAction(QCoreApplication.translate("fTools", "Create spatial index"), self.iface.mainWindow())
|
||||
self.dataManageMenu.addActions([self.define, self.spatJoin, self.splitVect, self.mergeShapes, self.spatialIndex])
|
||||
self.updateThemeIcons("theme")
|
||||
|
||||
self.menu.addMenu(self.analysisMenu)
|
||||
@ -235,6 +237,7 @@ class fToolsPlugin:
|
||||
QObject.connect(self.spatJoin, SIGNAL("triggered()"), self.dospatJoin)
|
||||
QObject.connect(self.splitVect, SIGNAL("triggered()"), self.dosplitVect)
|
||||
QObject.connect(self.mergeShapes, SIGNAL("triggered()"), self.doMergeShapes)
|
||||
QObject.connect(self.spatialIndex, SIGNAL("triggered()"), self.doSpatIndex)
|
||||
|
||||
def unload(self):
|
||||
pass
|
||||
@ -319,7 +322,7 @@ class fToolsPlugin:
|
||||
def dodelaunay(self):
|
||||
d = doGeometry.GeometryDialog(self.iface, 8)
|
||||
d.exec_()
|
||||
|
||||
|
||||
def dovoronoi(self):
|
||||
d = doGeometry.GeometryDialog(self.iface, 10)
|
||||
d.exec_()
|
||||
@ -392,3 +395,7 @@ class fToolsPlugin:
|
||||
d = doMergeShapes.Dialog(self.iface)
|
||||
d.exec_()
|
||||
|
||||
def doSpatIndex(self):
|
||||
d = doSpatialIndex.Dialog(self.iface)
|
||||
d.show()
|
||||
d.exec_()
|
||||
|
223
python/plugins/fTools/tools/doSpatialIndex.py
Normal file
223
python/plugins/fTools/tools/doSpatialIndex.py
Normal file
@ -0,0 +1,223 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
doSpatialIndex.py - build spatial index for vector layers or files
|
||||
--------------------------------------
|
||||
Date : 11-Nov-2011
|
||||
Copyright : (C) 2011 by Alexander Bruy
|
||||
Email : alexander dot bruy at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
from PyQt4.QtCore import *
|
||||
from PyQt4.QtGui import *
|
||||
|
||||
from qgis.core import *
|
||||
from qgis.gui import *
|
||||
|
||||
import ftools_utils
|
||||
|
||||
from ui_frmSpatialIndex import Ui_Dialog
|
||||
|
||||
class Dialog( QDialog, Ui_Dialog ):
|
||||
def __init__( self, iface ):
|
||||
QDialog.__init__( self )
|
||||
self.setupUi( self )
|
||||
self.iface = iface
|
||||
|
||||
self.workThread = None
|
||||
|
||||
self.btnOk = self.buttonBox.button( QDialogButtonBox.Ok )
|
||||
self.btnClose = self.buttonBox.button( QDialogButtonBox.Close )
|
||||
|
||||
QObject.connect( self.chkExternalFiles, SIGNAL( "stateChanged( int )" ), self.toggleExternalFiles )
|
||||
QObject.connect( self.btnSelectFiles, SIGNAL( "clicked()" ), self.selectFiles )
|
||||
QObject.connect( self.lstLayers, SIGNAL( "itemSelectionChanged()" ), self.updateLayerList )
|
||||
QObject.connect( self.btnSelectAll, SIGNAL( "clicked()" ), self.selectAll )
|
||||
QObject.connect( self.btnSelectNone, SIGNAL( "clicked()" ), self.selectNone )
|
||||
QObject.connect( self.btnClearList, SIGNAL( "clicked()" ), self.clearList )
|
||||
|
||||
self.manageGui()
|
||||
|
||||
def manageGui( self ):
|
||||
self.btnSelectFiles.setEnabled( False )
|
||||
self.btnClearList.setEnabled( False )
|
||||
|
||||
self.fillLayersList()
|
||||
|
||||
def fillLayersList( self ):
|
||||
self.lstLayers.clear()
|
||||
layers = ftools_utils.getLayerNames( [ QGis.Line, QGis.Point, QGis.Polygon ] )
|
||||
for lay in layers:
|
||||
source = ftools_utils.getVectorLayerByName( lay ).source()
|
||||
item = QListWidgetItem( lay, self.lstLayers )
|
||||
item.setData( Qt.UserRole, source )
|
||||
item.setData( Qt.ToolTipRole, source )
|
||||
|
||||
def toggleExternalFiles( self ):
|
||||
if self.chkExternalFiles.isChecked():
|
||||
self.btnSelectFiles.setEnabled( True )
|
||||
self.btnClearList.setEnabled( True )
|
||||
self.btnSelectAll.setEnabled( False )
|
||||
self.btnSelectNone.setEnabled( False )
|
||||
|
||||
self.lstLayers.clear()
|
||||
self.lstLayers.setSelectionMode( QAbstractItemView.NoSelection )
|
||||
self.layers = []
|
||||
else:
|
||||
self.btnSelectFiles.setEnabled( False )
|
||||
self.btnClearList.setEnabled( False )
|
||||
self.btnSelectAll.setEnabled( True )
|
||||
self.btnSelectNone.setEnabled( True )
|
||||
|
||||
self.fillLayersList()
|
||||
self.lstLayers.setSelectionMode( QAbstractItemView.ExtendedSelection )
|
||||
self.updateLayerList()
|
||||
|
||||
def updateLayerList( self ):
|
||||
self.layers = []
|
||||
selection = self.lstLayers.selectedItems()
|
||||
for item in selection:
|
||||
self.layers.append( item.text() )
|
||||
|
||||
def selectFiles( self ):
|
||||
filters = QgsProviderRegistry.instance().fileVectorFilters()
|
||||
( files, self.encoding ) = ftools_utils.openDialog( self, filtering = filters, dialogMode = "MultipleFiles" )
|
||||
if files is None:
|
||||
return
|
||||
|
||||
self.layers.extend( [ unicode( f ) for f in files ] )
|
||||
self.lstLayers.addItems( files )
|
||||
|
||||
def selectAll( self ):
|
||||
self.lstLayers.selectAll()
|
||||
|
||||
def selectNone( self ):
|
||||
self.lstLayers.clearSelection()
|
||||
|
||||
def clearList( self ):
|
||||
self.layers = []
|
||||
self.lstLayers.clear()
|
||||
|
||||
def accept( self ):
|
||||
QApplication.setOverrideCursor( Qt.WaitCursor )
|
||||
self.btnOk.setEnabled( False )
|
||||
|
||||
self.workThread = SpatialIdxThread( self.layers, self.chkExternalFiles.isChecked() )
|
||||
self.progressBar.setRange( 0, len( self.layers ) )
|
||||
|
||||
QObject.connect( self.workThread, SIGNAL( "layerProcessed()" ), self.layerProcessed )
|
||||
QObject.connect( self.workThread, SIGNAL( "processFinished( PyQt_PyObject )" ), self.processFinished )
|
||||
QObject.connect( self.workThread, SIGNAL( "processInterrupted()" ), self.processInterrupted )
|
||||
|
||||
self.btnClose.setText( self.tr( "Cancel" ) )
|
||||
QObject.disconnect( self.buttonBox, SIGNAL( "rejected()" ), self.reject )
|
||||
QObject.connect( self.btnClose, SIGNAL( "clicked()" ), self.stopProcessing )
|
||||
|
||||
self.workThread.start()
|
||||
|
||||
def layerProcessed( self ):
|
||||
self.progressBar.setValue( self.progressBar.value() + 1 )
|
||||
|
||||
def processInterrupted( self ):
|
||||
self.restoreGui()
|
||||
|
||||
def processFinished( self, errors ):
|
||||
self.stopProcessing()
|
||||
self.restoreGui()
|
||||
|
||||
if not errors.isEmpty():
|
||||
msg = QString( "Processing of the following layers/files ended with error:<br><br>" ).append( errors.join( "<br>" ) )
|
||||
QErrorMessage( self ).showMessage( msg )
|
||||
|
||||
QMessageBox.information( self, self.tr( "Finished" ), self.tr( "Processing completed." ) )
|
||||
|
||||
def stopProcessing( self ):
|
||||
if self.workThread != None:
|
||||
self.workThread.stop()
|
||||
self.workThread = None
|
||||
|
||||
def restoreGui( self ):
|
||||
self.progressBar.setValue( 0 )
|
||||
QApplication.restoreOverrideCursor()
|
||||
QObject.connect( self.buttonBox, SIGNAL( "rejected()" ), self.reject )
|
||||
self.btnClose.setText( self.tr( "Close" ) )
|
||||
self.btnOk.setEnabled( True )
|
||||
|
||||
if self.chkExternalFiles.isChecked():
|
||||
self.clearList()
|
||||
|
||||
class SpatialIdxThread( QThread ):
|
||||
def __init__( self, layers, isFiles ):
|
||||
QThread.__init__( self, QThread.currentThread() )
|
||||
self.layers = layers
|
||||
self.isFiles = isFiles
|
||||
|
||||
self.mutex = QMutex()
|
||||
self.stopMe = 0
|
||||
|
||||
self.errors = QStringList()
|
||||
|
||||
def run( self ):
|
||||
self.mutex.lock()
|
||||
self.stopMe = 0
|
||||
self.mutex.unlock()
|
||||
|
||||
interrupted = False
|
||||
|
||||
if self.isFiles:
|
||||
for layer in self.layers:
|
||||
vl = QgsVectorLayer( layer, "tmp", "ogr" )
|
||||
provider = vl.dataProvider()
|
||||
if provider.capabilities() & QgsVectorDataProvider.CreateSpatialIndex:
|
||||
if not provider.createSpatialIndex():
|
||||
self.errors.append( layer )
|
||||
else:
|
||||
self.errors.append( layer )
|
||||
|
||||
self.emit( SIGNAL( "layerProcessed()" ) )
|
||||
|
||||
self.mutex.lock()
|
||||
s = self.stopMe
|
||||
self.mutex.unlock()
|
||||
if s == 1:
|
||||
interrupted = True
|
||||
break
|
||||
else:
|
||||
for layer in self.layers:
|
||||
vl = ftools_utils.getVectorLayerByName( layer )
|
||||
provider = vl.dataProvider()
|
||||
if provider.capabilities() & QgsVectorDataProvider.CreateSpatialIndex:
|
||||
if not provider.createSpatialIndex():
|
||||
self.errors.append( layer )
|
||||
else:
|
||||
self.errors.append( layer )
|
||||
|
||||
self.emit( SIGNAL( "layerProcessed()" ) )
|
||||
|
||||
self.mutex.lock()
|
||||
s = self.stopMe
|
||||
self.mutex.unlock()
|
||||
if s == 1:
|
||||
interrupted = True
|
||||
break
|
||||
|
||||
if not interrupted:
|
||||
self.emit( SIGNAL( "processFinished( PyQt_PyObject )" ), self.errors )
|
||||
else:
|
||||
self.emit( SIGNAL( "processInterrupted()" ) )
|
||||
|
||||
def stop( self ):
|
||||
self.mutex.lock()
|
||||
self.stopMe = 1
|
||||
self.mutex.unlock()
|
||||
|
||||
QThread.wait( self )
|
127
python/plugins/fTools/tools/frmSpatialIndex.ui
Normal file
127
python/plugins/fTools/tools/frmSpatialIndex.ui
Normal file
@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>351</width>
|
||||
<height>272</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Build spatial index</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkExternalFiles">
|
||||
<property name="text">
|
||||
<string>Select files from disk</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSelectFiles">
|
||||
<property name="text">
|
||||
<string>Select files...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="lstLayers">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSelectAll">
|
||||
<property name="text">
|
||||
<string>Select all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnSelectNone">
|
||||
<property name="text">
|
||||
<string>Select none</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnClearList">
|
||||
<property name="text">
|
||||
<string>Clear list</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
Loading…
x
Reference in New Issue
Block a user