RefactoringRope/RefactoringServer.py

branch
server_client_variant
changeset 189
2711fdd91925
parent 188
05fb0977ce1b
child 191
2af42804bca2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RefactoringRope/RefactoringServer.py	Sun Sep 24 13:56:36 2017 +0200
@@ -0,0 +1,2181 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2010 - 2017 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the refactoring interface to rope.
+"""
+
+from __future__ import unicode_literals
+try:
+    str = unicode   # __IGNORE_WARNING__
+except NameError:
+    pass
+
+import os
+import sys
+
+sys.path.insert(0, os.path.dirname(__file__))
+
+from PyQt5.QtWidgets import QMenu, QApplication, QAction
+from PyQt5.Qsci import QsciScintilla
+
+from E5Gui.E5Application import e5App
+from E5Gui import E5MessageBox
+from E5Gui.E5Action import E5Action
+
+from .JsonServer import JsonServer
+from .RopeProgressDialog import RopeProgressDialog
+
+import Utilities
+import Preferences
+
+
+class RefactoringServer(JsonServer):
+    """
+    Class implementing the refactoring interface to rope.
+    """
+    def __init__(self, plugin, parent=None):
+        """
+        Constructor
+        
+        @param plugin reference to the plugin object
+        @param parent parent (QObject)
+        """
+        super(RefactoringServer, self).__init__(parent)
+        
+        self.__plugin = plugin
+        self.__ui = parent
+        self.__e5project = e5App().getObject("Project")
+        self.__projectpath = ''
+        self.__projectLanguage = ""
+        self.__projectopen = False
+        self.__ropeConfig = {}
+        
+        self.__mainMenu = None
+        self.__progressDialog = None
+        self.__helpDialog = None
+        self.__historyDialog = None
+        self.__refactoringDialogs = {}
+        
+        from FileSystemCommands import E5FileSystemCommands
+        self.__fsCommands = E5FileSystemCommands(self.__e5project)
+        
+        self.__methodMapping = {
+            "Config": self.__setConfig,
+            "Progress": self.__processProgress,
+            "QueryReferencesResult": self.__queryReferencesResult,
+            "QueryDefinitionResult": self.__queryDefinitionResult,
+            "QueryImplementationsResult": self.__queryImplementationsResult,
+            "SoaFinished": self.__soaFinished,
+            
+            "FileSystemCommand": self.__fsCommands.processFileSystemCommand,
+            
+            "ClientException": self.__processClientException,
+            
+            "HistoryResult": self.__processHistoryResult,
+            
+            "Changes": self.__processChanges,
+        }
+    
+    def getMainWindow(self):
+        """
+        Public method to get a reference to the IDE main window.
+        
+        @return reference to the IDE main window
+        @rtype UserInterface
+        """
+        return self.__ui
+    
+    def initActions(self):
+        """
+        Public method to define the refactoring actions.
+        """
+        self.actions = []
+        
+        #####################################################
+        ## Rename refactoring actions
+        #####################################################
+        
+        self.refactoringRenameAct = E5Action(
+            self.tr('Rename'),
+            self.tr('&Rename'),
+            0, 0,
+            self, 'refactoring_rename')
+        self.refactoringRenameAct.setStatusTip(self.tr(
+            'Rename the highlighted object'))
+        self.refactoringRenameAct.setWhatsThis(self.tr(
+            """<b>Rename</b>"""
+            """<p>Rename the highlighted Python object.</p>"""
+        ))
+        self.refactoringRenameAct.triggered.connect(
+            self.__rename)
+        self.actions.append(self.refactoringRenameAct)
+        
+        self.refactoringRenameLocalAct = E5Action(
+            self.tr('Local Rename'),
+            self.tr('&Local Rename'),
+            0, 0,
+            self, 'refactoring_rename_local')
+        self.refactoringRenameLocalAct.setStatusTip(self.tr(
+            'Rename the highlighted object in the current module only'))
+        self.refactoringRenameLocalAct.setWhatsThis(self.tr(
+            """<b>Local Rename</b>"""
+            """<p>Rename the highlighted Python object in the current"""
+            """ module only.</p>"""
+        ))
+        self.refactoringRenameLocalAct.triggered.connect(
+            self.__renameLocal)
+        self.actions.append(self.refactoringRenameLocalAct)
+        
+        self.refactoringRenameModuleAct = E5Action(
+            self.tr('Rename Current Module'),
+            self.tr('Rename Current Module'),
+            0, 0,
+            self, 'refactoring_rename_module')
+        self.refactoringRenameModuleAct.setStatusTip(self.tr(
+            'Rename the current module'))
+        self.refactoringRenameModuleAct.setWhatsThis(self.tr(
+            """<b>Rename Current Module</b>"""
+            """<p>Rename the current module.</p>"""
+        ))
+        self.refactoringRenameModuleAct.triggered.connect(
+            self.__renameModule)
+        self.actions.append(self.refactoringRenameModuleAct)
+        
+        self.refactoringChangeOccurrencesAct = E5Action(
+            self.tr('Change Occurrences'),
+            self.tr('Change &Occurrences'),
+            0, 0,
+            self, 'refactoring_change_occurrences')
+        self.refactoringChangeOccurrencesAct.setStatusTip(self.tr(
+            'Change all occurrences in the local scope'))
+        self.refactoringChangeOccurrencesAct.setWhatsThis(self.tr(
+            """<b>Change Occurrences</b>"""
+            """<p>Change all occurrences in the local scope.</p>"""
+        ))
+        self.refactoringChangeOccurrencesAct.triggered.connect(
+            self.__changeOccurrences)
+        self.actions.append(self.refactoringChangeOccurrencesAct)
+        
+        #####################################################
+        ## Extract refactoring actions
+        #####################################################
+        
+        self.refactoringExtractMethodAct = E5Action(
+            self.tr('Extract method'),
+            self.tr('Extract &Method'),
+            0, 0,
+            self, 'refactoring_extract_method')
+        self.refactoringExtractMethodAct.setStatusTip(self.tr(
+            'Extract the highlighted area as a method'))
+        self.refactoringExtractMethodAct.setWhatsThis(self.tr(
+            """<b>Extract method</b>"""
+            """<p>Extract the highlighted area as a method or function.</p>"""
+        ))
+        self.refactoringExtractMethodAct.triggered.connect(
+            self.__extractMethod)
+        self.actions.append(self.refactoringExtractMethodAct)
+        
+        self.refactoringExtractLocalVariableAct = E5Action(
+            self.tr('Extract local variable'),
+            self.tr('&Extract Local Variable'),
+            0, 0,
+            self, 'refactoring_extract_variable')
+        self.refactoringExtractLocalVariableAct.setStatusTip(self.tr(
+            'Extract the highlighted area as a local variable'))
+        self.refactoringExtractLocalVariableAct.setWhatsThis(self.tr(
+            """<b>Extract local variable</b>"""
+            """<p>Extract the highlighted area as a local variable.</p>"""
+        ))
+        self.refactoringExtractLocalVariableAct.triggered.connect(
+            self.__extractLocalVariable)
+        self.actions.append(self.refactoringExtractLocalVariableAct)
+        
+        #####################################################
+        ## Inline refactoring actions
+        #####################################################
+        
+        self.refactoringInlineAct = E5Action(
+            self.tr('Inline'),
+            self.tr('&Inline'),
+            0, 0,
+            self, 'refactoring_inline')
+        self.refactoringInlineAct.setStatusTip(self.tr(
+            'Inlines the selected local variable or method'))
+        self.refactoringInlineAct.setWhatsThis(self.tr(
+            """<b>Inline</b>"""
+            """<p>Inlines the selected local variable or method.</p>"""
+        ))
+        self.refactoringInlineAct.triggered.connect(
+            self.__inline)
+        self.actions.append(self.refactoringInlineAct)
+        
+        #####################################################
+        ## Move refactoring actions
+        #####################################################
+        
+        self.refactoringMoveMethodAct = E5Action(
+            self.tr('Move method'),
+            self.tr('Mo&ve Method'),
+            0, 0,
+            self, 'refactoring_move_method')
+        self.refactoringMoveMethodAct.setStatusTip(self.tr(
+            'Move the highlighted method to another class'))
+        self.refactoringMoveMethodAct.setWhatsThis(self.tr(
+            """<b>Move method</b>"""
+            """<p>Move the highlighted method to another class.</p>"""
+        ))
+        self.refactoringMoveMethodAct.triggered.connect(
+            lambda: self.__move("move_method"))
+        self.actions.append(self.refactoringMoveMethodAct)
+        
+        self.refactoringMoveModuleAct = E5Action(
+            self.tr('Move current module'),
+            self.tr('Move Current Module'),
+            0, 0,
+            self, 'refactoring_move_module')
+        self.refactoringMoveModuleAct.setStatusTip(self.tr(
+            'Move the current module to another package'))
+        self.refactoringMoveModuleAct.setWhatsThis(self.tr(
+            """<b>Move current module</b>"""
+            """<p>Move the current module to another package.</p>"""
+        ))
+        self.refactoringMoveModuleAct.triggered.connect(
+            lambda: self.__move("move_module"))
+        self.actions.append(self.refactoringMoveModuleAct)
+        
+        #####################################################
+        ## Use function refactoring action
+        #####################################################
+        
+        self.refactoringUseFunctionAct = E5Action(
+            self.tr('Use Function'),
+            self.tr('Use Function'),
+            0, 0,
+            self, 'refactoring_use_function')
+        self.refactoringUseFunctionAct.setStatusTip(self.tr(
+            'Use a function wherever possible.'))
+        self.refactoringUseFunctionAct.setWhatsThis(self.tr(
+            """<b>Use function</b>"""
+            """<p>Tries to use a function wherever possible.</p>"""
+        ))
+        self.refactoringUseFunctionAct.triggered.connect(
+            self.__useFunction)
+        self.actions.append(self.refactoringUseFunctionAct)
+        
+        #####################################################
+        ## Introduce refactorings actions
+        #####################################################
+        
+        self.refactoringIntroduceFactoryAct = E5Action(
+            self.tr('Introduce Factory Method'),
+            self.tr('Introduce &Factory Method'),
+            0, 0,
+            self, 'refactoring_introduce_factory_method')
+        self.refactoringIntroduceFactoryAct.setStatusTip(self.tr(
+            'Introduce a factory method or function'))
+        self.refactoringIntroduceFactoryAct.setWhatsThis(self.tr(
+            """<b>Introduce Factory Method</b>"""
+            """<p>Introduce a factory method or function.</p>"""
+        ))
+        self.refactoringIntroduceFactoryAct.triggered.connect(
+            self.__introduceFactoryMethod)
+        self.actions.append(self.refactoringIntroduceFactoryAct)
+        
+        self.refactoringIntroduceParameterAct = E5Action(
+            self.tr('Introduce Parameter'),
+            self.tr('Introduce &Parameter'),
+            0, 0,
+            self, 'refactoring_introduce_parameter_method')
+        self.refactoringIntroduceParameterAct.setStatusTip(self.tr(
+            'Introduce a parameter in a function'))
+        self.refactoringIntroduceParameterAct.setWhatsThis(self.tr(
+            """<b>Introduce Parameter</b>"""
+            """<p>Introduce a parameter in a function.</p>"""
+        ))
+        self.refactoringIntroduceParameterAct.triggered.connect(
+            self.__introduceParameter)
+        self.actions.append(self.refactoringIntroduceParameterAct)
+        
+        #####################################################
+        ## Import refactorings actions
+        #####################################################
+        
+        self.refactoringImportsOrganizeAct = E5Action(
+            self.tr('Organize Imports'),
+            self.tr('&Organize Imports'),
+            0, 0,
+            self, 'refactoring_organize_imports')
+        self.refactoringImportsOrganizeAct.setStatusTip(self.tr(
+            'Sort imports according to PEP-8'))
+        self.refactoringImportsOrganizeAct.setWhatsThis(self.tr(
+            """<b>Organize Imports</b>"""
+            """<p>Sort imports according to PEP-8.</p>"""
+        ))
+        self.refactoringImportsOrganizeAct.triggered.connect(
+            self.__importsOrganize)
+        self.actions.append(self.refactoringImportsOrganizeAct)
+        
+        self.refactoringImportsStarExpandAct = E5Action(
+            self.tr('Expand Star Imports'),
+            self.tr('E&xpand Star Imports'),
+            0, 0,
+            self, 'refactoring_expand_star_imports')
+        self.refactoringImportsStarExpandAct.setStatusTip(self.tr(
+            'Expand imports like "from xxx import *"'))
+        self.refactoringImportsStarExpandAct.setWhatsThis(self.tr(
+            """<b>Expand Star Imports</b>"""
+            """<p>Expand imports like "from xxx import *".</p>"""
+            """<p>Select the import to act on or none to do all."""
+            """ Unused imports are deleted.</p>"""
+        ))
+        self.refactoringImportsStarExpandAct.triggered.connect(
+            self.__importsExpandStar)
+        self.actions.append(self.refactoringImportsStarExpandAct)
+        
+        self.refactoringImportsRelativeToAbsoluteAct = E5Action(
+            self.tr('Relative to Absolute'),
+            self.tr('Relative to &Absolute'),
+            0, 0,
+            self, 'refactoring_relative_to_absolute_imports')
+        self.refactoringImportsRelativeToAbsoluteAct.setStatusTip(self.tr(
+            'Transform relative imports to absolute ones'))
+        self.refactoringImportsRelativeToAbsoluteAct.setWhatsThis(self.tr(
+            """<b>Relative to Absolute</b>"""
+            """<p>Transform relative imports to absolute ones.</p>"""
+            """<p>Select the import to act on or none to do all."""
+            """ Unused imports are deleted.</p>"""
+        ))
+        self.refactoringImportsRelativeToAbsoluteAct.triggered.connect(
+            self.__importsRelativeToAbsolute)
+        self.actions.append(self.refactoringImportsRelativeToAbsoluteAct)
+        
+        self.refactoringImportsFromsToImportsAct = E5Action(
+            self.tr('Froms to Imports'),
+            self.tr('Froms to &Imports'),
+            0, 0,
+            self, 'refactoring_froms_to_imports')
+        self.refactoringImportsFromsToImportsAct.setStatusTip(self.tr(
+            'Transform From imports to plain imports'))
+        self.refactoringImportsFromsToImportsAct.setWhatsThis(self.tr(
+            """<b>Froms to Imports</b>"""
+            """<p>Transform From imports to plain imports.</p>"""
+            """<p>Select the import to act on or none to do all."""
+            """ Unused imports are deleted.</p>"""
+        ))
+        self.refactoringImportsFromsToImportsAct.triggered.connect(
+            self.__importsFromToImport)
+        self.actions.append(self.refactoringImportsFromsToImportsAct)
+        
+        self.refactoringImportsHandleLongAct = E5Action(
+            self.tr('Handle Long Imports'),
+            self.tr('Handle &Long Imports'),
+            0, 0,
+            self, 'refactoring_organize_imports')
+        self.refactoringImportsHandleLongAct.setStatusTip(self.tr(
+            'Transform long import statements to look better'))
+        self.refactoringImportsHandleLongAct.setWhatsThis(self.tr(
+            """<b>Handle Long Imports</b>"""
+            """<p>Transform long import statements to look better.</p>"""
+            """<p>Select the import to act on or none to do all."""
+            """ Unused imports are deleted.</p>"""
+        ))
+        self.refactoringImportsHandleLongAct.triggered.connect(
+            self.__importsHandleLong)
+        self.actions.append(self.refactoringImportsHandleLongAct)
+        
+        #####################################################
+        ## Various refactorings actions
+        #####################################################
+        
+        self.refactoringRestructureAct = E5Action(
+            self.tr('Restructure'),
+            self.tr('Res&tructure'),
+            0, 0,
+            self, 'refactoring_restructure')
+        self.refactoringRestructureAct.setStatusTip(self.tr(
+            'Restructure code'))
+        self.refactoringRestructureAct.setWhatsThis(self.tr(
+            """<b>Restructure</b>"""
+            """<p>Restructure code. See "Rope Help" for examples.</p>"""
+        ))
+        self.refactoringRestructureAct.triggered.connect(
+            self.__restructure)
+        self.actions.append(self.refactoringRestructureAct)
+        
+        self.refactoringChangeSignatureAct = E5Action(
+            self.tr('Change Method Signature'),
+            self.tr('&Change Method Signature'),
+            0, 0,
+            self, 'refactoring_change_method_signature')
+        self.refactoringChangeSignatureAct.setStatusTip(self.tr(
+            'Change the signature of the selected method or function'))
+        self.refactoringChangeSignatureAct.setWhatsThis(self.tr(
+            """<b>Change Method Signature</b>"""
+            """<p>Change the signature of the selected method"""
+            """ or function.</p>"""
+        ))
+        self.refactoringChangeSignatureAct.triggered.connect(
+            self.__changeSignature)
+        self.actions.append(self.refactoringChangeSignatureAct)
+        
+        self.refactoringInlineArgumentDefaultAct = E5Action(
+            self.tr('Inline Argument Default'),
+            self.tr('Inline &Argument Default'),
+            0, 0,
+            self, 'refactoring_inline_argument_default')
+        self.refactoringInlineArgumentDefaultAct.setStatusTip(self.tr(
+            'Inline a parameters default value'))
+        self.refactoringInlineArgumentDefaultAct.setWhatsThis(self.tr(
+            """<b>Inline Argument Default</b>"""
+            """<p>Inline a parameters default value.</p>"""
+        ))
+        self.refactoringInlineArgumentDefaultAct.triggered.connect(
+            self.__inlineArgumentDefault)
+        self.actions.append(self.refactoringInlineArgumentDefaultAct)
+        
+        self.refactoringTransformModuleAct = E5Action(
+            self.tr('Transform Module to Package'),
+            self.tr('Transform Module to Package'),
+            0, 0,
+            self, 'refactoring_transform_module_to_package')
+        self.refactoringTransformModuleAct.setStatusTip(self.tr(
+            'Transform the current module to a package'))
+        self.refactoringTransformModuleAct.setWhatsThis(self.tr(
+            """<b>Transform Module to Package</b>"""
+            """<p>Transform the current module to a package.</p>"""
+        ))
+        self.refactoringTransformModuleAct.triggered.connect(
+            self.__transformModuleToPackage)
+        self.actions.append(self.refactoringTransformModuleAct)
+        
+        self.refactoringEncapsulateAttributeAct = E5Action(
+            self.tr('Encapsulate Attribute'),
+            self.tr('Encap&sulate Attribute'),
+            0, 0,
+            self, 'refactoring_encapsulate_attribute')
+        self.refactoringEncapsulateAttributeAct.setStatusTip(self.tr(
+            'Generate a getter/setter for an attribute'))
+        self.refactoringEncapsulateAttributeAct.setWhatsThis(self.tr(
+            """<b>Encapsulate Attribute</b>"""
+            """<p>Generate a getter/setter for an attribute and changes"""
+            """ its occurrences to use them.</p>"""
+        ))
+        self.refactoringEncapsulateAttributeAct.triggered.connect(
+            self.__encapsulateAttribute)
+        self.actions.append(self.refactoringEncapsulateAttributeAct)
+        
+        self.refactoringLocalVariableToAttributeAct = E5Action(
+            self.tr('Local Variable to Attribute'),
+            self.tr('Local Varia&ble to Attribute'),
+            0, 0,
+            self, 'refactoring_local_variable_to_attribute')
+        self.refactoringLocalVariableToAttributeAct.setStatusTip(self.tr(
+            'Change a local variable to an attribute'))
+        self.refactoringLocalVariableToAttributeAct.setWhatsThis(self.tr(
+            """<b>Local Variable to Attribute</b>"""
+            """<p>Change a local variable to an attribute.</p>"""
+        ))
+        self.refactoringLocalVariableToAttributeAct.triggered.connect(
+            self.__convertLocalToAttribute)
+        self.actions.append(self.refactoringLocalVariableToAttributeAct)
+        
+        self.refactoringMethodToMethodObjectAct = E5Action(
+            self.tr('Method To Method Object'),
+            self.tr('Method To Method Ob&ject'),
+            0, 0,
+            self, 'refactoring_method_to_methodobject')
+        self.refactoringMethodToMethodObjectAct.setStatusTip(self.tr(
+            'Transform a function or a method to a method object'))
+        self.refactoringMethodToMethodObjectAct.setWhatsThis(self.tr(
+            """<b>Method To Method Object</b>"""
+            """<p>Transform a function or a method to a method object.</p>"""
+        ))
+        self.refactoringMethodToMethodObjectAct.triggered.connect(
+            self.__methodToMethodObject)
+        self.actions.append(self.refactoringMethodToMethodObjectAct)
+        
+        #####################################################
+        ## History actions
+        #####################################################
+        
+        self.refactoringProjectHistoryAct = E5Action(
+            self.tr('Show Project History'),
+            self.tr('Show Project History...'),
+            0, 0,
+            self, 'refactoring_show_project_history')
+        self.refactoringProjectHistoryAct.setStatusTip(self.tr(
+            'Show the refactoring history of the project'))
+        self.refactoringProjectHistoryAct.setWhatsThis(self.tr(
+            """<b>Show Project History</b>"""
+            """<p>This opens a dialog to show the refactoring history of"""
+            """ the project.</p>"""
+        ))
+        self.refactoringProjectHistoryAct.triggered.connect(
+            self.__showProjectHistory)
+        self.actions.append(self.refactoringProjectHistoryAct)
+        
+        self.refactoringFileHistoryAct = E5Action(
+            self.tr('Show Current File History'),
+            self.tr('Show Current File History...'),
+            0, 0,
+            self, 'refactoring_show_file_history')
+        self.refactoringFileHistoryAct.setStatusTip(self.tr(
+            'Show the refactoring history of the current file'))
+        self.refactoringFileHistoryAct.setWhatsThis(self.tr(
+            """<b>Show Current File History</b>"""
+            """<p>This opens a dialog to show the refactoring history of"""
+            """ the current file.</p>"""
+        ))
+        self.refactoringFileHistoryAct.triggered.connect(
+            self.__showFileHistory)
+        self.actions.append(self.refactoringFileHistoryAct)
+        
+        self.refactoringClearHistoryAct = E5Action(
+            self.tr('Clear History'),
+            self.tr('Clear History'),
+            0, 0,
+            self, 'refactoring_clear_history')
+        self.refactoringClearHistoryAct.setStatusTip(self.tr(
+            'Clear the refactoring history'))
+        self.refactoringClearHistoryAct.setWhatsThis(self.tr(
+            """<b>Clear History</b>"""
+            """<p>Clears the refactoring history.</p>"""
+        ))
+        self.refactoringClearHistoryAct.triggered.connect(
+            self.__clearHistory)
+        self.actions.append(self.refactoringClearHistoryAct)
+        
+        #####################################################
+        ## Query actions
+        #####################################################
+        
+        self.queryReferencesAct = E5Action(
+            self.tr('Find occurrences'),
+            self.tr('Find &Occurrences'),
+            0, 0,
+            self, 'refactoring_find_occurrences')
+        self.queryReferencesAct.setStatusTip(self.tr(
+            'Find occurrences of the highlighted object'))
+        self.queryReferencesAct.setWhatsThis(self.tr(
+            """<b>Find occurrences</b>"""
+            """<p>Find occurrences of the highlighted class, method,"""
+            """ function or variable.</p>"""
+        ))
+        self.queryReferencesAct.triggered.connect(
+            self.__queryReferences)
+        self.actions.append(self.queryReferencesAct)
+        
+        self.queryDefinitionAct = E5Action(
+            self.tr('Find definition'),
+            self.tr('Find &Definition'),
+            0, 0,
+            self, 'refactoring_find_definition')
+        self.queryDefinitionAct.setStatusTip(self.tr(
+            'Find definition of the highlighted item'))
+        self.queryDefinitionAct.setWhatsThis(self.tr(
+            """<b>Find definition</b>"""
+            """<p>Find the definition of the highlighted class, method,"""
+            """ function or variable.</p>"""
+        ))
+        self.queryDefinitionAct.triggered.connect(
+            self.__queryDefinition)
+        self.actions.append(self.queryDefinitionAct)
+        
+        self.queryImplementationsAct = E5Action(
+            self.tr('Find implementations'),
+            self.tr('Find &Implementations'),
+            0, 0,
+            self, 'refactoring_find_implementations')
+        self.queryImplementationsAct.setStatusTip(self.tr(
+            'Find places where the selected method is overridden'))
+        self.queryImplementationsAct.setWhatsThis(self.tr(
+            """<b>Find implementations</b>"""
+            """<p>Find places where the selected method is overridden.</p>"""
+        ))
+        self.queryImplementationsAct.triggered.connect(
+            self.__queryImplementations)
+        self.actions.append(self.queryImplementationsAct)
+        
+        #####################################################
+        ## Various actions
+        #####################################################
+        
+        self.refactoringEditConfigAct = E5Action(
+            self.tr('Configure Rope'),
+            self.tr('&Configure Rope'),
+            0, 0,
+            self, 'refactoring_edit_config')
+        self.refactoringEditConfigAct.setStatusTip(self.tr(
+            'Open the rope configuration file'))
+        self.refactoringEditConfigAct.setWhatsThis(self.tr(
+            """<b>Configure Rope</b>"""
+            """<p>Opens the rope configuration file in an editor.</p>"""
+        ))
+        self.refactoringEditConfigAct.triggered.connect(
+            self.__editConfig)
+        self.refactoringEditConfigAct.setMenuRole(QAction.NoRole)
+        self.actions.append(self.refactoringEditConfigAct)
+        
+        self.refactoringHelpAct = E5Action(
+            self.tr('Rope Help'),
+            self.tr('Rope &Help'),
+            0, 0,
+            self, 'refactoring_help')
+        self.refactoringHelpAct.setStatusTip(self.tr(
+            'Show help about the rope refactorings'))
+        self.refactoringHelpAct.setWhatsThis(self.tr(
+            """<b>Rope help</b>"""
+            """<p>Show some help text about the rope refactorings.</p>"""
+        ))
+        self.refactoringHelpAct.triggered.connect(
+            self.__showRopeHelp)
+        self.actions.append(self.refactoringHelpAct)
+        
+        self.refactoringAllSoaAct = E5Action(
+            self.tr('Analyse all modules'),
+            self.tr('&Analyse all modules'),
+            0, 0,
+            self, 'refactoring_analyze_all')
+        self.refactoringAllSoaAct.setStatusTip(self.tr(
+            'Perform static object analysis on all modules'))
+        self.refactoringAllSoaAct.setWhatsThis(self.tr(
+            """<b>Analyse all modules</b>"""
+            """<p>Perform static object analysis (SOA) on all modules. """
+            """This might be time consuming. Analysis of all modules """
+            """should only be neccessary, if the project was created """
+            """with the rope plugin disabled or if files were added.</p>"""
+        ))
+        self.refactoringAllSoaAct.triggered.connect(
+            self.__performSOA)
+        self.actions.append(self.refactoringAllSoaAct)
+        
+        self.updateConfigAct = E5Action(
+            self.tr('Update Configuration'),
+            self.tr('&Update Configuration'),
+            0, 0,
+            self, 'refactoring_update_configuration')
+        self.updateConfigAct.setStatusTip(self.tr(
+            'Generates a new configuration file overwriting the current one.'))
+        self.updateConfigAct.setWhatsThis(self.tr(
+            """<b>Update Configuration</b>"""
+            """<p>Generates a new configuration file overwriting"""
+            """ the current one.</p>"""
+        ))
+        self.updateConfigAct.triggered.connect(
+            self.__updateConfig)
+        self.actions.append(self.updateConfigAct)
+        
+        for act in self.actions:
+            act.setEnabled(False)
+    
+    def initMenu(self):
+        """
+        Public slot to initialize the refactoring menu.
+        
+        @return the menu generated (QMenu)
+        """
+        menu = QMenu(self.tr('&Refactoring'), self.__ui)
+        menu.setTearOffEnabled(True)
+        
+        act = menu.addAction('rope', self.__ropeInfo)
+        font = act.font()
+        font.setBold(True)
+        act.setFont(font)
+        menu.addSeparator()
+        
+        smenu = menu.addMenu(self.tr("&Query"))
+        smenu.addAction(self.queryReferencesAct)
+        smenu.addAction(self.queryDefinitionAct)
+        smenu.addAction(self.queryImplementationsAct)
+        
+        smenu = menu.addMenu(self.tr("&Refactoring"))
+        smenu.addAction(self.refactoringRenameAct)
+        smenu.addAction(self.refactoringRenameLocalAct)
+        smenu.addAction(self.refactoringChangeOccurrencesAct)
+        smenu.addSeparator()
+        smenu.addAction(self.refactoringExtractMethodAct)
+        smenu.addAction(self.refactoringMoveMethodAct)
+        smenu.addSeparator()
+        smenu.addAction(self.refactoringInlineAct)
+        smenu.addSeparator()
+        smenu.addAction(self.refactoringExtractLocalVariableAct)
+        smenu.addSeparator()
+        smenu.addAction(self.refactoringUseFunctionAct)
+        smenu.addSeparator()
+        smenu.addAction(self.refactoringChangeSignatureAct)
+        smenu.addAction(self.refactoringInlineArgumentDefaultAct)
+        smenu.addSeparator()
+        smenu.addAction(self.refactoringRestructureAct)
+        smenu.addSeparator()
+        smenu.addAction(self.refactoringIntroduceFactoryAct)
+        smenu.addAction(self.refactoringIntroduceParameterAct)
+        smenu.addAction(self.refactoringMethodToMethodObjectAct)
+        smenu.addSeparator()
+        smenu.addAction(self.refactoringEncapsulateAttributeAct)
+        smenu.addAction(self.refactoringLocalVariableToAttributeAct)
+        smenu.addSeparator()
+        smenu.addAction(self.refactoringRenameModuleAct)
+        smenu.addAction(self.refactoringMoveModuleAct)
+        smenu.addAction(self.refactoringTransformModuleAct)
+        smenu.addSeparator()
+        
+        imenu = smenu.addMenu(self.tr("Im&ports"))
+        imenu.addAction(self.refactoringImportsOrganizeAct)
+        imenu.addAction(self.refactoringImportsStarExpandAct)
+        imenu.addAction(self.refactoringImportsRelativeToAbsoluteAct)
+        imenu.addAction(self.refactoringImportsFromsToImportsAct)
+        imenu.addAction(self.refactoringImportsHandleLongAct)
+        
+        smenu.addSeparator()
+        
+        hmenu = smenu.addMenu(self.tr("History"))
+        hmenu.aboutToShow.connect(self.__showRefactoringHistoryMenu)
+        hmenu.addAction(self.refactoringProjectHistoryAct)
+        hmenu.addAction(self.refactoringFileHistoryAct)
+        hmenu.addSeparator()
+        hmenu.addAction(self.refactoringClearHistoryAct)
+        
+        smenu = menu.addMenu(self.tr("&Utilities"))
+        smenu.addAction(self.refactoringAllSoaAct)
+        smenu.addSeparator()
+        smenu.addAction(self.updateConfigAct)
+        
+        menu.addSeparator()
+        menu.addAction(self.refactoringEditConfigAct)
+        menu.addAction(self.refactoringHelpAct)
+        
+        self.__mainMenu = menu
+        
+        return menu
+
+    ##################################################################
+    ## slots below implement general functionality
+    ##################################################################
+    
+    def __ropeInfo(self):
+        """
+        Private slot to show some info about rope.
+        """
+        if self.__ropeConfig:
+            E5MessageBox.about(
+                self.__ui,
+                self.tr("About rope"),
+                self.tr("{0}\nVersion {1}\n\n{2}".format(
+                    self.__ropeConfig["RopeInfo"],
+                    self.__ropeConfig["RopeVersion"],
+                    self.__ropeConfig["RopeCopyright"])))
+    
+    def __showRefactoringHistoryMenu(self):
+        """
+        Private slot called before the refactoring history menu is shown.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        enable = aw is not None and bool(aw.getFileName())
+        
+        self.refactoringFileHistoryAct.setEnabled(enable)
+    
+    def handleRopeError(self, result):
+        """
+        Public method to handle a rope error.
+        
+        @param result dictionary containing the error information
+        @type dict
+        @return flag indicating, that the error is to be ignored
+        @rtype bool
+        """
+        if "Error" not in result:
+            return True
+        
+        if "Title" in result:
+            title = result["Title"]
+        else:
+            title = self.tr("Rope Error")
+        
+        if result["Error"] == 'ModuleSyntaxError':
+            res = E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Rope error: {0}").format(
+                    result["ErrorString"]),
+                E5MessageBox.Ok | E5MessageBox.Open)
+            if res == E5MessageBox.Open:
+                e5App().getObject("ViewManager").openSourceFile(
+                    os.path.join(self.__e5project.getProjectPath(),
+                                 result["ErrorFile"]),
+                    result["ErrorLine"])
+        elif result["Error"] == "InterruptedTaskError":
+            return True
+        else:
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Rope error: {0}").format(
+                    result["ErrorString"])
+            )
+        
+        return False
+    
+    def __getOffset(self, editor, line, index):
+        r"""
+        Private method to get the offset into the text treating CRLF as ONE
+        character.
+        
+        Note: rope seems to convert all EOL styles to just \n.
+        
+        @param editor reference to the editor (Editor)
+        @param line line for the offset (integer)
+        @param index index into line for the offset (integer)
+        @return rope compliant offset into the file (integer)
+        """
+        source = editor.text()
+        offset = len("".join(source.splitlines(True)[:line])) + index
+        if editor.eolMode() == QsciScintilla.EolWindows:
+            offset -= line
+        return offset
+
+    ##################################################################
+    ## slots below implement the various refactorings
+    ##################################################################
+    
+    def __processChanges(self, result):
+        """
+        Private method to process the changes data sent by the refactoring
+        client.
+        
+        @param result dictionary containing the changes data
+        @type dict
+        """
+        if self.handleRopeError(result):
+            changeGroup = result["ChangeGroup"]
+            try:
+                self.__refactoringDialogs[changeGroup]\
+                .processChangeData(result)
+            except KeyError:
+                # ignore data for non-existing dialogs
+                pass
+    
+    def __refactoringDialogClosed(self, changeGroup):
+        """
+        Private slot handling the closing of a refactoring dialog.
+        
+        @param changeGroup name of the refactoring change group the dialog
+            belonged to
+        @type str
+        """
+        try:
+            del self.__refactoringDialogs[changeGroup]
+        except KeyError:
+            # it's gone already; ignore it
+            pass
+    
+    #####################################################
+    ## Rename refactorings
+    #####################################################
+    
+    def __rename(self):
+        """
+        Private slot to handle the Rename action.
+        """
+        self.__doRename(self.tr('Rename'))
+    
+    def __renameLocal(self):
+        """
+        Private slot to handle the Local Rename action.
+        """
+        self.__doRename(self.tr('Local Rename'), isLocal=True)
+    
+    def __renameModule(self):
+        """
+        Private slot to handle the Rename Current Module action.
+        """
+        self.__doRename(self.tr('Rename Current Module'),
+                        renameModule=True)
+    
+    def __doRename(self, title, isLocal=False, renameModule=False):
+        """
+        Private method to perform the various renaming refactorings.
+        
+        @param title title of the refactoring (string)
+        @param isLocal flag indicating to restrict refactoring to
+            the local file (boolean)
+        @param renameModule flag indicating a module rename refactoring
+            (boolean)
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        if not renameModule and not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight the declaration you want to rename"
+                        " and try again."))
+            return
+        
+        if isLocal:
+            if not self.confirmBufferIsSaved(aw):
+                return
+        else:
+            if not self.confirmAllBuffersSaved():
+                return
+        
+        filename = aw.getFileName()
+        if renameModule:
+            offset = None
+            selectedText, _ = os.path.splitext(os.path.basename(filename))
+        else:
+            line, index, line1, index1 = aw.getSelection()
+            if line != line1:
+                # selection span more than one line
+                E5MessageBox.warning(
+                    self.__ui, title,
+                    self.tr("The selection must not extend beyond"
+                            " one line."))
+                return
+            index = int(index + (index1 - index) / 2)
+            # keep it inside the object
+            offset = self.__getOffset(aw, line, index)
+            selectedText = aw.selectedText()
+        
+        from RenameDialog import RenameDialog
+        dlg = RenameDialog(self, title, filename, offset, isLocal,
+                           selectedText=selectedText, parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    def __changeOccurrences(self):
+        """
+        Private slot to perform the Change Occurrences refactoring.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Change Occurrences")
+        if not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight an occurrence to be changed"
+                        " and try again."))
+            return
+        
+        if not self.confirmBufferIsSaved(aw):
+            return
+        
+        filename = aw.getFileName()
+        line, index, line1, index1 = aw.getSelection()
+        offset = self.__getOffset(aw, line, index)
+        
+        from ChangeOccurrencesDialog import ChangeOccurrencesDialog
+        dlg = ChangeOccurrencesDialog(self, title, filename, offset,
+                                      parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    #####################################################
+    ## Extract refactorings
+    #####################################################
+    
+    def __extractMethod(self):
+        """
+        Private slot to handle the Extract Method action.
+        """
+        self.__doExtract(self.tr("Extract Method"), "method")
+    
+    def __extractLocalVariable(self):
+        """
+        Private slot to handle the Extract Local Variable action.
+        """
+        self.__doExtract(self.tr("Extract Local Variable"), "variable")
+    
+    def __doExtract(self, title, kind):
+        """
+        Private method to perform the extract refactoring.
+        
+        @param title title of the refactoring
+        @type str
+        @param kind kind of extraction to be done
+        @type str ("method" or "variable")
+        """
+        assert kind in ["variable", "method"]
+        
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        if not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight the region of code you want to extract"
+                        " and try again."))
+            return
+        
+        if not self.confirmBufferIsSaved(aw):
+            return
+        
+        filename = aw.getFileName()
+        startline, startcolumn, endline, endcolumn = aw.getSelection()
+        startOffset = self.__getOffset(aw, startline, startcolumn)
+        endOffset = self.__getOffset(aw, endline, endcolumn)
+        
+        from ExtractDialog import ExtractDialog
+        dlg = ExtractDialog(self, title, filename, startOffset, endOffset,
+                            kind, parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    #####################################################
+    ## Inline refactorings
+    #####################################################
+    
+    def __inline(self):
+        """
+        Private slot to handle the Inline Local Variable action.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Inline")
+        if not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight the local variable, method or parameter"
+                        " you want to inline and try again."))
+            return
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index, line1, index1 = aw.getSelection()
+        offset = self.__getOffset(aw, line, index)
+        
+        from InlineDialog import InlineDialog
+        dlg = InlineDialog(self, title, filename, offset, parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    #####################################################
+    ## Move refactorings
+    #####################################################
+    
+    def __move(self, moveKind):
+        """
+        Private slot to handle the Move Method action.
+        
+        @param moveKind kind of move to be performed
+        @type str (one of 'move_method' or 'move_module')
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        if moveKind == "move_method":
+            title = self.tr("Move Method")
+            if not aw.hasSelectedText():
+                # no selection available
+                E5MessageBox.warning(
+                    self.__ui, title,
+                    self.tr("Highlight the method to move"
+                            " and try again."))
+                return
+        else:
+            title = self.tr("Move Current Module")
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        if moveKind == "move_method":
+            line, index, line1, index1 = aw.getSelection()
+            offset = self.__getOffset(aw, line, index)
+        else:
+            offset = None
+        
+        from MoveDialog import MoveDialog
+        dlg = MoveDialog(self, title, filename, offset, parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    #####################################################
+    ## Use function refactoring
+    #####################################################
+    
+    def __useFunction(self):
+        """
+        Private slot to use a function wherever possible.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Use Function")
+        if not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight a global function and try again."))
+            return
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index, line1, index1 = aw.getSelection()
+        offset = self.__getOffset(aw, line, index)
+        
+        from UseFunctionDialog import UseFunctionDialog
+        dlg = UseFunctionDialog(self, title, filename, offset,
+                                parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    #####################################################
+    ## Introduce refactorings
+    #####################################################
+    
+    def __introduceFactoryMethod(self):
+        """
+        Private slot to introduce a factory method or global function.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Introduce Factory Method")
+        if not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight the class to introduce a factory"
+                        " method for and try again."))
+            return
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index, line1, index1 = aw.getSelection()
+        offset = self.__getOffset(aw, line, index)
+        
+        from IntroduceFactoryDialog import IntroduceFactoryDialog
+        dlg = IntroduceFactoryDialog(self, title, filename, offset,
+                                     parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    def __introduceParameter(self):
+        """
+        Private slot to introduce a parameter in a function.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Introduce Parameter")
+        if not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight the code for the new parameter"
+                        " and try again."))
+            return
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index, line1, index1 = aw.getSelection()
+        offset = self.__getOffset(aw, line, index)
+        
+        from IntroduceParameterDialog import IntroduceParameterDialog
+        dlg = IntroduceParameterDialog(self, title, filename, offset,
+                                       parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    #####################################################
+    ## Import refactorings
+    #####################################################
+    
+    def __importsOrganize(self):
+        """
+        Private slot to organize imports.
+        """
+        self.__doImports(
+            self.tr("Organize Imports"),
+            "organize_imports")
+    
+    def __importsExpandStar(self):
+        """
+        Private slot to expand star imports.
+        """
+        self.__doImports(
+            self.tr("Expand Star Imports"),
+            "expand_star_imports")
+    
+    def __importsRelativeToAbsolute(self):
+        """
+        Private slot to transform relative to absolute imports.
+        """
+        self.__doImports(
+            self.tr("Relative to Absolute"),
+            "relatives_to_absolutes")
+    
+    def __importsFromToImport(self):
+        """
+        Private slot to transform from imports to plain imports.
+        """
+        self.__doImports(
+            self.tr("Froms to Imports"),
+            "froms_to_imports")
+    
+    def __importsHandleLong(self):
+        """
+        Private slot to handle long imports.
+        """
+        self.__doImports(
+            self.tr("Handle Long Imports"),
+            "handle_long_imports")
+    
+    def __doImports(self, title, methodName):
+        """
+        Private method to perform the various imports refactorings.
+        
+        @param title title to be used for the import refactoring
+        @type str
+        @param methodName name of the method performing the import refactoring
+        @type str
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        if not self.confirmBufferIsSaved(aw):
+            return
+        
+        filename = aw.getFileName()
+        if aw.hasSelectedText():
+            line, index, line1, index1 = aw.getSelection()
+            offset = self.__getOffset(aw, line, index)
+        else:
+            offset = None
+        
+        from ConfirmationDialog import ConfirmationDialog
+        dlg = ConfirmationDialog(
+            self, title, "Imports", "CalculateImportsChanges", {
+                "MethodName": methodName,
+                "FileName": filename,
+                "Offset": offset,
+            },
+            parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    #####################################################
+    ## Various refactorings
+    #####################################################
+    
+    def __restructure(self):
+        """
+        Private slot to restructure code.
+        """
+        from RestructureDialog import RestructureDialog
+        title = self.tr("Restructure")
+        dlg = RestructureDialog(self, title, parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    def __changeSignature(self):
+        """
+        Private slot to change the signature of a method or function.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Change Method Signature")
+        if not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight the method or function to change"
+                        " and try again."))
+            return
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index, line1, index1 = aw.getSelection()
+        offset = self.__getOffset(aw, line, index)
+        
+        from ChangeSignatureDialog import ChangeSignatureDialog
+        dlg = ChangeSignatureDialog(self, title, filename, offset,
+                                    parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    def __inlineArgumentDefault(self):
+        """
+        Private slot to inline the default value of a parameter of a
+        method or function.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Inline Argument Default")
+        if not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight the method or function to inline"
+                        " a parameter's default and try again."))
+            return
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index, line1, index1 = aw.getSelection()
+        offset = self.__getOffset(aw, line, index)
+        
+        from InlineArgumentDefaultDialog import InlineArgumentDefaultDialog
+        dlg = InlineArgumentDefaultDialog(self, title, filename, offset,
+                                          parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    def __transformModuleToPackage(self):
+        """
+        Private slot to transform a module to a package.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Transform Module to Package")
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        
+        from ConfirmationDialog import ConfirmationDialog
+        dlg = ConfirmationDialog(
+            self, title, "ModuleToPackage", "CalculateModuleToPackageChanges",
+            {
+                "FileName": filename,
+            },
+            parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    def __encapsulateAttribute(self):
+        """
+        Private slot to encapsulate an attribute.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Encapsulate Attribute")
+        if not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight the attribute to encapsulate"
+                        " and try again."))
+            return
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index, line1, index1 = aw.getSelection()
+        offset = self.__getOffset(aw, line, index)
+        
+        from GetterSetterDialog import GetterSetterDialog
+        dlg = GetterSetterDialog(self, title, filename, offset,
+                                 parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    def __convertLocalToAttribute(self):
+        """
+        Private slot to convert a local variable to an attribute.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Local Variable to Attribute")
+        if not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight the local variable to make an attribute"
+                        " and try again."))
+            return
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index, line1, index1 = aw.getSelection()
+        offset = self.__getOffset(aw, line, index)
+        
+        from ConfirmationDialog import ConfirmationDialog
+        dlg = ConfirmationDialog(
+            self, title, "LocalToAttribute",
+            "CalculateLocalToAttributeChanges", {
+                "FileName": filename,
+                "Offset": offset,
+            },
+            parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    def __methodToMethodObject(self):
+        """
+        Private slot to change the signature of a method or function.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Replace Method With Method Object")
+        if not aw.hasSelectedText():
+            # no selection available
+            E5MessageBox.warning(
+                self.__ui, title,
+                self.tr("Highlight the method or function to convert"
+                        " and try again."))
+            return
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index, line1, index1 = aw.getSelection()
+        offset = self.__getOffset(aw, line, index)
+        
+        from MethodToMethodObjectDialog import MethodToMethodObjectDialog
+        dlg = MethodToMethodObjectDialog(self, title, filename, offset,
+                                         parent=self.__ui)
+        changeGroup = dlg.getChangeGroupName()
+        self.__refactoringDialogs[changeGroup] = dlg
+        dlg.finished.connect(
+            lambda: self.__refactoringDialogClosed(changeGroup))
+        dlg.show()
+    
+    #####################################################
+    ## Refactoring History
+    #####################################################
+    
+    def __showProjectHistory(self):
+        """
+        Private method to show the project refactoring history.
+        """
+        if self.__historyDialog is not None:
+            self.__historyDialog.close()
+        
+        from HistoryDialog import HistoryDialog
+        self.__historyDialog = HistoryDialog(self, parent=self.__ui)
+        self.__historyDialog.finished.connect(self.__historyDialogClosed)
+        self.__historyDialog.show()
+    
+    def __showFileHistory(self):
+        """
+        Private method to show the refactoring history of the current file.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        if self.__historyDialog is not None:
+            self.__historyDialog.close()
+        
+        from HistoryDialog import HistoryDialog
+        filename = aw.getFileName()
+        if filename:
+            self.__historyDialog = HistoryDialog(
+                self, filename=filename, parent=self.__ui)
+            self.__historyDialog.show()
+    
+    def __clearHistory(self):
+        """
+        Private slot to clear the redo and undo lists.
+        """
+        res = E5MessageBox.yesNo(
+            None,
+            self.tr("Clear History"),
+            self.tr("Do you really want to clear the refactoring history?"))
+        if res:
+            self.sendJson("History", {
+                "Subcommand": "Clear",
+            })
+            
+            if self.__historyDialog is not None:
+                self.__historyDialog.historyCleared()
+    
+    def __processHistoryResult(self, result):
+        """
+        Private method to process the history data sent by the refactoring
+        client.
+        
+        @param result dictionary containing the history data
+        @type dict
+        """
+        if self.handleRopeError(result) and self.__historyDialog is not None:
+            self.__historyDialog.processHistoryCommand(result)
+    
+    def __historyDialogClosed(self):
+        """
+        Private slot handling the closing of the history dialog.
+        """
+        self.__historyDialog = None
+    
+    #####################################################
+    ## Find actions including mouse click handler
+    #####################################################
+    
+    def __queryReferences(self):
+        """
+        Private slot to handle the Find References action.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Find Occurrences")
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index = aw.getCursorPosition()
+        offset = self.__getOffset(aw, line, index)
+        
+        self.sendJson("QueryReferences", {
+            "Title": title,
+            "FileName": filename,
+            "Offset": offset,
+        })
+    
+    def __queryReferencesResult(self, result):
+        """
+        Private method to handle the "Query References" result sent by
+        the client.
+        
+        @param result dictionary containing the result data
+        @type dict
+        """
+        if self.handleRopeError(result):
+            title = result["Title"]
+            if result["EntriesCount"] > 0:
+                from MatchesDialog import MatchesDialog
+                self.dlg = MatchesDialog(self.__ui, True)
+                self.dlg.show()
+                for occurrence in result["Entries"]:
+                    self.dlg.addEntry(
+                        # file name, lineno, unsure
+                        occurrence[0], occurrence[1], occurrence[2])
+            else:
+                E5MessageBox.warning(
+                    self.__ui, title,
+                    self.tr("No occurrences found."))
+    
+    def __queryDefinition(self):
+        """
+        Private slot to handle the Find Definition action.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Find Definition")
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index = aw.getCursorPosition()
+        offset = self.__getOffset(aw, line, index)
+        
+        self.sendJson("QueryDefinition", {
+            "Title": title,
+            "FileName": filename,
+            "Offset": offset,
+            "Source": aw.text(),
+            "Subcommand": "Query",
+        })
+    
+    def gotoDefinition(self, editor):
+        """
+        Public slot to find the definition for the word at the cursor position
+        and go to it.
+        
+        Note: This is executed upon a mouse click sequence.
+        
+        @param editor reference to the calling editor (Editor)
+        """
+        filename = editor.getFileName()
+        line, index = editor.getCursorPosition()
+        offset = self.__getOffset(editor, line, index)
+        
+        self.sendJson("QueryDefinition", {
+            "Title": "",
+            "FileName": filename,
+            "Offset": offset,
+            "Source": editor.text(),
+            "Subcommand": "Goto",
+        })
+    
+    def __queryDefinitionResult(self, result):
+        """
+        Private method to handle the "Query Definition" result sent by
+        the client.
+        
+        @param result dictionary containing the result data
+        @type dict
+        """
+        if result["Subcommand"] == "Query":
+            if self.handleRopeError(result):
+                title = result["Title"]
+                if "Location" in result:
+                    location = result["Location"]
+                    
+                    from MatchesDialog import MatchesDialog
+                    self.dlg = MatchesDialog(self.__ui, False)
+                    self.dlg.show()
+                    self.dlg.addEntry(location[0], location[1])
+                    # file name, lineno
+                else:
+                    E5MessageBox.warning(
+                        self.__ui, title,
+                        self.tr("No matching definition found."))
+        elif result["Subcommand"] == "Goto":
+            if "Error" not in result:
+                # ignore errors silently
+                if "Location" in result:
+                    location = result["Location"]
+                    try:
+                        e5App().getObject("ViewManager").openSourceFile(
+                            location[0], location[1], addNext=True)
+                    except TypeError:
+                        # backward compatibility; <= 17.03
+                        e5App().getObject("ViewManager").openSourceFile(
+                            location[0], location[1], next=True)
+                else:
+                    e5App().getObject("UserInterface").statusBar().showMessage(
+                        self.tr('No definition found'), 5000)
+    
+    def __queryImplementations(self):
+        """
+        Private slot to handle the Find Implementations action.
+        """
+        aw = e5App().getObject("ViewManager").activeWindow()
+        
+        if aw is None:
+            return
+        
+        title = self.tr("Find Implementations")
+        
+        if not self.confirmAllBuffersSaved():
+            return
+        
+        filename = aw.getFileName()
+        line, index = aw.getCursorPosition()
+        offset = self.__getOffset(aw, line, index)
+        
+        self.sendJson("QueryImplementations", {
+            "Title": title,
+            "FileName": filename,
+            "Offset": offset,
+        })
+    
+    def __queryImplementationsResult(self, result):
+        """
+        Private method to handle the "Query Implementations" result sent by
+        the client.
+        
+        @param result dictionary containing the result data
+        @type dict
+        """
+        if self.handleRopeError(result):
+            title = result["Title"]
+            if result["EntriesCount"] > 0:
+                from MatchesDialog import MatchesDialog
+                self.dlg = MatchesDialog(self.__ui, True)
+                self.dlg.show()
+                for occurrence in result["Entries"]:
+                    self.dlg.addEntry(
+                        # file name, lineno, unsure
+                        occurrence[0], occurrence[1], occurrence[2])
+            else:
+                E5MessageBox.warning(
+                    self.__ui, title, self.tr("No implementations found."))
+    
+    #####################################################
+    ## Various actions
+    #####################################################
+    
+    def __editConfig(self):
+        """
+        Private slot to open the rope configuration file in an editor.
+        """
+        ropedir = self.__ropeConfig["RopeFolderName"]
+        configfile = ""
+        if ropedir and os.path.exists(ropedir):
+            configfile = os.path.join(ropedir, "config.py")
+            if os.path.exists(configfile):
+                from QScintilla.MiniEditor import MiniEditor
+                self.__editor = MiniEditor(configfile)
+                self.__editor.show()
+                self.__editor.editorSaved.connect(self.__configChanged)
+            else:
+                E5MessageBox.critical(
+                    self.__ui,
+                    self.tr("Configure Rope"),
+                    self.tr("""The Rope configuration file '{0}' does"""
+                            """ not exist.""").format(configfile))
+        else:
+            E5MessageBox.critical(
+                self.__ui,
+                self.tr("Configure Rope"),
+                self.tr("""The Rope admin directory does not exist."""))
+    
+    def __updateConfig(self):
+        """
+        Private slot to update the configuration file.
+        """
+        res = E5MessageBox.yesNo(
+            self.__ui,
+            self.tr("Update Configuration"),
+            self.tr("""Shall rope's current configuration be replaced """
+                    """by a new default configuration?"""))
+        if res:
+            src = self.__defaultConfig()
+            cname = self.__ropeConfigFile()
+            if src != "" and cname is not None:
+                try:
+                    f = open(cname, "w")
+                    f.write(src)
+                    f.close()
+                    self.__configChanged()
+                    self.__editConfig()
+                except IOError as err:
+                    E5MessageBox.critical(
+                        None,
+                        self.tr("Update Configuration"),
+                        self.tr("""<p>The configuration could not be"""
+                                """ updated.</p><p>Reason: {0}</p>""")
+                        .format(str(err)))
+    
+    def __showRopeHelp(self):
+        """
+        Private slot to show help about the refactorings offered by Rope.
+        """
+        if self.__helpDialog is None:
+            from HelpDialog import HelpDialog
+            self.__helpDialog = \
+                HelpDialog(self.tr("Help about rope refactorings"),
+                           self.__ropeConfig["RopeHelpFile"])
+        self.__helpDialog.show()
+    
+    def __performSOA(self):
+        """
+        Private slot to perform SOA on all modules.
+        """
+        title = self.tr("Analyse all modules")
+        res = E5MessageBox.yesNo(
+            self.__ui,
+            title,
+            self.tr("""This action might take some time. """
+                    """Do you really want to perform SOA?"""))
+        if res:
+        
+            self.sendJson("PerformSoa", {
+                "Title": title,
+            })
+    
+    def __soaFinished(self, result):
+        """
+        Private method to handle the "Soa Finished" result sent by
+        the client.
+        
+        @param result dictionary containing the result data
+        @type dict
+        """
+        if self.handleRopeError(result):
+            title = result["Title"]
+            
+            E5MessageBox.information(
+                self.__ui,
+                title,
+                self.tr("""Static object analysis (SOA) done. """
+                        """SOA database updated."""))
+    
+    ##################################################################
+    ## methods below are private utility methods
+    ##################################################################
+    
+    def __processProgress(self, params):
+        """
+        Private method to handle Progress commands.
+        
+        @param params dictionary containing the progress data
+        @type dict
+        """
+        subcommand = params["Subcommand"]
+        if subcommand == "Init":
+            if self.__progressDialog is not None:
+                self.__progressDialog.reset()
+            
+            progressDialog = RopeProgressDialog(
+                self, params["Title"], params["Interruptable"])
+            progressDialog.show()
+            progressDialog.raise_()
+            self.__progressDialog = progressDialog
+            QApplication.processEvents()
+        
+        elif subcommand == "Progress":
+            if self.__progressDialog is not None:
+                self.__progressDialog.updateProgress(params)
+                self.__progressDialog.raise_()
+            
+        elif subcommand == "Reset":
+            if self.__progressDialog is not None:
+                self.__progressDialog.reset()
+    
+    def __setConfig(self, params):
+        """
+        Private method to set the rope client configuration data.
+        
+        @param params dictionary containing the configuration data
+        @type dict
+        """
+        self.__ropeConfig = params
+        # keys: RopeFolderName, DefaultConfig, RopeHelpFile,
+        #       RopeInfo, RopeVersion, RopeCopyright
+    
+    def __ropeConfigFile(self):
+        """
+        Private method to get the name of the rope configuration file.
+       
+        @return name of the rope configuration file (string)
+        """
+        configfile = None
+        if self.__ropeConfig:
+            ropedir = self.__ropeConfig["RopeFolderName"]
+            if ropedir:
+                configfile = os.path.join(ropedir, "config.py")
+                if not os.path.exists(configfile):
+                    configfile = None
+        return configfile
+    
+    def __configChanged(self):
+        """
+        Private slot called, when the rope config file has changed.
+        """
+        self.sendJson("ConfigChanged", {})
+    
+    def __defaultConfig(self):
+        """
+        Private slot to return the contents of rope's default configuration.
+        
+        @return string containing the source of rope's default
+            configuration (string)
+        """
+        if self.__ropeConfig and "DefaultConfig" in self.__ropeConfig:
+            return self.__ropeConfig["DefaultConfig"]
+        else:
+            return ""
+    
+    ##################################################################
+    ## methods below are public utility methods
+    ##################################################################
+    
+    def getActions(self):
+        """
+        Public method to get a list of all actions.
+        
+        @return list of all actions (list of E5Action)
+        """
+        return self.actions[:]
+    
+    def projectOpened(self):
+        """
+        Public slot to handle the projectOpened signal.
+        """
+        if self.__projectopen:
+            self.projectClosed()
+        
+        self.__projectopen = True
+        self.__projectpath = self.__e5project.getProjectPath()
+        self.__projectLanguage = self.__e5project.getProjectLanguage()
+        
+        ok = False
+        
+        if self.__projectLanguage.startswith("Python"):
+            # get interpreter from project first
+            interpreter = self.__e5project.getDebugProperty("INTERPRETER")
+            if not interpreter or not Utilities.isinpath(interpreter):
+                # get it from debugger settings second
+                if self.__projectLanguage == "Python2":
+                    interpreter = Preferences.getDebugger("PythonInterpreter")
+                elif self.__projectLanguage == "Python3":
+                    interpreter = Preferences.getDebugger("Python3Interpreter")
+                else:
+                    interpreter = ""
+            if interpreter:
+                ok = self.__startRefactoringClient(interpreter)
+                if not ok:
+                    self.__ui.appendToStderr(self.tr(
+                        "Project language '{0}' is not supported because"
+                        " the configured interpreter could not be started."
+                        " Refactoring is disabled."
+                    ).format(self.__projectLanguage))
+                else:
+                    for act in self.actions:
+                        act.setEnabled(True)
+            else:
+                self.__ui.appendToStderr(self.tr(
+                    "Project language '{0}' is not supported because no"
+                    " suitable interpreter is configured. Refactoring is"
+                    " disabled."
+                ).format(self.__projectLanguage))
+        else:
+            self.__ui.appendToStderr(self.tr(
+                "Refactoring for project language '{0}' is not supported."
+            ).format(self.__projectLanguage))
+        
+        self.__mainMenu.menuAction().setEnabled(ok)
+    
+    def projectClosed(self):
+        """
+        Public slot to handle the projectClosed signal.
+        """
+        for act in self.actions:
+            act.setEnabled(False)
+        self.__mainMenu.menuAction().setEnabled(False)
+        
+        if self.__helpDialog is not None:
+            self.__helpDialog.close()
+            self.__helpDialog = None
+        if self.__historyDialog is not None:
+            self.__historyDialog.close()
+            self.__historyDialog = None
+        for dlg in self.__refactoringDialogs.values():
+            dlg.close()
+        self.__refactoringDialogs = {}
+        
+        self.sendJson("CloseProject", {}, flush=True)
+        
+        self.__projectopen = False
+        self.__projectpath = ''
+        self.__projectLanguage = ""
+        self.__ropeConfig = {}
+        
+        self.stopClient()
+    
+    def confirmBufferIsSaved(self, editor):
+        """
+        Public method to check, if an editor has unsaved changes.
+        
+        @param editor reference to the editor to be checked
+        @return flag indicating, that the editor doesn't contain
+            unsaved edits (boolean)
+        """
+        res = editor.checkDirty()
+        self.sendJson("Validate", {})
+        return res
+    
+    def confirmAllBuffersSaved(self):
+        """
+        Public method to check, if any editor has unsaved changes.
+        
+        @return flag indicating, that no editor contains unsaved edits
+            (boolean)
+        """
+        res = e5App().getObject("ViewManager").checkAllDirty()
+        self.sendJson("Validate", {})
+        return res
+    
+    def refreshEditors(self, changedFiles):
+        """
+        Public method to refresh modified editors.
+        
+        @param changedFiles list of changed files
+        @type list of str
+        """
+        vm = e5App().getObject("ViewManager")
+        openFiles = [Utilities.normcasepath(f) for f in vm.getOpenFilenames()]
+        
+        for fileName in changedFiles:
+            normfile = Utilities.normcasepath(fileName)
+            if normfile in openFiles:
+                editor = vm.getEditor(normfile)[1]
+                editor.refresh()
+        
+        aw = vm.activeWindow()
+        if aw is not None:
+            filename = aw.getFileName()
+            if filename is not None:
+                vm.openSourceFile(filename, aw.getCursorPosition()[0] + 1)
+    
+    def reportChanged(self, filename, oldSource):
+        """
+        Public slot to report some changed sources.
+        
+        @param filename file name of the changed source (string)
+        @param oldSource source code before the change (string)
+        """
+        if self.__e5project.isOpen() and \
+                self.__e5project.isProjectFile(filename):
+            self.sendJson("ReportChanged", {
+                "FileName": filename,
+                "OldSource": oldSource,
+            })
+    
+    #######################################################################
+    ## Methods below handle the network connection
+    #######################################################################
+    
+    def handleCall(self, method, params):
+        """
+        Public method to handle a method call from the client.
+        
+        Note: This is an empty implementation that must be overridden in
+        derived classes.
+        
+        @param method requested method name
+        @type str
+        @param params dictionary with method specific parameters
+        @type dict
+        """
+        self.__methodMapping[method](params)
+    
+    def __processClientException(self, params):
+        """
+        Private method to handle exceptions of the refactoring client.
+        
+        @param params dictionary containing the exception data
+        @type dict
+        """
+        if params["ExceptionType"] == "ProtocolError":
+            E5MessageBox.critical(
+                None,
+                self.tr("Refactoring Protocol Error"),
+                self.tr("""<p>The data received from the refactoring"""
+                        """ server could not be decoded. Please report"""
+                        """ this issue with the received data to the"""
+                        """ eric bugs email address.</p>"""
+                        """<p>Error: {0}</p>"""
+                        """<p>Data:<br/>{0}</p>""").format(
+                    params["ExceptionValue"],
+                    Utilities.html_encode(params["ProtocolData"])),
+                E5MessageBox.StandardButtons(
+                    E5MessageBox.Ok))
+        else:
+            E5MessageBox.critical(
+                None,
+                self.tr("Refactoring Client Error"),
+                self.tr("<p>An exception happened in the refactoring"
+                        " client. Please report it to the eric bugs"
+                        " email address.</p>"
+                        "<p>Exception: {0}</p>"
+                        "<p>Value: {1}</p>"
+                        "Traceback: {2}</p>").format(
+                    Utilities.html_encode(params["ExceptionType"]),
+                    params["ExceptionValue"],
+                    params["Traceback"].replace("\r\n", "<br/>")
+                    .replace("\n", "<br/>").replace("\r", "<br/>"),
+                ),
+                E5MessageBox.StandardButtons(
+                    E5MessageBox.Ok))
+    
+    def __startRefactoringClient(self, interpreter):
+        """
+        Private method to start the refactoring client.
+        
+        @param interpreter interpreter to be used for the refactoring client
+        @type str
+        @return flag indicating a successful client start
+        @rtype bool
+        """
+        client = os.path.join(os.path.dirname(__file__),
+                              "RefactoringClient.py")
+        ok = self.startClient(interpreter, client, [self.__projectpath])
+        return ok

eric ide

mercurial