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 |
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 |