src/eric7/UI/CompareDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
--- a/src/eric7/UI/CompareDialog.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/UI/CompareDialog.py	Wed Jul 13 14:55:47 2022 +0200
@@ -30,7 +30,7 @@
     """
     Compare two sequences of lines; generate the delta for display side by
     side.
-    
+
     @param a first sequence of lines (list of strings)
     @param b second sequence of lines (list of strings)
     @param linenumberwidth width (in characters) of the linenumbers (integer)
@@ -49,37 +49,49 @@
     def removeMarkers(line):
         """
         Internal function to remove all diff markers.
-        
+
         @param line line to work on (string)
         @return line without diff markers (string)
         """
         return (
-            line
-            .replace('\0+', "")
-            .replace('\0-', "")
-            .replace('\0^', "")
-            .replace('\1', "")
+            line.replace("\0+", "")
+            .replace("\0-", "")
+            .replace("\0^", "")
+            .replace("\1", "")
         )
 
     linenumberformat = "{{0:{0:d}d}}".format(linenumberwidth)
-    emptylineno = ' ' * linenumberwidth
-    
-    for (ln1, l1), (ln2, l2), flag in _mdiff(a, b, None, None,
-                                             IS_CHARACTER_JUNK):
+    emptylineno = " " * linenumberwidth
+
+    for (ln1, l1), (ln2, l2), flag in _mdiff(a, b, None, None, IS_CHARACTER_JUNK):
         if not flag:
-            yield ('e', linenumberformat.format(ln1), l1,
-                   linenumberformat.format(ln2), l2)
+            yield (
+                "e",
+                linenumberformat.format(ln1),
+                l1,
+                linenumberformat.format(ln2),
+                l2,
+            )
             continue
         if ln2 == "" and l2 in ("\r\n", "\n", "\r"):
-            yield ('d', linenumberformat.format(ln1), removeMarkers(l1),
-                   emptylineno, l2)
+            yield (
+                "d",
+                linenumberformat.format(ln1),
+                removeMarkers(l1),
+                emptylineno,
+                l2,
+            )
             continue
         if ln1 == "" and l1 in ("\r\n", "\n", "\r"):
-            yield ('i', emptylineno, l1,
-                   linenumberformat.format(ln2), removeMarkers(l2))
+            yield (
+                "i",
+                emptylineno,
+                l1,
+                linenumberformat.format(ln2),
+                removeMarkers(l2),
+            )
             continue
-        yield ('r', linenumberformat.format(ln1), l1,
-               linenumberformat.format(ln2), l2)
+        yield ("r", linenumberformat.format(ln1), l1, linenumberformat.format(ln2), l2)
 
 
 class CompareDialog(QWidget, Ui_CompareDialog):
@@ -87,63 +99,66 @@
     Class implementing a dialog to compare two files and show the result side
     by side.
     """
+
     def __init__(self, files=None, parent=None):
         """
         Constructor
-        
+
         @param files list of files to compare and their label
             (list of two tuples of two strings)
         @param parent parent widget (QWidget)
         """
         super().__init__(parent)
         self.setupUi(self)
-        
+
         if files is None:
             files = []
-        
+
         self.file1Picker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
         self.file2Picker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
-        
+
         self.diffButton = self.buttonBox.addButton(
-            self.tr("Compare"), QDialogButtonBox.ButtonRole.ActionRole)
+            self.tr("Compare"), QDialogButtonBox.ButtonRole.ActionRole
+        )
         self.diffButton.setToolTip(
-            self.tr("Press to perform the comparison of the two files"))
+            self.tr("Press to perform the comparison of the two files")
+        )
         self.diffButton.setEnabled(False)
         self.diffButton.setDefault(True)
-        
+
         self.firstButton.setIcon(UI.PixmapCache.getIcon("2uparrow"))
         self.upButton.setIcon(UI.PixmapCache.getIcon("1uparrow"))
         self.downButton.setIcon(UI.PixmapCache.getIcon("1downarrow"))
         self.lastButton.setIcon(UI.PixmapCache.getIcon("2downarrow"))
