RefactoringRope/Refactoring.py

Sun, 14 Apr 2013 15:13:58 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 14 Apr 2013 15:13:58 +0200
changeset 48
de33dc93a3ac
parent 46
a726d19facfc
child 50
a29c3d2e6dc0
child 55
d501156be247
permissions
-rw-r--r--

Changed usage of QMessageBox and QFileDialog to the eric5 equivalents.

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

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

"""
Module implementing the refactoring interface to rope.
"""

import os
import sys

sys.path.insert(0, os.path.dirname(__file__))
import rope
import rope.base.libutils
import rope.base.exceptions

from PyQt4.QtCore import QObject
from PyQt4.QtGui import QMenu, QApplication, QDialog, QAction
from PyQt4.Qsci import QsciScintilla

from E5Gui.E5Application import e5App
from E5Gui import E5MessageBox
from E5Gui.E5Action import E5Action

import Utilities


class Refactoring(QObject):
    """
    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)
        """
        QObject.__init__(self, parent)
        
        self.__plugin = plugin
        self.__ui = parent
        self.__e5project = e5App().getObject("Project")
        self.__projectpath = ''
        self.__projectLanguage = ""
        self.__projectopen = False
        
        self.__mainMenu = None
        self.__helpDialog = None
        
        # Rope objects
        self.__project = None
        
        from FileSystemCommands import e5FileSystemCommands
        self.__fsCommands = e5FileSystemCommands(self.__e5project)
    
    def initActions(self):
        """
        Public method to define the refactoring actions.
        """
        self.actions = []
        
        #####################################################
        ## Rename refactoring actions
        #####################################################
        
        self.refactoringRenameAct = E5Action(self.trUtf8('Rename'),
                self.trUtf8('&Rename'),
                0, 0,
                self, 'refactoring_rename')
        self.refactoringRenameAct.setStatusTip(self.trUtf8(
            'Rename the highlighted object'))
        self.refactoringRenameAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Local Rename'),
                self.trUtf8('&Local Rename'),
                0, 0,
                self, 'refactoring_rename_local')
        self.refactoringRenameLocalAct.setStatusTip(self.trUtf8(
            'Rename the highlighted object in the current module only'))
        self.refactoringRenameLocalAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Rename Current Module'),
                self.trUtf8('Rename Current Module'),
                0, 0,
                self, 'refactoring_rename_module')
        self.refactoringRenameModuleAct.setStatusTip(self.trUtf8(
            'Rename the current module'))
        self.refactoringRenameModuleAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Change Occurrences'),
                self.trUtf8('Change &Occurrences'),
                0, 0,
                self, 'refactoring_change_occurrences')
        self.refactoringChangeOccurrencesAct.setStatusTip(self.trUtf8(
            'Change all occurrences in the local scope'))
        self.refactoringChangeOccurrencesAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Extract method'),
                self.trUtf8('Extract &Method'),
                0, 0,
                self, 'refactoring_extract_method')
        self.refactoringExtractMethodAct.setStatusTip(self.trUtf8(
            'Extract the highlighted area as a method'))
        self.refactoringExtractMethodAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Extract local variable'),
                self.trUtf8('&Extract Local Variable'),
                0, 0,
                self, 'refactoring_extract_variable')
        self.refactoringExtractLocalVariableAct.setStatusTip(self.trUtf8(
            'Extract the highlighted area as a local variable'))
        self.refactoringExtractLocalVariableAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Inline'),
                self.trUtf8('&Inline'),
                0, 0,
                self, 'refactoring_inline')
        self.refactoringInlineAct.setStatusTip(self.trUtf8(
            'Inlines the selected local variable or method'))
        self.refactoringInlineAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Move method'),
                self.trUtf8('Mo&ve Method'),
                0, 0,
                self, 'refactoring_move_method')
        self.refactoringMoveMethodAct.setStatusTip(self.trUtf8(
            'Move the highlighted method to another class'))
        self.refactoringMoveMethodAct.setWhatsThis(self.trUtf8(
            """<b>Move method</b>"""
            """<p>Move the highlighted method to another class.</p>"""
        ))
        self.refactoringMoveMethodAct.triggered[()].connect(
            self.__moveMethod)
        self.actions.append(self.refactoringMoveMethodAct)
        
        self.refactoringMoveModuleAct = E5Action(
                self.trUtf8('Move current module'),
                self.trUtf8('Move Current Module'),
                0, 0,
                self, 'refactoring_move_module')
        self.refactoringMoveModuleAct.setStatusTip(self.trUtf8(
            'Move the current module to another package'))
        self.refactoringMoveModuleAct.setWhatsThis(self.trUtf8(
            """<b>Move current module</b>"""
            """<p>Move the current module to another package.</p>"""
        ))
        self.refactoringMoveModuleAct.triggered[()].connect(
            self.__moveModule)
        self.actions.append(self.refactoringMoveModuleAct)
        
        #####################################################
        ## Use function refactoring action
        #####################################################
        
        self.refactoringUseFunctionAct = E5Action(
                self.trUtf8('Use Function'),
                self.trUtf8('Use Function'),
                0, 0,
                self, 'refactoring_use_function')
        self.refactoringUseFunctionAct.setStatusTip(self.trUtf8(
            'Use a function wherever possible.'))
        self.refactoringUseFunctionAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Introduce Factory Method'),
                self.trUtf8('Introduce &Factory Method'),
                0, 0,
                self, 'refactoring_introduce_factory_method')
        self.refactoringIntroduceFactoryAct.setStatusTip(self.trUtf8(
            'Introduce a factory method or function'))
        self.refactoringIntroduceFactoryAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Introduce Parameter'),
                self.trUtf8('Introduce &Parameter'),
                0, 0,
                self, 'refactoring_introduce_parameter_method')
        self.refactoringIntroduceParameterAct.setStatusTip(self.trUtf8(
            'Introduce a parameter in a function'))
        self.refactoringIntroduceParameterAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Organize Imports'),
                self.trUtf8('&Organize Imports'),
                0, 0,
                self, 'refactoring_organize_imports')
        self.refactoringImportsOrganizeAct.setStatusTip(self.trUtf8(
            'Sort imports according to PEP-8'))
        self.refactoringImportsOrganizeAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Expand Star Imports'),
                self.trUtf8('E&xpand Star Imports'),
                0, 0,
                self, 'refactoring_expand_star_imports')
        self.refactoringImportsStarExpandAct.setStatusTip(self.trUtf8(
            'Expand imports like "from xxx import *"'))
        self.refactoringImportsStarExpandAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Relative to Absolute'),
                self.trUtf8('Relative to &Absolute'),
                0, 0,
                self, 'refactoring_relative_to_absolute_imports')
        self.refactoringImportsRelativeToAbsoluteAct.setStatusTip(self.trUtf8(
            'Transform relative imports to absolute ones'))
        self.refactoringImportsRelativeToAbsoluteAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Froms to Imports'),
                self.trUtf8('Froms to &Imports'),
                0, 0,
                self, 'refactoring_froms_to_imports')
        self.refactoringImportsFromsToImportsAct.setStatusTip(self.trUtf8(
            'Transform From imports to plain imports'))
        self.refactoringImportsFromsToImportsAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Handle Long Imports'),
                self.trUtf8('Handle &Long Imports'),
                0, 0,
                self, 'refactoring_organize_imports')
        self.refactoringImportsHandleLongAct.setStatusTip(self.trUtf8(
            'Transform long import statements to look better'))
        self.refactoringImportsHandleLongAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Restructure'),
                self.trUtf8('Res&tructure'),
                0, 0,
                self, 'refactoring_restructure')
        self.refactoringRestructureAct.setStatusTip(self.trUtf8(
            'Restructure code'))
        self.refactoringRestructureAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Change Method Signature'),
                self.trUtf8('&Change Method Signature'),
                0, 0,
                self, 'refactoring_change_method_signature')
        self.refactoringChangeSignatureAct.setStatusTip(self.trUtf8(
            'Change the signature of the selected method or function'))
        self.refactoringChangeSignatureAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Inline Argument Default'),
                self.trUtf8('Inline &Argument Default'),
                0, 0,
                self, 'refactoring_inline_argument_default')
        self.refactoringInlineArgumentDefaultAct.setStatusTip(self.trUtf8(
            'Inline a parameters default value'))
        self.refactoringInlineArgumentDefaultAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Transform Module to Package'),
                self.trUtf8('Transform Module to Package'),
                0, 0,
                self, 'refactoring_transform_module_to_package')
        self.refactoringTransformModuleAct.setStatusTip(self.trUtf8(
            'Transform the current module to a package'))
        self.refactoringTransformModuleAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Encapsulate Attribute'),
                self.trUtf8('Encap&sulate Attribute'),
                0, 0,
                self, 'refactoring_encapsulate_attribute')
        self.refactoringEncapsulateAttributeAct.setStatusTip(self.trUtf8(
            'Generate a getter/setter for an attribute'))
        self.refactoringEncapsulateAttributeAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Local Variable to Attribute'),
                self.trUtf8('Local Varia&ble to Attribute'),
                0, 0,
                self, 'refactoring_local_variable_to_attribute')
        self.refactoringLocalVariableToAttributeAct.setStatusTip(self.trUtf8(
            'Change a local variable to an attribute'))
        self.refactoringLocalVariableToAttributeAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Method To Method Object'),
                self.trUtf8('Method To Method Ob&ject'),
                0, 0,
                self, 'refactoring_method_to_methodobject')
        self.refactoringMethodToMethodObjectAct.setStatusTip(self.trUtf8(
            'Transform a function or a method to a method object'))
        self.refactoringMethodToMethodObjectAct.setWhatsThis(self.trUtf8(
            """<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)
        
        #####################################################
        ## Undo/Redo actions
        #####################################################
        
        self.refactoringUndoAct = E5Action(self.trUtf8('Undo'),
                self.trUtf8('&Undo'),
                0, 0,
                self, 'refactoring_undo')
        self.refactoringUndoAct.setStatusTip(self.trUtf8(
            'Undo the last refactoring'))
        self.refactoringUndoAct.setWhatsThis(self.trUtf8(
            """<b>Undo</b>"""
            """<p>Undo the last refactoring.</p>"""
        ))
        self.refactoringUndoAct.triggered[()].connect(
            self.__undo)
        self.actions.append(self.refactoringUndoAct)
        
        self.refactoringRedoAct = E5Action(self.trUtf8('Redo'),
                self.trUtf8('Re&do'),
                0, 0,
                self, 'refactoring_redo')
        self.refactoringRedoAct.setStatusTip(self.trUtf8(
            'Redo the last refactoring'))
        self.refactoringRedoAct.setWhatsThis(self.trUtf8(
            """<b>Redo</b>"""
            """<p>Redo the last refactoring.</p>"""
        ))
        self.refactoringRedoAct.triggered[()].connect(
            self.__redo)
        self.actions.append(self.refactoringRedoAct)
        
        self.refactoringUndoHistoryAct = \
            E5Action(self.trUtf8('Show Project Undo History'),
                self.trUtf8('Show Project Undo History'),
                0, 0,
                self, 'refactoring_show_project_undo_history')
        self.refactoringUndoHistoryAct.setStatusTip(self.trUtf8(
            'Show the undo history of the project'))
        self.refactoringUndoHistoryAct.setWhatsThis(self.trUtf8(
            """<b>Show Project Undo History</b>"""
            """<p>Opens a dialog to show the undo history list of"""
            """ the project.</p>"""
        ))
        self.refactoringUndoHistoryAct.triggered[()].connect(
            self.__showProjectUndoHistory)
        self.actions.append(self.refactoringUndoHistoryAct)
        
        self.refactoringRedoHistoryAct = \
            E5Action(self.trUtf8('Show Project Redo History'),
                self.trUtf8('Show Project Redo History'),
                0, 0,
                self, 'refactoring_show_project_redo_history')
        self.refactoringRedoHistoryAct.setStatusTip(self.trUtf8(
            'Show the redo history of the project'))
        self.refactoringRedoHistoryAct.setWhatsThis(self.trUtf8(
            """<b>Show Project Redo History</b>"""
            """<p>Opens a dialog to show the redo history list of"""
            """ the project.</p>"""
        ))
        self.refactoringRedoHistoryAct.triggered[()].connect(
            self.__showProjectRedoHistory)
        self.actions.append(self.refactoringRedoHistoryAct)
        
        self.refactoringUndoFileHistoryAct = \
            E5Action(self.trUtf8('Show Current File Undo History'),
                self.trUtf8('Show Current File Undo History'),
                0, 0,
                self, 'refactoring_show_file_undo_history')
        self.refactoringUndoFileHistoryAct.setStatusTip(self.trUtf8(
            'Show the undo history of the current file'))
        self.refactoringUndoFileHistoryAct.setWhatsThis(self.trUtf8(
            """<b>Show Current File Undo History</b>"""
            """<p>Opens a dialog to show the undo history list of"""
            """ the current file.</p>"""
        ))
        self.refactoringUndoFileHistoryAct.triggered[()].connect(
            self.__showFileUndoHistory)
        self.actions.append(self.refactoringUndoFileHistoryAct)
        
        self.refactoringRedoFileHistoryAct = \
            E5Action(self.trUtf8('Show Current File Redo History'),
                self.trUtf8('Show Current File Redo History'),
                0, 0,
                self, 'refactoring_show_file_redo_history')
        self.refactoringRedoFileHistoryAct.setStatusTip(self.trUtf8(
            'Show the redo history of the current file'))
        self.refactoringRedoFileHistoryAct.setWhatsThis(self.trUtf8(
            """<b>Show Current File Redo History</b>"""
            """<p>Opens a dialog to show the redo history list of"""
            """ the current file.</p>"""
        ))
        self.refactoringRedoFileHistoryAct.triggered[()].connect(
            self.__showFileRedoHistory)
        self.actions.append(self.refactoringRedoFileHistoryAct)
        
        self.refactoringClearHistoryAct = \
            E5Action(self.trUtf8('Clear History'),
                self.trUtf8('Clear History'),
                0, 0,
                self, 'refactoring_clear_history')
        self.refactoringClearHistoryAct.setStatusTip(self.trUtf8(
            'Clear the refactoring history'))
        self.refactoringClearHistoryAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Find occurrences'),
                self.trUtf8('Find &Occurrences'),
                0, 0,
                self, 'refactoring_find_occurrences')
        self.queryReferencesAct.setStatusTip(self.trUtf8(
            'Find occurrences of the highlighted object'))
        self.queryReferencesAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Find definition'),
                self.trUtf8('Find &Definition'),
                0, 0,
                self, 'refactoring_find_definition')
        self.queryDefinitionAct.setStatusTip(self.trUtf8(
            'Find definition of the highlighted item'))
        self.queryDefinitionAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Find implementations'),
                self.trUtf8('Find &Implementations'),
                0, 0,
                self, 'refactoring_find_implementations')
        self.queryImplementationsAct.setStatusTip(self.trUtf8(
            'Find places where the selected method is overridden'))
        self.queryImplementationsAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Configure Rope'),
                self.trUtf8('&Configure Rope'),
                0, 0,
                self, 'refactoring_edit_config')
        self.refactoringEditConfigAct.setStatusTip(self.trUtf8(
            'Open the rope configuration file'))
        self.refactoringEditConfigAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Rope help'),
                self.trUtf8('Rope &Help'),
                0, 0,
                self, 'refactoring_help')
        self.refactoringHelpAct.setStatusTip(self.trUtf8(
            'Show help about the rope refactorings'))
        self.refactoringHelpAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Analyse all modules'),
                self.trUtf8('&Analyse all modules'),
                0, 0,
                self, 'refactoring_analyze_all')
        self.refactoringAllSoaAct.setStatusTip(self.trUtf8(
            'Perform static object analysis on all modules'))
        self.refactoringAllSoaAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('Update Configuration'),
                self.trUtf8('&Update Configuration'),
                0, 0,
                self, 'refactoring_update_configuration')
        self.updateConfigAct.setStatusTip(self.trUtf8(
            'Generates a new configuration file overwriting the current one.'))
        self.updateConfigAct.setWhatsThis(self.trUtf8(
            """<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.trUtf8('&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.trUtf8("&Query"))
        smenu.addAction(self.queryReferencesAct)
        smenu.addAction(self.queryDefinitionAct)
        smenu.addAction(self.queryImplementationsAct)
        
        smenu = menu.addMenu(self.trUtf8("&Refactoring"))
        smenu.aboutToShow.connect(self.__showRefactoringMenu)
        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.trUtf8("Im&ports"))
        imenu.addAction(self.refactoringImportsOrganizeAct)
        imenu.addAction(self.refactoringImportsStarExpandAct)
        imenu.addAction(self.refactoringImportsRelativeToAbsoluteAct)
        imenu.addAction(self.refactoringImportsFromsToImportsAct)
        imenu.addAction(self.refactoringImportsHandleLongAct)
        
        smenu.addSeparator()
        smenu.addAction(self.refactoringUndoAct)
        smenu.addAction(self.refactoringRedoAct)
        smenu.addSeparator()
        
        hmenu = smenu.addMenu(self.trUtf8("History"))
        hmenu.aboutToShow.connect(self.__showRefactoringHistoryMenu)
        hmenu.addAction(self.refactoringUndoHistoryAct)
        hmenu.addAction(self.refactoringUndoFileHistoryAct)
        hmenu.addSeparator()
        hmenu.addAction(self.refactoringRedoHistoryAct)
        hmenu.addAction(self.refactoringRedoFileHistoryAct)
        hmenu.addSeparator()
        hmenu.addAction(self.refactoringClearHistoryAct)
        
        smenu = menu.addMenu(self.trUtf8("&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.
        """
        E5MessageBox.about(self.__ui,
            self.trUtf8("About rope"),
            self.trUtf8("{0}\nVersion {1}\n\n{2}".format(
                rope.INFO, rope.VERSION, rope.COPYRIGHT)))
    
    def __canUndo(self):
        """
        Private slot to check, if there are changes to be undone.
        
        @return flag indicating, that undoable changes are available (boolean)
        """
        return self.__project is not None and \
               len(self.__project.history.undo_list) > 0
    
    def __canRedo(self):
        """
        Private slot to check, if there are changes to be redone.
        
        @return flag indicating, that redoable changes are available (boolean)
        """
        return self.__project is not None and \
               len(self.__project.history.redo_list) > 0
    
    def __getFileUndoList(self, resource):
        """
        Private slot to get a list of undoable changes.
        
        @param resource file resource to filter against
            (rope.base.resources.File)
        @return list of change objects (list of rope.base.change.Change)
        """
        undoList = []
        for change in self.__project.history.undo_list:
            if resource in change.get_changed_resources():
                undoList.append(change)
        return undoList
    
    def __getFileRedoList(self, resource):
        """
        Private slot to get a list of redoable changes.
        
        @param resource file resource to filter against
            (rope.base.resources.File)
        @return list of change objects (list of rope.base.change.Change)
        """
        redoList = []
        for change in self.__project.history.redo_list:
            if resource in change.get_changed_resources():
                redoList.append(change)
        return redoList
    
    def __canUndoFile(self, resource):
        """
        Private slot to check, if there are undoable changes for a resource.
        
        @param resource file resource to check against
            (rope.base.resources.File)
        @return flag indicating, that undoable changes are available (boolean)
        """
        return self.__canUndo() and len(self.__getFileUndoList(resource)) > 0
    
    def __canRedoFile(self, resource):
        """
        Private slot to check, if there are redoable changes for a resource.
        
        @param resource file resource to check against
            (rope.base.resources.File)
        @return flag indicating, that redoable changes are available (boolean)
        """
        return self.__canRedo() and len(self.__getFileRedoList(resource)) > 0
    
    def __showRefactoringMenu(self):
        """
        Private slot called before the refactoring menu is shown.
        """
        self.refactoringUndoAct.setEnabled(self.__canUndo())
        self.refactoringRedoAct.setEnabled(self.__canRedo())
    
    def __showRefactoringHistoryMenu(self):
        """
        Private slot called before the refactoring history menu is shown.
        """
        aw = e5App().getObject("ViewManager").activeWindow()
        resource = None
        if aw is not None:
            filename = aw.getFileName()
            resource = rope.base.libutils.path_to_resource(
                self.__project, filename)
        
        self.refactoringUndoHistoryAct.setEnabled(self.__canUndo())
        self.refactoringUndoFileHistoryAct.setEnabled(
            resource is not None and self.__canUndoFile(resource))
        self.refactoringRedoHistoryAct.setEnabled(self.__canRedo())
        self.refactoringRedoFileHistoryAct.setEnabled(
            resource is not None and self.__canRedoFile(resource))
    
    def handleRopeError(self, err, title, handle=None):
        """
        Public slot to handle a rope error.
        
        @param err rope exception object (Exception)
        @param title title to be displayed (string)
        @param handle reference to a taskhandle (ProgressHandle)
        """
        if handle is not None:
            handle.reset()
        if str(type(err)).split()[-1][1:-2].split('.')[-1] == \
                                                    'ModuleSyntaxError':
            res = E5MessageBox.warning(self.__ui, title,
                self.trUtf8("Rope error: {0}").format(str(err)),
                E5MessageBox.Ok | E5MessageBox.Open)
            if res == E5MessageBox.Open:
                e5App().getObject("ViewManager").openSourceFile(
                    os.path.join(self.__e5project.getProjectPath(),
                                 err.filename),
                    err.lineno)
        else:
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("Rope error: {0}").format(str(err)))
    
    def __getOffset(self, editor, line, index):
        """
        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)
        """
        offset = editor.positionFromLineIndex(line, index)
        if editor.eolMode() == QsciScintilla.EolWindows:
            offset -= line
        return offset

    ##################################################################
    ## slots below implement the various refactorings
    ##################################################################
    
    #####################################################
    ## Rename refactorings
    #####################################################
    
    def __rename(self):
        """
        Private slot to handle the Rename action.
        """
        self.__doRename(self.trUtf8('Rename'))
    
    def __renameLocal(self):
        """
        Private slot to handle the Local Rename action.
        """
        self.__doRename(self.trUtf8('Local Rename'), isLocal=True)
    
    def __renameModule(self):
        """
        Private slot to handle the Rename Current Module action.
        """
        self.__doRename(self.trUtf8('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.trUtf8("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
        else:
            line, index, line1, index1 = aw.getSelection()
            if line != line1:
                # selection span more than one line
                E5MessageBox.warning(self.__ui, title,
                    self.trUtf8("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)
        
        import rope.refactor.rename
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            renamer = rope.refactor.rename.Rename(
                self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        if isLocal:
            localResource = resource
        else:
            localResource = None
        from RenameDialog import RenameDialog
        self.dlg = RenameDialog(self, title, renamer, resource=localResource,
                                parent=self.__ui)
        self.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.trUtf8("Change Occurrences")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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)
        
        import rope.refactor.rename
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            renamer = rope.refactor.rename.ChangeOccurrences(
                        self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        from ChangeOccurrencesDialog import ChangeOccurrencesDialog
        self.dlg = ChangeOccurrencesDialog(self, title, renamer,
                                           parent=self.__ui)
        self.dlg.show()
    
    #####################################################
    ## Extract refactorings
    #####################################################
    
    def __extractMethod(self):
        """
        Private slot to handle the Extract Method action.
        """
        self.__doExtract(self.trUtf8("Extract Method"), "method")
    
    def __extractLocalVariable(self):
        """
        Private slot to handle the Extract Local Variable action.
        """
        self.__doExtract(self.trUtf8("Extract Local Variable"), "variable")
    
    def __doExtract(self, title, kind):
        """
        Private method to perform the extract refactoring.
        
        @param title title of the refactoring (string)
        @param kind kind of extraction to be done (string,
            "method" or "variable")
        """
        aw = e5App().getObject("ViewManager").activeWindow()
        
        if aw is None:
            return
        
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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)
        
        import rope.refactor.extract
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            if kind == "variable":
                extractor = rope.refactor.extract.ExtractVariable(
                    self.__project, resource, startOffset, endOffset)
            elif kind == "method":
                extractor = rope.refactor.extract.ExtractMethod(
                    self.__project, resource, startOffset, endOffset)
            else:
                raise Exception("Invalid extraction kind <{0}>.".format(kind))
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        from ExtractDialog import ExtractDialog
        self.dlg = ExtractDialog(self, title, extractor, parent=self.__ui)
        self.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.trUtf8("Inline")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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)
        
        import rope.refactor.inline
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            inliner = rope.refactor.inline.create_inline(
                self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        from InlineDialog import InlineDialog
        self.dlg = InlineDialog(self, title, inliner, parent=self.__ui)
        self.dlg.show()
    
    #####################################################
    ## Move refactorings
    #####################################################
    
    def __moveMethod(self):
        """
        Private slot to handle the Move Method action.
        """
        aw = e5App().getObject("ViewManager").activeWindow()
        
        if aw is None:
            return
        
        title = self.trUtf8("Move Method")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("Highlight the method to move"
                    " and try again."))
            return
        
        if not self.confirmAllBuffersSaved():
            return
        
        filename = aw.getFileName()
        line, index, line1, index1 = aw.getSelection()
        offset = self.__getOffset(aw, line, index)
        
        import rope.refactor.move
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            mover = rope.refactor.move.create_move(
                self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        if isinstance(mover, rope.refactor.move.MoveGlobal):
            from MoveGlobalMethodDialog import MoveGlobalMethodDialog
            self.dlg = MoveGlobalMethodDialog(self, title, mover,
                self.__project, parent=self.__ui)
        else:
            from MoveMethodDialog import MoveMethodDialog
            self.dlg = MoveMethodDialog(self, title, mover, parent=self.__ui)
        self.dlg.show()
    
    def __moveModule(self):
        """
        Private slot to handle the Move Current Module action.
        """
        aw = e5App().getObject("ViewManager").activeWindow()
        
        if aw is None:
            return
        
        title = self.trUtf8("Move Current Module")
        
        if not self.confirmAllBuffersSaved():
            return
        
        filename = aw.getFileName()
        offset = None
        
        import rope.refactor.move
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            mover = rope.refactor.move.create_move(
                self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        from MoveModuleDialog import MoveModuleDialog
        self.dlg = MoveModuleDialog(self, title, mover, parent=self.__ui)
        self.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.trUtf8("Use Function")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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)
        
        import rope.refactor.usefunction
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            user = rope.refactor.usefunction.UseFunction(
                self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        from UseFunctionDialog import UseFunctionDialog
        self.dlg = UseFunctionDialog(self, title, user, parent=self.__ui)
        self.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.trUtf8("Introduce Factory Method")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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)
        
        import rope.refactor.introduce_factory
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            introducer = \
                rope.refactor.introduce_factory.IntroduceFactoryRefactoring(
                self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        from IntroduceFactoryDialog import IntroduceFactoryDialog
        self.dlg = IntroduceFactoryDialog(self, title, introducer,
                                          parent=self.__ui)
        self.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.trUtf8("Introduce Parameter")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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)
        
        import rope.refactor.introduce_parameter
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            introducer = rope.refactor.introduce_parameter.IntroduceParameter(
            self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        from IntroduceParameterDialog import IntroduceParameterDialog
        self.dlg = IntroduceParameterDialog(self, title, introducer,
                                            parent=self.__ui)
        self.dlg.show()
    
    #####################################################
    ## Import refactorings
    #####################################################
    
    def __importsOrganize(self):
        """
        Private slot to organize imports.
        """
        from rope.refactor.importutils import ImportOrganizer
        self.__doImports(self.trUtf8("Organize Imports"),
            ImportOrganizer.organize_imports)
    
    def __importsExpandStar(self):
        """
        Private slot to expand star imports.
        """
        from rope.refactor.importutils import ImportOrganizer
        self.__doImports(self.trUtf8("Expand Star Imports"),
            ImportOrganizer.expand_star_imports)
    
    def __importsRelativeToAbsolute(self):
        """
        Private slot to transform relative to absolute imports.
        """
        from rope.refactor.importutils import ImportOrganizer
        self.__doImports(self.trUtf8("Relative to Absolute"),
            ImportOrganizer.relatives_to_absolutes)
    
    def __importsFromToImport(self):
        """
        Private slot to transform from imports to plain imports.
        """
        from rope.refactor.importutils import ImportOrganizer
        self.__doImports(self.trUtf8("Froms to Imports"),
            ImportOrganizer.froms_to_imports)
    
    def __importsHandleLong(self):
        """
        Private slot to handle long imports.
        """
        from rope.refactor.importutils import ImportOrganizer
        self.__doImports(self.trUtf8("Handle Long Imports"),
            ImportOrganizer.handle_long_imports)
    
    def __doImports(self, title, method):
        """
        Private method to perform the various imports refactorings.
        """
        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 rope.refactor.importutils import ImportOrganizer
        importOrganizer = ImportOrganizer(self.__project)
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            changes = method(importOrganizer, resource, offset=offset)
            if changes is not None:
                from ConfirmationDialog import ConfirmationDialog
                dlg = ConfirmationDialog(changes, self.__ui)
                if dlg.exec_() == QDialog.Accepted:
                    self.__project.do(changes)
                    self.refreshEditors(changes)
                    if self.__e5project.isDirty():
                        self.__e5project.saveProject()
            else:
                E5MessageBox.information(self.__ui, title,
                    self.trUtf8("The selected refactoring did not produce"
                                " any change."))
        except Exception as err:
            self.handleRopeError(err, title)
    
    #####################################################
    ## Various refactorings
    #####################################################
    
    def __restructure(self):
        """
        Private slot to restructure code.
        """
        from RestructureDialog import RestructureDialog
        title = self.trUtf8("Restructure")
        self.dlg = RestructureDialog(self, title, parent=self.__ui)
        self.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.trUtf8("Change Method Signature")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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)
        
        import rope.refactor.change_signature
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            changer = rope.refactor.change_signature.ChangeSignature(
                self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        from ChangeSignatureDialog import ChangeSignatureDialog
        self.dlg = ChangeSignatureDialog(self, title, changer,
                                         parent=self.__ui)
        self.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.trUtf8("Inline Argument Default")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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)
        
        import rope.refactor.change_signature
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            changer = rope.refactor.change_signature.ChangeSignature(
                self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        from InlineArgumentDefaultDialog import InlineArgumentDefaultDialog
        self.dlg = InlineArgumentDefaultDialog(self, title, changer,
                                               parent=self.__ui)
        self.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.trUtf8("Transform Module to Package")
        
        if not self.confirmAllBuffersSaved():
            return
        
        filename = aw.getFileName()
        
        import rope.refactor.topackage
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            changes = rope.refactor.topackage.ModuleToPackage(
                self.__project, resource).get_changes()
            self.__project.do(changes)
            if self.__e5project.isDirty():
                self.__e5project.saveProject()
        except Exception as err:
            self.handleRopeError(err, title)
            return
    
    def __encapsulateAttribute(self):
        """
        Private slot to encapsulate an attribute.
        """
        aw = e5App().getObject("ViewManager").activeWindow()
        
        if aw is None:
            return
        
        title = self.trUtf8("Encapsulate Attribute")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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)
        
        import rope.refactor.encapsulate_field
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            encapsulateField = \
                rope.refactor.encapsulate_field.EncapsulateField(
                    self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        from GetterSetterDialog import GetterSetterDialog
        dlg = GetterSetterDialog(encapsulateField.get_field_name())
        if dlg.exec_() == QDialog.Accepted:
            from ProgressHandle import ProgressHandle
            from ConfirmationDialog import ConfirmationDialog
            getter, setter = dlg.getData()
            handle = ProgressHandle(title, False, self.__ui)
            handle.show()
            QApplication.processEvents()
            try:
                changes = encapsulateField.get_changes(
                    getter=getter, setter=setter, task_handle=handle)
                handle.reset()
                dlg = ConfirmationDialog(changes, self.__ui)
                if dlg.exec_() == QDialog.Accepted:
                    self.__project.do(changes)
                    self.refreshEditors(changes)
                    if self.__e5project.isDirty():
                        self.__e5project.saveProject()
            except Exception as err:
                self.handleRopeError(err, title, handle)
    
    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.trUtf8("Local Variable to Attribute")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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)
        
        import rope.refactor.localtofield
        from ConfirmationDialog import ConfirmationDialog
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            changes = rope.refactor.localtofield.LocalToField(
                self.__project, resource, offset).get_changes()
            dlg = ConfirmationDialog(changes, self.__ui)
            if dlg.exec_() == QDialog.Accepted:
                self.__project.do(changes)
                self.refreshEditors(changes)
                if self.__e5project.isDirty():
                    self.__e5project.saveProject()
        except Exception as err:
            self.handleRopeError(err, title)
    
    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.trUtf8("Replace Method With Method Object")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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)
        
        import rope.refactor.method_object
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            converter = rope.refactor.method_object.MethodObject(
                self.__project, resource, offset)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        from MethodToMethodObjectDialog import MethodToMethodObjectDialog
        self.dlg = MethodToMethodObjectDialog(self, title, converter,
                                              parent=self.__ui)
        self.dlg.show()
    
    #####################################################
    ## Undo/Redo refactorings
    #####################################################
    
    def __undo(self):
        """
        Private slot to undo the last refactoring.
        """
        title = self.trUtf8("Undo refactoring")
        history = self.__project.history
        res = E5MessageBox.yesNo(None,
            title,
            self.trUtf8("""Shall the refactoring <b>{0}</b> be undone?""")\
                .format(Utilities.html_encode(
                    history.undo_list[-1].description)))
        if res:
            if not self.confirmAllBuffersSaved():
                return
            
            from ProgressHandle import ProgressHandle
            changes = history.undo_list[-1]
            handle = ProgressHandle(self.trUtf8("Undo"), False, self.__ui)
            handle.show()
            QApplication.processEvents()
            try:
                history.undo(task_handle=handle)
            except Exception as err:
                self.handleRopeError(err, title, handle)
            handle.reset()
            self.refreshEditors(changes)
            if self.__e5project.isDirty():
                self.__e5project.saveProject()
    
    def __redo(self):
        """
        Private slot to redo the last refactoring.
        """
        title = self.trUtf8("Redo refactoring")
        history = self.__project.history
        res = E5MessageBox.yesNo(None,
            title,
            self.trUtf8("""Shall the refactoring <b>{0}</b> be redone?""")\
                .format(Utilities.html_encode(
                    history.redo_list[-1].description)))
        if res:
            if not self.confirmAllBuffersSaved():
                return
            
            from ProgressHandle import ProgressHandle
            changes = history.redo_list[-1]
            handle = ProgressHandle(self.trUtf8("Redo"), False, self.__ui)
            handle.show()
            QApplication.processEvents()
            try:
                history.redo(task_handle=handle)
            except Exception as err:
                self.handleRopeError(err, title, handle)
            handle.reset()
            self.refreshEditors(changes)
            if self.__e5project.isDirty():
                self.__e5project.saveProject()
    
    def __showProjectUndoHistory(self):
        """
        Private method to show list of changes available for an undo operation.
        """
        from HistoryDialog import HistoryDialog
        undoList = list(reversed(self.__project.history.undo_list))
        self.dlg = HistoryDialog(self, undoList, True, self.__ui)
        self.dlg.show()
    
    def __showProjectRedoHistory(self):
        """
        Private method to show list of changes available for a redo operation.
        """
        from HistoryDialog import HistoryDialog
        redoList = self.__project.history.redo_list
        self.dlg = HistoryDialog(self, redoList, False, self.__ui)
        self.dlg.show()
    
    def __showFileUndoHistory(self):
        """
        Private method to show list of changes related to the current file
        available for an undo operation.
        """
        aw = e5App().getObject("ViewManager").activeWindow()
        
        if aw is None:
            return
        
        from HistoryDialog import HistoryDialog
        filename = aw.getFileName()
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        undoList = list(reversed(self.__getFileUndoList(resource)))
        self.dlg = HistoryDialog(self, undoList, True, self.__ui)
        self.dlg.show()
    
    def __showFileRedoHistory(self):
        """
        Private method to show list of changes related to the current file
        available for a redo operation.
        """
        aw = e5App().getObject("ViewManager").activeWindow()
        
        if aw is None:
            return
        
        from HistoryDialog import HistoryDialog
        filename = aw.getFileName()
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        redoList = self.__getFileRedoList(resource)
        self.dlg = HistoryDialog(self, redoList, False, self.__ui)
        self.dlg.show()
    
    def __clearHistory(self):
        """
        Private slot to clear the redo and undo lists.
        """
        res = E5MessageBox.yesNo(None,
            self.trUtf8("Clear History"),
            self.trUtf8("""Do you really want to clear the undo"""
                        """ and redo history?"""))
        if res:
            self.__project.history.clear()
    
    #####################################################
    ## Find actions
    #####################################################
    
    def __queryReferences(self):
        """
        Private slot to handle the Find References action.
        """
        aw = e5App().getObject("ViewManager").activeWindow()
        
        if aw is None:
            return
        
        title = self.trUtf8("Find Occurrences")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("Highlight the class, method, function or variable"
                    " to search 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)
        
        import rope.contrib.findit
        from ProgressHandle import ProgressHandle
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        handle = ProgressHandle(title, True, self.__ui)
        handle.show()
        QApplication.processEvents()
        try:
            occurrences = rope.contrib.findit.find_occurrences(
                self.__project, resource, offset,
                unsure=True, in_hierarchy=True, task_handle=handle)
        except Exception as err:
            self.handleRopeError(err, title, handle)
            return
        handle.reset()
        
        if occurrences:
            from MatchesDialog import MatchesDialog
            self.dlg = MatchesDialog(self.__ui, True)
            self.dlg.show()
            for occurrence in occurrences:
                self.dlg.addEntry(occurrence.resource,
                    occurrence.lineno, occurrence.unsure)
        else:
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("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.trUtf8("Find &Definition")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("Highlight the class, method, function or"
                    " variable reference to search definition 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)
        
        import rope.contrib.findit
        resource = rope.base.libutils.path_to_resource(
            self.__project, filename)
        try:
            location = rope.contrib.findit.find_definition(
                self.__project, aw.text(), offset, resource)
        except Exception as err:
            self.handleRopeError(err, title)
            return
        
        if location is not None:
            from MatchesDialog import MatchesDialog
            self.dlg = MatchesDialog(self.__ui, False)
            self.dlg.show()
            self.dlg.addEntry(location.resource, location.lineno)
        else:
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("No matching definition found."))
    
    def __queryImplementations(self):
        """
        Private slot to handle the Find Implementations action.
        """
        aw = e5App().getObject("ViewManager").activeWindow()
        
        if aw is None:
            return
        
        title = self.trUtf8("Find Implementations")
        if not aw.hasSelectedText():
            # no selection available
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("Highlight the method to search 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)
        
        import rope.contrib.findit
        from ProgressHandle import ProgressHandle
        resource = rope.base.libutils.path_to_resource(self.__project,
            filename)
        handle = ProgressHandle(title, True, self.__ui)
        handle.show()
        QApplication.processEvents()
        try:
            occurrences = rope.contrib.findit.find_implementations(
                self.__project, resource, offset, task_handle=handle)
        except Exception as err:
            self.handleRopeError(err, title, handle)
            return
        handle.reset()
        
        if occurrences:
            from MatchesDialog import MatchesDialog
            self.dlg = MatchesDialog(self.__ui, True)
            self.dlg.show()
            for occurrence in occurrences:
                self.dlg.addEntry(occurrence.resource,
                    occurrence.lineno, occurrence.unsure)
        else:
            E5MessageBox.warning(self.__ui, title,
                self.trUtf8("No occurrences found."))
    
    #####################################################
    ## Various actions
    #####################################################
    
    def __editConfig(self):
        """
        Private slot to open the rope configuration file in an editor.
        """
        ropedir = self.__project.ropefolder
        configfile = ""
        if ropedir is not None:
            configfile = os.path.join(ropedir.real_path, "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.trUtf8("Configure Rope"),
                    self.trUtf8("""The Rope configuration file '{0}' does"""
                                """ not exist.""").format(configfile))
        else:
            E5MessageBox.critical(self.__ui,
                self.trUtf8("Configure Rope"),
                self.trUtf8("""The Rope admin directory does not exist."""))
    
    def __updateConfig(self):
        """
        Private slot to update the configuration file.
        """
        res = E5MessageBox.yesNo(self.__ui,
            self.trUtf8("Update Configuration"),
            self.trUtf8("""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.trUtf8("Update Configuration"),
                        self.trUtf8("""<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
            helpfile = os.path.join(os.path.dirname(__file__),
                                    "rope", "docs", "overview.txt")
            self.__helpDialog = \
                HelpDialog(self.trUtf8("Help about rope refactorings"),
                           helpfile)
        self.__helpDialog.show()
    
    def __performSOA(self):
        """
        Private slot to perform SOA on all modules.
        """
        title = self.trUtf8("Analyse all modules")
        res = E5MessageBox.yesNo(self.__ui,
            title,
            self.trUtf8("""This action might take some time. """
                        """Do you really want to perform SOA?"""))
        if res:
            from ProgressHandle import ProgressHandle
            handle = ProgressHandle(title, True, self.__ui)
            handle.show()
            QApplication.processEvents()
            try:
                rope.base.libutils.analyze_modules(self.__project,
                    task_handle=handle)
                handle.reset()
                E5MessageBox.information(self.__ui,
                    title,
                    self.trUtf8("""Static object analysis (SOA) done. """
                                """SOA database updated."""))
            except Exception as err:
                self.handleRopeError(err, title, handle)
    
    ##################################################################
    ## methods below are private utility methods
    ##################################################################
    
    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.__project is not None:
            ropedir = self.__project.ropefolder
            if ropedir is not None:
                configfile = os.path.join(ropedir.real_path, "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.
        """
        import rope.base.project
        self.__project.close()
        self.__project = rope.base.project.Project(self.__projectpath,
            fscommands=self.__fsCommands)
    
    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.__project is not None:
            return self.__project._default_config()
        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()
        
        if self.__projectLanguage in ["Python3"]:
            import rope.base.project
            self.__project = rope.base.project.Project(self.__projectpath,
                fscommands=self.__fsCommands)
            for act in self.actions:
                act.setEnabled(True)
    
    def projectClosed(self):
        """
        Public slot to handle the projectClosed signal.
        """
        for act in self.actions:
            act.setEnabled(False)
        
        if self.__project is not None:
            self.__project.close()
            self.__project = None
        
        self.__projectopen = False
        self.__projectpath = ''
        self.__projectLanguage = ""
    
    def getProject(self):
        """
        Public method to get a reference to the rope project object.
        
        @return reference to the rope project object (RopeProject)
        """
        return self.__project
    
    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.__project.validate(self.__project.root)
        return res
    
    def confirmAllBuffersSaved(self):
        """
        Private 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.__project.validate(self.__project.root)
        return res
    
    def refreshEditors(self, changes):
        """
        Public method to refresh modified editors.
        
        @param reference to the Changes object (rope.base.change.ChangeSet)
        """
        vm = e5App().getObject("ViewManager")
        
        changedFiles = []
        for resource in changes.get_changed_resources():
            if not resource.is_folder():
                changedFiles.append(resource.real_path)
        
        openFiles = [Utilities.normcasepath(f) for f in vm.getOpenFilenames()]
        
        for file in changedFiles:
            normfile = Utilities.normcasepath(file)
            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)

eric ide

mercurial