src/eric7/Plugins/VcsPlugins/vcsPySvn/SvnDiffDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
33 33
34 class SvnDiffDialog(QWidget, SvnDialogMixin, Ui_SvnDiffDialog): 34 class SvnDiffDialog(QWidget, SvnDialogMixin, Ui_SvnDiffDialog):
35 """ 35 """
36 Class implementing a dialog to show the output of the svn diff command. 36 Class implementing a dialog to show the output of the svn diff command.
37 """ 37 """
38
38 def __init__(self, vcs, parent=None): 39 def __init__(self, vcs, parent=None):
39 """ 40 """
40 Constructor 41 Constructor
41 42
42 @param vcs reference to the vcs object 43 @param vcs reference to the vcs object
43 @param parent parent widget (QWidget) 44 @param parent parent widget (QWidget)
44 """ 45 """
45 super().__init__(parent) 46 super().__init__(parent)
46 self.setupUi(self) 47 self.setupUi(self)
47 SvnDialogMixin.__init__(self) 48 SvnDialogMixin.__init__(self)
48 49
49 self.refreshButton = self.buttonBox.addButton( 50 self.refreshButton = self.buttonBox.addButton(
50 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole) 51 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole
51 self.refreshButton.setToolTip( 52 )
52 self.tr("Press to refresh the display")) 53 self.refreshButton.setToolTip(self.tr("Press to refresh the display"))
53 self.refreshButton.setEnabled(False) 54 self.refreshButton.setEnabled(False)
54 self.buttonBox.button( 55 self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setEnabled(False)
55 QDialogButtonBox.StandardButton.Save).setEnabled(False) 56 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
56 self.buttonBox.button( 57 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
57 QDialogButtonBox.StandardButton.Close).setEnabled(False) 58
58 self.buttonBox.button(
59 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
60
61 self.searchWidget.attachTextEdit(self.contents) 59 self.searchWidget.attachTextEdit(self.contents)
62 60
63 self.vcs = vcs 61 self.vcs = vcs
64 62
65 font = Preferences.getEditorOtherFonts("MonospacedFont") 63 font = Preferences.getEditorOtherFonts("MonospacedFont")
66 self.contents.document().setDefaultFont(font) 64 self.contents.document().setDefaultFont(font)
67 65
68 self.highlighter = SvnDiffHighlighter(self.contents.document()) 66 self.highlighter = SvnDiffHighlighter(self.contents.document())
69 67
70 self.client = self.vcs.getClient() 68 self.client = self.vcs.getClient()
71 self.client.callback_cancel = self._clientCancelCallback 69 self.client.callback_cancel = self._clientCancelCallback
72 self.client.callback_get_login = self._clientLoginCallback 70 self.client.callback_get_login = self._clientLoginCallback
73 self.client.callback_ssl_server_trust_prompt = ( 71 self.client.callback_ssl_server_trust_prompt = (
74 self._clientSslServerTrustPromptCallback 72 self._clientSslServerTrustPromptCallback
75 ) 73 )
76 74
77 def __getVersionArg(self, version): 75 def __getVersionArg(self, version):
78 """ 76 """
79 Private method to get a pysvn revision object for the given version 77 Private method to get a pysvn revision object for the given version
80 number. 78 number.
81 79
82 @param version revision (integer or string) 80 @param version revision (integer or string)
83 @return revision object (pysvn.Revision) 81 @return revision object (pysvn.Revision)
84 """ 82 """
85 if isinstance(version, int): 83 if isinstance(version, int):
86 return pysvn.Revision(pysvn.opt_revision_kind.number, version) 84 return pysvn.Revision(pysvn.opt_revision_kind.number, version)
87 elif version.startswith("{"): 85 elif version.startswith("{"):
88 dateStr = version[1:-1] 86 dateStr = version[1:-1]
89 secs = QDateTime.fromString( 87 secs = QDateTime.fromString(dateStr, Qt.DateFormat.ISODate).toTime_t()
90 dateStr, Qt.DateFormat.ISODate).toTime_t()
91 return pysvn.Revision(pysvn.opt_revision_kind.date, secs) 88 return pysvn.Revision(pysvn.opt_revision_kind.date, secs)
92 else: 89 else:
93 return { 90 return {
94 "HEAD": pysvn.Revision(pysvn.opt_revision_kind.head), 91 "HEAD": pysvn.Revision(pysvn.opt_revision_kind.head),
95 "COMMITTED": pysvn.Revision(pysvn.opt_revision_kind.committed), 92 "COMMITTED": pysvn.Revision(pysvn.opt_revision_kind.committed),
96 "BASE": pysvn.Revision(pysvn.opt_revision_kind.base), 93 "BASE": pysvn.Revision(pysvn.opt_revision_kind.base),
97 "WORKING": pysvn.Revision(pysvn.opt_revision_kind.working), 94 "WORKING": pysvn.Revision(pysvn.opt_revision_kind.working),
98 "PREV": pysvn.Revision(pysvn.opt_revision_kind.previous), 95 "PREV": pysvn.Revision(pysvn.opt_revision_kind.previous),
99 }.get(version, pysvn.Revision(pysvn.opt_revision_kind.unspecified)) 96 }.get(version, pysvn.Revision(pysvn.opt_revision_kind.unspecified))
100 97
101 def __getDiffSummaryKind(self, summaryKind): 98 def __getDiffSummaryKind(self, summaryKind):
102 """ 99 """
103 Private method to get a string descripion of the diff summary. 100 Private method to get a string descripion of the diff summary.
104 101
105 @param summaryKind (pysvn.diff_summarize.summarize_kind) 102 @param summaryKind (pysvn.diff_summarize.summarize_kind)
106 @return one letter string indicating the change type (string) 103 @return one letter string indicating the change type (string)
107 """ 104 """
108 if summaryKind == pysvn.diff_summarize_kind.delete: 105 if summaryKind == pysvn.diff_summarize_kind.delete:
109 return "D" 106 return "D"
113 return "A" 110 return "A"
114 elif summaryKind == pysvn.diff_summarize_kind.normal: 111 elif summaryKind == pysvn.diff_summarize_kind.normal:
115 return "N" 112 return "N"
116 else: 113 else:
117 return " " 114 return " "
118 115
119 def start(self, fn, versions=None, urls=None, summary=False, pegRev=None, 116 def start(
120 refreshable=False): 117 self,
118 fn,
119 versions=None,
120 urls=None,
121 summary=False,
122 pegRev=None,
123 refreshable=False,
124 ):
121 """ 125 """
122 Public slot to start the svn diff command. 126 Public slot to start the svn diff command.
123 127
124 @param fn filename to be diffed (string) 128 @param fn filename to be diffed (string)
125 @param versions list of versions to be diffed (list of up to 2 integer 129 @param versions list of versions to be diffed (list of up to 2 integer
126 or None) 130 or None)
127 @param urls list of repository URLs (list of 2 strings) 131 @param urls list of repository URLs (list of 2 strings)
128 @param summary flag indicating a summarizing diff 132 @param summary flag indicating a summarizing diff
129 (only valid for URL diffs) (boolean) 133 (only valid for URL diffs) (boolean)
130 @param pegRev revision number the filename is valid (integer) 134 @param pegRev revision number the filename is valid (integer)
131 @param refreshable flag indicating a refreshable diff (boolean) 135 @param refreshable flag indicating a refreshable diff (boolean)
132 """ 136 """
133 self.refreshButton.setVisible(refreshable) 137 self.refreshButton.setVisible(refreshable)
134 138
135 self.buttonBox.button( 139 self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setEnabled(False)
136 QDialogButtonBox.StandardButton.Save).setEnabled(False) 140 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
137 self.buttonBox.button( 141 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
138 QDialogButtonBox.StandardButton.Close).setEnabled(False) 142 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
139 self.buttonBox.button( 143
140 QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
141 self.buttonBox.button(
142 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
143
144 self._reset() 144 self._reset()
145 self.errorGroup.hide() 145 self.errorGroup.hide()
146 146
147 self.filename = fn 147 self.filename = fn
148 148
149 self.contents.clear() 149 self.contents.clear()
150 self.highlighter.regenerateRules() 150 self.highlighter.regenerateRules()
151 self.paras = 0 151 self.paras = 0
152 152
153 self.filesCombo.clear() 153 self.filesCombo.clear()
154 154
155 self.__oldFile = "" 155 self.__oldFile = ""
156 self.__oldFileLine = -1 156 self.__oldFileLine = -1
157 self.__fileSeparators = [] 157 self.__fileSeparators = []
158 158
159 if Utilities.hasEnvironmentEntry('TEMP'): 159 if Utilities.hasEnvironmentEntry("TEMP"):
160 tmpdir = Utilities.getEnvironmentEntry('TEMP') 160 tmpdir = Utilities.getEnvironmentEntry("TEMP")
161 elif Utilities.hasEnvironmentEntry('TMPDIR'): 161 elif Utilities.hasEnvironmentEntry("TMPDIR"):
162 tmpdir = Utilities.getEnvironmentEntry('TMPDIR') 162 tmpdir = Utilities.getEnvironmentEntry("TMPDIR")
163 elif Utilities.hasEnvironmentEntry('TMP'): 163 elif Utilities.hasEnvironmentEntry("TMP"):
164 tmpdir = Utilities.getEnvironmentEntry('TMP') 164 tmpdir = Utilities.getEnvironmentEntry("TMP")
165 elif os.path.exists('/var/tmp'): # secok 165 elif os.path.exists("/var/tmp"): # secok
166 tmpdir = '/var/tmp' # secok 166 tmpdir = "/var/tmp" # secok
167 elif os.path.exists('/usr/tmp'): 167 elif os.path.exists("/usr/tmp"):
168 tmpdir = '/usr/tmp' 168 tmpdir = "/usr/tmp"
169 elif os.path.exists('/tmp'): # secok 169 elif os.path.exists("/tmp"): # secok
170 tmpdir = '/tmp' # secok 170 tmpdir = "/tmp" # secok
171 else: 171 else:
172 EricMessageBox.critical( 172 EricMessageBox.critical(
173 self, 173 self,
174 self.tr("Subversion Diff"), 174 self.tr("Subversion Diff"),
175 self.tr("""There is no temporary directory available.""")) 175 self.tr("""There is no temporary directory available."""),
176 )
176 return 177 return
177 178
178 tmpdir = os.path.join(tmpdir, 'svn_tmp') 179 tmpdir = os.path.join(tmpdir, "svn_tmp")
179 if not os.path.exists(tmpdir): 180 if not os.path.exists(tmpdir):
180 os.mkdir(tmpdir) 181 os.mkdir(tmpdir)
181 182
182 opts = self.vcs.options['global'] + self.vcs.options['diff'] 183 opts = self.vcs.options["global"] + self.vcs.options["diff"]
183 recurse = "--non-recursive" not in opts 184 recurse = "--non-recursive" not in opts
184 185
185 if versions is not None: 186 if versions is not None:
186 self.raise_() 187 self.raise_()
187 self.activateWindow() 188 self.activateWindow()
188 rev1 = self.__getVersionArg(versions[0]) 189 rev1 = self.__getVersionArg(versions[0])
189 if len(versions) == 1: 190 if len(versions) == 1:
191 else: 192 else:
192 rev2 = self.__getVersionArg(versions[1]) 193 rev2 = self.__getVersionArg(versions[1])
193 else: 194 else:
194 rev1 = self.__getVersionArg("BASE") 195 rev1 = self.__getVersionArg("BASE")
195 rev2 = self.__getVersionArg("WORKING") 196 rev2 = self.__getVersionArg("WORKING")
196 197
197 if urls is not None: 198 if urls is not None:
198 rev1 = self.__getVersionArg("HEAD") 199 rev1 = self.__getVersionArg("HEAD")
199 rev2 = self.__getVersionArg("HEAD") 200 rev2 = self.__getVersionArg("HEAD")
200 201
201 if isinstance(fn, list): 202 if isinstance(fn, list):
202 dname, fnames = self.vcs.splitPathList(fn) 203 dname, fnames = self.vcs.splitPathList(fn)
203 else: 204 else:
204 dname, fname = self.vcs.splitPath(fn) 205 dname, fname = self.vcs.splitPath(fn)
205 fnames = [fname] 206 fnames = [fname]
206 207
207 with EricOverrideCursor(): 208 with EricOverrideCursor():
208 cwd = os.getcwd() 209 cwd = os.getcwd()
209 os.chdir(dname) 210 os.chdir(dname)
210 try: 211 try:
211 dname = ericApp().getObject('Project').getRelativePath(dname) 212 dname = ericApp().getObject("Project").getRelativePath(dname)
212 if dname: 213 if dname:
213 dname += "/" 214 dname += "/"
214 with EricMutexLocker(self.vcs.vcsExecutionMutex): 215 with EricMutexLocker(self.vcs.vcsExecutionMutex):
215 for name in fnames: 216 for name in fnames:
216 self.__showError( 217 self.__showError(
217 self.tr("Processing file '{0}'...\n").format(name)) 218 self.tr("Processing file '{0}'...\n").format(name)
219 )
218 if urls is not None: 220 if urls is not None:
219 url1 = "{0}/{1}{2}".format(urls[0], dname, name) 221 url1 = "{0}/{1}{2}".format(urls[0], dname, name)
220 url2 = "{0}/{1}{2}".format(urls[1], dname, name) 222 url2 = "{0}/{1}{2}".format(urls[1], dname, name)
221 if summary: 223 if summary:
222 diff_summary = self.client.diff_summarize( 224 diff_summary = self.client.diff_summarize(
223 url1, revision1=rev1, 225 url1,
224 url_or_path2=url2, revision2=rev2, 226 revision1=rev1,
225 recurse=recurse) 227 url_or_path2=url2,
228 revision2=rev2,
229 recurse=recurse,
230 )
226 diff_list = [] 231 diff_list = []
227 for diff_sum in diff_summary: 232 for diff_sum in diff_summary:
228 path = diff_sum['path'] 233 path = diff_sum["path"]
229 diff_list.append("{0} {1}".format( 234 diff_list.append(
230 self.__getDiffSummaryKind( 235 "{0} {1}".format(
231 diff_sum['summarize_kind']), 236 self.__getDiffSummaryKind(
232 path)) 237 diff_sum["summarize_kind"]
238 ),
239 path,
240 )
241 )
233 diffText = os.linesep.join(diff_list) 242 diffText = os.linesep.join(diff_list)
234 else: 243 else:
235 diffText = self.client.diff( 244 diffText = self.client.diff(
236 tmpdir, 245 tmpdir,
237 url1, revision1=rev1, 246 url1,
238 url_or_path2=url2, revision2=rev2, 247 revision1=rev1,
239 recurse=recurse) 248 url_or_path2=url2,
249 revision2=rev2,
250 recurse=recurse,
251 )
240 else: 252 else:
241 if pegRev is not None: 253 if pegRev is not None:
242 diffText = self.client.diff_peg( 254 diffText = self.client.diff_peg(
243 tmpdir, name, 255 tmpdir,
256 name,
244 peg_revision=self.__getVersionArg(pegRev), 257 peg_revision=self.__getVersionArg(pegRev),
245 revision_start=rev1, revision_end=rev2, 258 revision_start=rev1,
246 recurse=recurse) 259 revision_end=rev2,
260 recurse=recurse,
261 )
247 else: 262 else:
248 diffText = self.client.diff( 263 diffText = self.client.diff(
249 tmpdir, name, 264 tmpdir,
250 revision1=rev1, revision2=rev2, 265 name,
251 recurse=recurse) 266 revision1=rev1,
267 revision2=rev2,
268 recurse=recurse,
269 )
252 for counter, line in enumerate(diffText.splitlines()): 270 for counter, line in enumerate(diffText.splitlines()):
253 if ( 271 if line.startswith("--- ") or line.startswith("+++ "):
254 line.startswith("--- ") or
255 line.startswith("+++ ")
256 ):
257 self.__processFileLine(line) 272 self.__processFileLine(line)
258 273
259 self.__appendText( 274 self.__appendText("{0}{1}".format(line, os.linesep))
260 "{0}{1}".format(line, os.linesep)) 275 if counter % 30 == 0 and self._clientCancelCallback():
261 if (
262 counter % 30 == 0 and
263 self._clientCancelCallback()
264 ):
265 # check for cancel every 30 lines 276 # check for cancel every 30 lines
266 break 277 break
267 if self._clientCancelCallback(): 278 if self._clientCancelCallback():
268 break 279 break
269 except pysvn.ClientError as e: 280 except pysvn.ClientError as e:
270 self.__showError(e.args[0]) 281 self.__showError(e.args[0])
271 os.chdir(cwd) 282 os.chdir(cwd)
272 self.__finish() 283 self.__finish()
273 284
274 if self.paras == 0: 285 if self.paras == 0:
275 self.contents.setPlainText(self.tr('There is no difference.')) 286 self.contents.setPlainText(self.tr("There is no difference."))
276 287
277 self.buttonBox.button( 288 self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setEnabled(
278 QDialogButtonBox.StandardButton.Save).setEnabled(self.paras > 0) 289 self.paras > 0
279 290 )
291
280 def __appendText(self, line): 292 def __appendText(self, line):
281 """ 293 """
282 Private method to append text to the end of the contents pane. 294 Private method to append text to the end of the contents pane.
283 295
284 @param line line of text to insert (string) 296 @param line line of text to insert (string)
285 """ 297 """
286 tc = self.contents.textCursor() 298 tc = self.contents.textCursor()
287 tc.movePosition(QTextCursor.MoveOperation.End) 299 tc.movePosition(QTextCursor.MoveOperation.End)
288 self.contents.setTextCursor(tc) 300 self.contents.setTextCursor(tc)
289 self.contents.insertPlainText(line) 301 self.contents.insertPlainText(line)
290 self.paras += 1 302 self.paras += 1
291 303
292 def __extractFileName(self, line): 304 def __extractFileName(self, line):
293 """ 305 """
294 Private method to extract the file name out of a file separator line. 306 Private method to extract the file name out of a file separator line.
295 307
296 @param line line to be processed (string) 308 @param line line to be processed (string)
297 @return extracted file name (string) 309 @return extracted file name (string)
298 """ 310 """
299 f = line.split(None, 1)[1] 311 f = line.split(None, 1)[1]
300 f = f.rsplit(None, 2)[0] 312 f = f.rsplit(None, 2)[0]
301 return f 313 return f
302 314
303 def __processFileLine(self, line): 315 def __processFileLine(self, line):
304 """ 316 """
305 Private slot to process a line giving the old/new file. 317 Private slot to process a line giving the old/new file.
306 318
307 @param line line to be processed (string) 319 @param line line to be processed (string)
308 """ 320 """
309 if line.startswith('---'): 321 if line.startswith("---"):
310 self.__oldFileLine = self.paras 322 self.__oldFileLine = self.paras
311 self.__oldFile = self.__extractFileName(line) 323 self.__oldFile = self.__extractFileName(line)
312 else: 324 else:
313 self.__fileSeparators.append( 325 self.__fileSeparators.append(
314 (self.__oldFile, self.__extractFileName(line), 326 (self.__oldFile, self.__extractFileName(line), self.__oldFileLine)
315 self.__oldFileLine)) 327 )
316 328
317 def __finish(self): 329 def __finish(self):
318 """ 330 """
319 Private slot called when the user pressed the button. 331 Private slot called when the user pressed the button.
320 """ 332 """
321 self.refreshButton.setEnabled(True) 333 self.refreshButton.setEnabled(True)
322 self.buttonBox.button( 334 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
323 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) 335 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
324 self.buttonBox.button( 336 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
325 QDialogButtonBox.StandardButton.Close).setEnabled(True) 337 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
326 self.buttonBox.button( 338
327 QDialogButtonBox.StandardButton.Close).setEnabled(True)
328 self.buttonBox.button(
329 QDialogButtonBox.StandardButton.Close).setDefault(True)
330
331 tc = self.contents.textCursor() 339 tc = self.contents.textCursor()
332 tc.movePosition(QTextCursor.MoveOperation.Start) 340 tc.movePosition(QTextCursor.MoveOperation.Start)
333 self.contents.setTextCursor(tc) 341 self.contents.setTextCursor(tc)
334 self.contents.ensureCursorVisible() 342 self.contents.ensureCursorVisible()
335 343
336 self.filesCombo.addItem(self.tr("<Start>"), 0) 344 self.filesCombo.addItem(self.tr("<Start>"), 0)
337 self.filesCombo.addItem(self.tr("<End>"), -1) 345 self.filesCombo.addItem(self.tr("<End>"), -1)
338 for oldFile, newFile, pos in sorted(self.__fileSeparators): 346 for oldFile, newFile, pos in sorted(self.__fileSeparators):
339 if oldFile != newFile: 347 if oldFile != newFile:
340 self.filesCombo.addItem( 348 self.filesCombo.addItem("{0}\n{1}".format(oldFile, newFile), pos)
341 "{0}\n{1}".format(oldFile, newFile), pos)
342 else: 349 else:
343 self.filesCombo.addItem(oldFile, pos) 350 self.filesCombo.addItem(oldFile, pos)
344 351
345 self._cancel() 352 self._cancel()
346 353
347 def on_buttonBox_clicked(self, button): 354 def on_buttonBox_clicked(self, button):
348 """ 355 """
349 Private slot called by a button of the button box clicked. 356 Private slot called by a button of the button box clicked.
350 357
351 @param button button that was clicked (QAbstractButton) 358 @param button button that was clicked (QAbstractButton)
352 """ 359 """
353 if button == self.buttonBox.button( 360 if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
354 QDialogButtonBox.StandardButton.Close
355 ):
356 self.close() 361 self.close()
357 elif button == self.buttonBox.button( 362 elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel):
358 QDialogButtonBox.StandardButton.Cancel
359 ):
360 self.__finish() 363 self.__finish()
361 elif button == self.buttonBox.button( 364 elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Save):
362 QDialogButtonBox.StandardButton.Save
363 ):
364 self.on_saveButton_clicked() 365 self.on_saveButton_clicked()
365 elif button == self.refreshButton: 366 elif button == self.refreshButton:
366 self.on_refreshButton_clicked() 367 self.on_refreshButton_clicked()
367 368
368 @pyqtSlot(int) 369 @pyqtSlot(int)
369 def on_filesCombo_activated(self, index): 370 def on_filesCombo_activated(self, index):
370 """ 371 """
371 Private slot to handle the selection of a file. 372 Private slot to handle the selection of a file.
372 373
373 @param index activated row (integer) 374 @param index activated row (integer)
374 """ 375 """
375 para = self.filesCombo.itemData(index) 376 para = self.filesCombo.itemData(index)
376 377
377 if para == 0: 378 if para == 0:
378 tc = self.contents.textCursor() 379 tc = self.contents.textCursor()
379 tc.movePosition(QTextCursor.MoveOperation.Start) 380 tc.movePosition(QTextCursor.MoveOperation.Start)
380 self.contents.setTextCursor(tc) 381 self.contents.setTextCursor(tc)
381 self.contents.ensureCursorVisible() 382 self.contents.ensureCursorVisible()
388 # step 1: move cursor to end 389 # step 1: move cursor to end
389 tc = self.contents.textCursor() 390 tc = self.contents.textCursor()
390 tc.movePosition(QTextCursor.MoveOperation.End) 391 tc.movePosition(QTextCursor.MoveOperation.End)
391 self.contents.setTextCursor(tc) 392 self.contents.setTextCursor(tc)
392 self.contents.ensureCursorVisible() 393 self.contents.ensureCursorVisible()
393 394
394 # step 2: move cursor to desired line 395 # step 2: move cursor to desired line
395 tc = self.contents.textCursor() 396 tc = self.contents.textCursor()
396 delta = tc.blockNumber() - para 397 delta = tc.blockNumber() - para
397 tc.movePosition( 398 tc.movePosition(
398 QTextCursor.MoveOperation.PreviousBlock, 399 QTextCursor.MoveOperation.PreviousBlock,
399 QTextCursor.MoveMode.MoveAnchor, 400 QTextCursor.MoveMode.MoveAnchor,
400 delta) 401 delta,
402 )
401 self.contents.setTextCursor(tc) 403 self.contents.setTextCursor(tc)
402 self.contents.ensureCursorVisible() 404 self.contents.ensureCursorVisible()
403 405
404 @pyqtSlot() 406 @pyqtSlot()
405 def on_saveButton_clicked(self): 407 def on_saveButton_clicked(self):
406 """ 408 """
407 Private slot to handle the Save button press. 409 Private slot to handle the Save button press.
408 410
409 It saves the diff shown in the dialog to a file in the local 411 It saves the diff shown in the dialog to a file in the local
410 filesystem. 412 filesystem.
411 """ 413 """
412 if isinstance(self.filename, list): 414 if isinstance(self.filename, list):
413 if len(self.filename) > 1: 415 if len(self.filename) > 1:
414 fname = self.vcs.splitPathList(self.filename)[0] 416 fname = self.vcs.splitPathList(self.filename)[0]
415 else: 417 else:
416 dname, fname = self.vcs.splitPath(self.filename[0]) 418 dname, fname = self.vcs.splitPath(self.filename[0])
417 if fname != '.': 419 if fname != ".":
418 fname = "{0}.diff".format(self.filename[0]) 420 fname = "{0}.diff".format(self.filename[0])
419 else: 421 else:
420 fname = dname 422 fname = dname
421 else: 423 else:
422 fname = self.vcs.splitPath(self.filename)[0] 424 fname = self.vcs.splitPath(self.filename)[0]
423 425
424 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( 426 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
425 self, 427 self,
426 self.tr("Save Diff"), 428 self.tr("Save Diff"),
427 fname, 429 fname,
428 self.tr("Patch Files (*.diff)"), 430 self.tr("Patch Files (*.diff)"),
429 None, 431 None,
430 EricFileDialog.DontConfirmOverwrite) 432 EricFileDialog.DontConfirmOverwrite,
431 433 )
434
432 if not fname: 435 if not fname:
433 return # user aborted 436 return # user aborted
434 437
435 fpath = pathlib.Path(fname) 438 fpath = pathlib.Path(fname)
436 if not fpath.suffix: 439 if not fpath.suffix:
437 ex = selectedFilter.split("(*")[1].split(")")[0] 440 ex = selectedFilter.split("(*")[1].split(")")[0]
438 if ex: 441 if ex:
439 fpath = fpath.with_suffix(ex) 442 fpath = fpath.with_suffix(ex)
440 if fpath.exists(): 443 if fpath.exists():
441 res = EricMessageBox.yesNo( 444 res = EricMessageBox.yesNo(
442 self, 445 self,
443 self.tr("Save Diff"), 446 self.tr("Save Diff"),
444 self.tr("<p>The patch file <b>{0}</b> already exists." 447 self.tr(
445 " Overwrite it?</p>").format(fpath), 448 "<p>The patch file <b>{0}</b> already exists." " Overwrite it?</p>"
446 icon=EricMessageBox.Warning) 449 ).format(fpath),
450 icon=EricMessageBox.Warning,
451 )
447 if not res: 452 if not res:
448 return 453 return
449 454
450 eol = ericApp().getObject("Project").getEolString() 455 eol = ericApp().getObject("Project").getEolString()
451 try: 456 try:
452 with fpath.open("w", encoding="utf-8", newline="") as f: 457 with fpath.open("w", encoding="utf-8", newline="") as f:
453 f.write(eol.join(self.contents.toPlainText().splitlines())) 458 f.write(eol.join(self.contents.toPlainText().splitlines()))
454 except OSError as why: 459 except OSError as why:
455 EricMessageBox.critical( 460 EricMessageBox.critical(
456 self, self.tr('Save Diff'), 461 self,
462 self.tr("Save Diff"),
457 self.tr( 463 self.tr(
458 '<p>The patch file <b>{0}</b> could not be saved.' 464 "<p>The patch file <b>{0}</b> could not be saved."
459 '<br>Reason: {1}</p>') 465 "<br>Reason: {1}</p>"
460 .format(fpath, str(why))) 466 ).format(fpath, str(why)),
461 467 )
468
462 @pyqtSlot() 469 @pyqtSlot()
463 def on_refreshButton_clicked(self): 470 def on_refreshButton_clicked(self):
464 """ 471 """
465 Private slot to refresh the display. 472 Private slot to refresh the display.
466 """ 473 """
467 self.buttonBox.button( 474 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
468 QDialogButtonBox.StandardButton.Close).setEnabled(False) 475
469 476 self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setEnabled(False)
470 self.buttonBox.button(
471 QDialogButtonBox.StandardButton.Save).setEnabled(False)
472 self.refreshButton.setEnabled(False) 477 self.refreshButton.setEnabled(False)
473 478
474 self.start(self.filename, refreshable=True) 479 self.start(self.filename, refreshable=True)
475 480
476 def __showError(self, msg): 481 def __showError(self, msg):
477 """ 482 """
478 Private slot to show an error message. 483 Private slot to show an error message.
479 484
480 @param msg error message to show (string) 485 @param msg error message to show (string)
481 """ 486 """
482 self.errorGroup.show() 487 self.errorGroup.show()
483 self.errors.insertPlainText(msg) 488 self.errors.insertPlainText(msg)
484 self.errors.ensureCursorVisible() 489 self.errors.ensureCursorVisible()

eric ide

mercurial