| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- from PyQt5.QtWidgets import QFileDialog, QDialog, QLineEdit, QHBoxLayout, QVBoxLayout, QLabel, QPushButton, QMessageBox
- from PyQt5.QtCore import QTimer
- from .datasource import change_datasource
- from .uri import Uri
- from .file_manager import FileManager
- from file_management.providers.errors import FileDoesNotExistError, LayerOpenError
- from qgis.core import QgsProject
- def rename(view, iface, rename_type, settings):
- layer = view.currentLayer()
- if layer is None:
- return
- uri = Uri(layer)
- renamer = Renamer(view, iface, uri, rename_type)
- if not renamer.is_valid():
- QMessageBox.critical(iface.mainWindow(), 'Rename Layer',
- f'Layer format not supported yet: {uri.ext()[1:].upper()}')
- return
- target_uri = renamer.file_dialog()
- if not target_uri:
- return
- if renamer.exists(target_uri):
- overwrite = renamer.ask_overwrite(target_uri, iface)
- if not overwrite:
- return
- try:
- renamer.delete(target_uri)
- except LayerOpenError:
- if rename_type == 'layer':
- QMessageBox.critical(iface.mainWindow(), 'Rename Layer',
- f'Target layer {target_uri.layer_name()} is currently open in QGIS. '
- 'Remove open layers before overwriting')
- elif rename_type == 'database':
- QMessageBox.critical(iface.mainWindow(), 'Rename Layer',
- f'Target database {target_uri.database()} has layers open in QGIS. '
- 'Remove open layers before overwriting')
- return
- except PermissionError:
- QMessageBox.critical(iface.mainWindow(), 'Rename Layer', 'Target layer locked by another process')
- return
- renamer.rename(target_uri)
- class Renamer:
- def __init__(self, view=None, iface=None, uri=None, rename_type=None):
- self._view = view
- self._iface = iface
- self._timer = QTimer()
- self._timer.setSingleShot(True)
- self._timer.setInterval(300)
- self._renamed_layers = []
- self._src_uri = uri
- self._file_manager = FileManager(self._src_uri)
- self._rename_type = rename_type
- def is_valid(self):
- return self._file_manager.is_valid()
- def file_dialog(self):
- # assumed to be QgsVectorLayer
- if self._src_uri.is_memory_layer() or (self._src_uri.is_database() and self._rename_type == 'layer'):
- dialog = QDialog(self._iface.mainWindow())
- label = QLabel()
- line_edit = QLineEdit()
- layout = QVBoxLayout()
- label.setText(f'Choose new name for: {self._src_uri.layer_name()}')
- line_edit.setText(self._src_uri.layer_name())
- line_edit.selectAll()
- layout.addWidget(label)
- layout.addWidget(line_edit)
- button_layout = QHBoxLayout()
- ok_btn = QPushButton('Ok')
- cancel_btn = QPushButton('Cancel')
- button_layout.addStretch()
- button_layout.addWidget(ok_btn)
- button_layout.addWidget(cancel_btn)
- layout.addLayout(button_layout)
- dialog.setLayout(layout)
- ok_btn.clicked.connect(dialog.accept)
- cancel_btn.clicked.connect(dialog.reject)
- dialog.exec_()
- if dialog.result() == QDialog.Rejected:
- return
- target_file = self._src_uri.database()
- target_name = line_edit.text()
- if not target_name or target_name == self._src_uri.layer_name():
- return
- else:
- ext = self._src_uri.ext()
- filter_ = f'{self._file_manager.provider_name()} (*{ext.lower()} *{ext.upper()})'
- target_file = QFileDialog.getSaveFileName(self._iface.mainWindow(), 'Rename',
- self._src_uri.database(), filter_)[0]
- target_name = None
- if self._src_uri.is_database():
- target_name = self._src_uri.layer_name()
- if not target_file:
- return
- target_uri = Uri()
- target_uri.set_database(target_file)
- target_uri.set_layer_name(target_name)
- target_uri.build(self._src_uri)
- return target_uri
- def exists(self, target_uri):
- if self._rename_type == 'layer':
- return self._layer_exists(target_uri)
- elif self._rename_type == 'database':
- return self._database_exists(target_uri)
- def _layer_exists(self, target_uri):
- return self._file_manager.layer_exists(target_uri)
- def _database_exists(self, target_uri):
- return self._file_manager.database_exists(target_uri)
- def ask_overwrite(self, target_uri, iface):
- if self._rename_type == 'layer':
- return self._ask_overwrite_layer(target_uri, iface)
- elif self._rename_type == 'database':
- return self._ask_overwrite_database(target_uri, iface)
- def _ask_overwrite_layer(self, target_uri, iface):
- return self._file_manager.ask_overwrite_layer(target_uri, iface)
- def _ask_overwrite_database(self, target_uri, iface):
- return self._file_manager.ask_overwrite_database(target_uri, iface)
- def delete(self, target_uri):
- if self._rename_type == 'layer':
- self._delete_layer(target_uri)
- elif self._rename_type == 'database':
- self._delete_database(target_uri)
- def _delete_layer(self, target_uri):
- # if existing layer is open in workspace, stop overwrite
- for layer_id, layer_ in QgsProject.instance().mapLayers().items():
- if Uri(layer_).layer_uri() == target_uri.layer_uri():
- raise LayerOpenError
- self._file_manager.delete_layer(target_uri)
- def _delete_database(self, target_uri):
- for layer_id, layer_ in QgsProject.instance().mapLayers().items():
- if Uri(layer_).database() == target_uri.database():
- raise LayerOpenError
- self._file_manager.delete_database(target_uri)
- def rename(self, target_uri):
- if self._rename_type == 'layer':
- self._rename_layer(target_uri)
- elif self._rename_type == 'database':
- self._rename_database(target_uri)
- def _rename_database(self, target_uri):
- legint = QgsProject.instance().layerTreeRoot()
- for layer_id, layer_ in QgsProject.instance().mapLayers().items():
- if Uri(layer_).database() == self._src_uri.database():
- tree_layer = legint.findLayer(layer_id)
- if tree_layer is not None:
- # change datasource
- target_uri_ = Uri(layer_)
- target_uri_.set_database(target_uri.database())
- target_uri_.build()
- change_datasource(layer_, target_uri_)
- layer_.dataProvider().reloadData()
- self._renamed_layers.append((layer_, target_uri_))
- self._timer.timeout.connect(lambda: self.rename_file())
- self._timer.start()
- def _rename_layer(self, target_uri):
- # rename all layers in Legend that use this datasource
- legint = QgsProject.instance().layerTreeRoot()
- for layer_id, layer_ in QgsProject.instance().mapLayers().items():
- if Uri(layer_).layer_uri() == self._src_uri.layer_uri():
- tree_layer = legint.findLayer(layer_id)
- if tree_layer is not None:
- tree_layer.setName(target_uri.layer_name())
- # change datasource
- target_uri_ = Uri(uri=target_uri)
- target_uri_.build(Uri(layer_))
- change_datasource(layer_, target_uri_)
- layer_.dataProvider().reloadData()
- self._renamed_layers.append((layer_, target_uri_))
- self._timer.timeout.connect(lambda: self.rename_file())
- self._timer.start()
- def rename_file(self):
- for i, (layer, target_uri) in enumerate(self._renamed_layers):
- if i == 0:
- # rename on disk
- try:
- if self._rename_type == 'layer':
- self._file_manager.rename_layer(target_uri)
- elif self._rename_type == 'database':
- self._file_manager.rename_database(target_uri)
- except FileDoesNotExistError:
- print('source file does not exist error')
- except FileExistsError:
- print('destination file exists error')
- except PermissionError:
- print('permission error')
- # refresh again from source
- change_datasource(layer, target_uri)
- layer.dataProvider().forceReload()
- layer.dataProvider().reloadData()
- layer.reload()
- self._view.refreshLayerSymbology(layer.id())
- self._iface.mapCanvas().refresh()
|