src/eric7/Plugins/VcsPlugins/vcsMercurial/ShelveExtension/HgShelveBrowserDialog.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) 2014 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing Mercurial shelve browser dialog.
8 """
9
10 from PyQt6.QtCore import pyqtSlot, Qt, QPoint
11 from PyQt6.QtWidgets import (
12 QWidget, QDialogButtonBox, QTreeWidgetItem, QAbstractButton, QMenu,
13 QHeaderView, QApplication
14 )
15
16 from EricGui.EricOverrideCursor import EricOverrideCursor
17
18 from .Ui_HgShelveBrowserDialog import Ui_HgShelveBrowserDialog
19
20
21 class HgShelveBrowserDialog(QWidget, Ui_HgShelveBrowserDialog):
22 """
23 Class implementing Mercurial shelve browser dialog.
24 """
25 NameColumn = 0
26 AgeColumn = 1
27 MessageColumn = 2
28
29 def __init__(self, vcs, parent=None):
30 """
31 Constructor
32
33 @param vcs reference to the vcs object
34 @param parent parent widget (QWidget)
35 """
36 super().__init__(parent)
37 self.setupUi(self)
38
39 self.buttonBox.button(
40 QDialogButtonBox.StandardButton.Close).setEnabled(False)
41 self.buttonBox.button(
42 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
43
44 self.__position = QPoint()
45
46 self.__fileStatisticsRole = Qt.ItemDataRole.UserRole
47 self.__totalStatisticsRole = Qt.ItemDataRole.UserRole + 1
48
49 self.shelveList.header().setSortIndicator(
50 0, Qt.SortOrder.AscendingOrder)
51
52 self.refreshButton = self.buttonBox.addButton(
53 self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole)
54 self.refreshButton.setToolTip(
55 self.tr("Press to refresh the list of shelves"))
56 self.refreshButton.setEnabled(False)
57
58 self.vcs = vcs
59 self.__hgClient = vcs.getClient()
60 self.__resetUI()
61
62 self.__contextMenu = QMenu()
63 self.__unshelveAct = self.__contextMenu.addAction(
64 self.tr("Restore selected shelve"), self.__unshelve)
65 self.__deleteAct = self.__contextMenu.addAction(
66 self.tr("Delete selected shelves"), self.__deleteShelves)
67 self.__contextMenu.addAction(
68 self.tr("Delete all shelves"), self.__cleanupShelves)
69
70 def closeEvent(self, e):
71 """
72 Protected slot implementing a close event handler.
73
74 @param e close event (QCloseEvent)
75 """
76 if self.__hgClient.isExecuting():
77 self.__hgClient.cancel()
78
79 self.__position = self.pos()
80
81 e.accept()
82
83 def show(self):
84 """
85 Public slot to show the dialog.
86 """
87 if not self.__position.isNull():
88 self.move(self.__position)
89 self.__resetUI()
90
91 super().show()
92
93 def __resetUI(self):
94 """
95 Private method to reset the user interface.
96 """
97 self.shelveList.clear()
98
99 def __resizeColumnsShelves(self):
100 """
101 Private method to resize the shelve list columns.
102 """
103 self.shelveList.header().resizeSections(
104 QHeaderView.ResizeMode.ResizeToContents)
105 self.shelveList.header().setStretchLastSection(True)
106
107 def __generateShelveEntry(self, name, age, message, fileStatistics,
108 totals):
109 """
110 Private method to generate the shelve items.
111
112 @param name name of the shelve (string)
113 @param age age of the shelve (string)
114 @param message shelve message (string)
115 @param fileStatistics per file change statistics (tuple of
116 four strings with file name, number of changes, number of
117 added lines and number of deleted lines)
118 @param totals overall statistics (tuple of three strings with
119 number of changed files, number of added lines and number
120 of deleted lines)
121 """
122 itm = QTreeWidgetItem(self.shelveList, [name, age, message])
123 itm.setData(0, self.__fileStatisticsRole, fileStatistics)
124 itm.setData(0, self.__totalStatisticsRole, totals)
125
126 def __getShelveEntries(self):
127 """
128 Private method to retrieve the list of shelves.
129 """
130 self.buttonBox.button(
131 QDialogButtonBox.StandardButton.Close).setEnabled(False)
132 self.buttonBox.button(
133 QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
134 self.buttonBox.button(
135 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
136 QApplication.processEvents()
137
138 self.buf = []
139 self.errors.clear()
140 self.intercept = False
141
142 args = self.vcs.initCommand("shelve")
143 args.append("--list")
144 args.append("--stat")
145
146 with EricOverrideCursor():
147 out, err = self.__hgClient.runcommand(args)
148 self.buf = out.splitlines(True)
149 if err:
150 self.__showError(err)
151 self.__processBuffer()
152 self.__finish()
153
154 def start(self):
155 """
156 Public slot to start the hg shelve command.
157 """
158 self.errorGroup.hide()
159 QApplication.processEvents()
160
161 self.activateWindow()
162 self.raise_()
163
164 self.shelveList.clear()
165 self.__started = True
166 self.__getShelveEntries()
167
168 def __finish(self):
169 """
170 Private slot called when the process finished or the user pressed
171 the button.
172 """
173 self.buttonBox.button(
174 QDialogButtonBox.StandardButton.Close).setEnabled(True)
175 self.buttonBox.button(
176 QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
177 self.buttonBox.button(
178 QDialogButtonBox.StandardButton.Close).setDefault(True)
179
180 self.refreshButton.setEnabled(True)
181
182 def __processBuffer(self):
183 """
184 Private method to process the buffered output of the hg shelve command.
185 """
186 lastWasFileStats = False
187 firstLine = True
188 itemData = {}
189 for line in self.buf:
190 if firstLine:
191 name, line = line.split("(", 1)
192 age, message = line.split(")", 1)
193 itemData["name"] = name.strip()
194 itemData["age"] = age.strip()
195 itemData["message"] = message.strip()
196 itemData["files"] = []
197 firstLine = False
198 elif '|' in line:
199 # file stats: foo.py | 3 ++-
200 file, changes = line.strip().split("|", 1)
201 if changes.strip().endswith(("+", "-")):
202 total, addDelete = changes.strip().split(None, 1)
203 additions = str(addDelete.count("+"))
204 deletions = str(addDelete.count("-"))
205 else:
206 total = changes.strip()
207 additions = '0'
208 deletions = '0'
209 itemData["files"].append((file, total, additions, deletions))
210 lastWasFileStats = True
211 elif lastWasFileStats:
212 # summary line
213 # 2 files changed, 15 insertions(+), 1 deletions(-)
214 total, added, deleted = line.strip().split(",", 2)
215 total = total.split()[0]
216 added = added.split()[0]
217 deleted = deleted.split()[0]
218 itemData["summary"] = (total, added, deleted)
219
220 self.__generateShelveEntry(
221 itemData["name"], itemData["age"], itemData["message"],
222 itemData["files"], itemData["summary"])
223
224 lastWasFileStats = False
225 firstLine = True
226 itemData = {}
227
228 self.__resizeColumnsShelves()
229
230 if self.__started:
231 self.shelveList.setCurrentItem(self.shelveList.topLevelItem(0))
232 self.__started = False
233
234 def __showError(self, out):
235 """
236 Private slot to show some error.
237
238 @param out error to be shown (string)
239 """
240 self.errorGroup.show()
241 self.errors.insertPlainText(out)
242 self.errors.ensureCursorVisible()
243
244 @pyqtSlot(QAbstractButton)
245 def on_buttonBox_clicked(self, button):
246 """
247 Private slot called by a button of the button box clicked.
248
249 @param button button that was clicked (QAbstractButton)
250 """
251 if button == self.buttonBox.button(
252 QDialogButtonBox.StandardButton.Close
253 ):
254 self.close()
255 elif button == self.buttonBox.button(
256 QDialogButtonBox.StandardButton.Cancel
257 ):
258 self.cancelled = True
259 self.__hgClient.cancel()
260 elif button == self.refreshButton:
261 self.on_refreshButton_clicked()
262
263 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
264 def on_shelveList_currentItemChanged(self, current, previous):
265 """
266 Private slot called, when the current item of the shelve list changes.
267
268 @param current reference to the new current item (QTreeWidgetItem)
269 @param previous reference to the old current item (QTreeWidgetItem)
270 """
271 self.statisticsList.clear()
272 if current:
273 for dataSet in current.data(0, self.__fileStatisticsRole):
274 QTreeWidgetItem(self.statisticsList, list(dataSet))
275 self.statisticsList.header().resizeSections(
276 QHeaderView.ResizeMode.ResizeToContents)
277 self.statisticsList.header().setStretchLastSection(True)
278
279 totals = current.data(0, self.__totalStatisticsRole)
280 self.filesLabel.setText(
281 self.tr("%n file(s) changed", None, int(totals[0])))
282 self.insertionsLabel.setText(
283 self.tr("%n line(s) inserted", None, int(totals[1])))
284 self.deletionsLabel.setText(
285 self.tr("%n line(s) deleted", None, int(totals[2])))
286 else:
287 self.filesLabel.setText("")
288 self.insertionsLabel.setText("")
289 self.deletionsLabel.setText("")
290
291 @pyqtSlot(QPoint)
292 def on_shelveList_customContextMenuRequested(self, pos):
293 """
294 Private slot to show the context menu of the shelve list.
295
296 @param pos position of the mouse pointer (QPoint)
297 """
298 selectedItemsCount = len(self.shelveList.selectedItems())
299 self.__unshelveAct.setEnabled(selectedItemsCount == 1)
300 self.__deleteAct.setEnabled(selectedItemsCount > 0)
301
302 self.__contextMenu.popup(self.mapToGlobal(pos))
303
304 @pyqtSlot()
305 def on_refreshButton_clicked(self):
306 """
307 Private slot to refresh the list of shelves.
308 """
309 self.buttonBox.button(
310 QDialogButtonBox.StandardButton.Close).setEnabled(False)
311 self.buttonBox.button(
312 QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
313 self.buttonBox.button(
314 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
315
316 self.refreshButton.setEnabled(False)
317
318 self.start()
319
320 def __unshelve(self):
321 """
322 Private slot to restore the selected shelve of changes.
323 """
324 itm = self.shelveList.selectedItems()[0]
325 if itm is not None:
326 name = itm.text(self.NameColumn)
327 self.vcs.getExtensionObject("shelve").hgUnshelve(shelveName=name)
328 self.on_refreshButton_clicked()
329
330 def __deleteShelves(self):
331 """
332 Private slot to delete the selected shelves.
333 """
334 shelveNames = []
335 for itm in self.shelveList.selectedItems():
336 shelveNames.append(itm.text(self.NameColumn))
337 if shelveNames:
338 self.vcs.getExtensionObject("shelve").hgDeleteShelves(
339 shelveNames=shelveNames)
340 self.on_refreshButton_clicked()
341
342 def __cleanupShelves(self):
343 """
344 Private slot to delete all shelves.
345 """
346 self.vcs.getExtensionObject("shelve").hgCleanupShelves()
347 self.on_refreshButton_clicked()

eric ide

mercurial