src/eric7/Plugins/VcsPlugins/vcsMercurial/HgSummaryDialog.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) 2013 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to show some summary information of the working
8 directory state.
9 """
10
11 from PyQt6.QtCore import pyqtSlot
12 from PyQt6.QtWidgets import QDialog, QDialogButtonBox
13
14 from .Ui_HgSummaryDialog import Ui_HgSummaryDialog
15
16
17 class HgSummaryDialog(QDialog, Ui_HgSummaryDialog):
18 """
19 Class implementing a dialog to show some summary information of the working
20 directory state.
21 """
22 def __init__(self, vcs, parent=None):
23 """
24 Constructor
25
26 @param vcs reference to the vcs object
27 @param parent parent widget (QWidget)
28 """
29 super().__init__(parent)
30 self.setupUi(self)
31
32 self.refreshButton = self.buttonBox.addButton(
33 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole)
34 self.refreshButton.setToolTip(
35 self.tr("Press to refresh the summary display"))
36 self.refreshButton.setEnabled(False)
37
38 self.vcs = vcs
39 self.vcs.committed.connect(self.__committed)
40
41 def start(self, mq=False, largefiles=False):
42 """
43 Public slot to start the hg summary command.
44
45 @param mq flag indicating to show the queue status as well (boolean)
46 @param largefiles flag indicating to show the largefiles status as
47 well (boolean)
48 """
49 self.errorGroup.hide()
50 self.refreshButton.setEnabled(False)
51 self.summary.clear()
52
53 self.__mq = mq
54 self.__largefiles = largefiles
55
56 args = self.vcs.initCommand("summary")
57 if self.vcs.canPull():
58 args.append("--remote")
59 if self.__mq:
60 args.append("--mq")
61 if self.__largefiles:
62 args.append("--large")
63
64 client = self.vcs.getClient()
65 output, error = client.runcommand(args)
66 if error:
67 self.__showError(error)
68 else:
69 self.__processOutput(output.splitlines())
70
71 self.refreshButton.setEnabled(True)
72
73 def on_buttonBox_clicked(self, button):
74 """
75 Private slot called by a button of the button box clicked.
76
77 @param button button that was clicked (QAbstractButton)
78 """
79 if button == self.buttonBox.button(
80 QDialogButtonBox.StandardButton.Close
81 ):
82 self.close()
83 elif button == self.refreshButton:
84 self.on_refreshButton_clicked()
85
86 @pyqtSlot()
87 def on_refreshButton_clicked(self):
88 """
89 Private slot to refresh the status display.
90 """
91 self.start(mq=self.__mq)
92
93 def __committed(self):
94 """
95 Private slot called after the commit has finished.
96 """
97 if self.isVisible():
98 self.on_refreshButton_clicked()
99
100 def __showError(self, out):
101 """
102 Private slot to show some error.
103
104 @param out error to be shown (string)
105 """
106 self.errorGroup.show()
107 self.errors.insertPlainText(out)
108 self.errors.ensureCursorVisible()
109
110 def __processOutput(self, output):
111 """
112 Private method to process the output into nice readable text.
113
114 @param output output from the summary command (string)
115 """
116 infoDict = {}
117
118 # step 1: parse the output
119 while output:
120 line = output.pop(0)
121 if ':' not in line:
122 continue
123 name, value = line.split(": ", 1)
124 value = value.strip()
125
126 if name == "parent":
127 if " " in value:
128 parent, tags = value.split(" ", 1)
129 else:
130 parent = value
131 tags = ""
132 rev, node = parent.split(":")
133
134 remarks = []
135 if tags:
136 if " (empty repository)" in tags:
137 remarks.append("@EMPTY@")
138 tags = tags.replace(" (empty repository)", "")
139 if " (no revision checked out)" in tags:
140 remarks.append("@NO_REVISION@")
141 tags = tags.replace(" (no revision checked out)", "")
142 else:
143 tags = None
144
145 value = infoDict.get(name, [])
146
147 if rev == "-1":
148 value.append((int(rev), node, tags, None, remarks))
149 else:
150 message = output.pop(0).strip()
151 value.append((int(rev), node, tags, message, remarks))
152 elif name in ("branch", "bookmarks"):
153 pass
154 elif name == "commit":
155 stateDict = {}
156 if "(" in value:
157 if value.startswith("("):
158 states = ""
159 remark = value[1:-1]
160 else:
161 states, remark = value.rsplit(" (", 1)
162 remark = remark[:-1]
163 else:
164 states = value
165 remark = ""
166 states = states.split(", ")
167 for state in states:
168 if state:
169 count, category = state.split(" ")
170 stateDict[category] = count
171 value = (stateDict, remark)
172 elif name == "update":
173 if value.endswith("(current)"):
174 value = ("@CURRENT@", 0, 0)
175 elif value.endswith("(update)"):
176 value = ("@UPDATE@", int(value.split(" ", 1)[0]), 0)
177 elif value.endswith("(merge)"):
178 parts = value.split(", ")
179 value = ("@MERGE@", int(parts[0].split(" ", 1)[0]),
180 int(parts[1].split(" ", 1)[0]))
181 else:
182 value = ("@UNKNOWN@", 0, 0)
183 elif name == "remote":
184 if value == "(synced)":
185 value = (0, 0, 0, 0)
186 else:
187 inc = incb = outg = outgb = 0
188 for val in value.split(", "):
189 count, category = val.split(" ", 1)
190 if category == "outgoing":
191 outg = int(count)
192 elif category.endswith("incoming"):
193 inc = int(count)
194 elif category == "incoming bookmarks":
195 incb = int(count)
196 elif category == "outgoing bookmarks":
197 outgb = int(count)
198 value = (inc, outg, incb, outgb)
199 elif name == "mq":
200 if value == "(empty queue)":
201 value = (0, 0)
202 else:
203 applied = unapplied = 0
204 for val in value.split(", "):
205 count, category = val.split(" ", 1)
206 if category == "applied":
207 applied = int(count)
208 elif category == "unapplied":
209 unapplied = int(count)
210 value = (applied, unapplied)
211 elif name == "largefiles":
212 if not value[0].isdigit():
213 value = 0
214 else:
215 value = int(value.split(None, 1)[0])
216 else:
217 # ignore unknown entries
218 continue
219
220 infoDict[name] = value
221
222 # step 2: build the output
223 if infoDict:
224 info = ["<table>"]
225 for pindex, (rev, node, tags, message, remarks) in enumerate(
226 infoDict["parent"], start=1
227 ):
228 changeset = "{0}:{1}".format(rev, node)
229 if len(infoDict["parent"]) > 1:
230 info.append(self.tr(
231 "<tr><td><b>Parent #{0}</b></td><td>{1}</td></tr>")
232 .format(pindex, changeset))
233 else:
234 info.append(self.tr(
235 "<tr><td><b>Parent</b></td><td>{0}</td></tr>")
236 .format(changeset))
237 if tags:
238 info.append(self.tr(
239 "<tr><td><b>Tags</b></td><td>{0}</td></tr>")
240 .format('<br/>'.join(tags.split())))
241 if message:
242 info.append(self.tr(
243 "<tr><td><b>Commit Message</b></td><td>{0}</td></tr>")
244 .format(message))
245 if remarks:
246 rem = []
247 if "@EMPTY@" in remarks:
248 rem.append(self.tr("empty repository"))
249 if "@NO_REVISION@" in remarks:
250 rem.append(self.tr("no revision checked out"))
251 info.append(self.tr(
252 "<tr><td><b>Remarks</b></td><td>{0}</td></tr>")
253 .format(", ".join(rem)))
254 if "branch" in infoDict:
255 info.append(self.tr(
256 "<tr><td><b>Branch</b></td><td>{0}</td></tr>")
257 .format(infoDict["branch"]))
258 if "bookmarks" in infoDict:
259 bookmarks = infoDict["bookmarks"].split()
260 for i in range(len(bookmarks)):
261 if bookmarks[i].startswith("*"):
262 bookmarks[i] = "<b>{0}</b>".format(bookmarks[i])
263 info.append(self.tr(
264 "<tr><td><b>Bookmarks</b></td><td>{0}</td></tr>")
265 .format('<br/>'.join(bookmarks)))
266 if "commit" in infoDict:
267 cinfo = []
268 for category, count in infoDict["commit"][0].items():
269 if category == "modified":
270 cinfo.append(self.tr("{0} modified").format(count))
271 elif category == "added":
272 cinfo.append(self.tr("{0} added").format(count))
273 elif category == "removed":
274 cinfo.append(self.tr("{0} removed").format(count))
275 elif category == "renamed":
276 cinfo.append(self.tr("{0} renamed").format(count))
277 elif category == "copied":
278 cinfo.append(self.tr("{0} copied").format(count))
279 elif category == "deleted":
280 cinfo.append(self.tr("{0} deleted").format(count))
281 elif category == "unknown":
282 cinfo.append(self.tr("{0} unknown").format(count))
283 elif category == "ignored":
284 cinfo.append(self.tr("{0} ignored").format(count))
285 elif category == "unresolved":
286 cinfo.append(
287 self.tr("{0} unresolved").format(count))
288 elif category == "subrepos":
289 cinfo.append(self.tr("{0} subrepos").format(count))
290 remark = infoDict["commit"][1]
291 if remark == "merge":
292 cinfo.append(self.tr("Merge needed"))
293 elif remark == "new branch":
294 cinfo.append(self.tr("New Branch"))
295 elif remark == "head closed":
296 cinfo.append(self.tr("Head is closed"))
297 elif remark == "clean":
298 cinfo.append(self.tr("No commit required"))
299 elif remark == "new branch head":
300 cinfo.append(self.tr("New Branch Head"))
301 info.append(self.tr(
302 "<tr><td><b>Commit Status</b></td><td>{0}</td></tr>")
303 .format("<br/>".join(cinfo)))
304 if "update" in infoDict:
305 if infoDict["update"][0] == "@CURRENT@":
306 uinfo = self.tr("current")
307 elif infoDict["update"][0] == "@UPDATE@":
308 uinfo = self.tr(
309 "%n new changeset(s)<br/>Update required", "",
310 infoDict["update"][1])
311 elif infoDict["update"][0] == "@MERGE@":
312 uinfo1 = self.tr(
313 "%n new changeset(s)", "", infoDict["update"][1])
314 uinfo2 = self.tr(
315 "%n branch head(s)", "", infoDict["update"][2])
316 uinfo = self.tr(
317 "{0}<br/>{1}<br/>Merge required",
318 "0 is changesets, 1 is branch heads"
319 ).format(uinfo1, uinfo2)
320 else:
321 uinfo = self.tr("unknown status")
322 info.append(self.tr(
323 "<tr><td><b>Update Status</b></td><td>{0}</td></tr>")
324 .format(uinfo))
325 if "remote" in infoDict:
326 if infoDict["remote"] == (0, 0, 0, 0):
327 rinfo = self.tr("synched")
328 else:
329 li = []
330 if infoDict["remote"][0]:
331 li.append(self.tr("1 or more incoming changesets"))
332 if infoDict["remote"][1]:
333 li.append(self.tr("%n outgoing changeset(s)", "",
334 infoDict["remote"][1]))
335 if infoDict["remote"][2]:
336 li.append(self.tr("%n incoming bookmark(s)", "",
337 infoDict["remote"][2]))
338 if infoDict["remote"][3]:
339 li.append(self.tr("%n outgoing bookmark(s)", "",
340 infoDict["remote"][3]))
341 rinfo = "<br/>".join(li)
342 info.append(self.tr(
343 "<tr><td><b>Remote Status</b></td><td>{0}</td></tr>")
344 .format(rinfo))
345 if "mq" in infoDict:
346 if infoDict["mq"] == (0, 0):
347 qinfo = self.tr("empty queue")
348 else:
349 li = []
350 if infoDict["mq"][0]:
351 li.append(self.tr("{0} applied")
352 .format(infoDict["mq"][0]))
353 if infoDict["mq"][1]:
354 li.append(self.tr("{0} unapplied")
355 .format(infoDict["mq"][1]))
356 qinfo = "<br/>".join(li)
357 info.append(self.tr(
358 "<tr><td><b>Queues Status</b></td><td>{0}</td></tr>")
359 .format(qinfo))
360 if "largefiles" in infoDict:
361 if infoDict["largefiles"] == 0:
362 lfInfo = self.tr("No files to upload")
363 else:
364 lfInfo = self.tr("%n file(s) to upload", "",
365 infoDict["largefiles"])
366 info.append(self.tr(
367 "<tr><td><b>Large Files</b></td><td>{0}</td></tr>")
368 .format(lfInfo))
369 info.append("</table>")
370 else:
371 info = [self.tr("<p>No status information available.</p>")]
372
373 self.summary.insertHtml("\n".join(info))

eric ide

mercurial