-        
-        self.totalLabel.setText(self.tr('Total: {0}').format(0))
-        self.changedLabel.setText(self.tr('Changed: {0}').format(0))
-        self.addedLabel.setText(self.tr('Added: {0}').format(0))
-        self.deletedLabel.setText(self.tr('Deleted: {0}').format(0))
-        
-        self.updateInterval = 20    # update every 20 lines
-        
+
+        self.totalLabel.setText(self.tr("Total: {0}").format(0))
+        self.changedLabel.setText(self.tr("Changed: {0}").format(0))
+        self.addedLabel.setText(self.tr("Added: {0}").format(0))
+        self.deletedLabel.setText(self.tr("Deleted: {0}").format(0))
+
+        self.updateInterval = 20  # update every 20 lines
+
         self.vsb1 = self.contents_1.verticalScrollBar()
         self.hsb1 = self.contents_1.horizontalScrollBar()
         self.vsb2 = self.contents_2.verticalScrollBar()
         self.hsb2 = self.contents_2.horizontalScrollBar()
-        
+
         self.on_synchronizeCheckBox_toggled(True)
-        
+
         self.__generateFormats()
-        
+
         # connect some of our widgets explicitly
         self.file1Picker.textChanged.connect(self.__fileChanged)
         self.file2Picker.textChanged.connect(self.__fileChanged)
         self.vsb1.valueChanged.connect(self.__scrollBarMoved)
         self.vsb1.valueChanged.connect(self.vsb2.setValue)
         self.vsb2.valueChanged.connect(self.vsb1.setValue)
-        
+
         self.diffParas = []
         self.currentDiffPos = -1
-        
+
         self.markerPattern = r"\0\+|\0\^|\0\-"
-        
+
         if len(files) == 2:
             self.filesGroup.hide()
             self.file1Picker.setText(files[0][1])
@@ -155,7 +170,7 @@
         else:
             self.file1Label.hide()
             self.file2Label.hide()
-    
+
     def __generateFormats(self):
         """
         Private method to generate the various text formats.
@@ -166,33 +181,35 @@
         self.contents_2.setFontFamily(font.family())
         self.contents_2.setFontPointSize(font.pointSize())
         self.fontHeight = QFontMetrics(self.contents_1.currentFont()).height()
-        
+
         self.cNormalFormat = self.contents_1.currentCharFormat()
         self.cInsertedFormat = self.contents_1.currentCharFormat()
         self.cInsertedFormat.setBackground(
-            QBrush(Preferences.getDiffColour("AddedColor")))
+            QBrush(Preferences.getDiffColour("AddedColor"))
+        )
         self.cDeletedFormat = self.contents_1.currentCharFormat()
         self.cDeletedFormat.setBackground(
-            QBrush(Preferences.getDiffColour("RemovedColor")))
+            QBrush(Preferences.getDiffColour("RemovedColor"))
+        )
         self.cReplacedFormat = self.contents_1.currentCharFormat()
         self.cReplacedFormat.setBackground(
-            QBrush(Preferences.getDiffColour("ReplacedColor")))
-    
+            QBrush(Preferences.getDiffColour("ReplacedColor"))
+        )
+
     def show(self, filename=None):
         """
         Public slot to show the dialog.
-        
+
         @param filename name of a file to use as the first file (string)
         """
         if filename:
             self.file1Picker.setText(filename)
         super().show()
-        
-    def __appendText(self, pane, linenumber, line, charFormat,
-                     interLine=False):
+
+    def __appendText(self, pane, linenumber, line, charFormat, interLine=False):
         """
         Private method to append text to the end of the contents pane.
-        
+
         @param pane text edit widget to append text to (QTextedit)
         @param linenumber number of line to insert (string)
         @param line text to insert (string)
@@ -207,8 +224,8 @@
             pane.insertPlainText("{0} ".format(linenumber))
             for txt in re.split(self.markerPattern, line):
                 if txt:
-                    if txt.count('\1'):
-                        txt1, txt = txt.split('\1', 1)
+                    if txt.count("\1"):
+                        txt1, txt = txt.split("\1", 1)
                         tc = pane.textCursor()
                         tc.movePosition(QTextCursor.MoveOperation.End)
                         pane.setTextCursor(tc)
@@ -225,12 +242,12 @@
     def on_buttonBox_clicked(self, button):
         """
         Private slot called by a button of the button box clicked.
-        
+
         @param button button that was clicked (QAbstractButton)
         """
         if button == self.diffButton:
             self.on_diffButton_clicked()
