--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RefactoringRope/Refactoring.py Sun Jan 23 19:55:56 2011 +0100 @@ -0,0 +1,323 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2011 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.project +import rope.base.exceptions + +from PyQt4.QtCore import QObject, SIGNAL +from PyQt4.QtGui import QMenu + +from E5Gui.E5Application import e5App + +from E5Gui import E5MessageBox +from E5Gui.E5Action import E5Action + +from QScintilla.MiniEditor import MiniEditor + +from FileSystemCommands import e5FileSystemCommands +from HelpDialog import HelpDialog + + +class Refactoring(QObject): + """ + Class implementing the refactoring interface to rope. + """ + def __init__(self, plugin, newStyle, parent = None): + """ + Constructor + + @param plugin reference to the plugin object + @param newStyle flag indicating usage of new style signals (bool) + @param parent parent (QObject) + """ + QObject.__init__(self, parent) + + self.__plugin = plugin + self.__newStyle = newStyle + 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 + self.__fsCommands = e5FileSystemCommands(self.__e5project) + + def initActions(self): + """ + Public method to define the refactoring actions. + """ + self.actions = [] + + + ##################################################### + ## 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>""" + )) + if self.__newStyle: + self.refactoringEditConfigAct.triggered[()].connect( + self.__editConfig) + else: + self.connect(self.refactoringEditConfigAct, SIGNAL('triggered()'), + self.__editConfig) + 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>""" + )) + if self.__newStyle: + self.refactoringHelpAct.triggered[()].connect( + self.__showRopeHelp) + else: + self.connect(self.refactoringHelpAct, SIGNAL('triggered()'), + self.__showRopeHelp) + self.actions.append(self.refactoringHelpAct) + + 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() + + 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))) + + ##################################################### + ## 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): + self.__editor = MiniEditor(configfile) + self.__editor.show() + if self.__newStyle: + self.__editor.editorSaved.connect(self.__configChanged) + else: + self.connect(self.__editor, SIGNAL("editorSaved"), + 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 __showRopeHelp(self): + """ + Private slot to show help about the refactorings offered by Rope. + """ + if self.__helpDialog is None: + 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() + + ################################################################## + ## 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. + """ + 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"]: + 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 +## """ +## res = editor.checkDirty() +## self.__project.validate(self.__project.root) +## return res +## +## def confirmAllBuffersSaved(self): +## """ +## Private method to check, if any editor has unsaved changes. +## """ +## 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)