eric6/Plugins/VcsPlugins/vcsSubversion/SvnChangeListsDialog.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) 2012 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to browse the change lists.
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, Qt, QProcess, QRegExp, QTimer
19 from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QListWidgetItem, \
20 QLineEdit
21
22 from E5Gui import E5MessageBox
23
24 from .Ui_SvnChangeListsDialog import Ui_SvnChangeListsDialog
25
26 import Preferences
27 from Globals import strToQByteArray
28
29
30 class SvnChangeListsDialog(QDialog, Ui_SvnChangeListsDialog):
31 """
32 Class implementing a dialog to browse the change lists.
33 """
34 def __init__(self, vcs, parent=None):
35 """
36 Constructor
37
38 @param vcs reference to the vcs object
39 @param parent parent widget (QWidget)
40 """
41 super(SvnChangeListsDialog, self).__init__(parent)
42 self.setupUi(self)
43 self.setWindowFlags(Qt.Window)
44
45 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
46 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
47
48 self.vcs = vcs
49
50 self.process = QProcess()
51 self.process.finished.connect(self.__procFinished)
52 self.process.readyReadStandardOutput.connect(self.__readStdout)
53 self.process.readyReadStandardError.connect(self.__readStderr)
54
55 self.rx_status = QRegExp(
56 '(.{8,9})\\s+([0-9-]+)\\s+([0-9?]+)\\s+(\\S+)\\s+(.+)\\s*')
57 # flags (8 or 9 anything), revision, changed rev, author, path
58 self.rx_status2 = \
59 QRegExp('(.{8,9})\\s+(.+)\\s*')
60 # flags (8 or 9 anything), path
61 self.rx_changelist = \
62 QRegExp('--- \\S+ .([\\w\\s]+).:\\s+')
63 # three dashes, Changelist (translated), quote,
64 # changelist name, quote, :
65
66 @pyqtSlot(QListWidgetItem, QListWidgetItem)
67 def on_changeLists_currentItemChanged(self, current, previous):
68 """
69 Private slot to handle the selection of a new item.
70
71 @param current current item (QListWidgetItem)
72 @param previous previous current item (QListWidgetItem)
73 """
74 self.filesList.clear()
75 if current is not None:
76 changelist = current.text()
77 if changelist in self.changeListsDict:
78 self.filesList.addItems(
79 sorted(self.changeListsDict[changelist]))
80
81 def start(self, path):
82 """
83 Public slot to populate the data.
84
85 @param path directory name to show change lists for (string)
86 """
87 self.changeListsDict = {}
88
89 self.filesLabel.setText(
90 self.tr("Files (relative to {0}):").format(path))
91
92 self.errorGroup.hide()
93 self.intercept = False
94
95 self.path = path
96 self.currentChangelist = ""
97
98 args = []
99 args.append('status')
100 self.vcs.addArguments(args, self.vcs.options['global'])
101 self.vcs.addArguments(args, self.vcs.options['status'])
102 if '--verbose' not in self.vcs.options['global'] and \
103 '--verbose' not in self.vcs.options['status']:
104 args.append('--verbose')
105 if isinstance(path, list):
106 self.dname, fnames = self.vcs.splitPathList(path)
107 self.vcs.addArguments(args, fnames)
108 else:
109 self.dname, fname = self.vcs.splitPath(path)
110 args.append(fname)
111
112 self.process.setWorkingDirectory(self.dname)
113
114 self.process.start('svn', args)
115 procStarted = self.process.waitForStarted(5000)
116 if not procStarted:
117 self.inputGroup.setEnabled(False)
118 self.inputGroup.hide()
119 E5MessageBox.critical(
120 self,
121 self.tr('Process Generation Error'),
122 self.tr(
123 'The process {0} could not be started. '
124 'Ensure, that it is in the search path.'
125 ).format('svn'))
126 else:
127 self.inputGroup.setEnabled(True)
128 self.inputGroup.show()
129
130 def __finish(self):
131 """
132 Private slot called when the process finished or the user pressed
133 the button.
134 """
135 if self.process is not None and \
136 self.process.state() != QProcess.NotRunning:
137 self.process.terminate()
138 QTimer.singleShot(2000, self.process.kill)
139 self.process.waitForFinished(3000)
140
141 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
142 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
143 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
144
145 self.inputGroup.setEnabled(False)
146 self.inputGroup.hide()
147
148 if len(self.changeListsDict) == 0:
149 self.changeLists.addItem(self.tr("No changelists found"))
150 self.buttonBox.button(QDialogButtonBox.Close).setFocus(
151 Qt.OtherFocusReason)
152 else:
153 self.changeLists.addItems(sorted(self.changeListsDict.keys()))
154 self.changeLists.setCurrentRow(0)
155 self.changeLists.setFocus(Qt.OtherFocusReason)
156
157 def on_buttonBox_clicked(self, button):
158 """
159 Private slot called by a button of the button box clicked.
160
161 @param button button that was clicked (QAbstractButton)
162 """
163 if button == self.buttonBox.button(QDialogButtonBox.Close):
164 self.close()
165 elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
166 self.__finish()
167
168 def __procFinished(self, exitCode, exitStatus):
169 """
170 Private slot connected to the finished signal.
171
172 @param exitCode exit code of the process (integer)
173 @param exitStatus exit status of the process (QProcess.ExitStatus)
174 """
175 self.__finish()
176
177 def __readStdout(self):
178 """
179 Private slot to handle the readyReadStandardOutput signal.
180
181 It reads the output of the process, formats it and inserts it into
182 the contents pane.
183 """
184 if self.process is not None:
185 self.process.setReadChannel(QProcess.StandardOutput)
186
187 while self.process.canReadLine():
188 s = str(self.process.readLine(),
189 Preferences.getSystem("IOEncoding"),
190 'replace')
191 if self.currentChangelist != "" and \
192 self.rx_status.exactMatch(s):
193 file = self.rx_status.cap(5).strip()
194 filename = file.replace(self.path + os.sep, "")
195 if filename not in \
196 self.changeListsDict[self.currentChangelist]:
197 self.changeListsDict[self.currentChangelist].append(
198 filename)
199 elif self.currentChangelist != "" and \
200 self.rx_status2.exactMatch(s):
201 file = self.rx_status2.cap(2).strip()
202 filename = file.replace(self.path + os.sep, "")
203 if filename not in \
204 self.changeListsDict[self.currentChangelist]:
205 self.changeListsDict[self.currentChangelist].append(
206 filename)
207 elif self.rx_changelist.exactMatch(s):
208 self.currentChangelist = self.rx_changelist.cap(1)
209 if self.currentChangelist not in self.changeListsDict:
210 self.changeListsDict[self.currentChangelist] = []
211
212 def __readStderr(self):
213 """
214 Private slot to handle the readyReadStandardError signal.
215
216 It reads the error output of the process and inserts it into the
217 error pane.
218 """
219 if self.process is not None:
220 self.errorGroup.show()
221 s = str(self.process.readAllStandardError(),
222 Preferences.getSystem("IOEncoding"),
223 'replace')
224 self.errors.insertPlainText(s)
225 self.errors.ensureCursorVisible()
226
227 def on_passwordCheckBox_toggled(self, isOn):
228 """
229 Private slot to handle the password checkbox toggled.
230
231 @param isOn flag indicating the status of the check box (boolean)
232 """
233 if isOn:
234 self.input.setEchoMode(QLineEdit.Password)
235 else:
236 self.input.setEchoMode(QLineEdit.Normal)
237
238 @pyqtSlot()
239 def on_sendButton_clicked(self):
240 """
241 Private slot to send the input to the subversion process.
242 """
243 inputTxt = self.input.text()
244 inputTxt += os.linesep
245
246 if self.passwordCheckBox.isChecked():
247 self.errors.insertPlainText(os.linesep)
248 self.errors.ensureCursorVisible()
249 else:
250 self.errors.insertPlainText(inputTxt)
251 self.errors.ensureCursorVisible()
252
253 self.process.write(strToQByteArray(inputTxt))
254
255 self.passwordCheckBox.setChecked(False)
256 self.input.clear()
257
258 def on_input_returnPressed(self):
259 """
260 Private slot to handle the press of the return key in the input field.
261 """
262 self.intercept = True
263 self.on_sendButton_clicked()
264
265 def keyPressEvent(self, evt):
266 """
267 Protected slot to handle a key press event.
268
269 @param evt the key press event (QKeyEvent)
270 """
271 if self.intercept:
272 self.intercept = False
273 evt.accept()
274 return
275 super(SvnChangeListsDialog, self).keyPressEvent(evt)

eric ide

mercurial