-        
+
     @pyqtSlot()
     def on_diffButton_clicked(self):
         """
@@ -244,9 +261,10 @@
             EricMessageBox.critical(
                 self,
                 self.tr("Compare Files"),
-                self.tr(
-                    """<p>The file <b>{0}</b> could not be read.</p>""")
-                .format(filename1))
+                self.tr("""<p>The file <b>{0}</b> could not be read.</p>""").format(
+                    filename1
+                ),
+            )
             return
 
         filename2 = self.file2Picker.text()
@@ -257,17 +275,18 @@
             EricMessageBox.critical(
                 self,
                 self.tr("Compare Files"),
-                self.tr(
-                    """<p>The file <b>{0}</b> could not be read.</p>""")
-                .format(filename2))
+                self.tr("""<p>The file <b>{0}</b> could not be read.</p>""").format(
+                    filename2
+                ),
+            )
             return
-        
+
         self.__compare(lines1, lines2)
-        
+
     def compare(self, lines1, lines2, name1="", name2=""):
         """
         Public method to compare two lists of text.
-        
+
         @param lines1 text to compare against (string or list of strings)
         @param lines2 text to compare (string or list of strings)
         @param name1 name to be shown for the first text (string)
@@ -282,55 +301,55 @@
             self.file2Picker.setReadOnly(True)
         self.diffButton.setEnabled(False)
         self.diffButton.hide()
-        
+
         if isinstance(lines1, str):
             lines1 = lines1.splitlines(True)
         if isinstance(lines2, str):
             lines2 = lines2.splitlines(True)
-        
+
         self.__compare(lines1, lines2)
-        
+
     def __compare(self, lines1, lines2):
         """
         Private method to compare two lists of text.
-        
+
         @param lines1 text to compare against (list of strings)
         @param lines2 text to compare (list of strings)
         """
         self.contents_1.clear()
         self.contents_2.clear()
-        
+
         self.__generateFormats()
-        
+
         # counters for changes
         added = 0
         deleted = 0
         changed = 0
-        
+
         self.diffParas = []
         self.currentDiffPos = -1
-        oldOpcode = ''
+        oldOpcode = ""
         for paras, (opcode, ln1, l1, ln2, l2) in enumerate(
             sbsdiff(lines1, lines2), start=1
         ):
-            if opcode in 'idr':
+            if opcode in "idr":
                 if oldOpcode != opcode:
                     oldOpcode = opcode
                     self.diffParas.append(paras)
                     # update counters
-                    if opcode == 'i':
+                    if opcode == "i":
                         added += 1
-                    elif opcode == 'd':
+                    elif opcode == "d":
                         deleted += 1
-                    elif opcode == 'r':
+                    elif opcode == "r":
                         changed += 1
-                if opcode == 'i':
+                if opcode == "i":
                     format1 = self.cNormalFormat
                     format2 = self.cInsertedFormat
-                elif opcode == 'd':
+                elif opcode == "d":
                     format1 = self.cDeletedFormat
                     format2 = self.cNormalFormat
-                elif opcode == 'r':
+                elif opcode == "r":
                     if ln1.strip():
                         format1 = self.cReplacedFormat
                     else:
@@ -340,31 +359,30 @@
                     else:
                         format2 = self.cNormalFormat
             else:
-                oldOpcode = ''
+                oldOpcode = ""
                 format1 = self.cNormalFormat
                 format2 = self.cNormalFormat
-            self.__appendText(self.contents_1, ln1, l1, format1, opcode == 'r')
-            self.__appendText(self.contents_2, ln2, l2, format2, opcode == 'r')
+            self.__appendText(self.contents_1, ln1, l1, format1, opcode == "r")
+            self.__appendText(self.contents_2, ln2, l2, format2, opcode == "r")
             if not (paras % self.updateInterval):
                 QApplication.processEvents()
-        
+
         self.vsb1.setValue(0)
         self.vsb2.setValue(0)
         self.firstButton.setEnabled(False)
         self.upButton.setEnabled(False)
         self.downButton.setEnabled(
-            len(self.diffParas) > 0 and
-            (self.vsb1.isVisible() or self.vsb2.isVisible()))
+            len(self.diffParas) > 0 and (self.vsb1.isVisible() or self.vsb2.isVisible())
+        )
         self.lastButton.setEnabled(
-            len(self.diffParas) > 0 and
-            (self.vsb1.isVisible() or self.vsb2.isVisible()))
-        
-        self.totalLabel.setText(self.tr('Total: {0}')
-                                    .format(added + deleted + changed))
-        self.changedLabel.setText(self.tr('Changed: {0}').format(changed))
-        self.addedLabel.setText(self.tr('Added: {0}').format(added))
-        self.deletedLabel.setText(self.tr('Deleted: {0}').format(deleted))
-        
+            len(self.diffParas) > 0 and (self.vsb1.isVisible() or self.vsb2.isVisible())
+        )
+
+        self.totalLabel.setText(self.tr("Total: {0}").format(added + deleted + changed))
+        self.changedLabel.setText(self.tr("Changed: {0}").format(changed))
+        self.addedLabel.setText(self.tr("Added: {0}").format(added))
+        self.deletedLabel.setText(self.tr("Deleted: {0}").format(deleted))
+
         # move to the first difference
         self.downButton.click()
 
