src/eric7/Plugins/VcsPlugins/vcsSubversion/SvnPropListDialog.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) 2003 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to show the output of the svn proplist command
8 process.
9 """
10
11 import re
12
13 from PyQt6.QtCore import pyqtSlot, Qt, QTimer, QProcess, QProcessEnvironment
14 from PyQt6.QtWidgets import (
15 QWidget, QHeaderView, QDialogButtonBox, QTreeWidgetItem
16 )
17
18 from EricWidgets import EricMessageBox
19
20 from .Ui_SvnPropListDialog import Ui_SvnPropListDialog
21
22 import Preferences
23
24
25 class SvnPropListDialog(QWidget, Ui_SvnPropListDialog):
26 """
27 Class implementing a dialog to show the output of the svn proplist command
28 process.
29 """
30 def __init__(self, vcs, parent=None):
31 """
32 Constructor
33
34 @param vcs reference to the vcs object
35 @param parent parent widget (QWidget)
36 """
37 super().__init__(parent)
38 self.setupUi(self)
39
40 self.refreshButton = self.buttonBox.addButton(
41 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole)
42 self.refreshButton.setToolTip(
43 self.tr("Press to refresh the properties display"))
44 self.refreshButton.setEnabled(False)
45 self.buttonBox.button(
46 QDialogButtonBox.StandardButton.Close).setEnabled(False)
47 self.buttonBox.button(
48 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
49
50 self.process = QProcess()
51 env = QProcessEnvironment.systemEnvironment()
52 env.insert("LANG", "C")
53 self.process.setProcessEnvironment(env)
54 self.vcs = vcs
55
56 self.propsList.headerItem().setText(self.propsList.columnCount(), "")
57 self.propsList.header().setSortIndicator(
58 0, Qt.SortOrder.AscendingOrder)
59
60 self.process.finished.connect(self.__procFinished)
61 self.process.readyReadStandardOutput.connect(self.__readStdout)
62 self.process.readyReadStandardError.connect(self.__readStderr)
63
64 self.rx_path = re.compile(r"Properties on '([^']+)':\s*")
65 self.rx_prop = re.compile(r" (.*) *: *(.*)[\r\n]")
66
67 def __resort(self):
68 """
69 Private method to resort the tree.
70 """
71 self.propsList.sortItems(
72 self.propsList.sortColumn(),
73 self.propsList.header().sortIndicatorOrder())
74
75 def __resizeColumns(self):
76 """
77 Private method to resize the list columns.
78 """
79 self.propsList.header().resizeSections(
80 QHeaderView.ResizeMode.ResizeToContents)
81 self.propsList.header().setStretchLastSection(True)
82
83 def __generateItem(self, path, propName, propValue):
84 """
85 Private method to generate a properties item in the properties list.
86
87 @param path file/directory name the property applies to (string)
88 @param propName name of the property (string)
89 @param propValue value of the property (string)
90 """
91 QTreeWidgetItem(self.propsList, [path, propName, propValue.strip()])
92
93 def closeEvent(self, e):
94 """
95 Protected slot implementing a close event handler.
96
97 @param e close event (QCloseEvent)
98 """
99 if (
100 self.process is not None and
101 self.process.state() != QProcess.ProcessState.NotRunning
102 ):
103 self.process.terminate()
104 QTimer.singleShot(2000, self.process.kill)
105 self.process.waitForFinished(3000)
106
107 e.accept()
108
109 def start(self, fn, recursive=False):
110 """
111 Public slot to start the svn status command.
112
113 @param fn filename(s) (string or list of string)
114 @param recursive flag indicating a recursive list is requested
115 """
116 self.errorGroup.hide()
117
118 self.propsList.clear()
119 self.lastPath = None
120 self.lastProp = None
121 self.propBuffer = ""
122
123 self.__args = fn
124 self.__recursive = recursive
125
126 self.buttonBox.button(
127 QDialogButtonBox.StandardButton.Close).setEnabled(False)
128 self.buttonBox.button(
129 QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
130 self.buttonBox.button(
131 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
132 self.refreshButton.setEnabled(False)
133
134 self.process.kill()
135
136 args = []
137 args.append('proplist')
138 self.vcs.addArguments(args, self.vcs.options['global'])
139 args.append('--verbose')
140 if recursive:
141 args.append('--recursive')
142 if isinstance(fn, list):
143 dname, fnames = self.vcs.splitPathList(fn)
144 self.vcs.addArguments(args, fnames)
145 else:
146 dname, fname = self.vcs.splitPath(fn)
147 args.append(fname)
148
149 self.process.setWorkingDirectory(dname)
150
151 self.process.start('svn', args)
152 procStarted = self.process.waitForStarted(5000)
153 if not procStarted:
154 EricMessageBox.critical(
155 self,
156 self.tr('Process Generation Error'),
157 self.tr(
158 'The process {0} could not be started. '
159 'Ensure, that it is in the search path.'
160 ).format('svn'))
161
162 def __finish(self):
163 """
164 Private slot called when the process finished or the user pressed the
165 button.
166 """
167 if (
168 self.process is not None and
169 self.process.state() != QProcess.ProcessState.NotRunning
170 ):
171 self.process.terminate()
172 QTimer.singleShot(2000, self.process.kill)
173 self.process.waitForFinished(3000)
174
175 self.buttonBox.button(
176 QDialogButtonBox.StandardButton.Close).setEnabled(True)
177 self.buttonBox.button(
178 QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
179 self.buttonBox.button(
180 QDialogButtonBox.StandardButton.Close).setDefault(True)
181
182 self.refreshButton.setEnabled(True)
183
184 if self.lastProp:
185 self.__generateItem(self.lastPath, self.lastProp, self.propBuffer)
186
187 self.__resort()
188 self.__resizeColumns()
189
190 def on_buttonBox_clicked(self, button):
191 """
192 Private slot called by a button of the button box clicked.
193
194 @param button button that was clicked (QAbstractButton)
195 """
196 if button == self.buttonBox.button(
197 QDialogButtonBox.StandardButton.Close
198 ):
199 self.close()
200 elif button == self.buttonBox.button(
201 QDialogButtonBox.StandardButton.Cancel
202 ):
203 self.__finish()
204 elif button == self.refreshButton:
205 self.on_refreshButton_clicked()
206
207 @pyqtSlot()
208 def on_refreshButton_clicked(self):
209 """
210 Private slot to refresh the status display.
211 """
212 self.start(self.__args, recursive=self.__recursive)
213
214 def __procFinished(self, exitCode, exitStatus):
215 """
216 Private slot connected to the finished signal.
217
218 @param exitCode exit code of the process (integer)
219 @param exitStatus exit status of the process (QProcess.ExitStatus)
220 """
221 if self.lastPath is None:
222 self.__generateItem('', 'None', '')
223
224 self.__finish()
225
226 def __readStdout(self):
227 """
228 Private slot to handle the readyReadStandardOutput signal.
229
230 It reads the output of the process, formats it and inserts it into
231 the contents pane.
232 """
233 self.process.setReadChannel(QProcess.ProcessChannel.StandardOutput)
234
235 while self.process.canReadLine():
236 s = str(self.process.readLine(),
237 Preferences.getSystem("IOEncoding"),
238 'replace')
239 match = self.rx_path.fullmatch(s) or self.rx_prop.fullmatch(s)
240 if match is None:
241 self.propBuffer += ' '
242 self.propBuffer += s
243 elif match.re is self.rx_path:
244 if self.lastProp:
245 self.__generateItem(
246 self.lastPath, self.lastProp, self.propBuffer)
247 self.lastPath = match.group(1)
248 self.lastProp = None
249 self.propBuffer = ""
250 elif match.re is self.rx_prop:
251 if self.lastProp:
252 self.__generateItem(
253 self.lastPath, self.lastProp, self.propBuffer)
254 self.lastProp = match.group(1)
255 self.propBuffer = match.group(2)
256
257 def __readStderr(self):
258 """
259 Private slot to handle the readyReadStandardError signal.
260
261 It reads the error output of the process and inserts it into the
262 error pane.
263 """
264 if self.process is not None:
265 self.errorGroup.show()
266 s = str(self.process.readAllStandardError(),
267 Preferences.getSystem("IOEncoding"),
268 'replace')
269 self.errors.insertPlainText(s)
270 self.errors.ensureCursorVisible()

eric ide

mercurial