UI/DiffDialog.py

changeset 3012
d177226027e2
parent 2965
d133c7edd88a
child 3020
542e97d4ecb3
child 3057
10516539f238
equal deleted inserted replaced
3011:18292228c724 3012:d177226027e2
131 by time.ctime(). If not specified, the strings default to blanks. 131 by time.ctime(). If not specified, the strings default to blanks.
132 132
133 Example: 133 Example:
134 134
135 <pre> 135 <pre>
136 &gt;&gt;&gt; print ''.join(context_diff('one\ntwo\nthree\nfour\n'.splitlines(1), 136 &gt;&gt;&gt; print ''.join(
137 ... context_diff('one\ntwo\nthree\nfour\n'.splitlines(1),
137 ... 'zero\none\ntree\nfour\n'.splitlines(1), 'Original', 'Current', 138 ... 'zero\none\ntree\nfour\n'.splitlines(1), 'Original', 'Current',
138 ... 'Sat Jan 26 23:30:50 1991', 'Fri Jun 06 10:22:46 2003')), 139 ... 'Sat Jan 26 23:30:50 1991', 'Fri Jun 06 10:22:46 2003')),
139 *** Original Sat Jan 26 23:30:50 1991 140 *** Original Sat Jan 26 23:30:50 1991
140 --- Current Fri Jun 06 10:22:46 2003 141 --- Current Fri Jun 06 10:22:46 2003
141 *************** 142 ***************
160 @param n number of lines of context (integer) 161 @param n number of lines of context (integer)
161 @param lineterm line termination string (string) 162 @param lineterm line termination string (string)
162 @return a generator yielding lines of differences 163 @return a generator yielding lines of differences
163 """ 164 """
164 started = False 165 started = False
165 prefixmap = {'insert': '+ ', 'delete': '- ', 'replace': '! ', 'equal': ' '} 166 prefixmap = {'insert': '+ ', 'delete': '- ', 'replace': '! ',
167 'equal': ' '}
166 for group in SequenceMatcher(None, a, b).get_grouped_opcodes(n): 168 for group in SequenceMatcher(None, a, b).get_grouped_opcodes(n):
167 if not started: 169 if not started:
168 yield '*** {0}\t{1}{2}'.format(fromfile, fromfiledate, lineterm) 170 yield '*** {0}\t{1}{2}'.format(fromfile, fromfiledate, lineterm)
169 yield '--- {0}\t{1}{2}'.format(tofile, tofiledate, lineterm) 171 yield '--- {0}\t{1}{2}'.format(tofile, tofiledate, lineterm)
170 started = True 172 started = True
171 173
172 yield '***************{0}'.format(lineterm) 174 yield '***************{0}'.format(lineterm)
173 if group[-1][2] - group[0][1] >= 2: 175 if group[-1][2] - group[0][1] >= 2:
174 yield '*** {0:d},{1:d} ****{2}'.format(group[0][1] + 1, group[-1][2], lineterm) 176 yield '*** {0:d},{1:d} ****{2}'.format(
177 group[0][1] + 1, group[-1][2], lineterm)
175 else: 178 else:
176 yield '*** {0:d} ****{1}'.format(group[-1][2], lineterm) 179 yield '*** {0:d} ****{1}'.format(group[-1][2], lineterm)
177 visiblechanges = [e for e in group if e[0] in ('replace', 'delete')] 180 visiblechanges = [e for e in group if e[0] in ('replace', 'delete')]
178 if visiblechanges: 181 if visiblechanges:
179 for tag, i1, i2, _, _ in group: 182 for tag, i1, i2, _, _ in group:
180 if tag != 'insert': 183 if tag != 'insert':
181 for line in a[i1:i2]: 184 for line in a[i1:i2]:
182 yield prefixmap[tag] + line 185 yield prefixmap[tag] + line
183 186
184 if group[-1][4] - group[0][3] >= 2: 187 if group[-1][4] - group[0][3] >= 2:
185 yield '--- {0:d},{1:d} ----{2}'.format(group[0][3] + 1, group[-1][4], lineterm) 188 yield '--- {0:d},{1:d} ----{2}'.format(
189 group[0][3] + 1, group[-1][4], lineterm)
186 else: 190 else:
187 yield '--- {0:d} ----{1}'.format(group[-1][4], lineterm) 191 yield '--- {0:d} ----{1}'.format(group[-1][4], lineterm)
188 visiblechanges = [e for e in group if e[0] in ('replace', 'insert')] 192 visiblechanges = [e for e in group if e[0] in ('replace', 'insert')]
189 if visiblechanges: 193 if visiblechanges:
190 for tag, _, _, j1, j2 in group: 194 for tag, _, _, j1, j2 in group:
207 self.setupUi(self) 211 self.setupUi(self)
208 212
209 self.file1Completer = E5FileCompleter(self.file1Edit) 213 self.file1Completer = E5FileCompleter(self.file1Edit)
210 self.file2Completer = E5FileCompleter(self.file2Edit) 214 self.file2Completer = E5FileCompleter(self.file2Edit)
211 215
212 self.diffButton = \ 216 self.diffButton = self.buttonBox.addButton(
213 self.buttonBox.addButton(self.trUtf8("Compare"), QDialogButtonBox.ActionRole) 217 self.trUtf8("Compare"), QDialogButtonBox.ActionRole)
214 self.diffButton.setToolTip( 218 self.diffButton.setToolTip(
215 self.trUtf8("Press to perform the comparison of the two files")) 219 self.trUtf8("Press to perform the comparison of the two files"))
216 self.saveButton = \ 220 self.saveButton = self.buttonBox.addButton(
217 self.buttonBox.addButton(self.trUtf8("Save"), QDialogButtonBox.ActionRole) 221 self.trUtf8("Save"), QDialogButtonBox.ActionRole)
218 self.saveButton.setToolTip(self.trUtf8("Save the output to a patch file")) 222 self.saveButton.setToolTip(
223 self.trUtf8("Save the output to a patch file"))
219 self.diffButton.setEnabled(False) 224 self.diffButton.setEnabled(False)
220 self.saveButton.setEnabled(False) 225 self.saveButton.setEnabled(False)
221 self.diffButton.setDefault(True) 226 self.diffButton.setDefault(True)
222 227
223 self.filename1 = '' 228 self.filename1 = ''
311 f.write(txt) 316 f.write(txt)
312 except UnicodeError: 317 except UnicodeError:
313 pass 318 pass
314 f.close() 319 f.close()
315 except IOError as why: 320 except IOError as why:
316 E5MessageBox.critical(self, self.trUtf8('Save Diff'), 321 E5MessageBox.critical(
317 self.trUtf8('<p>The patch file <b>{0}</b> could not be saved.<br />' 322 self, self.trUtf8('Save Diff'),
318 'Reason: {1}</p>') 323 self.trUtf8(
319 .format(fname, str(why))) 324 '<p>The patch file <b>{0}</b> could not be saved.<br />'
325 'Reason: {1}</p>').format(fname, str(why)))
320 326
321 @pyqtSlot() 327 @pyqtSlot()
322 def on_diffButton_clicked(self): 328 def on_diffButton_clicked(self):
323 """ 329 """
324 Private slot to handle the Compare button press. 330 Private slot to handle the Compare button press.
333 lines1 = f1.readlines() 339 lines1 = f1.readlines()
334 f1.close() 340 f1.close()
335 except IOError: 341 except IOError:
336 E5MessageBox.critical(self, 342 E5MessageBox.critical(self,
337 self.trUtf8("Compare Files"), 343 self.trUtf8("Compare Files"),
338 self.trUtf8("""<p>The file <b>{0}</b> could not be read.</p>""") 344 self.trUtf8(
345 """<p>The file <b>{0}</b> could not be read.</p>""")
339 .format(self.filename1)) 346 .format(self.filename1))
340 return 347 return
341 348
342 self.filename2 = Utilities.toNativeSeparators(self.file2Edit.text()) 349 self.filename2 = Utilities.toNativeSeparators(self.file2Edit.text())
343 try: 350 try:
349 lines2 = f2.readlines() 356 lines2 = f2.readlines()
350 f2.close() 357 f2.close()
351 except IOError: 358 except IOError:
352 E5MessageBox.critical(self, 359 E5MessageBox.critical(self,
353 self.trUtf8("Compare Files"), 360 self.trUtf8("Compare Files"),
354 self.trUtf8("""<p>The file <b>{0}</b> could not be read.</p>""") 361 self.trUtf8(
362 """<p>The file <b>{0}</b> could not be read.</p>""")
355 .format(self.filename2)) 363 .format(self.filename2))
356 return 364 return
357 365
358 self.contents.clear() 366 self.contents.clear()
359 self.saveButton.setEnabled(False) 367 self.saveButton.setEnabled(False)
360 368
361 if self.unifiedRadioButton.isChecked(): 369 if self.unifiedRadioButton.isChecked():
362 self.__generateUnifiedDiff(lines1, lines2, self.filename1, self.filename2, 370 self.__generateUnifiedDiff(
363 filemtime1, filemtime2) 371 lines1, lines2, self.filename1, self.filename2,
372 filemtime1, filemtime2)
364 else: 373 else:
365 self.__generateContextDiff(lines1, lines2, self.filename1, self.filename2, 374 self.__generateContextDiff(
366 filemtime1, filemtime2) 375 lines1, lines2, self.filename1, self.filename2,
376 filemtime1, filemtime2)
367 377
368 tc = self.contents.textCursor() 378 tc = self.contents.textCursor()
369 tc.movePosition(QTextCursor.Start) 379 tc.movePosition(QTextCursor.Start)
370 self.contents.setTextCursor(tc) 380 self.contents.setTextCursor(tc)
371 self.contents.ensureCursorVisible() 381 self.contents.ensureCursorVisible()
412 paras += 1 422 paras += 1
413 if not (paras % self.updateInterval): 423 if not (paras % self.updateInterval):
414 QApplication.processEvents() 424 QApplication.processEvents()
415 425
416 if paras == 0: 426 if paras == 0:
417 self.__appendText(self.trUtf8('There is no difference.'), self.cNormalFormat) 427 self.__appendText(
428 self.trUtf8('There is no difference.'), self.cNormalFormat)
418 429
419 def __generateContextDiff(self, a, b, fromfile, tofile, 430 def __generateContextDiff(self, a, b, fromfile, tofile,
420 fromfiledate, tofiledate): 431 fromfiledate, tofiledate):
421 """ 432 """
422 Private slot to generate a context diff output. 433 Private slot to generate a context diff output.
435 format = self.cAddedFormat 446 format = self.cAddedFormat
436 elif line.startswith('- '): 447 elif line.startswith('- '):
437 format = self.cRemovedFormat 448 format = self.cRemovedFormat
438 elif line.startswith('! '): 449 elif line.startswith('! '):
439 format = self.cReplacedFormat 450 format = self.cReplacedFormat
440 elif (line.startswith('*** ') or line.startswith('--- ')) and paras > 1: 451 elif (line.startswith('*** ') or line.startswith('--- ')) and \
452 paras > 1:
441 format = self.cLineNoFormat 453 format = self.cLineNoFormat
442 else: 454 else:
443 format = self.cNormalFormat 455 format = self.cNormalFormat
444 self.__appendText(line, format) 456 self.__appendText(line, format)
445 paras += 1 457 paras += 1
446 if not (paras % self.updateInterval): 458 if not (paras % self.updateInterval):
447 QApplication.processEvents() 459 QApplication.processEvents()
448 460
449 if paras == 0: 461 if paras == 0:
450 self.__appendText(self.trUtf8('There is no difference.'), self.cNormalFormat) 462 self.__appendText(
463 self.trUtf8('There is no difference.'), self.cNormalFormat)
451 464
452 def __fileChanged(self): 465 def __fileChanged(self):
453 """ 466 """
454 Private slot to enable/disable the Compare button. 467 Private slot to enable/disable the Compare button.
455 """ 468 """
500 513
501 @param parent reference to the parent widget (QWidget) 514 @param parent reference to the parent widget (QWidget)
502 """ 515 """
503 super().__init__(parent) 516 super().__init__(parent)
504 517
505 self.setStyle(Preferences.getUI("Style"), Preferences.getUI("StyleSheet")) 518 self.setStyle(Preferences.getUI("Style"),
519 Preferences.getUI("StyleSheet"))
506 520
507 self.cw = DiffDialog(self) 521 self.cw = DiffDialog(self)
508 self.cw.installEventFilter(self) 522 self.cw.installEventFilter(self)
509 size = self.cw.size() 523 size = self.cw.size()
510 self.setCentralWidget(self.cw) 524 self.setCentralWidget(self.cw)

eric ide

mercurial