@@ -376,31 +394,31 @@
             value = (self.diffParas[self.currentDiffPos] - 1) * self.fontHeight
             self.vsb1.setValue(value)
             self.vsb2.setValue(value)
-    
+
     def __scrollBarMoved(self, value):
         """
         Private slot to enable the buttons and set the current diff position
         depending on scrollbar position.
-        
+
         @param value scrollbar position (integer)
         """
         tPos = value / self.fontHeight + 1
         bPos = (value + self.vsb1.pageStep()) / self.fontHeight + 1
-        
+
         self.currentDiffPos = -1
-        
+
         if self.diffParas:
             self.firstButton.setEnabled(tPos > self.diffParas[0])
             self.upButton.setEnabled(tPos > self.diffParas[0])
             self.downButton.setEnabled(bPos < self.diffParas[-1])
             self.lastButton.setEnabled(bPos < self.diffParas[-1])
-            
+
             if tPos >= self.diffParas[0]:
                 for diffPos in self.diffParas:
                     self.currentDiffPos += 1
                     if tPos <= diffPos:
                         break
-    
+
     @pyqtSlot()
     def on_upButton_clicked(self):
         """
@@ -408,7 +426,7 @@
         """
         self.currentDiffPos -= 1
         self.__moveTextToCurrentDiffPos()
-    
+
     @pyqtSlot()
     def on_downButton_clicked(self):
         """
@@ -416,7 +434,7 @@
         """
         self.currentDiffPos += 1
         self.__moveTextToCurrentDiffPos()
-    
+
     @pyqtSlot()
     def on_firstButton_clicked(self):
         """
@@ -424,7 +442,7 @@
         """
         self.currentDiffPos = 0
         self.__moveTextToCurrentDiffPos()
-    
+
     @pyqtSlot()
     def on_lastButton_clicked(self):
         """
@@ -432,15 +450,12 @@
         """
         self.currentDiffPos = len(self.diffParas) - 1
         self.__moveTextToCurrentDiffPos()
-    
+
     def __fileChanged(self):
         """
         Private slot to enable/disable the Compare button.
         """
-        if (
-            not self.file1Picker.text() or
-            not self.file2Picker.text()
-        ):
+        if not self.file1Picker.text() or not self.file2Picker.text():
             self.diffButton.setEnabled(False)
         else:
             self.diffButton.setEnabled(True)
@@ -449,7 +464,7 @@
     def on_synchronizeCheckBox_toggled(self, sync):
         """
         Private slot to connect or disconnect the scrollbars of the displays.
-        
+
         @param sync flag indicating synchronisation status (boolean)
         """
         if sync:
@@ -465,29 +480,29 @@
     """
     Main window class for the standalone dialog.
     """
+
     def __init__(self, files=None, parent=None):
         """
         Constructor
-        
+
         @param files list of files to compare and their label
             (list of two tuples of two strings)
         @param parent reference to the parent widget (QWidget)
         """
         super().__init__(parent)
-        
-        self.setStyle(Preferences.getUI("Style"),
-                      Preferences.getUI("StyleSheet"))
-        
+
+        self.setStyle(Preferences.getUI("Style"), Preferences.getUI("StyleSheet"))
+
         self.cw = CompareDialog(files, self)
         self.cw.installEventFilter(self)
         size = self.cw.size()
         self.setCentralWidget(self.cw)
         self.resize(size)
-    
+
     def eventFilter(self, obj, event):
         """
         Public method to filter events.
-        
+
         @param obj reference to the object the event is meant for (QObject)
         @param event reference to the event object (QEvent)
         @return flag indicating, whether the event was handled (boolean)
@@ -495,5 +510,5 @@
         if event.type() == QEvent.Type.Close:
             QApplication.exit()
             return True
-        
+
         return False

eric ide

mercurial