Created
November 1, 2021 00:43
-
-
Save gacarrillor/ab596923d676fd0c0d1c5b253a57e2e7 to your computer and use it in GitHub Desktop.
Note this uses PyQt4. It was uploaded only for reference.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# *************************************************************************** | |
# | |
# Code borrowed from TableManager | |
# | |
# Copyright (C) 2008 Borys Jurgiel | |
# Adapted by Germán Carrillo to rename Shapefiles (2015) | |
# | |
# *************************************************************************** | |
# * * | |
# * 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 qgis.core import * | |
from qgis.gui import * | |
from PyQt4.QtCore import * | |
from PyQt4.QtGui import * | |
import sys | |
DEBUGMODE=True | |
########## CLASS TableManager ############################## | |
class RenameShapefiles(): | |
def __init__(self, iface, layer): | |
self.iface = iface | |
self.layer = None | |
if type(layer) is None: | |
print "This doesn't seem to be a valid layer..." | |
return | |
if not layer.type() == QgsMapLayer.VectorLayer: | |
print layer.name() + " is not a vector layer..." | |
return | |
self.layer = layer | |
self.provider = self.layer.dataProvider() | |
self.fields = self.readFields( self.provider.fields() ) | |
if not self.provider.storageType() == 'ESRI Shapefile': # Is provider saveable? | |
print self.layer.name() + " is not a Shapefile layer..." | |
return | |
self.readData() | |
def readFields(self, providerFields): # Populates the self.fields dictionary with providerFields | |
fieldsDict = {} | |
i=0 | |
for field in providerFields: | |
fieldsDict.update({i:field}) | |
i+=1 | |
return fieldsDict | |
def formatFieldType(self, field): | |
if field.type() == QVariant.Date: | |
return field.typeName() | |
elif field.type() == QVariant.Double: | |
return "%s(%d,%d)" % (field.typeName(), field.length(), field.precision()) | |
else: | |
return "%s(%d)" % (field.typeName(), field.length()) | |
def readData(self): # Reads data from the 'provider' QgsDataProvider into the 'data' list [[column1] [column2] [column3]...] | |
fields = self.fields | |
self.data = [] | |
for i in range(len(fields)): | |
self.data += [[]] | |
for feat in self.provider.getFeatures(): | |
attrs = feat.attributes() | |
for i in range(len(attrs)): | |
self.data[i] += [attrs[i]] | |
def doSave(self): # Called when appropriate button was pressed | |
# I believe the procedure below is as much safe as possible. | |
if not self.layer: | |
return | |
layerName = self.layer.name() | |
srcName = layerName | |
encoding = self.provider.encoding() | |
tmpDir = QDir.tempPath() | |
srcPath = self.provider.dataSourceUri().split('|')[0] | |
srcOrigPath = QFileInfo(srcPath).path() + '/' + QFileInfo(srcPath).baseName() | |
originalName = QFileInfo(srcPath).baseName() | |
srcPath = QFileInfo(srcPath).path() + '/' + layerName | |
if originalName == layerName: | |
print "Layer "+ layerName+" has nothing to rename..." | |
return | |
# without this one line code in win xp, srcName return something wrong,see below (patch from Volkan Kepoglu - thanks!) | |
srcPath = srcPath.replace("\\","/") | |
srcOrigPath = srcOrigPath.replace("\\","/") | |
# write the layer to the temporary directory | |
if self.writeToFile(tmpDir+'/'+srcName+'.shp', encoding) != 0: | |
QMessageBox.warning(self, 'Table Manager', "Failed saving the changes to the temporary directory: "+tmpDir+" !\nThe layer won't be changed, please use the Save As button.") | |
QgsVectorFileWriter.deleteShapeFile(tmpDir+'/'+srcName+'.shp') | |
return | |
# try to remove the old .dbf~ backup | |
QFile(srcOrigPath+'.dbf~').remove() | |
QFile.remove( tmpDir+'/'+srcName+'.qml' ) | |
self.layer.saveNamedStyle( tmpDir+'/'+srcName+'.qml' ) | |
QgsMapLayerRegistry.instance().removeMapLayers([self.layer.id()]) | |
#Rename files | |
QFile(srcOrigPath+'.shx').rename(srcPath+'.shx') | |
QFile(srcOrigPath+'.prj').rename(srcPath+'.prj') | |
QFile(srcOrigPath+'.qpj').rename(srcPath+'.qpj') | |
QFile(srcOrigPath+'.shp').rename(srcPath+'.shp') | |
########### | |
# rename the oryginal .dbf file to .dbf~ | |
if not QFile(srcOrigPath+'.dbf').rename(srcPath+'.dbf~'): | |
QMessageBox.warning(self, 'Table Manager', 'Failed backuping the old table to '+srcPath+'.dbf~\nThe layer won\'t be changed, please use the Save As button.') | |
# we don't return now because layer has to be reloaded''' | |
# copy the .dbf from the temp directory to the target location | |
elif QFile(tmpDir+'/'+srcName+'.dbf').copy(srcPath+'.dbf'): | |
# dbf file copied. Copy also cpg if present | |
pass | |
else: | |
# something went wrong with copying the dbf file. Restore the dbf~ file | |
if not QFile(srcPath+'.dbf~').rename(srcPath+'.dbf'): | |
QMessageBox.warning(self, 'Table Manager', 'WARNING! I can neither save the new {0}.dbf file\nnor restore it from the '+srcName+'.dbf~ backup.\nPlease check it manually!') | |
QgsVectorFileWriter.deleteShapeFile(tmpDir+'/'+srcName+'.shp') | |
return | |
# dbf~ file restored : | |
QMessageBox.warning(self, 'Table Manager', "Failed saving the changes to "+srcPath+".dbf\nThe layer will not be changed, please use the Save As button.") | |
''' | |
QgsVectorFileWriter.deleteShapeFile(tmpDir+'/'+srcName+'.shp') | |
return | |
we don't return now because layer has to be reloaded | |
''' | |
# clean the temp directory | |
QgsVectorFileWriter.deleteShapeFile(tmpDir+'/'+srcName+'.shp') | |
# create the new layer | |
'''layerName = self.layer.name()''' | |
newLayer = QgsVectorLayer(srcPath+'.shp', layerName, 'ogr') | |
if not newLayer.isValid(): | |
QMessageBox.warning(self, 'Table Manager', "WARNING! The changes seem to be commited, but I can't reload the layer!\nPlease check it out!\nThe old table is backuped as "+srcName+".dbf~.") | |
return | |
# copy the style (it's possible only if the clasyfying field was not renamed!) | |
'''#newLayer.copySymbologySettings(self.layer)''' | |
resp = newLayer.loadNamedStyle( tmpDir+'/'+srcName+'.qml' ) | |
if not resp[1]: | |
QMessageBox.warning(self, 'Table Manager', "This layer will be reloaded without its previous style (loading style failed)") | |
QFile.remove( tmpDir+'/'+srcName+'.qml' ) | |
# set encoding | |
newLayer.setProviderEncoding( encoding ) | |
# reload the layer | |
QgsMapLayerRegistry.instance().addMapLayers([newLayer]) | |
# point the self.layer to the new one. | |
self.layer = newLayer | |
self.provider = self.layer.dataProvider() | |
self.fields = self.readFields( self.provider.fields() ) | |
def writeToFile(self, filePath, encoding, driverName = 'ESRI Shapefile'): # write data to a shapefile | |
if QFile(filePath).exists(): | |
try: | |
QgsVectorFileWriter.deleteShapeFile(filePath) | |
except: | |
QMessageBox.warning(self, 'Table Manager', 'Cannot overwrite an existing shapefile.\nPlease remove it manually.') | |
return 1 | |
# create destination layer | |
fields = QgsFields() | |
keys = self.fields.keys() | |
keys.sort() | |
for key in keys: | |
fields.append(self.fields[key]) | |
if driverName == 'ESRI Shapefile': | |
#lco = ["ENCODING="+encoding , "SHAPE_ENCODING="+encoding] | |
lco = ["ENCODING="+encoding] | |
settings = QSettings() | |
else: | |
lco = [] | |
writer = QgsVectorFileWriter(filePath, encoding, fields, self.provider.geometryType(), self.provider.crs(), driverName, [], lco) | |
if writer.hasError(): | |
QMessageBox.warning(self, 'Table Manager', "Error creating file. The errror message was:" + "<br/>" + writer.errorMessage() ) | |
return 2 | |
geom = QgsGeometry() | |
n = 0 | |
for feat in self.provider.getFeatures(): | |
geom = feat.geometry() | |
outFeat = QgsFeature() | |
if geom: | |
outFeat.setGeometry(geom) | |
attrs = [] | |
for i in range(len(self.fields)): | |
try: | |
attrs += [self.data[i][n]] | |
except: | |
attrs += [''] | |
outFeat.initAttributes(len(attrs)) | |
outFeat.setAttributes(attrs) | |
writer.addFeature(outFeat) | |
n += 1 | |
del writer | |
return 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment