src/eric7/Plugins/VcsPlugins/vcsMercurial/HgDiffDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
26 class HgDiffDialog(QWidget, Ui_HgDiffDialog): 26 class HgDiffDialog(QWidget, Ui_HgDiffDialog):
27 """ 27 """
28 Class implementing a dialog to show the output of the hg diff command 28 Class implementing a dialog to show the output of the hg diff command
29 process. 29 process.
30 """ 30 """
31
31 def __init__(self, vcs, parent=None): 32 def __init__(self, vcs, parent=None):
32 """ 33 """
33 Constructor 34 Constructor
34 35
35 @param vcs reference to the vcs object 36 @param vcs reference to the vcs object
36 @param parent parent widget (QWidget) 37 @param parent parent widget (QWidget)
37 """ 38 """
38 super().__init__(parent) 39 super().__init__(parent)
39 self.setupUi(self) 40 self.setupUi(self)
40 41
41 self.refreshButton = self.buttonBox.addButton( 42 self.refreshButton = self.buttonBox.addButton(
42 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole) 43 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole
43 self.refreshButton.setToolTip( 44 )
44 self.tr("Press to refresh the display")) 45 self.refreshButton.setToolTip(self.tr("Press to refresh the display"))
45 self.refreshButton.setEnabled(False) 46 self.refreshButton.setEnabled(False)
46 self.buttonBox.button( 47 self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setEnabled(False)
47 QDialogButtonBox.StandardButton.Save).setEnabled(False) 48 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
48 self.buttonBox.button( 49
49 QDialogButtonBox.StandardButton.Close).setDefault(True)
50
51 self.searchWidget.attachTextEdit(self.contents) 50 self.searchWidget.attachTextEdit(self.contents)
52 51
53 self.vcs = vcs 52 self.vcs = vcs
54 53
55 font = Preferences.getEditorOtherFonts("MonospacedFont") 54 font = Preferences.getEditorOtherFonts("MonospacedFont")
56 self.contents.document().setDefaultFont(font) 55 self.contents.document().setDefaultFont(font)
57 56
58 self.highlighter = HgDiffHighlighter(self.contents.document()) 57 self.highlighter = HgDiffHighlighter(self.contents.document())
59 58
60 self.__diffGenerator = HgDiffGenerator(vcs, self) 59 self.__diffGenerator = HgDiffGenerator(vcs, self)
61 self.__diffGenerator.finished.connect(self.__generatorFinished) 60 self.__diffGenerator.finished.connect(self.__generatorFinished)
62 61
63 def closeEvent(self, e): 62 def closeEvent(self, e):
64 """ 63 """
65 Protected slot implementing a close event handler. 64 Protected slot implementing a close event handler.
66 65
67 @param e close event (QCloseEvent) 66 @param e close event (QCloseEvent)
68 """ 67 """
69 self.__diffGenerator.stopProcess() 68 self.__diffGenerator.stopProcess()
70 e.accept() 69 e.accept()
71 70
72 def start(self, fn, versions=None, bundle=None, qdiff=False, 71 def start(self, fn, versions=None, bundle=None, qdiff=False, refreshable=False):
73 refreshable=False):
74 """ 72 """
75 Public slot to start the hg diff command. 73 Public slot to start the hg diff command.
76 74
77 @param fn filename to be diffed (string) 75 @param fn filename to be diffed (string)
78 @param versions list of versions to be diffed (list of up to 76 @param versions list of versions to be diffed (list of up to
79 2 strings or None) 77 2 strings or None)
80 @param bundle name of a bundle file (string) 78 @param bundle name of a bundle file (string)
81 @param qdiff flag indicating qdiff command shall be used (boolean) 79 @param qdiff flag indicating qdiff command shall be used (boolean)
82 @param refreshable flag indicating a refreshable diff (boolean) 80 @param refreshable flag indicating a refreshable diff (boolean)
83 """ 81 """
84 self.refreshButton.setVisible(refreshable) 82 self.refreshButton.setVisible(refreshable)
85 83
86 self.errorGroup.hide() 84 self.errorGroup.hide()
87 self.filename = fn 85 self.filename = fn
88 86
89 self.contents.clear() 87 self.contents.clear()
90 self.filesCombo.clear() 88 self.filesCombo.clear()
91 self.highlighter.regenerateRules() 89 self.highlighter.regenerateRules()
92 90
93 if qdiff: 91 if qdiff:
94 self.setWindowTitle(self.tr("Patch Contents")) 92 self.setWindowTitle(self.tr("Patch Contents"))
95 93
96 self.raise_() 94 self.raise_()
97 self.activateWindow() 95 self.activateWindow()
98 96
99 procStarted = self.__diffGenerator.start( 97 procStarted = self.__diffGenerator.start(
100 fn, versions=versions, bundle=bundle, qdiff=qdiff) 98 fn, versions=versions, bundle=bundle, qdiff=qdiff
99 )
101 if not procStarted: 100 if not procStarted:
102 EricMessageBox.critical( 101 EricMessageBox.critical(
103 self, 102 self,
104 self.tr('Process Generation Error'), 103 self.tr("Process Generation Error"),
105 self.tr( 104 self.tr(
106 'The process {0} could not be started. ' 105 "The process {0} could not be started. "
107 'Ensure, that it is in the search path.' 106 "Ensure, that it is in the search path."
108 ).format('hg')) 107 ).format("hg"),
109 108 )
109
110 def __generatorFinished(self): 110 def __generatorFinished(self):
111 """ 111 """
112 Private slot connected to the finished signal. 112 Private slot connected to the finished signal.
113 """ 113 """
114 self.refreshButton.setEnabled(True) 114 self.refreshButton.setEnabled(True)
115 115
116 diff, errors, fileSeparators = self.__diffGenerator.getResult() 116 diff, errors, fileSeparators = self.__diffGenerator.getResult()
117 117
118 if diff: 118 if diff:
119 self.contents.setPlainText("".join(diff)) 119 self.contents.setPlainText("".join(diff))
120 else: 120 else:
121 self.contents.setPlainText( 121 self.contents.setPlainText(self.tr("There is no difference."))
122 self.tr('There is no difference.')) 122
123
124 if errors: 123 if errors:
125 self.errorGroup.show() 124 self.errorGroup.show()
126 self.errors.setPlainText("".join(errors)) 125 self.errors.setPlainText("".join(errors))
127 self.errors.ensureCursorVisible() 126 self.errors.ensureCursorVisible()
128 127
129 self.buttonBox.button( 128 self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setEnabled(
130 QDialogButtonBox.StandardButton.Save).setEnabled(bool(diff)) 129 bool(diff)
131 self.buttonBox.button( 130 )
132 QDialogButtonBox.StandardButton.Close).setEnabled(True) 131 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
133 self.buttonBox.button( 132 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
134 QDialogButtonBox.StandardButton.Close).setDefault(True) 133 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus(
135 self.buttonBox.button( 134 Qt.FocusReason.OtherFocusReason
136 QDialogButtonBox.StandardButton.Close).setFocus( 135 )
137 Qt.FocusReason.OtherFocusReason) 136
138
139 tc = self.contents.textCursor() 137 tc = self.contents.textCursor()
140 tc.movePosition(QTextCursor.MoveOperation.Start) 138 tc.movePosition(QTextCursor.MoveOperation.Start)
141 self.contents.setTextCursor(tc) 139 self.contents.setTextCursor(tc)
142 self.contents.ensureCursorVisible() 140 self.contents.ensureCursorVisible()
143 141
144 self.filesCombo.addItem(self.tr("<Start>"), 0) 142 self.filesCombo.addItem(self.tr("<Start>"), 0)
145 self.filesCombo.addItem(self.tr("<End>"), -1) 143 self.filesCombo.addItem(self.tr("<End>"), -1)
146 for oldFile, newFile, pos in sorted(fileSeparators): 144 for oldFile, newFile, pos in sorted(fileSeparators):
147 if not oldFile: 145 if not oldFile:
148 self.filesCombo.addItem(newFile, pos) 146 self.filesCombo.addItem(newFile, pos)
149 elif oldFile != newFile: 147 elif oldFile != newFile:
150 self.filesCombo.addItem( 148 self.filesCombo.addItem("{0}\n{1}".format(oldFile, newFile), pos)
151 "{0}\n{1}".format(oldFile, newFile), pos)
152 else: 149 else:
153 self.filesCombo.addItem(oldFile, pos) 150 self.filesCombo.addItem(oldFile, pos)
154 151
155 def on_buttonBox_clicked(self, button): 152 def on_buttonBox_clicked(self, button):
156 """ 153 """
157 Private slot called by a button of the button box clicked. 154 Private slot called by a button of the button box clicked.
158 155
159 @param button button that was clicked (QAbstractButton) 156 @param button button that was clicked (QAbstractButton)
160 """ 157 """
161 if button == self.buttonBox.button( 158 if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Save):
162 QDialogButtonBox.StandardButton.Save
163 ):
164 self.on_saveButton_clicked() 159 self.on_saveButton_clicked()
165 elif button == self.refreshButton: 160 elif button == self.refreshButton:
166 self.on_refreshButton_clicked() 161 self.on_refreshButton_clicked()
167 162
168 @pyqtSlot(int) 163 @pyqtSlot(int)
169 def on_filesCombo_activated(self, index): 164 def on_filesCombo_activated(self, index):
170 """ 165 """
171 Private slot to handle the selection of a file. 166 Private slot to handle the selection of a file.
172 167
173 @param index activated row (integer) 168 @param index activated row (integer)
174 """ 169 """
175 para = self.filesCombo.itemData(index) 170 para = self.filesCombo.itemData(index)
176 171
177 if para == 0: 172 if para == 0:
178 tc = self.contents.textCursor() 173 tc = self.contents.textCursor()
179 tc.movePosition(QTextCursor.MoveOperation.Start) 174 tc.movePosition(QTextCursor.MoveOperation.Start)
180 self.contents.setTextCursor(tc) 175 self.contents.setTextCursor(tc)
181 self.contents.ensureCursorVisible() 176 self.contents.ensureCursorVisible()
188 # step 1: move cursor to end 183 # step 1: move cursor to end
189 tc = self.contents.textCursor() 184 tc = self.contents.textCursor()
190 tc.movePosition(QTextCursor.MoveOperation.End) 185 tc.movePosition(QTextCursor.MoveOperation.End)
191 self.contents.setTextCursor(tc) 186 self.contents.setTextCursor(tc)
192 self.contents.ensureCursorVisible() 187 self.contents.ensureCursorVisible()
193 188
194 # step 2: move cursor to desired line 189 # step 2: move cursor to desired line
195 tc = self.contents.textCursor() 190 tc = self.contents.textCursor()
196 delta = tc.blockNumber() - para 191 delta = tc.blockNumber() - para
197 tc.movePosition(QTextCursor.MoveOperation.PreviousBlock, 192 tc.movePosition(
198 QTextCursor.MoveMode.MoveAnchor, 193 QTextCursor.MoveOperation.PreviousBlock,
199 delta) 194 QTextCursor.MoveMode.MoveAnchor,
200 self.contents.setTextCursor(tc) 195 delta,
201 self.contents.ensureCursorVisible() 196 )
202 197 self.contents.setTextCursor(tc)
198 self.contents.ensureCursorVisible()
199
203 @pyqtSlot() 200 @pyqtSlot()
204 def on_saveButton_clicked(self): 201 def on_saveButton_clicked(self):
205 """ 202 """
206 Private slot to handle the Save button press. 203 Private slot to handle the Save button press.
207 204
208 It saves the diff shown in the dialog to a file in the local 205 It saves the diff shown in the dialog to a file in the local
209 filesystem. 206 filesystem.
210 """ 207 """
211 if isinstance(self.filename, list): 208 if isinstance(self.filename, list):
212 if len(self.filename) > 1: 209 if len(self.filename) > 1:
213 fname = self.vcs.splitPathList(self.filename)[0] 210 fname = self.vcs.splitPathList(self.filename)[0]
214 else: 211 else:
215 dname, fname = self.vcs.splitPath(self.filename[0]) 212 dname, fname = self.vcs.splitPath(self.filename[0])
216 if fname != '.': 213 if fname != ".":
217 fname = "{0}.diff".format(self.filename[0]) 214 fname = "{0}.diff".format(self.filename[0])
218 else: 215 else:
219 fname = dname 216 fname = dname
220 else: 217 else:
221 fname = self.vcs.splitPath(self.filename)[0] 218 fname = self.vcs.splitPath(self.filename)[0]
222 219
223 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( 220 fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
224 self, 221 self,
225 self.tr("Save Diff"), 222 self.tr("Save Diff"),
226 fname, 223 fname,
227 self.tr("Patch Files (*.diff)"), 224 self.tr("Patch Files (*.diff)"),
228 None, 225 None,
229 EricFileDialog.DontConfirmOverwrite) 226 EricFileDialog.DontConfirmOverwrite,
230 227 )
228
231 if not fname: 229 if not fname:
232 return # user aborted 230 return # user aborted
233 231
234 fpath = pathlib.Path(fname) 232 fpath = pathlib.Path(fname)
235 if not fpath.suffix: 233 if not fpath.suffix:
236 ex = selectedFilter.split("(*")[1].split(")")[0] 234 ex = selectedFilter.split("(*")[1].split(")")[0]
237 if ex: 235 if ex:
238 fpath = fpath.with_suffix(ex) 236 fpath = fpath.with_suffix(ex)
239 if fpath.exists(): 237 if fpath.exists():
240 res = EricMessageBox.yesNo( 238 res = EricMessageBox.yesNo(
241 self, 239 self,
242 self.tr("Save Diff"), 240 self.tr("Save Diff"),
243 self.tr("<p>The patch file <b>{0}</b> already exists." 241 self.tr(
244 " Overwrite it?</p>").format(fpath), 242 "<p>The patch file <b>{0}</b> already exists." " Overwrite it?</p>"
245 icon=EricMessageBox.Warning) 243 ).format(fpath),
244 icon=EricMessageBox.Warning,
245 )
246 if not res: 246 if not res:
247 return 247 return
248 248
249 eol = ericApp().getObject("Project").getEolString() 249 eol = ericApp().getObject("Project").getEolString()
250 try: 250 try:
251 with fpath.open("w", encoding="utf-8", newline="") as f: 251 with fpath.open("w", encoding="utf-8", newline="") as f:
252 f.write(eol.join(self.contents.toPlainText().splitlines())) 252 f.write(eol.join(self.contents.toPlainText().splitlines()))
253 except OSError as why: 253 except OSError as why:
254 EricMessageBox.critical( 254 EricMessageBox.critical(
255 self, self.tr('Save Diff'), 255 self,
256 self.tr("Save Diff"),
256 self.tr( 257 self.tr(
257 '<p>The patch file <b>{0}</b> could not be saved.' 258 "<p>The patch file <b>{0}</b> could not be saved."
258 '<br>Reason: {1}</p>') 259 "<br>Reason: {1}</p>"
259 .format(fpath, str(why))) 260 ).format(fpath, str(why)),
260 261 )
262
261 @pyqtSlot() 263 @pyqtSlot()
262 def on_refreshButton_clicked(self): 264 def on_refreshButton_clicked(self):
263 """ 265 """
264 Private slot to refresh the display. 266 Private slot to refresh the display.
265 """ 267 """
266 self.buttonBox.button( 268 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
267 QDialogButtonBox.StandardButton.Close).setEnabled(False) 269
268 270 self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setEnabled(False)
269 self.buttonBox.button(
270 QDialogButtonBox.StandardButton.Save).setEnabled(False)
271 self.refreshButton.setEnabled(False) 271 self.refreshButton.setEnabled(False)
272 272
273 self.start(self.filename, refreshable=True) 273 self.start(self.filename, refreshable=True)

eric ide

mercurial