src/eric7/Plugins/VcsPlugins/vcsSubversion/SvnPropListDialog.py

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

eric ide

mercurial