src/eric7/Plugins/VcsPlugins/vcsGit/GitDescribeDialog.py

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

eric ide

mercurial