RefactoringRope/Refactoring.py

changeset 3
3be1b4662b48
parent 2
fc72a5b922a6
child 4
2e2463ef1aae
equal deleted inserted replaced
2:fc72a5b922a6 3:3be1b4662b48
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.refactor.rename
20 ##import rope.refactor.extract
21 ##import rope.refactor.usefunction
22 ##import rope.refactor.inline
23 ##import rope.refactor.move
24 ##import rope.refactor.change_signature
25 ##import rope.refactor.introduce_factory
26 ##import rope.refactor.introduce_parameter
27 ##import rope.refactor.method_object
28 ##import rope.refactor.encapsulate_field
29 ##import rope.refactor.localtofield
30 ##import rope.refactor.topackage
31 ##from rope.refactor.importutils import ImportOrganizer
32
19 import rope.contrib.findit 33 import rope.contrib.findit
34 ##import rope.contrib.finderrors
20 35
21 from PyQt4.QtCore import QObject, SIGNAL 36 from PyQt4.QtCore import QObject, SIGNAL
22 from PyQt4.QtGui import QMenu, QApplication, QMessageBox 37 from PyQt4.QtGui import QMenu, QApplication, QMessageBox
23 38
24 from E5Gui.E5Application import e5App 39 from E5Gui.E5Application import e5App
27 from E5Gui.E5Action import E5Action 42 from E5Gui.E5Action import E5Action
28 43
29 from QScintilla.MiniEditor import MiniEditor 44 from QScintilla.MiniEditor import MiniEditor
30 45
31 from FileSystemCommands import e5FileSystemCommands 46 from FileSystemCommands import e5FileSystemCommands
47 from ProgressHandle import ProgressHandle
32 from HelpDialog import HelpDialog 48 from HelpDialog import HelpDialog
33 from ProgressHandle import ProgressHandle
34 from MatchesDialog import MatchesDialog 49 from MatchesDialog import MatchesDialog
50 from RenameDialog import RenameDialog
51 from ChangeOccurrencesDialog import ChangeOccurrencesDialog
35 52
36 import Utilities 53 import Utilities
37 54
38 55
39 class Refactoring(QObject): 56 class Refactoring(QObject):
68 def initActions(self): 85 def initActions(self):
69 """ 86 """
70 Public method to define the refactoring actions. 87 Public method to define the refactoring actions.
71 """ 88 """
72 self.actions = [] 89 self.actions = []
90
91 #####################################################
92 ## Rename refactoring actions
93 #####################################################
94
95 self.refactoringRenameAct = E5Action(self.trUtf8('Rename'),
96 self.trUtf8('&Rename'),
97 0, 0,
98 self,'refactoring_rename')
99 self.refactoringRenameAct.setStatusTip(self.trUtf8(
100 'Rename the highlighted object'))
101 self.refactoringRenameAct.setWhatsThis(self.trUtf8(
102 """<b>Rename</b>"""
103 """<p>Rename the highlighted Python object.</p>"""
104 ))
105 if self.__newStyle:
106 self.refactoringRenameAct.triggered[()].connect(
107 self.__rename)
108 else:
109 self.connect(self.refactoringRenameAct, SIGNAL('triggered()'),
110 self.__rename)
111 self.actions.append(self.refactoringRenameAct)
112
113 self.refactoringRenameLocalAct = E5Action(self.trUtf8('Local Rename'),
114 self.trUtf8('&Local Rename'),
115 0, 0,
116 self,'refactoring_rename_local')
117 self.refactoringRenameLocalAct.setStatusTip(self.trUtf8(
118 'Rename the highlighted object in the current module only'))
119 self.refactoringRenameLocalAct.setWhatsThis(self.trUtf8(
120 """<b>Local Rename</b>"""
121 """<p>Rename the highlighted Python object in the current"""
122 """ module only.</p>"""
123 ))
124 if self.__newStyle:
125 self.refactoringRenameLocalAct.triggered[()].connect(
126 self.__renameLocal)
127 else:
128 self.connect(self.refactoringRenameLocalAct,
129 SIGNAL('triggered()'), self.__renameLocal)
130 self.actions.append(self.refactoringRenameLocalAct)
131
132 self.refactoringRenameModuleAct = E5Action(
133 self.trUtf8('Rename Current Module'),
134 self.trUtf8('Rename Current Module'),
135 0, 0,
136 self,'refactoring_rename_module')
137 self.refactoringRenameModuleAct.setStatusTip(self.trUtf8(
138 'Rename the current module'))
139 self.refactoringRenameModuleAct.setWhatsThis(self.trUtf8(
140 """<b>Rename Current Module</b>"""
141 """<p>Rename the current module.</p>"""
142 ))
143 if self.__newStyle:
144 self.refactoringRenameModuleAct.triggered[()].connect(
145 self.__renameModule)
146 else:
147 self.connect(self.refactoringRenameModuleAct,
148 SIGNAL('triggered()'), self.__renameModule)
149 self.actions.append(self.refactoringRenameModuleAct)
150
151 self.refactoringChangeOccurrencesAct = E5Action(
152 self.trUtf8('Change Occurrences'),
153 self.trUtf8('Change &Occurrences'),
154 0, 0,
155 self,'refactoring_change_occurrences')
156 self.refactoringChangeOccurrencesAct.setStatusTip(self.trUtf8(
157 'Change all occurrences in the local scope'))
158 self.refactoringChangeOccurrencesAct.setWhatsThis(self.trUtf8(
159 """<b>Change Occurrences</b>"""
160 """<p>Change all occurrences in the local scope.</p>"""
161 ))
162 if self.__newStyle:
163 self.refactoringChangeOccurrencesAct.triggered[()].connect(
164 self.__changeOccurrences)
165 else:
166 self.connect(self.refactoringChangeOccurrencesAct,
167 SIGNAL('triggered()'), self.__changeOccurrences)
168 self.actions.append(self.refactoringChangeOccurrencesAct)
73 169
74 ##################################################### 170 #####################################################
75 ## Query actions 171 ## Query actions
76 ##################################################### 172 #####################################################
77 173
193 smenu = menu.addMenu(self.trUtf8("&Query")) 289 smenu = menu.addMenu(self.trUtf8("&Query"))
194 smenu.addAction(self.queryReferencesAct) 290 smenu.addAction(self.queryReferencesAct)
195 smenu.addAction(self.queryDefinitionAct) 291 smenu.addAction(self.queryDefinitionAct)
196 smenu.addAction(self.queryImplementationsAct) 292 smenu.addAction(self.queryImplementationsAct)
197 293
294 smenu = menu.addMenu(self.trUtf8("&Refactoring"))
295 if self.__newStyle:
296 smenu.aboutToShow.connect(self.__showRefactoringMenu)
297 else:
298 self.connect(smenu, SIGNAL("aboutToShow()"),
299 self.__showRefactoringMenu)
300 smenu.addAction(self.refactoringRenameAct)
301 smenu.addAction(self.refactoringRenameLocalAct)
302 smenu.addAction(self.refactoringChangeOccurrencesAct)
303 smenu.addSeparator()
304 smenu.addAction(self.refactoringRenameModuleAct)
305 smenu.addSeparator()
306
198 menu.addSeparator() 307 menu.addSeparator()
199 menu.addAction(self.refactoringEditConfigAct) 308 menu.addAction(self.refactoringEditConfigAct)
200 menu.addAction(self.refactoringHelpAct) 309 menu.addAction(self.refactoringHelpAct)
201 310
202 self.__mainMenu = menu 311 self.__mainMenu = menu
212 """ 321 """
213 E5MessageBox.about(self.__ui, 322 E5MessageBox.about(self.__ui,
214 self.trUtf8("About rope"), 323 self.trUtf8("About rope"),
215 self.trUtf8("{0}\nVersion {1}\n\n{2}".format( 324 self.trUtf8("{0}\nVersion {1}\n\n{2}".format(
216 rope.INFO, rope.VERSION, rope.COPYRIGHT))) 325 rope.INFO, rope.VERSION, rope.COPYRIGHT)))
326
327 def __canUndo(self):
328 """
329 Private slot to check, if there are changes to be undone.
330
331 @return flag indicating, that undoable changes are available (boolean)
332 """
333 return self.__project is not None and \
334 len(self.__project.history.undo_list) > 0
335
336 def __canRedo(self):
337 """
338 Private slot to check, if there are changes to be redone.
339
340 @return flag indicating, that redoable changes are available (boolean)
341 """
342 return self.__project is not None and \
343 len(self.__project.history.redo_list) > 0
344
345 def __getFileUndoList(self, resource):
346 """
347 Private slot to get a list of undoable changes.
348
349 @param resource file resource to filter against
350 (rope.base.resources.File)
351 @return list of change objects (list of rope.base.change.Change)
352 """
353 undoList = []
354 for change in self.__project.history.undo_list:
355 if resource in change.get_changed_resources():
356 undoList.append(change)
357 return undoList
358
359 def __getFileRedoList(self, resource):
360 """
361 Private slot to get a list of redoable changes.
362
363 @param resource file resource to filter against
364 (rope.base.resources.File)
365 @return list of change objects (list of rope.base.change.Change)
366 """
367 redoList = []
368 for change in self.__project.history.redo_list:
369 if resource in change.get_changed_resources():
370 redoList.append(change)
371 return redoList
372
373 def __canUndoFile(self, resource):
374 """
375 Private slot to check, if there are undoable changes for a resource.
376
377 @param resource file resource to check against
378 (rope.base.resources.File)
379 @return flag indicating, that undoable changes are available (boolean)
380 """
381 return self.__canUndo() and len(self.__getFileUndoList(resource)) > 0
382
383 def __canRedoFile(self, resource):
384 """
385 Private slot to check, if there are redoable changes for a resource.
386
387 @param resource file resource to check against
388 (rope.base.resources.File)
389 @return flag indicating, that redoable changes are available (boolean)
390 """
391 return self.__canRedo() and len(self.__getFileRedoList(resource)) > 0
392
393 def __showRefactoringMenu(self):
394 """
395 Private slot called before the refactoring menu is shown.
396 """
397 # TODO: enable these once undo/redo has been implemented
398 ## self.refactoringUndoAct.setEnabled(self.__canUndo())
399 ## self.refactoringRedoAct.setEnabled(self.__canRedo())
217 400
218 def handleRopeError(self, err, title, handle=None): 401 def handleRopeError(self, err, title, handle=None):
219 """ 402 """
220 Public slot to handle a rope error. 403 Public slot to handle a rope error.
221 404
237 err.lineno) 420 err.lineno)
238 else: 421 else:
239 E5MessageBox.warning(self.__ui, title, 422 E5MessageBox.warning(self.__ui, title,
240 self.trUtf8("Rope error: {0}").format(str(err))) 423 self.trUtf8("Rope error: {0}").format(str(err)))
241 424
425 ##################################################################
426 ## slots below implement the various refactorings
427 ##################################################################
428
429 #####################################################
430 ## Rename refactorings
431 #####################################################
432
433 def __rename(self):
434 """
435 Private slot to handle the Rename action.
436 """
437 self.__doRename(self.trUtf8('Rename'))
438
439 def __renameLocal(self):
440 """
441 Private slot to handle the Local Rename action.
442 """
443 self.__doRename(self.trUtf8('Local Rename'), isLocal=True)
444
445 def __renameModule(self):
446 """
447 Private slot to handle the Rename Current Module action.
448 """
449 self.__doRename(self.trUtf8('Rename Current Module'),
450 renameModule=True)
451
452 def __doRename(self, title, isLocal=False, renameModule=False):
453 """
454 Private method to perform the various renaming refactorings.
455
456 @param title title of the refactoring (string)
457 @param isLocal flag indicating to restrict refactoring to
458 the local file (boolean)
459 @param renameModule flag indicating a module rename refactoring
460 (boolean)
461 """
462 aw = e5App().getObject("ViewManager").activeWindow()
463
464 if aw is None:
465 return
466
467 if not renameModule and not aw.hasSelectedText():
468 # no selection available
469 E5MessageBox.warning(self.__ui, title,
470 self.trUtf8("Highlight the declaration you want to rename"
471 " and try again."))
472 return
473
474 if isLocal:
475 if not self.confirmBufferIsSaved(aw):
476 return
477 else:
478 if not self.confirmAllBuffersSaved():
479 return
480
481 filename = aw.getFileName()
482 if renameModule:
483 offset = None
484 else:
485 line, index, line1, index1 = aw.getSelection()
486 if line != line1:
487 # selection span more than one line
488 E5MessageBox.warning(self.__ui, title,
489 self.trUtf8("The selection must not extend beyond"
490 " one line."))
491 return
492 index = int(index + (index1 - index) / 2)
493 # keep it inside the object
494 offset = aw.positionFromLineIndex(line, index)
495
496 resource = rope.base.libutils.path_to_resource(
497 self.__project, filename)
498 try:
499 renamer = rope.refactor.rename.Rename(
500 self.__project, resource, offset)
501 except Exception as err:
502 self.handleRopeError(err, title)
503 return
504
505 if isLocal:
506 localResource = resource
507 else:
508 localResource = None
509 self.dlg = RenameDialog(self, title, renamer, resource=localResource,
510 parent=self.__ui)
511 self.dlg.show()
512
513 def __changeOccurrences(self):
514 """
515 Private slot to perform the Change Occurrences refactoring.
516 """
517 aw = e5App().getObject("ViewManager").activeWindow()
518
519 if aw is None:
520 return
521
522 title = self.trUtf8("Change Occurrences")
523 if not aw.hasSelectedText():
524 # no selection available
525 E5MessageBox.warning(self.__ui, title,
526 self.trUtf8("Highlight an occurrence to be changed"
527 " and try again."))
528 return
529
530 if not self.confirmBufferIsSaved(aw):
531 return
532
533 filename = aw.getFileName()
534 line, index, line1, index1 = aw.getSelection()
535 offset = aw.positionFromLineIndex(line, index)
536
537 resource = rope.base.libutils.path_to_resource(
538 self.__project, filename)
539 try:
540 renamer = rope.refactor.rename.ChangeOccurrences(
541 self.__project, resource, offset)
542 except Exception as err:
543 self.handleRopeError(err, title)
544 return
545
546 self.dlg = ChangeOccurrencesDialog(self, title, renamer,
547 parent=self.__ui)
548 self.dlg.show()
549
242 ##################################################### 550 #####################################################
243 ## Find actions 551 ## Find actions
244 ##################################################### 552 #####################################################
245 553
246 def __queryReferences(self): 554 def __queryReferences(self):

eric ide

mercurial