RefactoringRope/MoveDialog.py

branch
server_client_variant
changeset 178
70b4fb448811
parent 147
3f8a995f6e49
child 189
2711fdd91925
equal deleted inserted replaced
177:963fc1b0ba6e 178:70b4fb448811
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2010 - 2017 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the Move Method or Module dialog.
8 """
9
10 from __future__ import unicode_literals
11
12 import os
13
14 from PyQt5.QtCore import pyqtSlot
15 from PyQt5.QtWidgets import QDialogButtonBox, QAbstractButton
16
17 from E5Gui import E5FileDialog, E5MessageBox
18 from E5Gui.E5Application import e5App
19 from E5Gui.E5Completers import E5FileCompleter
20
21 from Ui_MoveDialog import Ui_MoveDialog
22 from RefactoringDialogBase import RefactoringDialogBase
23
24 import Utilities
25
26
27 class MoveDialog(RefactoringDialogBase, Ui_MoveDialog):
28 """
29 Class implementing the Move Method or Module dialog.
30 """
31 def __init__(self, refactoring, title, filename, offset, parent=None):
32 """
33 Constructor
34
35 @param refactoring reference to the main refactoring object
36 @type Refactoring
37 @param title title of the dialog
38 @type str
39 @param filename file name to be worked on
40 @type str
41 @param offset offset within file
42 @type int or None
43 @param parent reference to the parent widget
44 @type QWidget
45 """
46 RefactoringDialogBase.__init__(self, refactoring, title, parent)
47 self.setupUi(self)
48
49 self._changeGroupName = "Move"
50
51 self.__destinationCompleter = E5FileCompleter(self.destinationEdit)
52
53 self.__filename = filename
54 self.__offset = offset
55
56 self.__project = e5App().getObject("Project")
57
58 self.__okButton = self.buttonBox.button(QDialogButtonBox.Ok)
59 self.__okButton.setEnabled(False)
60 self.__previewButton = self.buttonBox.addButton(
61 self.tr("Preview"), QDialogButtonBox.ActionRole)
62 self.__previewButton.setDefault(True)
63
64 self.moveStackWidget.setCurrentIndex(0)
65
66 self.__moveType = ""
67
68 if offset is None:
69 # it is a 'move module' refactoring, no need to determine
70 # the move type via the client
71 self.__processMoveType({"Kind": "move_module"})
72 else:
73 self._refactoring.sendJson("RequestMoveType", {
74 "ChangeGroup": self._changeGroupName,
75 "Title": self._title,
76 "FileName": self.__filename,
77 "Offset": self.__offset,
78 })
79
80 def __processMoveType(self, data):
81 """
82 Private method to process the move type data sent by the refactoring
83 client in order to polish the dialog.
84
85 @param data dictionary containing the move type data
86 @type dict
87 """
88 self.__moveType = data["Kind"]
89
90 if self.__moveType == "move_method":
91 self.setWindowTitle(self.tr("Move Method"))
92 self.moveStackWidget.setCurrentIndex(1)
93 self.methodEdit.setText(data["Method"])
94 self.methodEdit.selectAll()
95 elif self.__moveType == "move_global_method":
96 self.setWindowTitle(self.tr("Move Global Method"))
97 self.moveStackWidget.setCurrentIndex(2)
98 self.destinationLabel.setText(self.tr("Destination Module:"))
99 self.destinationEdit.setToolTip(self.tr(
100 "Enter the destination module for the method"))
101 self.selectButton.setToolTip(self.tr(
102 "Select the destination module via a file selection dialog"))
103 elif self.__moveType == "move_module":
104 self.setWindowTitle(self.tr("Move Module"))
105 self.moveStackWidget.setCurrentIndex(2)
106 self.destinationLabel.setText(self.tr("Destination Package:"))
107 self.destinationEdit.setToolTip(self.tr(
108 "Enter the destination package for the module"))
109 self.selectButton.setToolTip(self.tr(
110 "Select the destination package via a directory selection"
111 " dialog"))
112 else:
113 self.setWindowTitle(self.tr("Move"))
114 self.moveStackWidget.setCurrentIndex(0)
115
116 self.__updateUI()
117
118 msh = self.minimumSizeHint()
119 self.resize(max(self.width(), msh.width()), msh.height())
120
121 @pyqtSlot(str)
122 def on_attributeEdit_textChanged(self, text):
123 """
124 Private slot to react to changes of the attribute.
125
126 @param text text entered into the edit
127 @type str
128 """
129 self.__updateUI()
130
131 @pyqtSlot(str)
132 def on_methodEdit_textChanged(self, text):
133 """
134 Private slot to react to changes of the method.
135
136 @param text text entered into the edit
137 @type str
138 """
139 self.__updateUI()
140
141 @pyqtSlot(str)
142 def on_destinationEdit_textChanged(self, text):
143 """
144 Private slot to react to changes of the destination module.
145
146 @param text text entered into the edit
147 @type str
148 """
149 self.__updateUI()
150
151 def __updateUI(self):
152 """
153 Private method to perform various UI updates.
154 """
155 if self.__moveType == "move_method":
156 enable = self.attributeEdit.text() != "" and \
157 self.methodEdit.text() != ""
158 elif self.__moveType in ["move_global_method", "move_module"]:
159 enable = self.destinationEdit.text() != ""
160 else:
161 enable = False
162
163 self.__okButton.setEnabled(enable)
164 self.__previewButton.setEnabled(enable)
165
166 @pyqtSlot()
167 def on_selectButton_clicked(self):
168 """
169 Private slot called to select the destination module via a file
170 selection dialog.
171 """
172 dest = self.destinationEdit.text()
173 if not dest:
174 dest = self.__project.getProjectPath()
175 elif not os.path.isabs(dest):
176 dest = os.path.join(self.__project.getProjectPath(), dest)
177 if self.__moveType == "move_global_method":
178 destination = E5FileDialog.getOpenFileName(
179 self,
180 self.windowTitle(),
181 dest,
182 self.tr("Python Files (*.py *.py2 *.py3);;All Files (*)"))
183 else:
184 # move_module
185 destination = E5FileDialog.getExistingDirectory(
186 self,
187 self.windowTitle(),
188 dest)
189
190 if destination:
191 destination = Utilities.toNativeSeparators(destination)
192 if not self.__project.startswithProjectPath(destination):
193 if self.__moveType == "move_global_method":
194 errorMessage = self.tr("""The selected module must be """
195 """inside the project.""")
196 else:
197 # move_module
198 errorMessage = self.tr("""The selected directory must"""
199 """ be inside the project.""")
200 E5MessageBox.critical(
201 self,
202 self.windowTitle(),
203 errorMessage)
204 return
205
206 if self.__moveType == "move_global_method":
207 if not os.path.exists(destination):
208 E5MessageBox.critical(
209 self,
210 self.windowTitle(),
211 self.tr("""The selected module <b>{0}</b> does"""
212 """ not exist.""").format(destination))
213 return
214 else:
215 # move_module
216 if not os.path.exists(
217 os.path.join(destination, "__init__.py")):
218 E5MessageBox.critical(
219 self,
220 self.windowTitle(),
221 self.tr("""The selected directory <b>{0}</b> is"""
222 """ not a package.""").format(destination))
223 return
224
225 destination = self.__project.getRelativePath(destination)
226 self.destinationEdit.setText(destination)
227
228 def __checkDestination(self):
229 """
230 Private method to check the destination entered.
231
232 @return flag indicating a valid entry (boolean)
233 """
234 destination = os.path.join(
235 self.__project.getProjectPath(),
236 self.destinationEdit.text())
237 if self.__moveType == "move_global_method":
238 if not os.path.exists(destination):
239 E5MessageBox.critical(
240 self,
241 self.windowTitle(),
242 self.tr("""The selected module <b>{0}</b> does"""
243 """ not exist.""").format(destination))
244 return False
245 else:
246 # move_module
247 if not os.path.exists(os.path.join(destination, "__init__.py")):
248 E5MessageBox.critical(
249 self,
250 self.windowTitle(),
251 self.tr("""The selected directory <b>{0}</b> is"""
252 """ not a package.""").format(destination))
253 return False
254
255 return True
256
257 @pyqtSlot(QAbstractButton)
258 def on_buttonBox_clicked(self, button):
259 """
260 Private slot to act on the button pressed.
261
262 @param button reference to the button pressed
263 @type QAbstractButton
264 """
265 if self.__moveType == "move_method" or (
266 self.__moveType in ["move_global_method", "move_module"] and
267 self.__checkDestination()):
268 if button == self.__previewButton:
269 self.requestPreview()
270 elif button == self.__okButton:
271 self.applyChanges()
272
273 def _calculateChanges(self):
274 """
275 Protected method to initiate the calculation of the changes.
276 """
277 newName = self.methodEdit.text()
278 if not newName:
279 newName = None
280
281 self._refactoring.sendJson("CalculateMoveChanges", {
282 "ChangeGroup": self._changeGroupName,
283 "Title": self.windowTitle(),
284 "FileName": self.__filename,
285 "Offset": self.__offset,
286 "Kind": self.__moveType,
287 "NewName": newName,
288 "Attribute": self.attributeEdit.text(),
289 "DestinationModule": self.destinationEdit.text(),
290 })
291
292 def processChangeData(self, data):
293 """
294 Public method to process the change data sent by the refactoring
295 client.
296
297 @param data dictionary containing the change data
298 @type dict
299 """
300 subcommand = data["Subcommand"]
301 if subcommand == "MoveType":
302 self.__processMoveType(data)
303 else:
304 # pass on to base class
305 RefactoringDialogBase.processChangeData(self, data)

eric ide

mercurial