17 class HgSummaryDialog(QDialog, Ui_HgSummaryDialog): |
17 class HgSummaryDialog(QDialog, Ui_HgSummaryDialog): |
18 """ |
18 """ |
19 Class implementing a dialog to show some summary information of the working |
19 Class implementing a dialog to show some summary information of the working |
20 directory state. |
20 directory state. |
21 """ |
21 """ |
|
22 |
22 def __init__(self, vcs, parent=None): |
23 def __init__(self, vcs, parent=None): |
23 """ |
24 """ |
24 Constructor |
25 Constructor |
25 |
26 |
26 @param vcs reference to the vcs object |
27 @param vcs reference to the vcs object |
27 @param parent parent widget (QWidget) |
28 @param parent parent widget (QWidget) |
28 """ |
29 """ |
29 super().__init__(parent) |
30 super().__init__(parent) |
30 self.setupUi(self) |
31 self.setupUi(self) |
31 |
32 |
32 self.refreshButton = self.buttonBox.addButton( |
33 self.refreshButton = self.buttonBox.addButton( |
33 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole) |
34 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole |
34 self.refreshButton.setToolTip( |
35 ) |
35 self.tr("Press to refresh the summary display")) |
36 self.refreshButton.setToolTip(self.tr("Press to refresh the summary display")) |
36 self.refreshButton.setEnabled(False) |
37 self.refreshButton.setEnabled(False) |
37 |
38 |
38 self.vcs = vcs |
39 self.vcs = vcs |
39 self.vcs.committed.connect(self.__committed) |
40 self.vcs.committed.connect(self.__committed) |
40 |
41 |
41 def start(self, mq=False, largefiles=False): |
42 def start(self, mq=False, largefiles=False): |
42 """ |
43 """ |
43 Public slot to start the hg summary command. |
44 Public slot to start the hg summary command. |
44 |
45 |
45 @param mq flag indicating to show the queue status as well (boolean) |
46 @param mq flag indicating to show the queue status as well (boolean) |
46 @param largefiles flag indicating to show the largefiles status as |
47 @param largefiles flag indicating to show the largefiles status as |
47 well (boolean) |
48 well (boolean) |
48 """ |
49 """ |
49 self.errorGroup.hide() |
50 self.errorGroup.hide() |
50 self.refreshButton.setEnabled(False) |
51 self.refreshButton.setEnabled(False) |
51 self.summary.clear() |
52 self.summary.clear() |
52 |
53 |
53 self.__mq = mq |
54 self.__mq = mq |
54 self.__largefiles = largefiles |
55 self.__largefiles = largefiles |
55 |
56 |
56 args = self.vcs.initCommand("summary") |
57 args = self.vcs.initCommand("summary") |
57 if self.vcs.canPull(): |
58 if self.vcs.canPull(): |
58 args.append("--remote") |
59 args.append("--remote") |
59 if self.__mq: |
60 if self.__mq: |
60 args.append("--mq") |
61 args.append("--mq") |
61 if self.__largefiles: |
62 if self.__largefiles: |
62 args.append("--large") |
63 args.append("--large") |
63 |
64 |
64 client = self.vcs.getClient() |
65 client = self.vcs.getClient() |
65 output, error = client.runcommand(args) |
66 output, error = client.runcommand(args) |
66 if error: |
67 if error: |
67 self.__showError(error) |
68 self.__showError(error) |
68 else: |
69 else: |
69 self.__processOutput(output.splitlines()) |
70 self.__processOutput(output.splitlines()) |
70 |
71 |
71 self.refreshButton.setEnabled(True) |
72 self.refreshButton.setEnabled(True) |
72 |
73 |
73 def on_buttonBox_clicked(self, button): |
74 def on_buttonBox_clicked(self, button): |
74 """ |
75 """ |
75 Private slot called by a button of the button box clicked. |
76 Private slot called by a button of the button box clicked. |
76 |
77 |
77 @param button button that was clicked (QAbstractButton) |
78 @param button button that was clicked (QAbstractButton) |
78 """ |
79 """ |
79 if button == self.buttonBox.button( |
80 if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close): |
80 QDialogButtonBox.StandardButton.Close |
|
81 ): |
|
82 self.close() |
81 self.close() |
83 elif button == self.refreshButton: |
82 elif button == self.refreshButton: |
84 self.on_refreshButton_clicked() |
83 self.on_refreshButton_clicked() |
85 |
84 |
86 @pyqtSlot() |
85 @pyqtSlot() |
87 def on_refreshButton_clicked(self): |
86 def on_refreshButton_clicked(self): |
88 """ |
87 """ |
89 Private slot to refresh the status display. |
88 Private slot to refresh the status display. |
90 """ |
89 """ |
91 self.start(mq=self.__mq) |
90 self.start(mq=self.__mq) |
92 |
91 |
93 def __committed(self): |
92 def __committed(self): |
94 """ |
93 """ |
95 Private slot called after the commit has finished. |
94 Private slot called after the commit has finished. |
96 """ |
95 """ |
97 if self.isVisible(): |
96 if self.isVisible(): |
98 self.on_refreshButton_clicked() |
97 self.on_refreshButton_clicked() |
99 |
98 |
100 def __showError(self, out): |
99 def __showError(self, out): |
101 """ |
100 """ |
102 Private slot to show some error. |
101 Private slot to show some error. |
103 |
102 |
104 @param out error to be shown (string) |
103 @param out error to be shown (string) |
105 """ |
104 """ |
106 self.errorGroup.show() |
105 self.errorGroup.show() |
107 self.errors.insertPlainText(out) |
106 self.errors.insertPlainText(out) |
108 self.errors.ensureCursorVisible() |
107 self.errors.ensureCursorVisible() |
109 |
108 |
110 def __processOutput(self, output): |
109 def __processOutput(self, output): |
111 """ |
110 """ |
112 Private method to process the output into nice readable text. |
111 Private method to process the output into nice readable text. |
113 |
112 |
114 @param output output from the summary command (string) |
113 @param output output from the summary command (string) |
115 """ |
114 """ |
116 infoDict = {} |
115 infoDict = {} |
117 |
116 |
118 # step 1: parse the output |
117 # step 1: parse the output |
119 while output: |
118 while output: |
120 line = output.pop(0) |
119 line = output.pop(0) |
121 if ':' not in line: |
120 if ":" not in line: |
122 continue |
121 continue |
123 name, value = line.split(": ", 1) |
122 name, value = line.split(": ", 1) |
124 value = value.strip() |
123 value = value.strip() |
125 |
124 |
126 if name == "parent": |
125 if name == "parent": |
127 if " " in value: |
126 if " " in value: |
128 parent, tags = value.split(" ", 1) |
127 parent, tags = value.split(" ", 1) |
129 else: |
128 else: |
130 parent = value |
129 parent = value |
131 tags = "" |
130 tags = "" |
132 rev, node = parent.split(":") |
131 rev, node = parent.split(":") |
133 |
132 |
134 remarks = [] |
133 remarks = [] |
135 if tags: |
134 if tags: |
136 if " (empty repository)" in tags: |
135 if " (empty repository)" in tags: |
137 remarks.append("@EMPTY@") |
136 remarks.append("@EMPTY@") |
138 tags = tags.replace(" (empty repository)", "") |
137 tags = tags.replace(" (empty repository)", "") |
139 if " (no revision checked out)" in tags: |
138 if " (no revision checked out)" in tags: |
140 remarks.append("@NO_REVISION@") |
139 remarks.append("@NO_REVISION@") |
141 tags = tags.replace(" (no revision checked out)", "") |
140 tags = tags.replace(" (no revision checked out)", "") |
142 else: |
141 else: |
143 tags = None |
142 tags = None |
144 |
143 |
145 value = infoDict.get(name, []) |
144 value = infoDict.get(name, []) |
146 |
145 |
147 if rev == "-1": |
146 if rev == "-1": |
148 value.append((int(rev), node, tags, None, remarks)) |
147 value.append((int(rev), node, tags, None, remarks)) |
149 else: |
148 else: |
150 message = output.pop(0).strip() |
149 message = output.pop(0).strip() |
151 value.append((int(rev), node, tags, message, remarks)) |
150 value.append((int(rev), node, tags, message, remarks)) |
214 else: |
216 else: |
215 value = int(value.split(None, 1)[0]) |
217 value = int(value.split(None, 1)[0]) |
216 else: |
218 else: |
217 # ignore unknown entries |
219 # ignore unknown entries |
218 continue |
220 continue |
219 |
221 |
220 infoDict[name] = value |
222 infoDict[name] = value |
221 |
223 |
222 # step 2: build the output |
224 # step 2: build the output |
223 if infoDict: |
225 if infoDict: |
224 info = ["<table>"] |
226 info = ["<table>"] |
225 for pindex, (rev, node, tags, message, remarks) in enumerate( |
227 for pindex, (rev, node, tags, message, remarks) in enumerate( |
226 infoDict["parent"], start=1 |
228 infoDict["parent"], start=1 |
227 ): |
229 ): |
228 changeset = "{0}:{1}".format(rev, node) |
230 changeset = "{0}:{1}".format(rev, node) |
229 if len(infoDict["parent"]) > 1: |
231 if len(infoDict["parent"]) > 1: |
230 info.append(self.tr( |
232 info.append( |
231 "<tr><td><b>Parent #{0}</b></td><td>{1}</td></tr>") |
233 self.tr( |
232 .format(pindex, changeset)) |
234 "<tr><td><b>Parent #{0}</b></td><td>{1}</td></tr>" |
233 else: |
235 ).format(pindex, changeset) |
234 info.append(self.tr( |
236 ) |
235 "<tr><td><b>Parent</b></td><td>{0}</td></tr>") |
237 else: |
236 .format(changeset)) |
238 info.append( |
|
239 self.tr("<tr><td><b>Parent</b></td><td>{0}</td></tr>").format( |
|
240 changeset |
|
241 ) |
|
242 ) |
237 if tags: |
243 if tags: |
238 info.append(self.tr( |
244 info.append( |
239 "<tr><td><b>Tags</b></td><td>{0}</td></tr>") |
245 self.tr("<tr><td><b>Tags</b></td><td>{0}</td></tr>").format( |
240 .format('<br/>'.join(tags.split()))) |
246 "<br/>".join(tags.split()) |
|
247 ) |
|
248 ) |
241 if message: |
249 if message: |
242 info.append(self.tr( |
250 info.append( |
243 "<tr><td><b>Commit Message</b></td><td>{0}</td></tr>") |
251 self.tr( |
244 .format(message)) |
252 "<tr><td><b>Commit Message</b></td><td>{0}</td></tr>" |
|
253 ).format(message) |
|
254 ) |
245 if remarks: |
255 if remarks: |
246 rem = [] |
256 rem = [] |
247 if "@EMPTY@" in remarks: |
257 if "@EMPTY@" in remarks: |
248 rem.append(self.tr("empty repository")) |
258 rem.append(self.tr("empty repository")) |
249 if "@NO_REVISION@" in remarks: |
259 if "@NO_REVISION@" in remarks: |
250 rem.append(self.tr("no revision checked out")) |
260 rem.append(self.tr("no revision checked out")) |
251 info.append(self.tr( |
261 info.append( |
252 "<tr><td><b>Remarks</b></td><td>{0}</td></tr>") |
262 self.tr("<tr><td><b>Remarks</b></td><td>{0}</td></tr>").format( |
253 .format(", ".join(rem))) |
263 ", ".join(rem) |
|
264 ) |
|
265 ) |
254 if "branch" in infoDict: |
266 if "branch" in infoDict: |
255 info.append(self.tr( |
267 info.append( |
256 "<tr><td><b>Branch</b></td><td>{0}</td></tr>") |
268 self.tr("<tr><td><b>Branch</b></td><td>{0}</td></tr>").format( |
257 .format(infoDict["branch"])) |
269 infoDict["branch"] |
|
270 ) |
|
271 ) |
258 if "bookmarks" in infoDict: |
272 if "bookmarks" in infoDict: |
259 bookmarks = infoDict["bookmarks"].split() |
273 bookmarks = infoDict["bookmarks"].split() |
260 for i in range(len(bookmarks)): |
274 for i in range(len(bookmarks)): |
261 if bookmarks[i].startswith("*"): |
275 if bookmarks[i].startswith("*"): |
262 bookmarks[i] = "<b>{0}</b>".format(bookmarks[i]) |
276 bookmarks[i] = "<b>{0}</b>".format(bookmarks[i]) |
263 info.append(self.tr( |
277 info.append( |
264 "<tr><td><b>Bookmarks</b></td><td>{0}</td></tr>") |
278 self.tr("<tr><td><b>Bookmarks</b></td><td>{0}</td></tr>").format( |
265 .format('<br/>'.join(bookmarks))) |
279 "<br/>".join(bookmarks) |
|
280 ) |
|
281 ) |
266 if "commit" in infoDict: |
282 if "commit" in infoDict: |
267 cinfo = [] |
283 cinfo = [] |
268 for category, count in infoDict["commit"][0].items(): |
284 for category, count in infoDict["commit"][0].items(): |
269 if category == "modified": |
285 if category == "modified": |
270 cinfo.append(self.tr("{0} modified").format(count)) |
286 cinfo.append(self.tr("{0} modified").format(count)) |
296 cinfo.append(self.tr("Head is closed")) |
311 cinfo.append(self.tr("Head is closed")) |
297 elif remark == "clean": |
312 elif remark == "clean": |
298 cinfo.append(self.tr("No commit required")) |
313 cinfo.append(self.tr("No commit required")) |
299 elif remark == "new branch head": |
314 elif remark == "new branch head": |
300 cinfo.append(self.tr("New Branch Head")) |
315 cinfo.append(self.tr("New Branch Head")) |
301 info.append(self.tr( |
316 info.append( |
302 "<tr><td><b>Commit Status</b></td><td>{0}</td></tr>") |
317 self.tr( |
303 .format("<br/>".join(cinfo))) |
318 "<tr><td><b>Commit Status</b></td><td>{0}</td></tr>" |
|
319 ).format("<br/>".join(cinfo)) |
|
320 ) |
304 if "update" in infoDict: |
321 if "update" in infoDict: |
305 if infoDict["update"][0] == "@CURRENT@": |
322 if infoDict["update"][0] == "@CURRENT@": |
306 uinfo = self.tr("current") |
323 uinfo = self.tr("current") |
307 elif infoDict["update"][0] == "@UPDATE@": |
324 elif infoDict["update"][0] == "@UPDATE@": |
308 uinfo = self.tr( |
325 uinfo = self.tr( |
309 "%n new changeset(s)<br/>Update required", "", |
326 "%n new changeset(s)<br/>Update required", |
310 infoDict["update"][1]) |
327 "", |
|
328 infoDict["update"][1], |
|
329 ) |
311 elif infoDict["update"][0] == "@MERGE@": |
330 elif infoDict["update"][0] == "@MERGE@": |
312 uinfo1 = self.tr( |
331 uinfo1 = self.tr("%n new changeset(s)", "", infoDict["update"][1]) |
313 "%n new changeset(s)", "", infoDict["update"][1]) |
332 uinfo2 = self.tr("%n branch head(s)", "", infoDict["update"][2]) |
314 uinfo2 = self.tr( |
|
315 "%n branch head(s)", "", infoDict["update"][2]) |
|
316 uinfo = self.tr( |
333 uinfo = self.tr( |
317 "{0}<br/>{1}<br/>Merge required", |
334 "{0}<br/>{1}<br/>Merge required", |
318 "0 is changesets, 1 is branch heads" |
335 "0 is changesets, 1 is branch heads", |
319 ).format(uinfo1, uinfo2) |
336 ).format(uinfo1, uinfo2) |
320 else: |
337 else: |
321 uinfo = self.tr("unknown status") |
338 uinfo = self.tr("unknown status") |
322 info.append(self.tr( |
339 info.append( |
323 "<tr><td><b>Update Status</b></td><td>{0}</td></tr>") |
340 self.tr( |
324 .format(uinfo)) |
341 "<tr><td><b>Update Status</b></td><td>{0}</td></tr>" |
|
342 ).format(uinfo) |
|
343 ) |
325 if "remote" in infoDict: |
344 if "remote" in infoDict: |
326 if infoDict["remote"] == (0, 0, 0, 0): |
345 if infoDict["remote"] == (0, 0, 0, 0): |
327 rinfo = self.tr("synched") |
346 rinfo = self.tr("synched") |
328 else: |
347 else: |
329 li = [] |
348 li = [] |
330 if infoDict["remote"][0]: |
349 if infoDict["remote"][0]: |
331 li.append(self.tr("1 or more incoming changesets")) |
350 li.append(self.tr("1 or more incoming changesets")) |
332 if infoDict["remote"][1]: |
351 if infoDict["remote"][1]: |
333 li.append(self.tr("%n outgoing changeset(s)", "", |
352 li.append( |
334 infoDict["remote"][1])) |
353 self.tr( |
|
354 "%n outgoing changeset(s)", "", infoDict["remote"][1] |
|
355 ) |
|
356 ) |
335 if infoDict["remote"][2]: |
357 if infoDict["remote"][2]: |
336 li.append(self.tr("%n incoming bookmark(s)", "", |
358 li.append( |
337 infoDict["remote"][2])) |
359 self.tr( |
|
360 "%n incoming bookmark(s)", "", infoDict["remote"][2] |
|
361 ) |
|
362 ) |
338 if infoDict["remote"][3]: |
363 if infoDict["remote"][3]: |
339 li.append(self.tr("%n outgoing bookmark(s)", "", |
364 li.append( |
340 infoDict["remote"][3])) |
365 self.tr( |
|
366 "%n outgoing bookmark(s)", "", infoDict["remote"][3] |
|
367 ) |
|
368 ) |
341 rinfo = "<br/>".join(li) |
369 rinfo = "<br/>".join(li) |
342 info.append(self.tr( |
370 info.append( |
343 "<tr><td><b>Remote Status</b></td><td>{0}</td></tr>") |
371 self.tr( |
344 .format(rinfo)) |
372 "<tr><td><b>Remote Status</b></td><td>{0}</td></tr>" |
|
373 ).format(rinfo) |
|
374 ) |
345 if "mq" in infoDict: |
375 if "mq" in infoDict: |
346 if infoDict["mq"] == (0, 0): |
376 if infoDict["mq"] == (0, 0): |
347 qinfo = self.tr("empty queue") |
377 qinfo = self.tr("empty queue") |
348 else: |
378 else: |
349 li = [] |
379 li = [] |
350 if infoDict["mq"][0]: |
380 if infoDict["mq"][0]: |
351 li.append(self.tr("{0} applied") |
381 li.append(self.tr("{0} applied").format(infoDict["mq"][0])) |
352 .format(infoDict["mq"][0])) |
|
353 if infoDict["mq"][1]: |
382 if infoDict["mq"][1]: |
354 li.append(self.tr("{0} unapplied") |
383 li.append(self.tr("{0} unapplied").format(infoDict["mq"][1])) |
355 .format(infoDict["mq"][1])) |
|
356 qinfo = "<br/>".join(li) |
384 qinfo = "<br/>".join(li) |
357 info.append(self.tr( |
385 info.append( |
358 "<tr><td><b>Queues Status</b></td><td>{0}</td></tr>") |
386 self.tr( |
359 .format(qinfo)) |
387 "<tr><td><b>Queues Status</b></td><td>{0}</td></tr>" |
|
388 ).format(qinfo) |
|
389 ) |
360 if "largefiles" in infoDict: |
390 if "largefiles" in infoDict: |
361 if infoDict["largefiles"] == 0: |
391 if infoDict["largefiles"] == 0: |
362 lfInfo = self.tr("No files to upload") |
392 lfInfo = self.tr("No files to upload") |
363 else: |
393 else: |
364 lfInfo = self.tr("%n file(s) to upload", "", |
394 lfInfo = self.tr("%n file(s) to upload", "", infoDict["largefiles"]) |
365 infoDict["largefiles"]) |
395 info.append( |
366 info.append(self.tr( |
396 self.tr("<tr><td><b>Large Files</b></td><td>{0}</td></tr>").format( |
367 "<tr><td><b>Large Files</b></td><td>{0}</td></tr>") |
397 lfInfo |
368 .format(lfInfo)) |
398 ) |
|
399 ) |
369 info.append("</table>") |
400 info.append("</table>") |
370 else: |
401 else: |
371 info = [self.tr("<p>No status information available.</p>")] |
402 info = [self.tr("<p>No status information available.</p>")] |
372 |
403 |
373 self.summary.insertHtml("\n".join(info)) |
404 self.summary.insertHtml("\n".join(info)) |