Plugins/VcsPlugins/vcsGit/GitDescribeDialog.py

changeset 6020
baf6da1ae288
child 6048
82ad8ec9548c
equal deleted inserted replaced
6019:58ecdaf0b789 6020:baf6da1ae288
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2014 - 2017 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to show the results of the git describe action.
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_GitDescribeDialog import Ui_GitDescribeDialog
25
26 from .GitUtilities import strToQByteArray
27
28 import Preferences
29
30
31 class GitDescribeDialog(QDialog, Ui_GitDescribeDialog):
32 """
33 Class implementing a dialog to show the results of the git describe action.
34 """
35 def __init__(self, vcs, parent=None):
36 """
37 Constructor
38
39 @param vcs reference to the vcs object
40 @param parent reference to the parent widget (QWidget)
41 """
42 super(GitDescribeDialog, self).__init__(parent)
43 self.setupUi(self)
44 self.setWindowFlags(Qt.Window)
45
46 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
47 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
48
49 self.process = QProcess()
50 self.vcs = vcs
51
52 self.tagList.headerItem().setText(self.tagList.columnCount(), "")
53 self.tagList.header().setSortIndicator(1, Qt.AscendingOrder)
54
55 self.process.finished.connect(self.__procFinished)
56 self.process.readyReadStandardOutput.connect(self.__readStdout)
57 self.process.readyReadStandardError.connect(self.__readStderr)
58
59 self.show()
60 QCoreApplication.processEvents()
61
62 def closeEvent(self, e):
63 """
64 Protected slot implementing a close event handler.
65
66 @param e close event (QCloseEvent)
67 """
68 if self.process is not None and \
69 self.process.state() != QProcess.NotRunning:
70 self.process.terminate()
71 QTimer.singleShot(2000, self.process.kill)
72 self.process.waitForFinished(3000)
73
74 e.accept()
75
76 def start(self, path, commits):
77 """
78 Public slot to start the tag/branch list command.
79
80 @param path name of directory to be listed (string)
81 @param commits list of commits to be described (list of string)
82 """
83 self.tagList.clear()
84 self.errorGroup.hide()
85
86 self.intercept = False
87 self.activateWindow()
88
89 self.__commits = commits[:]
90 self.__tagInfoLines = []
91
92 dname, fname = self.vcs.splitPath(path)
93
94 # find the root of the repo
95 self.repodir = dname
96 while not os.path.isdir(os.path.join(self.repodir, self.vcs.adminDir)):
97 self.repodir = os.path.dirname(self.repodir)
98 if os.path.splitdrive(self.repodir)[1] == os.sep:
99 return
100
101 args = self.vcs.initCommand("describe")
102 args.append('--abbrev={0}'.format(
103 self.vcs.getPlugin().getPreferences("CommitIdLength")))
104 if commits:
105 args.extend(commits)
106 else:
107 args.append('--dirty')
108
109 self.process.kill()
110 self.process.setWorkingDirectory(self.repodir)
111
112 self.process.start('git', args)
113 procStarted = self.process.waitForStarted(5000)
114 if not procStarted:
115 self.inputGroup.setEnabled(False)
116 self.inputGroup.hide()
117 E5MessageBox.critical(
118 self,
119 self.tr('Process Generation Error'),
120 self.tr(
121 'The process {0} could not be started. '
122 'Ensure, that it is in the search path.'
123 ).format('git'))
124 else:
125 self.inputGroup.setEnabled(True)
126 self.inputGroup.show()
127
128 def __finish(self):
129 """
130 Private slot called when the process finished or the user pressed
131 the button.
132 """
133 if self.process is not None and \
134 self.process.state() != QProcess.NotRunning:
135 self.process.terminate()
136 QTimer.singleShot(2000, self.process.kill)
137 self.process.waitForFinished(3000)
138
139 self.inputGroup.setEnabled(False)
140 self.inputGroup.hide()
141
142 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
143 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
144 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
145 self.buttonBox.button(QDialogButtonBox.Close).setFocus(
146 Qt.OtherFocusReason)
147
148 self.__resizeColumns()
149 self.__resort()
150
151 def on_buttonBox_clicked(self, button):
152 """
153 Private slot called by a button of the button box clicked.
154
155 @param button button that was clicked (QAbstractButton)
156 """
157 if button == self.buttonBox.button(QDialogButtonBox.Close):
158 self.close()
159 elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
160 self.__finish()
161
162 def __procFinished(self, exitCode, exitStatus):
163 """
164 Private slot connected to the finished signal.
165
166 @param exitCode exit code of the process (integer)
167 @param exitStatus exit status of the process (QProcess.ExitStatus)
168 """
169 if self.__tagInfoLines:
170 if self.__commits:
171 for commit, tagInfo in zip(self.__commits,
172 self.__tagInfoLines):
173 QTreeWidgetItem(self.tagList, [commit, tagInfo])
174 else:
175 for tagInfo in self.__tagInfoLines:
176 QTreeWidgetItem(self.tagList, ["", tagInfo])
177
178 self.__finish()
179
180 def __resort(self):
181 """
182 Private method to resort the tree.
183 """
184 self.tagList.sortItems(
185 self.tagList.sortColumn(),
186 self.tagList.header().sortIndicatorOrder())
187
188 def __resizeColumns(self):
189 """
190 Private method to resize the list columns.
191 """
192 self.tagList.header().resizeSections(QHeaderView.ResizeToContents)
193 self.tagList.header().setStretchLastSection(True)
194
195 def __readStdout(self):
196 """
197 Private slot to handle the readyReadStdout signal.
198
199 It reads the output of the process, formats it and inserts it into
200 the contents pane.
201 """
202 self.process.setReadChannel(QProcess.StandardOutput)
203
204 while self.process.canReadLine():
205 s = str(self.process.readLine(),
206 Preferences.getSystem("IOEncoding"),
207 'replace')
208 self.__tagInfoLines.append(s.strip())
209
210 def __readStderr(self):
211 """
212 Private slot to handle the readyReadStderr signal.
213
214 It reads the error output of the process and inserts it into the
215 error pane.
216 """
217 if self.process is not None:
218 s = str(self.process.readAllStandardError(),
219 Preferences.getSystem("IOEncoding"),
220 'replace')
221 self.errorGroup.show()
222 self.errors.insertPlainText(s)
223 self.errors.ensureCursorVisible()
224
225 def on_passwordCheckBox_toggled(self, isOn):
226 """
227 Private slot to handle the password checkbox toggled.
228
229 @param isOn flag indicating the status of the check box (boolean)
230 """
231 if isOn:
232 self.input.setEchoMode(QLineEdit.Password)
233 else:
234 self.input.setEchoMode(QLineEdit.Normal)
235
236 @pyqtSlot()
237 def on_sendButton_clicked(self):
238 """
239 Private slot to send the input to the git process.
240 """
241 inputTxt = self.input.text()
242 inputTxt += os.linesep
243
244 if self.passwordCheckBox.isChecked():
245 self.errors.insertPlainText(os.linesep)
246 self.errors.ensureCursorVisible()
247 else:
248 self.errors.insertPlainText(inputTxt)
249 self.errors.ensureCursorVisible()
250
251 self.process.write(strToQByteArray(inputTxt))
252
253 self.passwordCheckBox.setChecked(False)
254 self.input.clear()
255
256 def on_input_returnPressed(self):
257 """
258 Private slot to handle the press of the return key in the input field.
259 """
260 self.intercept = True
261 self.on_sendButton_clicked()
262
263 def keyPressEvent(self, evt):
264 """
265 Protected slot to handle a key press event.
266
267 @param evt the key press event (QKeyEvent)
268 """
269 if self.intercept:
270 self.intercept = False
271 evt.accept()
272 return
273
274 super(GitDescribeDialog, self).keyPressEvent(evt)

eric ide

mercurial