|
|
@@ -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 ) |