|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2005 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the base class of the VCS project browser helper. |
|
8 """ |
|
9 |
|
10 import os |
|
11 |
|
12 from PyQt5.QtCore import QObject, QCoreApplication |
|
13 from PyQt5.QtWidgets import QDialog |
|
14 |
|
15 from E5Gui.E5Application import e5App |
|
16 |
|
17 from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog |
|
18 |
|
19 from Project.ProjectBrowserModel import ( |
|
20 ProjectBrowserSimpleDirectoryItem, ProjectBrowserFileItem, |
|
21 ProjectBrowserDirectoryItem |
|
22 ) |
|
23 |
|
24 import Preferences |
|
25 |
|
26 |
|
27 class VcsProjectBrowserHelper(QObject): |
|
28 """ |
|
29 Class implementing the base class of the VCS project browser helper. |
|
30 """ |
|
31 def __init__(self, vcsObject, browserObject, projectObject, |
|
32 isTranslationsBrowser, parent=None, name=None): |
|
33 """ |
|
34 Constructor |
|
35 |
|
36 @param vcsObject reference to the vcs object |
|
37 @param browserObject reference to the project browser object |
|
38 @param projectObject reference to the project object |
|
39 @param isTranslationsBrowser flag indicating, the helper is requested |
|
40 for the translations browser (this needs some special treatment) |
|
41 @param parent parent widget (QWidget) |
|
42 @param name name of this object (string) |
|
43 """ |
|
44 super().__init__(parent) |
|
45 if name: |
|
46 self.setObjectName(name) |
|
47 |
|
48 self.vcs = vcsObject |
|
49 self.browser = browserObject |
|
50 self.isTranslationsBrowser = isTranslationsBrowser |
|
51 self.project = projectObject |
|
52 |
|
53 def addVCSMenus(self, mainMenu, multiMenu, backMenu, dirMenu, |
|
54 dirMultiMenu): |
|
55 """ |
|
56 Public method to add the VCS entries to the various project browser |
|
57 menus. |
|
58 |
|
59 @param mainMenu reference to the main menu (QPopupMenu) |
|
60 @param multiMenu reference to the multiple selection menu (QPopupMenu) |
|
61 @param backMenu reference to the background menu (QPopupMenu) |
|
62 @param dirMenu reference to the directory menu (QPopupMenu) |
|
63 @param dirMultiMenu reference to the multiple selection directory |
|
64 menu (QPopupMenu) |
|
65 """ |
|
66 self._addVCSMenu(mainMenu) |
|
67 self._addVCSMenuMulti(multiMenu) |
|
68 self._addVCSMenuBack(backMenu) |
|
69 self._addVCSMenuDir(dirMenu) |
|
70 self._addVCSMenuDirMulti(dirMultiMenu) |
|
71 |
|
72 def showContextMenu(self, menu, standardItems): |
|
73 """ |
|
74 Public slot called before the context menu is shown. |
|
75 |
|
76 It enables/disables the VCS menu entries depending on the overall |
|
77 VCS status and the file status. |
|
78 |
|
79 @param menu reference to the menu to be shown |
|
80 @param standardItems array of standard items that need |
|
81 activation/deactivation depending on the overall VCS status |
|
82 @exception RuntimeError to indicate that this method must be |
|
83 implemented by a subclass |
|
84 """ |
|
85 raise RuntimeError('Not implemented') |
|
86 |
|
87 def showContextMenuMulti(self, menu, standardItems): |
|
88 """ |
|
89 Public slot called before the context menu (multiple selections) is |
|
90 shown. |
|
91 |
|
92 It enables/disables the VCS menu entries depending on the overall |
|
93 VCS status and the files status. |
|
94 |
|
95 @param menu reference to the menu to be shown |
|
96 @param standardItems array of standard items that need |
|
97 activation/deactivation depending on the overall VCS status |
|
98 @exception RuntimeError to indicate that this method must be |
|
99 implemented by a subclass |
|
100 """ |
|
101 raise RuntimeError('Not implemented') |
|
102 |
|
103 def showContextMenuDir(self, menu, standardItems): |
|
104 """ |
|
105 Public slot called before the context menu is shown. |
|
106 |
|
107 It enables/disables the VCS menu entries depending on the overall |
|
108 VCS status and the directory status. |
|
109 |
|
110 @param menu reference to the menu to be shown |
|
111 @param standardItems array of standard items that |
|
112 need activation/deactivation depending on the overall VCS status |
|
113 @exception RuntimeError to indicate that this method must be |
|
114 implemented by a subclass |
|
115 """ |
|
116 raise RuntimeError('Not implemented') |
|
117 |
|
118 def showContextMenuDirMulti(self, menu, standardItems): |
|
119 """ |
|
120 Public slot called before the context menu is shown. |
|
121 |
|
122 It enables/disables the VCS menu entries depending on the overall |
|
123 VCS status and the directory status. |
|
124 |
|
125 @param menu reference to the menu to be shown |
|
126 @param standardItems array of standard items that need |
|
127 activation/deactivation depending on the overall VCS status |
|
128 @exception RuntimeError to indicate that this method must be |
|
129 implemented by a subclass |
|
130 """ |
|
131 raise RuntimeError('Not implemented') |
|
132 |
|
133 ########################################################################### |
|
134 ## General menu handling methods below |
|
135 ########################################################################### |
|
136 |
|
137 def _VCSUpdate(self): |
|
138 """ |
|
139 Protected slot called by the context menu to update a file from the |
|
140 VCS repository. |
|
141 """ |
|
142 if self.isTranslationsBrowser: |
|
143 names = [itm.dirName() |
|
144 for itm in self.browser.getSelectedItems( |
|
145 [ProjectBrowserSimpleDirectoryItem])] |
|
146 if not names: |
|
147 names = [itm.fileName() |
|
148 for itm in self.browser.getSelectedItems( |
|
149 [ProjectBrowserFileItem])] |
|
150 else: |
|
151 names = [] |
|
152 for itm in self.browser.getSelectedItems(): |
|
153 try: |
|
154 name = itm.fileName() |
|
155 except AttributeError: |
|
156 name = itm.dirName() |
|
157 names.append(name) |
|
158 self.vcs.vcsUpdate(names) |
|
159 |
|
160 def _VCSCommit(self): |
|
161 """ |
|
162 Protected slot called by the context menu to commit the changes to the |
|
163 VCS repository. |
|
164 """ |
|
165 if self.isTranslationsBrowser: |
|
166 names = [itm.dirName() |
|
167 for itm in self.browser.getSelectedItems( |
|
168 [ProjectBrowserSimpleDirectoryItem])] |
|
169 if not names: |
|
170 names = [itm.fileName() |
|
171 for itm in self.browser.getSelectedItems( |
|
172 [ProjectBrowserFileItem])] |
|
173 else: |
|
174 names = [] |
|
175 for itm in self.browser.getSelectedItems(): |
|
176 try: |
|
177 name = itm.fileName() |
|
178 except AttributeError: |
|
179 name = itm.dirName() |
|
180 names.append(name) |
|
181 if Preferences.getVCS("AutoSaveFiles"): |
|
182 vm = e5App().getObject("ViewManager") |
|
183 for name in names: |
|
184 vm.saveEditor(name) |
|
185 self.vcs.vcsCommit(names, '') |
|
186 |
|
187 def _VCSAdd(self): |
|
188 """ |
|
189 Protected slot called by the context menu to add the selected file to |
|
190 the VCS repository. |
|
191 """ |
|
192 if self.isTranslationsBrowser: |
|
193 items = self.browser.getSelectedItems( |
|
194 [ProjectBrowserSimpleDirectoryItem]) |
|
195 if items: |
|
196 names = [itm.dirName() for itm in items] |
|
197 qnames = [] |
|
198 else: |
|
199 items = self.browser.getSelectedItems([ProjectBrowserFileItem]) |
|
200 names = [] |
|
201 qnames = [] |
|
202 for itm in items: |
|
203 name = itm.fileName() |
|
204 if name.endswith('.qm'): |
|
205 qnames.append(name) |
|
206 else: |
|
207 names.append(name) |
|
208 else: |
|
209 names = [] |
|
210 for itm in self.browser.getSelectedItems(): |
|
211 try: |
|
212 name = itm.fileName() |
|
213 except AttributeError: |
|
214 name = itm.dirName() |
|
215 names.append(name) |
|
216 qnames = [] |
|
217 |
|
218 if not len(names + qnames): |
|
219 return |
|
220 |
|
221 if len(names + qnames) == 1: |
|
222 if names: |
|
223 self.vcs.vcsAdd(names[0], os.path.isdir(names[0])) |
|
224 else: |
|
225 if self.vcs.canDetectBinaries: |
|
226 self.vcs.vcsAdd(qnames) |
|
227 else: |
|
228 self.vcs.vcsAddBinary(qnames) |
|
229 else: |
|
230 if self.vcs.canDetectBinaries: |
|
231 self.vcs.vcsAdd(names + qnames) |
|
232 else: |
|
233 self.vcs.vcsAdd(names) |
|
234 if len(qnames): |
|
235 self.vcs.vcsAddBinary(qnames) |
|
236 for fn in names + qnames: |
|
237 self._updateVCSStatus(fn) |
|
238 |
|
239 def _VCSAddTree(self): |
|
240 """ |
|
241 Protected slot called by the context menu. |
|
242 |
|
243 It is used to add the selected |
|
244 directory tree to the VCS repository. |
|
245 """ |
|
246 names = [] |
|
247 for itm in self.browser.getSelectedItems(): |
|
248 try: |
|
249 name = itm.fileName() |
|
250 except AttributeError: |
|
251 name = itm.dirName() |
|
252 names.append(name) |
|
253 self.vcs.vcsAddTree(names) |
|
254 for fn in names: |
|
255 self._updateVCSStatus(fn) |
|
256 |
|
257 def _VCSRemove(self): |
|
258 """ |
|
259 Protected slot called by the context menu to remove the selected file |
|
260 from the VCS repository. |
|
261 """ |
|
262 if self.isTranslationsBrowser: |
|
263 items = self.browser.getSelectedItems( |
|
264 [ProjectBrowserSimpleDirectoryItem]) |
|
265 if items: |
|
266 return # not supported |
|
267 |
|
268 isRemoveDirs = False |
|
269 items = self.browser.getSelectedItems([ProjectBrowserFileItem]) |
|
270 names = [itm.fileName() for itm in items] |
|
271 |
|
272 dlg = DeleteFilesConfirmationDialog( |
|
273 self.parent(), |
|
274 QCoreApplication.translate( |
|
275 "VcsProjectBrowserHelper", |
|
276 "Remove from repository (and disk)"), |
|
277 QCoreApplication.translate( |
|
278 "VcsProjectBrowserHelper", |
|
279 "Do you really want to remove these translation files from" |
|
280 " the repository (and disk)?"), |
|
281 names) |
|
282 else: |
|
283 items = self.browser.getSelectedItems() |
|
284 isRemoveDirs = ( |
|
285 len(items) == self.browser.getSelectedItemsCount( |
|
286 [ProjectBrowserSimpleDirectoryItem, |
|
287 ProjectBrowserDirectoryItem]) |
|
288 ) |
|
289 if isRemoveDirs: |
|
290 names = [itm.dirName() for itm in items] |
|
291 else: |
|
292 names = [itm.fileName() for itm in items] |
|
293 files = [self.browser.project.getRelativePath(name) |
|
294 for name in names] |
|
295 |
|
296 dlg = DeleteFilesConfirmationDialog( |
|
297 self.parent(), |
|
298 QCoreApplication.translate( |
|
299 "VcsProjectBrowserHelper", |
|
300 "Remove from repository (and disk)"), |
|
301 QCoreApplication.translate( |
|
302 "VcsProjectBrowserHelper", |
|
303 "Do you really want to remove these files/directories" |
|
304 " from the repository (and disk)?"), |
|
305 files) |
|
306 |
|
307 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
308 status = self.vcs.vcsRemove(names) |
|
309 if status: |
|
310 if isRemoveDirs: |
|
311 self.browser._removeDir() |
|
312 # remove directories from Project |
|
313 else: |
|
314 self.browser._removeFile() # remove file(s) from project |
|
315 |
|
316 def _VCSLog(self): |
|
317 """ |
|
318 Protected slot called by the context menu to show the VCS log of a |
|
319 file/directory. |
|
320 """ |
|
321 # kept for backward compatibility for plug-ins |
|
322 self._VCSLogBrowser() |
|
323 |
|
324 def _VCSLogBrowser(self): |
|
325 """ |
|
326 Protected slot called by the context menu to show the log browser for a |
|
327 file. |
|
328 """ |
|
329 itm = self.browser.currentItem() |
|
330 try: |
|
331 fn = itm.fileName() |
|
332 isFile = True |
|
333 except AttributeError: |
|
334 fn = itm.dirName() |
|
335 isFile = False |
|
336 self.vcs.vcsLogBrowser(fn, isFile=isFile) |
|
337 |
|
338 def _VCSDiff(self): |
|
339 """ |
|
340 Protected slot called by the context menu to show the difference of a |
|
341 file/directory to the repository. |
|
342 """ |
|
343 names = [] |
|
344 for itm in self.browser.getSelectedItems(): |
|
345 try: |
|
346 name = itm.fileName() |
|
347 except AttributeError: |
|
348 name = itm.dirName() |
|
349 names.append(name) |
|
350 self.vcs.vcsDiff(names) |
|
351 |
|
352 def _VCSStatus(self): |
|
353 """ |
|
354 Protected slot called by the context menu to show the status of a file. |
|
355 """ |
|
356 if self.isTranslationsBrowser: |
|
357 items = self.browser.getSelectedItems( |
|
358 [ProjectBrowserSimpleDirectoryItem]) |
|
359 if items: |
|
360 names = [itm.dirName() for itm in items] |
|
361 else: |
|
362 items = self.browser.getSelectedItems([ProjectBrowserFileItem]) |
|
363 names = [itm.fileName() for itm in items] |
|
364 else: |
|
365 names = [] |
|
366 for itm in self.browser.getSelectedItems(): |
|
367 try: |
|
368 name = itm.fileName() |
|
369 except AttributeError: |
|
370 name = itm.dirName() |
|
371 names.append(name) |
|
372 self.vcs.vcsStatus(names) |
|
373 |
|
374 def _VCSRevert(self): |
|
375 """ |
|
376 Protected slot called by the context menu to revert changes made to a |
|
377 file. |
|
378 """ |
|
379 names = [] |
|
380 for itm in self.browser.getSelectedItems(): |
|
381 try: |
|
382 name = itm.fileName() |
|
383 except AttributeError: |
|
384 name = itm.dirName() |
|
385 names.append(name) |
|
386 self.vcs.vcsRevert(names) |
|
387 |
|
388 def _VCSMerge(self): |
|
389 """ |
|
390 Protected slot called by the context menu to merge changes into to a |
|
391 file. |
|
392 """ |
|
393 itm = self.browser.currentItem() |
|
394 try: |
|
395 name = itm.fileName() |
|
396 except AttributeError: |
|
397 name = itm.dirName() |
|
398 self.vcs.vcsMerge(name) |
|
399 |
|
400 def _VCSInfoDisplay(self): |
|
401 """ |
|
402 Protected slot called to show some vcs information. |
|
403 """ |
|
404 from .RepositoryInfoDialog import VcsRepositoryInfoDialog |
|
405 info = self.vcs.vcsRepositoryInfos(self.project.ppath) |
|
406 dlg = VcsRepositoryInfoDialog(None, info) |
|
407 dlg.exec() |
|
408 |
|
409 def _updateVCSStatus(self, name): |
|
410 """ |
|
411 Protected method to update the VCS status of an item. |
|
412 |
|
413 @param name filename or directoryname of the item to be updated |
|
414 (string) |
|
415 """ |
|
416 self.project.getModel().updateVCSStatus(name) |