Tue, 10 Dec 2024 15:49:01 +0100
Updated copyright for 2025.
# -*- coding: utf-8 -*- # Copyright (c) 2010 - 2025 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the Move Method or Module dialog. """ import os from PyQt6.QtCore import pyqtSlot from PyQt6.QtWidgets import QAbstractButton, QDialogButtonBox from eric7.EricWidgets import EricFileDialog, EricMessageBox from eric7.EricWidgets.EricApplication import ericApp from eric7.EricWidgets.EricCompleters import EricFileCompleter try: from eric7.SystemUtilities.FileSystemUtilities import toNativeSeparators except ImportError: # backward compatibility for eric < 23.1 from eric7.Utilities import toNativeSeparators from .RefactoringDialogBase import RefactoringDialogBase from .Ui_MoveDialog import Ui_MoveDialog class MoveDialog(RefactoringDialogBase, Ui_MoveDialog): """ Class implementing the Move Method or Module dialog. """ def __init__(self, refactoring, title, filename, offset, parent=None): """ Constructor @param refactoring reference to the main refactoring object @type RefactoringServer @param title title of the dialog @type str @param filename file name to be worked on @type str @param offset offset within file @type int or None @param parent reference to the parent widget @type QWidget """ RefactoringDialogBase.__init__(self, refactoring, title, parent) self.setupUi(self) self._changeGroupName = "Move" self.__destinationCompleter = EricFileCompleter(self.destinationEdit) self.__filename = filename self.__offset = offset self.__project = ericApp().getObject("Project") self.__okButton = self.buttonBox.button(QDialogButtonBox.StandardButton.Ok) self.__okButton.setEnabled(False) self.__previewButton = self.buttonBox.addButton( self.tr("Preview"), QDialogButtonBox.ButtonRole.ActionRole ) self.__previewButton.setDefault(True) self.moveStackWidget.setCurrentIndex(0) self.__moveType = "" if offset is None: # it is a 'move module' refactoring, no need to determine # the move type via the client self.__processMoveType({"Kind": "move_module"}) else: self._refactoring.sendJson( "RequestMoveType", { "ChangeGroup": self._changeGroupName, "Title": self._title, "FileName": self.__filename, "Offset": self.__offset, }, ) def __processMoveType(self, data): """ Private method to process the move type data sent by the refactoring client in order to polish the dialog. @param data dictionary containing the move type data @type dict """ self.__moveType = data["Kind"] if self.__moveType == "move_method": self.setWindowTitle(self.tr("Move Method")) self.moveStackWidget.setCurrentIndex(1) self.methodEdit.setText(data["Method"]) self.methodEdit.selectAll() elif self.__moveType == "move_global_method": self.setWindowTitle(self.tr("Move Global Method")) self.moveStackWidget.setCurrentIndex(2) self.destinationLabel.setText(self.tr("Destination Module:")) self.destinationEdit.setToolTip( self.tr("Enter the destination module for the method") ) self.selectButton.setToolTip( self.tr("Select the destination module via a file selection dialog") ) elif self.__moveType == "move_module": self.setWindowTitle(self.tr("Move Module")) self.moveStackWidget.setCurrentIndex(2) self.destinationLabel.setText(self.tr("Destination Package:")) self.destinationEdit.setToolTip( self.tr("Enter the destination package for the module") ) self.selectButton.setToolTip( self.tr( "Select the destination package via a directory selection dialog" ) ) else: self.setWindowTitle(self.tr("Move")) self.moveStackWidget.setCurrentIndex(0) self.__updateUI() msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) @pyqtSlot(str) def on_attributeEdit_textChanged(self, text): # noqa: U100 """ Private slot to react to changes of the attribute. @param text text entered into the edit @type str """ self.__updateUI() @pyqtSlot(str) def on_methodEdit_textChanged(self, text): # noqa: U100 """ Private slot to react to changes of the method. @param text text entered into the edit @type str """ self.__updateUI() @pyqtSlot(str) def on_destinationEdit_textChanged(self, text): # noqa: U100 """ Private slot to react to changes of the destination module. @param text text entered into the edit @type str """ self.__updateUI() def __updateUI(self): """ Private method to perform various UI updates. """ if self.__moveType == "move_method": enable = self.attributeEdit.text() != "" and self.methodEdit.text() != "" elif self.__moveType in ["move_global_method", "move_module"]: enable = self.destinationEdit.text() != "" else: enable = False self.__okButton.setEnabled(enable) self.__previewButton.setEnabled(enable) @pyqtSlot() def on_selectButton_clicked(self): """ Private slot called to select the destination module via a file selection dialog. """ dest = self.destinationEdit.text() if not dest: dest = self.__project.getProjectPath() elif not os.path.isabs(dest): dest = os.path.join(self.__project.getProjectPath(), dest) destination = ( EricFileDialog.getOpenFileName( self, self.windowTitle(), dest, self.tr("Python Files (*.py *.py3);;All Files (*)"), ) if self.__moveType == "move_global_method" else # move_module EricFileDialog.getExistingDirectory(self, self.windowTitle(), dest) ) if destination: destination = toNativeSeparators(destination) if not self.__project.startswithProjectPath(destination): if self.__moveType == "move_global_method": errorMessage = self.tr( """The selected module must be inside the project.""" ) else: # move_module errorMessage = self.tr( """The selected directory must be inside the project.""" ) EricMessageBox.critical(self, self.windowTitle(), errorMessage) return if self.__moveType == "move_global_method": if not os.path.exists(destination): EricMessageBox.critical( self, self.windowTitle(), self.tr( """The selected module <b>{0}</b> does not exist.""" ).format(destination), ) return else: # move_module if not os.path.exists(os.path.join(destination, "__init__.py")): EricMessageBox.critical( self, self.windowTitle(), self.tr( """The selected directory <b>{0}</b> is""" """ not a package.""" ).format(destination), ) return destination = self.__project.getRelativePath(destination) self.destinationEdit.setText(destination) def __checkDestination(self): """ Private method to check the destination entered. @return flag indicating a valid entry @rtype bool """ destination = os.path.join( self.__project.getProjectPath(), self.destinationEdit.text() ) if self.__moveType == "move_global_method": if not os.path.exists(destination): EricMessageBox.critical( self, self.windowTitle(), self.tr( """The selected module <b>{0}</b> does not exist.""" ).format(destination), ) return False else: # move_module if not os.path.exists(os.path.join(destination, "__init__.py")): EricMessageBox.critical( self, self.windowTitle(), self.tr( """The selected directory <b>{0}</b> is not a package.""" ).format(destination), ) return False return True @pyqtSlot(QAbstractButton) def on_buttonBox_clicked(self, button): """ Private slot to act on the button pressed. @param button reference to the button pressed @type QAbstractButton """ if self.__moveType == "move_method" or ( self.__moveType in ["move_global_method", "move_module"] and self.__checkDestination() ): if button == self.__previewButton: self.requestPreview() elif button == self.__okButton: self.applyChanges() def _calculateChanges(self): """ Protected method to initiate the calculation of the changes. """ newName = self.methodEdit.text() if not newName: newName = None self._refactoring.sendJson( "CalculateMoveChanges", { "ChangeGroup": self._changeGroupName, "Title": self.windowTitle(), "FileName": self.__filename, "Offset": self.__offset, "Kind": self.__moveType, "NewName": newName, "Attribute": self.attributeEdit.text(), "DestinationModule": self.destinationEdit.text(), }, ) def processChangeData(self, data): """ Public method to process the change data sent by the refactoring client. @param data dictionary containing the change data @type dict """ subcommand = data["Subcommand"] if subcommand == "MoveType": self.__processMoveType(data) else: # pass on to base class RefactoringDialogBase.processChangeData(self, data)