RefactoringRope/MoveDialog.py

Fri, 22 Sep 2017 19:47:36 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 22 Sep 2017 19:47:36 +0200
branch
server_client_variant
changeset 178
70b4fb448811
parent 147
RefactoringRope/MoveMethodDialog.py@3f8a995f6e49
child 189
2711fdd91925
permissions
-rw-r--r--

Implemented the distributed "Move ..." method.

# -*- coding: utf-8 -*-

# Copyright (c) 2010 - 2017 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the Move Method or Module dialog.
"""

from __future__ import unicode_literals

import os

from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QDialogButtonBox, QAbstractButton

from E5Gui import E5FileDialog, E5MessageBox
from E5Gui.E5Application import e5App
from E5Gui.E5Completers import E5FileCompleter

from Ui_MoveDialog import Ui_MoveDialog
from RefactoringDialogBase import RefactoringDialogBase

import Utilities


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 Refactoring
        @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 = E5FileCompleter(self.destinationEdit)
        
        self.__filename = filename
        self.__offset = offset
        
        self.__project = e5App().getObject("Project")
        
        self.__okButton = self.buttonBox.button(QDialogButtonBox.Ok)
        self.__okButton.setEnabled(False)
        self.__previewButton = self.buttonBox.addButton(
            self.tr("Preview"), QDialogButtonBox.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):
        """
        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):
        """
        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):
        """
        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)
        if self.__moveType == "move_global_method":
            destination = E5FileDialog.getOpenFileName(
                self,
                self.windowTitle(),
                dest,
                self.tr("Python Files (*.py *.py2 *.py3);;All Files (*)"))
        else:
            # move_module
            destination = E5FileDialog.getExistingDirectory(
                self,
                self.windowTitle(),
                dest)
        
        if destination:
            destination = Utilities.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.""")
                E5MessageBox.critical(
                    self,
                    self.windowTitle(),
                    errorMessage)
                return
            
            if self.__moveType == "move_global_method":
                if not os.path.exists(destination):
                    E5MessageBox.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")):
                    E5MessageBox.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 (boolean)
        """
        destination = os.path.join(
            self.__project.getProjectPath(),
            self.destinationEdit.text())
        if self.__moveType == "move_global_method":
            if not os.path.exists(destination):
                E5MessageBox.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")):
                E5MessageBox.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)

eric ide

mercurial