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