eric6/Plugins/VcsPlugins/vcsMercurial/HgBookmarksInOutDialog.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 7192
a22eee00b052
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2011 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to show a list of incoming or outgoing bookmarks.
8 """
9
10 from __future__ import unicode_literals
11 try:
12 str = unicode
13 except NameError:
14 pass
15
16 import os
17
18 from PyQt5.QtCore import pyqtSlot, QProcess, Qt, QTimer, QCoreApplication
19 from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QHeaderView, \
20 QTreeWidgetItem, QLineEdit
21
22 from E5Gui import E5MessageBox
23
24 from .Ui_HgBookmarksInOutDialog import Ui_HgBookmarksInOutDialog
25
26 from Globals import strToQByteArray
27
28
29 class HgBookmarksInOutDialog(QDialog, Ui_HgBookmarksInOutDialog):
30 """
31 Class implementing a dialog to show a list of incoming or outgoing
32 bookmarks.
33 """
34 INCOMING = 0
35 OUTGOING = 1
36
37 def __init__(self, vcs, mode, parent=None):
38 """
39 Constructor
40
41 @param vcs reference to the vcs object
42 @param mode mode of the dialog (HgBookmarksInOutDialog.INCOMING,
43 HgBookmarksInOutDialog.OUTGOING)
44 @param parent reference to the parent widget (QWidget)
45 @exception ValueError raised to indicate an invalid dialog mode
46 """
47 super(HgBookmarksInOutDialog, self).__init__(parent)
48 self.setupUi(self)
49 self.setWindowFlags(Qt.Window)
50
51 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
52 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
53
54 if mode not in [self.INCOMING, self.OUTGOING]:
55 raise ValueError("Bad value for mode")
56 if mode == self.INCOMING:
57 self.setWindowTitle(self.tr("Mercurial Incoming Bookmarks"))
58 elif mode == self.OUTGOING:
59 self.setWindowTitle(self.tr("Mercurial Outgoing Bookmarks"))
60
61 self.process = QProcess()
62 self.vcs = vcs
63 self.mode = mode
64 self.__hgClient = vcs.getClient()
65
66 self.bookmarksList.headerItem().setText(
67 self.bookmarksList.columnCount(), "")
68 self.bookmarksList.header().setSortIndicator(3, Qt.AscendingOrder)
69
70 self.process.finished.connect(self.__procFinished)
71 self.process.readyReadStandardOutput.connect(self.__readStdout)
72 self.process.readyReadStandardError.connect(self.__readStderr)
73
74 self.show()
75 QCoreApplication.processEvents()
76
77 def closeEvent(self, e):
78 """
79 Protected slot implementing a close event handler.
80
81 @param e close event (QCloseEvent)
82 """
83 if self.__hgClient:
84 if self.__hgClient.isExecuting():
85 self.__hgClient.cancel()
86 else:
87 if self.process is not None and \
88 self.process.state() != QProcess.NotRunning:
89 self.process.terminate()
90 QTimer.singleShot(2000, self.process.kill)
91 self.process.waitForFinished(3000)
92
93 e.accept()
94
95 def start(self, path):
96 """
97 Public slot to start the bookmarks command.
98
99 @param path name of directory to be listed (string)
100 @exception ValueError raised to indicate an invalid dialog mode
101 """
102 self.errorGroup.hide()
103
104 self.intercept = False
105 self.activateWindow()
106
107 dname, fname = self.vcs.splitPath(path)
108
109 # find the root of the repo
110 repodir = dname
111 while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
112 repodir = os.path.dirname(repodir)
113 if os.path.splitdrive(repodir)[1] == os.sep:
114 return
115
116 if self.mode == self.INCOMING:
117 args = self.vcs.initCommand("incoming")
118 elif self.mode == self.OUTGOING:
119 args = self.vcs.initCommand("outgoing")
120 else:
121 raise ValueError("Bad value for mode")
122 args.append('--bookmarks')
123
124 if self.__hgClient:
125 self.inputGroup.setEnabled(False)
126 self.inputGroup.hide()
127
128 out, err = self.__hgClient.runcommand(args)
129 if err:
130 self.__showError(err)
131 if out:
132 for line in out.splitlines():
133 self.__processOutputLine(line)
134 if self.__hgClient.wasCanceled():
135 break
136 self.__finish()
137 else:
138 self.process.kill()
139 self.process.setWorkingDirectory(repodir)
140
141 self.process.start('hg', args)
142 procStarted = self.process.waitForStarted(5000)
143 if not procStarted:
144 self.inputGroup.setEnabled(False)
145 self.inputGroup.hide()
146 E5MessageBox.critical(
147 self,
148 self.tr('Process Generation Error'),
149 self.tr(
150 'The process {0} could not be started. '
151 'Ensure, that it is in the search path.'
152 ).format('hg'))
153 else:
154 self.inputGroup.setEnabled(True)
155 self.inputGroup.show()
156
157 def __finish(self):
158 """
159 Private slot called when the process finished or the user pressed
160 the button.
161 """
162 if self.process is not None and \
163 self.process.state() != QProcess.NotRunning:
164 self.process.terminate()
165 QTimer.singleShot(2000, self.process.kill)
166 self.process.waitForFinished(3000)
167
168 self.inputGroup.setEnabled(False)
169 self.inputGroup.hide()
170
171 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
172 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
173 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
174 self.buttonBox.button(QDialogButtonBox.Close).setFocus(
175 Qt.OtherFocusReason)
176
177 if self.bookmarksList.topLevelItemCount() == 0:
178 # no bookmarks defined
179 self.__generateItem(self.tr("no bookmarks found"), "")
180 self.__resizeColumns()
181 self.__resort()
182
183 def on_buttonBox_clicked(self, button):
184 """
185 Private slot called by a button of the button box clicked.
186
187 @param button button that was clicked (QAbstractButton)
188 """
189 if button == self.buttonBox.button(QDialogButtonBox.Close):
190 self.close()
191 elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
192 if self.__hgClient:
193 self.__hgClient.cancel()
194 else:
195 self.__finish()
196
197 def __procFinished(self, exitCode, exitStatus):
198 """
199 Private slot connected to the finished signal.
200
201 @param exitCode exit code of the process (integer)
202 @param exitStatus exit status of the process (QProcess.ExitStatus)
203 """
204 self.__finish()
205
206 def __resort(self):
207 """
208 Private method to resort the tree.
209 """
210 self.bookmarksList.sortItems(
211 self.bookmarksList.sortColumn(),
212 self.bookmarksList.header().sortIndicatorOrder())
213
214 def __resizeColumns(self):
215 """
216 Private method to resize the list columns.
217 """
218 self.bookmarksList.header().resizeSections(
219 QHeaderView.ResizeToContents)
220 self.bookmarksList.header().setStretchLastSection(True)
221
222 def __generateItem(self, changeset, name):
223 """
224 Private method to generate a bookmark item in the bookmarks list.
225
226 @param changeset changeset of the bookmark (string)
227 @param name name of the bookmark (string)
228 """
229 QTreeWidgetItem(self.bookmarksList, [
230 name,
231 changeset])
232
233 def __readStdout(self):
234 """
235 Private slot to handle the readyReadStdout signal.
236
237 It reads the output of the process, formats it and inserts it into
238 the contents pane.
239 """
240 self.process.setReadChannel(QProcess.StandardOutput)
241
242 while self.process.canReadLine():
243 s = str(self.process.readLine(), self.vcs.getEncoding(), 'replace')
244 self.__processOutputLine(s)
245
246 def __processOutputLine(self, line):
247 """
248 Private method to process the lines of output.
249
250 @param line output line to be processed (string)
251 """
252 if line.startswith(" "):
253 li = line.strip().split()
254 changeset = li[-1]
255 del li[-1]
256 name = " ".join(li)
257 self.__generateItem(changeset, name)
258
259 def __readStderr(self):
260 """
261 Private slot to handle the readyReadStderr signal.
262
263 It reads the error output of the process and inserts it into the
264 error pane.
265 """
266 if self.process is not None:
267 s = str(self.process.readAllStandardError(),
268 self.vcs.getEncoding(), 'replace')
269 self.__showError(s)
270
271 def __showError(self, out):
272 """
273 Private slot to show some error.
274
275 @param out error to be shown (string)
276 """
277 self.errorGroup.show()
278 self.errors.insertPlainText(out)
279 self.errors.ensureCursorVisible()
280
281 def on_passwordCheckBox_toggled(self, isOn):
282 """
283 Private slot to handle the password checkbox toggled.
284
285 @param isOn flag indicating the status of the check box (boolean)
286 """
287 if isOn:
288 self.input.setEchoMode(QLineEdit.Password)
289 else:
290 self.input.setEchoMode(QLineEdit.Normal)
291
292 @pyqtSlot()
293 def on_sendButton_clicked(self):
294 """
295 Private slot to send the input to the subversion process.
296 """
297 inputTxt = self.input.text()
298 inputTxt += os.linesep
299
300 if self.passwordCheckBox.isChecked():
301 self.errors.insertPlainText(os.linesep)
302 self.errors.ensureCursorVisible()
303 else:
304 self.errors.insertPlainText(inputTxt)
305 self.errors.ensureCursorVisible()
306
307 self.process.write(strToQByteArray(inputTxt))
308
309 self.passwordCheckBox.setChecked(False)
310 self.input.clear()
311
312 def on_input_returnPressed(self):
313 """
314 Private slot to handle the press of the return key in the input field.
315 """
316 self.intercept = True
317 self.on_sendButton_clicked()
318
319 def keyPressEvent(self, evt):
320 """
321 Protected slot to handle a key press event.
322
323 @param evt the key press event (QKeyEvent)
324 """
325 if self.intercept:
326 self.intercept = False
327 evt.accept()
328 return
329 super(HgBookmarksInOutDialog, self).keyPressEvent(evt)

eric ide

mercurial