RefactoringRope/Refactoring.py

changeset 2
fc72a5b922a6
parent 1
9f687137a929
child 3
3be1b4662b48
equal deleted inserted replaced
1:9f687137a929 2:fc72a5b922a6
14 import rope 14 import rope
15 import rope.base.libutils 15 import rope.base.libutils
16 import rope.base.project 16 import rope.base.project
17 import rope.base.exceptions 17 import rope.base.exceptions
18 18
19 import rope.contrib.findit
20
19 from PyQt4.QtCore import QObject, SIGNAL 21 from PyQt4.QtCore import QObject, SIGNAL
20 from PyQt4.QtGui import QMenu 22 from PyQt4.QtGui import QMenu, QApplication, QMessageBox
21 23
22 from E5Gui.E5Application import e5App 24 from E5Gui.E5Application import e5App
23 25
24 from E5Gui import E5MessageBox 26 from E5Gui import E5MessageBox
25 from E5Gui.E5Action import E5Action 27 from E5Gui.E5Action import E5Action
26 28
27 from QScintilla.MiniEditor import MiniEditor 29 from QScintilla.MiniEditor import MiniEditor
28 30
29 from FileSystemCommands import e5FileSystemCommands 31 from FileSystemCommands import e5FileSystemCommands
30 from HelpDialog import HelpDialog 32 from HelpDialog import HelpDialog
33 from ProgressHandle import ProgressHandle
34 from MatchesDialog import MatchesDialog
35
36 import Utilities
31 37
32 38
33 class Refactoring(QObject): 39 class Refactoring(QObject):
34 """ 40 """
35 Class implementing the refactoring interface to rope. 41 Class implementing the refactoring interface to rope.
36 """ 42 """
37 def __init__(self, plugin, newStyle, parent = None): 43 def __init__(self, plugin, newStyle, parent=None):
38 """ 44 """
39 Constructor 45 Constructor
40 46
41 @param plugin reference to the plugin object 47 @param plugin reference to the plugin object
42 @param newStyle flag indicating usage of new style signals (bool) 48 @param newStyle flag indicating usage of new style signals (bool)
63 """ 69 """
64 Public method to define the refactoring actions. 70 Public method to define the refactoring actions.
65 """ 71 """
66 self.actions = [] 72 self.actions = []
67 73
74 #####################################################
75 ## Query actions
76 #####################################################
77
78 self.queryReferencesAct = E5Action(self.trUtf8('Find occurrences'),
79 self.trUtf8('Find &Occurrences'),
80 0, 0,
81 self,'refactoring_find_occurrences')
82 self.queryReferencesAct.setStatusTip(self.trUtf8(
83 'Find occurrences of the highlighted object'))
84 self.queryReferencesAct.setWhatsThis(self.trUtf8(
85 """<b>Find occurrences</b>"""
86 """<p>Find occurrences of the highlighted class, method,"""
87 """ function or variable.</p>"""
88 ))
89 if self.__newStyle:
90 self.queryReferencesAct.triggered[()].connect(
91 self.__queryReferences)
92 else:
93 self.connect(self.queryReferencesAct, SIGNAL('triggered()'),
94 self.__queryReferences)
95 self.actions.append(self.queryReferencesAct)
96
97 self.queryDefinitionAct = E5Action(self.trUtf8('Find definition'),
98 self.trUtf8('Find &Definition'),
99 0, 0,
100 self,'refactoring_find_definition')
101 self.queryDefinitionAct.setStatusTip(self.trUtf8(
102 'Find definition of the highlighted item'))
103 self.queryDefinitionAct.setWhatsThis(self.trUtf8(
104 """<b>Find definition</b>"""
105 """<p>Find the definition of the highlighted class, method,"""
106 """ function or variable.</p>"""
107 ))
108 if self.__newStyle:
109 self.queryDefinitionAct.triggered[()].connect(
110 self.__queryDefinition)
111 else:
112 self.connect(self.queryDefinitionAct, SIGNAL('triggered()'),
113 self.__queryDefinition)
114 self.actions.append(self.queryDefinitionAct)
115
116 self.queryImplementationsAct = E5Action(
117 self.trUtf8('Find implementations'),
118 self.trUtf8('Find &Implementations'),
119 0, 0,
120 self,'refactoring_find_implementations')
121 self.queryImplementationsAct.setStatusTip(self.trUtf8(
122 'Find places where the selected method is overridden'))
123 self.queryImplementationsAct.setWhatsThis(self.trUtf8(
124 """<b>Find implementations</b>"""
125 """<p>Find places where the selected method is overridden.</p>"""
126 ))
127 if self.__newStyle:
128 self.queryImplementationsAct.triggered[()].connect(
129 self.__queryImplementations)
130 else:
131 self.connect(self.queryImplementationsAct, SIGNAL('triggered()'),
132 self.__queryImplementations)
133 self.actions.append(self.queryImplementationsAct)
68 134
69 ##################################################### 135 #####################################################
70 ## Various actions 136 ## Various actions
71 ##################################################### 137 #####################################################
72 138
122 font = act.font() 188 font = act.font()
123 font.setBold(True) 189 font.setBold(True)
124 act.setFont(font) 190 act.setFont(font)
125 menu.addSeparator() 191 menu.addSeparator()
126 192
193 smenu = menu.addMenu(self.trUtf8("&Query"))
194 smenu.addAction(self.queryReferencesAct)
195 smenu.addAction(self.queryDefinitionAct)
196 smenu.addAction(self.queryImplementationsAct)
197
127 menu.addSeparator() 198 menu.addSeparator()
128 menu.addAction(self.refactoringEditConfigAct) 199 menu.addAction(self.refactoringEditConfigAct)
129 menu.addAction(self.refactoringHelpAct) 200 menu.addAction(self.refactoringHelpAct)
130 201
131 self.__mainMenu = menu 202 self.__mainMenu = menu
141 """ 212 """
142 E5MessageBox.about(self.__ui, 213 E5MessageBox.about(self.__ui,
143 self.trUtf8("About rope"), 214 self.trUtf8("About rope"),
144 self.trUtf8("{0}\nVersion {1}\n\n{2}".format( 215 self.trUtf8("{0}\nVersion {1}\n\n{2}".format(
145 rope.INFO, rope.VERSION, rope.COPYRIGHT))) 216 rope.INFO, rope.VERSION, rope.COPYRIGHT)))
217
218 def handleRopeError(self, err, title, handle=None):
219 """
220 Public slot to handle a rope error.
221
222 @param err rope exception object (Exception)
223 @param title title to be displayed (string)
224 @param handle reference to a taskhandle (ProgressHandle)
225 """
226 if handle is not None:
227 handle.reset()
228 if str(type(err)).split()[-1][1:-2].split('.')[-1] == \
229 'ModuleSyntaxError':
230 res = E5MessageBox.warning(self.__ui, title,
231 self.trUtf8("Rope error: {0}").format(str(err)),
232 QMessageBox.Ok | QMessageBox.Open)
233 if res == QMessageBox.Open:
234 e5App().getObject("ViewManager").openSourceFile(
235 os.path.join(self.__e4project.getProjectPath(),
236 err.filename),
237 err.lineno)
238 else:
239 E5MessageBox.warning(self.__ui, title,
240 self.trUtf8("Rope error: {0}").format(str(err)))
241
242 #####################################################
243 ## Find actions
244 #####################################################
245
246 def __queryReferences(self):
247 """
248 Private slot to handle the Find References action.
249 """
250 aw = e5App().getObject("ViewManager").activeWindow()
251
252 if aw is None:
253 return
254
255 title = self.trUtf8("Find Occurrences")
256 if not aw.hasSelectedText():
257 # no selection available
258 E5MessageBox.warning(self.__ui, title,
259 self.trUtf8("Highlight the class, method, function or variable"
260 " to search for and try again."))
261 return
262
263 if not self.confirmAllBuffersSaved():
264 return
265
266 filename = aw.getFileName()
267 line, index, line1, index1 = aw.getSelection()
268 offset = aw.positionFromLineIndex(line, index)
269
270 resource = rope.base.libutils.path_to_resource(
271 self.__project, filename)
272 handle = ProgressHandle(title, True, self.__ui)
273 handle.show()
274 QApplication.processEvents()
275 try:
276 occurrences = rope.contrib.findit.find_occurrences(
277 self.__project, resource, offset,
278 unsure = True, in_hierarchy = True, task_handle = handle)
279 except Exception as err:
280 self.handleRopeError(err, title, handle)
281 return
282 handle.reset()
283
284 if occurrences:
285 self.dlg = MatchesDialog(self.__ui, True)
286 self.dlg.show()
287 for occurrence in occurrences:
288 self.dlg.addEntry(occurrence.resource,
289 occurrence.lineno, occurrence.unsure)
290 else:
291 E5MessageBox.warning(self.__ui, title,
292 self.trUtf8("No occurrences found."))
293
294 def __queryDefinition(self):
295 """
296 Private slot to handle the Find Definition action
297 """
298 aw = e5App().getObject("ViewManager").activeWindow()
299
300 if aw is None:
301 return
302
303 title = self.trUtf8("Find &Definition")
304 if not aw.hasSelectedText():
305 # no selection available
306 E5MessageBox.warning(self.__ui, title,
307 self.trUtf8("Highlight the class, method, function or"
308 " variable reference to search definition for and"
309 " try again."))
310 return
311
312 if not self.confirmAllBuffersSaved():
313 return
314
315 filename = aw.getFileName()
316 line, index, line1, index1 = aw.getSelection()
317 offset = aw.positionFromLineIndex(line, index)
318
319 resource = rope.base.libutils.path_to_resource(
320 self.__project, filename)
321 try:
322 location = rope.contrib.findit.find_definition(
323 self.__project, aw.text(), offset, resource)
324 except Exception as err:
325 self.handleRopeError(err, title)
326 return
327
328 if location is not None:
329 self.dlg = MatchesDialog(self.__ui, False)
330 self.dlg.show()
331 self.dlg.addEntry(location.resource, location.lineno)
332 else:
333 E5MessageBox.warning(self.__ui, title,
334 self.trUtf8("No matching definition found."))
335
336 def __queryImplementations(self):
337 """
338 Private slot to handle the Find Implementations action.
339 """
340 aw = e5App().getObject("ViewManager").activeWindow()
341
342 if aw is None:
343 return
344
345 title = self.trUtf8("Find Implementations")
346 if not aw.hasSelectedText():
347 # no selection available
348 E5MessageBox.warning(self.__ui, title,
349 self.trUtf8("Highlight the method to search for"
350 " and try again."))
351 return
352
353 if not self.confirmAllBuffersSaved():
354 return
355
356 filename = aw.getFileName()
357 line, index, line1, index1 = aw.getSelection()
358 offset = aw.positionFromLineIndex(line, index)
359
360 resource = rope.base.libutils.path_to_resource(self.__project,
361 filename)
362 handle = ProgressHandle(title, True, self.__ui)
363 handle.show()
364 QApplication.processEvents()
365 try:
366 occurrences = rope.contrib.findit.find_implementations(
367 self.__project, resource, offset, task_handle = handle)
368 except Exception as err:
369 self.handleRopeError(err, title, handle)
370 return
371 handle.reset()
372
373 if occurrences:
374 self.dlg = MatchesDialog(self.__ui, True)
375 self.dlg.show()
376 for occurrence in occurrences:
377 self.dlg.addEntry(occurrence.resource,
378 occurrence.lineno, occurrence.unsure)
379 else:
380 E5MessageBox.warning(self.__ui, title,
381 self.trUtf8("No occurrences found."))
146 382
147 ##################################################### 383 #####################################################
148 ## Various actions 384 ## Various actions
149 ##################################################### 385 #####################################################
150 386
274 Public method to get a reference to the rope project object. 510 Public method to get a reference to the rope project object.
275 511
276 @return reference to the rope project object (RopeProject) 512 @return reference to the rope project object (RopeProject)
277 """ 513 """
278 return self.__project 514 return self.__project
279 ## 515
280 ## def confirmBufferIsSaved(self, editor): 516 def confirmBufferIsSaved(self, editor):
281 ## """ 517 """
282 ## Public method to check, if an editor has unsaved changes. 518 Public method to check, if an editor has unsaved changes.
283 ## 519
284 ## @param editor reference to the editor to be checked 520 @param editor reference to the editor to be checked
285 ## """ 521 @return flag indicating, that the editor doesn't contain
286 ## res = editor.checkDirty() 522 unsaved edits (boolean)
287 ## self.__project.validate(self.__project.root) 523 """
288 ## return res 524 res = editor.checkDirty()
289 ## 525 self.__project.validate(self.__project.root)
290 ## def confirmAllBuffersSaved(self): 526 return res
291 ## """ 527
292 ## Private method to check, if any editor has unsaved changes. 528 def confirmAllBuffersSaved(self):
293 ## """ 529 """
294 ## res = e5App().getObject("ViewManager").checkAllDirty() 530 Private method to check, if any editor has unsaved changes.
295 ## self.__project.validate(self.__project.root) 531
296 ## return res 532 @return flag indicating, that no editor contains unsaved edits
297 ## 533 (boolean)
298 ## def refreshEditors(self, changes): 534 """
299 ## """ 535 res = e5App().getObject("ViewManager").checkAllDirty()
300 ## Public method to refresh modified editors. 536 self.__project.validate(self.__project.root)
301 ## 537 return res
302 ## @param reference to the Changes object (rope.base.change.ChangeSet) 538
303 ## """ 539 def refreshEditors(self, changes):
304 ## vm = e5App().getObject("ViewManager") 540 """
305 ## 541 Public method to refresh modified editors.
306 ## changedFiles = [] 542
307 ## for resource in changes.get_changed_resources(): 543 @param reference to the Changes object (rope.base.change.ChangeSet)
308 ## if not resource.is_folder(): 544 """
309 ## changedFiles.append(resource.real_path) 545 vm = e5App().getObject("ViewManager")
310 ## 546
311 ## openFiles = [Utilities.normcasepath(f) for f in vm.getOpenFilenames()] 547 changedFiles = []
312 ## 548 for resource in changes.get_changed_resources():
313 ## for file in changedFiles: 549 if not resource.is_folder():
314 ## normfile = Utilities.normcasepath(file) 550 changedFiles.append(resource.real_path)
315 ## if normfile in openFiles: 551
316 ## editor = vm.getEditor(normfile)[1] 552 openFiles = [Utilities.normcasepath(f) for f in vm.getOpenFilenames()]
317 ## editor.refresh() 553
318 ## 554 for file in changedFiles:
319 ## aw = vm.activeWindow() 555 normfile = Utilities.normcasepath(file)
320 ## if aw is not None: 556 if normfile in openFiles:
321 ## filename = aw.getFileName() 557 editor = vm.getEditor(normfile)[1]
322 ## if filename is not None: 558 editor.refresh()
323 ## vm.openSourceFile(filename, aw.getCursorPosition()[0] + 1) 559
560 aw = vm.activeWindow()
561 if aw is not None:
562 filename = aw.getFileName()
563 if filename is not None:
564 vm.openSourceFile(filename, aw.getCursorPosition()[0] + 1)
565

eric ide

mercurial