5 |
5 |
6 """ |
6 """ |
7 Module implementing a VCS Status widget for the sidebar/toolbar. |
7 Module implementing a VCS Status widget for the sidebar/toolbar. |
8 """ |
8 """ |
9 |
9 |
|
10 import contextlib |
|
11 import os |
|
12 |
10 from PyQt6.QtCore import pyqtSlot, Qt |
13 from PyQt6.QtCore import pyqtSlot, Qt |
11 from PyQt6.QtWidgets import ( |
14 from PyQt6.QtWidgets import ( |
12 QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QListView, |
15 QWidget, QVBoxLayout, QHBoxLayout, QLabel, QSizePolicy, QListView, |
13 QListWidget, QListWidgetItem, QToolButton |
16 QListWidget, QListWidgetItem, QToolButton, QAbstractItemView |
14 ) |
17 ) |
15 |
18 |
|
19 from EricWidgets.EricApplication import ericApp |
|
20 from EricWidgets import EricMessageBox |
|
21 |
|
22 import Preferences |
16 import UI.PixmapCache |
23 import UI.PixmapCache |
17 |
24 |
18 |
25 |
19 class StatusWidget(QWidget): |
26 class StatusWidget(QWidget): |
20 """ |
27 """ |
21 Class implementing a VCS Status widget for the sidebar/toolbox. |
28 Class implementing a VCS Status widget for the sidebar/toolbox. |
22 """ |
29 """ |
|
30 StatusDataRole = Qt.ItemDataRole.UserRole + 1 |
|
31 |
23 def __init__(self, project, parent=None): |
32 def __init__(self, project, parent=None): |
24 """ |
33 """ |
25 Constructor |
34 Constructor |
26 |
35 |
27 @param project reference to the project object |
36 @param project reference to the project object |
44 self.__infoLabel = QLabel(self) |
53 self.__infoLabel = QLabel(self) |
45 self.__infoLabel.setSizePolicy( |
54 self.__infoLabel.setSizePolicy( |
46 QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred) |
55 QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred) |
47 self.__topLayout.addWidget(self.__infoLabel) |
56 self.__topLayout.addWidget(self.__infoLabel) |
48 |
57 |
|
58 self.__commitToggleButton = QToolButton(self) |
|
59 self.__commitToggleButton.setIcon(UI.PixmapCache.getIcon("check")) |
|
60 self.__commitToggleButton.setToolTip( |
|
61 self.tr("Press to toggle the commit markers")) |
|
62 self.__commitToggleButton.clicked.connect(self.__toggleCheckMark) |
|
63 self.__topLayout.addWidget(self.__commitToggleButton) |
|
64 |
|
65 self.__commitButton = QToolButton(self) |
|
66 self.__commitButton.setIcon(UI.PixmapCache.getIcon("vcsCommit")) |
|
67 self.__commitButton.setToolTip( |
|
68 self.tr("Press to commit the marked entries")) |
|
69 self.__commitButton.clicked.connect(self.__commit) |
|
70 self.__topLayout.addWidget(self.__commitButton) |
|
71 |
|
72 self.__addButton = QToolButton(self) |
|
73 self.__addButton.setIcon(UI.PixmapCache.getIcon("vcsAdd")) |
|
74 self.__addButton.setToolTip( |
|
75 self.tr("Press to add the selected, untracked entries")) |
|
76 self.__addButton.clicked.connect(self.__addUntracked) |
|
77 self.__topLayout.addWidget(self.__addButton) |
|
78 |
49 self.__reloadButton = QToolButton(self) |
79 self.__reloadButton = QToolButton(self) |
50 self.__reloadButton.setIcon(UI.PixmapCache.getIcon("reload")) |
80 self.__reloadButton.setIcon(UI.PixmapCache.getIcon("reload")) |
|
81 self.__reloadButton.setToolTip( |
|
82 self.tr("Press to reload the status list")) |
51 self.__reloadButton.clicked.connect(self.__reload) |
83 self.__reloadButton.clicked.connect(self.__reload) |
52 self.__topLayout.addWidget(self.__reloadButton) |
84 self.__topLayout.addWidget(self.__reloadButton) |
53 |
85 |
54 self.__layout.addLayout(self.__topLayout) |
86 self.__layout.addLayout(self.__topLayout) |
55 |
87 |
56 self.__statusList = QListWidget(self) |
88 self.__statusList = QListWidget(self) |
57 self.__statusList.setAlternatingRowColors(True) |
89 self.__statusList.setAlternatingRowColors(True) |
58 self.__statusList.setSortingEnabled(True) |
90 self.__statusList.setSortingEnabled(True) |
59 self.__statusList.setViewMode(QListView.ViewMode.ListMode) |
91 self.__statusList.setViewMode(QListView.ViewMode.ListMode) |
60 self.__statusList.setTextElideMode(Qt.TextElideMode.ElideLeft) |
92 self.__statusList.setTextElideMode(Qt.TextElideMode.ElideLeft) |
|
93 self.__statusList.setSelectionMode( |
|
94 QAbstractItemView.SelectionMode.ExtendedSelection) |
61 self.__layout.addWidget(self.__statusList) |
95 self.__layout.addWidget(self.__statusList) |
62 |
96 |
63 self.setLayout(self.__layout) |
97 self.setLayout(self.__layout) |
|
98 |
|
99 self.__statusIcons = { |
|
100 "A": "vcs-added", # added |
|
101 "M": "vcs-modified", # modified |
|
102 "O": "vcs-removed", # removed |
|
103 "R": "vcs-renamed", # renamed |
|
104 "U": "vcs-update-required", # update needed |
|
105 "Z": "vcs-conflicting", # conflict |
|
106 "?": "vcs-untracked", # not tracked |
|
107 "!": "vcs-missing", # missing |
|
108 } |
|
109 self.__statusTexts = { |
|
110 "A": self.tr("added"), |
|
111 "M": self.tr("modified"), |
|
112 "O": self.tr("removed"), |
|
113 "R": self.tr("renamed"), |
|
114 "U": self.tr("needs update"), |
|
115 "Z": self.tr("conflict"), |
|
116 "?": self.tr("not tracked"), |
|
117 "!": self.tr("missing"), |
|
118 } |
64 |
119 |
65 if self.__project.isOpen(): |
120 if self.__project.isOpen(): |
66 self.__projectOpened() |
121 self.__projectOpened() |
67 else: |
122 else: |
68 self.__projectClosed() |
123 self.__projectClosed() |
69 |
124 |
70 self.__project.projectOpened.connect(self.__projectOpened) |
125 self.__project.projectOpened.connect(self.__projectOpened) |
71 self.__project.projectClosed.connect(self.__projectClosed) |
126 self.__project.projectClosed.connect(self.__projectClosed) |
|
127 self.__project.vcsCommitted.connect(self.__committed) |
72 self.__project.vcsStatusMonitorInfo.connect(self.__setInfoText) |
128 self.__project.vcsStatusMonitorInfo.connect(self.__setInfoText) |
73 self.__project.vcsStatusMonitorData.connect(self.__processStatusData) |
129 self.__project.vcsStatusMonitorAllData.connect( |
|
130 self.__processStatusData) |
74 |
131 |
75 @pyqtSlot() |
132 @pyqtSlot() |
76 def __projectOpened(self): |
133 def __projectOpened(self): |
77 """ |
134 """ |
78 Private slot to handle the opening of a project. |
135 Private slot to handle the opening of a project. |
120 <li>"M" path has local changes</li> |
177 <li>"M" path has local changes</li> |
121 <li>"O" path was removed</li> |
178 <li>"O" path was removed</li> |
122 <li>"R" path was deleted and then re-added</li> |
179 <li>"R" path was deleted and then re-added</li> |
123 <li>"U" path needs an update</li> |
180 <li>"U" path needs an update</li> |
124 <li>"Z" path contains a conflict</li> |
181 <li>"Z" path contains a conflict</li> |
|
182 <li>"?" path is not tracked</li> |
|
183 <li>"!" path is missing</li> |
125 <li>" " path is back at normal</li> |
184 <li>" " path is back at normal</li> |
126 </ul> |
185 </ul> |
127 |
186 |
128 @param data list of VCS status data |
187 @param data dictionary containing the status data |
129 @type list of str |
188 @type dict |
130 """ |
189 """ |
131 self.__statusList.clear() |
190 self.__statusList.clear() |
132 |
191 |
133 for entry in data: |
192 for name, status in data.items(): |
134 QListWidgetItem(entry, self.__statusList) |
193 if status: |
|
194 itm = QListWidgetItem(name, self.__statusList) |
|
195 with contextlib.suppress(KeyError): |
|
196 itm.setToolTip(self.__statusTexts[status]) |
|
197 itm.setIcon(UI.PixmapCache.getIcon( |
|
198 self.__statusIcons[status])) |
|
199 itm.setData(self.StatusDataRole, status) |
|
200 if status in "AMOR": |
|
201 itm.setFlags( |
|
202 itm.flags() | Qt.ItemFlag.ItemIsUserCheckable) |
|
203 itm.setCheckState(Qt.CheckState.Checked) |
|
204 else: |
|
205 itm.setFlags( |
|
206 itm.flags() & ~Qt.ItemFlag.ItemIsUserCheckable) |
|
207 |
135 self.__statusList.sortItems(Qt.SortOrder.AscendingOrder) |
208 self.__statusList.sortItems(Qt.SortOrder.AscendingOrder) |
|
209 |
|
210 @pyqtSlot() |
|
211 def __toggleCheckMark(self): |
|
212 """ |
|
213 Private slot to toggle the check marks. |
|
214 """ |
|
215 for row in range(self.__statusList.count()): |
|
216 itm = self.__statusList.item(row) |
|
217 if ( |
|
218 itm.flags() & Qt.ItemFlag.ItemIsUserCheckable == |
|
219 Qt.ItemFlag.ItemIsUserCheckable |
|
220 ): |
|
221 if itm.checkState() == Qt.CheckState.Unchecked: |
|
222 itm.setCheckState(Qt.CheckState.Checked) |
|
223 else: |
|
224 itm.setCheckState(Qt.CheckState.Unchecked) |
|
225 |
|
226 @pyqtSlot() |
|
227 def __commit(self): |
|
228 """ |
|
229 Private slot to handle the commit button. |
|
230 """ |
|
231 projectPath = self.__project.getProjectPath() |
|
232 names = [] |
|
233 |
|
234 for row in range(self.__statusList.count()): |
|
235 itm = self.__statusList.item(row) |
|
236 if itm.checkState() == Qt.CheckState.Checked: |
|
237 names.append(os.path.join(projectPath, itm.text())) |
|
238 |
|
239 if not names: |
|
240 EricMessageBox.information( |
|
241 self, |
|
242 self.tr("Commit"), |
|
243 self.tr("""There are no entries selected to be""" |
|
244 """ committed.""")) |
|
245 return |
|
246 |
|
247 if Preferences.getVCS("AutoSaveFiles"): |
|
248 vm = ericApp().getObject("ViewManager") |
|
249 for name in names: |
|
250 vm.saveEditor(name) |
|
251 vcs = self.__project.getVcs() |
|
252 vcs and vcs.vcsCommit(names, '') |
|
253 |
|
254 @pyqtSlot() |
|
255 def __committed(self): |
|
256 """ |
|
257 Private slot called after the commit has been completed. |
|
258 """ |
|
259 self.__reload() |
|
260 |
|
261 @pyqtSlot() |
|
262 def __addUntracked(self): |
|
263 """ |
|
264 Private slot to add the selected untracked entries. |
|
265 """ |
|
266 projectPath = self.__project.getProjectPath() |
|
267 |
|
268 names = [ |
|
269 os.path.join(projectPath, itm.text()) |
|
270 for itm in self.__statusList.selectedItems() |
|
271 if itm.data(self.StatusDataRole) == "?" |
|
272 ] |
|
273 |
|
274 if not names: |
|
275 EricMessageBox.information( |
|
276 self, |
|
277 self.tr("Add"), |
|
278 self.tr("""There are no unversioned entries""" |
|
279 """ available/selected.""")) |
|
280 return |
|
281 |
|
282 vcs = self.__project.getVcs() |
|
283 vcs and vcs.vcsAdd(names) |
|
284 self.__reload() |