src/eric7/Plugins/VcsPlugins/vcsMercurial/ShelveBuiltin/HgShelveBrowserDialog.py

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

eric ide

mercurial