eric7/Project/ProjectOthersBrowser.py

branch
eric7
changeset 8312
800c432b34c8
parent 8282
16b243bdb12f
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2002 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a class used to display the parts of the project, that
8 don't fit the other categories.
9 """
10
11 import contextlib
12
13 from PyQt5.QtCore import QModelIndex, pyqtSignal, QUrl
14 from PyQt5.QtGui import QDesktopServices
15 from PyQt5.QtWidgets import QDialog, QMenu
16
17 from E5Gui import E5MessageBox
18
19 from .ProjectBrowserModel import (
20 ProjectBrowserFileItem, ProjectBrowserSimpleDirectoryItem,
21 ProjectBrowserDirectoryItem, ProjectBrowserOthersType
22 )
23 from .ProjectBaseBrowser import ProjectBaseBrowser
24
25 import Utilities.MimeTypes
26 import Preferences
27
28
29 class ProjectOthersBrowser(ProjectBaseBrowser):
30 """
31 A class used to display the parts of the project, that don't fit the
32 other categories.
33
34 @signal showMenu(str, QMenu) emitted when a menu is about to be shown.
35 The name of the menu and a reference to the menu are given.
36 """
37 showMenu = pyqtSignal(str, QMenu)
38
39 def __init__(self, project, parent=None):
40 """
41 Constructor
42
43 @param project reference to the project object
44 @param parent parent widget of this browser (QWidget)
45 """
46 ProjectBaseBrowser.__init__(self, project, ProjectBrowserOthersType,
47 parent)
48
49 self.selectedItemsFilter = [ProjectBrowserFileItem,
50 ProjectBrowserDirectoryItem]
51 self.specialMenuEntries = [1]
52
53 self.setWindowTitle(self.tr('Others'))
54
55 self.setWhatsThis(self.tr(
56 """<b>Project Others Browser</b>"""
57 """<p>This allows to easily see all other files and directories"""
58 """ contained in the current project. Several actions can be"""
59 """ executed via the context menu. The entry which is registered"""
60 """ in the project is shown in a different colour.</p>"""
61 ))
62
63 project.prepareRepopulateItem.connect(self._prepareRepopulateItem)
64 project.completeRepopulateItem.connect(self._completeRepopulateItem)
65
66 def _createPopupMenus(self):
67 """
68 Protected overloaded method to generate the popup menu.
69 """
70 ProjectBaseBrowser._createPopupMenus(self)
71
72 self.menu.addAction(
73 self.tr('Open in Hex Editor'), self._openHexEditor)
74 self.editPixmapAct = self.menu.addAction(
75 self.tr('Open in Icon Editor'), self._editPixmap)
76 self.menu.addSeparator()
77 self.mimeTypeAct = self.menu.addAction(
78 self.tr('Show Mime-Type'), self.__showMimeType)
79 self.menu.addSeparator()
80 self.renameFileAct = self.menu.addAction(
81 self.tr('Rename file'), self._renameFile)
82 self.menuActions.append(self.renameFileAct)
83 act = self.menu.addAction(
84 self.tr('Remove from project'), self.__removeItem)
85 self.menuActions.append(act)
86 act = self.menu.addAction(self.tr('Delete'), self.__deleteItem)
87 self.menuActions.append(act)
88 self.menu.addSeparator()
89 self.menu.addAction(
90 self.tr('Add files...'), self.project.addOthersFiles)
91 self.menu.addAction(
92 self.tr('Add directory...'), self.project.addOthersDir)
93 self.menu.addSeparator()
94 self.menu.addAction(self.tr('Refresh'), self.__refreshItem)
95 self.menu.addSeparator()
96 self.menu.addAction(
97 self.tr('Copy Path to Clipboard'), self._copyToClipboard)
98 self.menu.addSeparator()
99 self.menu.addAction(
100 self.tr('Expand all directories'), self._expandAllDirs)
101 self.menu.addAction(
102 self.tr('Collapse all directories'), self._collapseAllDirs)
103 self.menu.addSeparator()
104 self.menu.addAction(self.tr('Configure...'), self._configure)
105
106 self.backMenu = QMenu(self)
107 self.backMenu.addAction(
108 self.tr('Add files...'), self.project.addOthersFiles)
109 self.backMenu.addAction(
110 self.tr('Add directory...'), self.project.addOthersDir)
111 self.backMenu.addSeparator()
112 self.backMenu.addAction(
113 self.tr('Expand all directories'), self._expandAllDirs)
114 self.backMenu.addAction(
115 self.tr('Collapse all directories'), self._collapseAllDirs)
116 self.backMenu.addSeparator()
117 self.backMenu.addAction(self.tr('Configure...'), self._configure)
118 self.backMenu.setEnabled(False)
119
120 self.multiMenu.addSeparator()
121 act = self.multiMenu.addAction(
122 self.tr('Remove from project'), self.__removeItem)
123 self.multiMenuActions.append(act)
124 act = self.multiMenu.addAction(
125 self.tr('Delete'), self.__deleteItem)
126 self.multiMenuActions.append(act)
127 self.multiMenu.addSeparator()
128 self.multiMenu.addAction(
129 self.tr('Expand all directories'), self._expandAllDirs)
130 self.multiMenu.addAction(
131 self.tr('Collapse all directories'), self._collapseAllDirs)
132 self.multiMenu.addSeparator()
133 self.multiMenu.addAction(self.tr('Configure...'), self._configure)
134
135 self.menu.aboutToShow.connect(self.__showContextMenu)
136 self.multiMenu.aboutToShow.connect(self.__showContextMenuMulti)
137 self.backMenu.aboutToShow.connect(self.__showContextMenuBack)
138 self.mainMenu = self.menu
139
140 def _contextMenuRequested(self, coord):
141 """
142 Protected slot to show the context menu.
143
144 @param coord the position of the mouse pointer (QPoint)
145 """
146 if not self.project.isOpen():
147 return
148
149 with contextlib.suppress(Exception):
150 cnt = self.getSelectedItemsCount()
151 if cnt <= 1:
152 index = self.indexAt(coord)
153 if index.isValid():
154 self._selectSingleItem(index)
155 cnt = self.getSelectedItemsCount()
156
157 if cnt > 1:
158 self.multiMenu.popup(self.mapToGlobal(coord))
159 else:
160 index = self.indexAt(coord)
161 if cnt == 1 and index.isValid():
162 itm = self.model().item(index)
163 if isinstance(itm, ProjectBrowserFileItem):
164 self.editPixmapAct.setVisible(itm.isPixmapFile())
165 self.mimeTypeAct.setVisible(True)
166 self.menu.popup(self.mapToGlobal(coord))
167 elif isinstance(itm, ProjectBrowserDirectoryItem):
168 self.editPixmapAct.setVisible(False)
169 self.mimeTypeAct.setVisible(False)
170 self.menu.popup(self.mapToGlobal(coord))
171 else:
172 self.backMenu.popup(self.mapToGlobal(coord))
173 else:
174 self.backMenu.popup(self.mapToGlobal(coord))
175
176 def __showContextMenu(self):
177 """
178 Private slot called by the menu aboutToShow signal.
179 """
180 self._showContextMenu(self.menu)
181
182 self.showMenu.emit("Main", self.menu)
183
184 def __showContextMenuMulti(self):
185 """
186 Private slot called by the multiMenu aboutToShow signal.
187 """
188 ProjectBaseBrowser._showContextMenuMulti(self, self.multiMenu)
189
190 self.showMenu.emit("MainMulti", self.multiMenu)
191
192 def __showContextMenuBack(self):
193 """
194 Private slot called by the backMenu aboutToShow signal.
195 """
196 ProjectBaseBrowser._showContextMenuBack(self, self.backMenu)
197
198 self.showMenu.emit("MainBack", self.backMenu)
199
200 def _showContextMenu(self, menu):
201 """
202 Protected slot called before the context menu is shown.
203
204 It enables/disables the VCS menu entries depending on the overall
205 VCS status and the file status.
206
207 @param menu Reference to the popup menu (QPopupMenu)
208 """
209 if self.project.vcs is None:
210 for act in self.menuActions:
211 act.setEnabled(True)
212 itm = self.model().item(self.currentIndex())
213 if isinstance(
214 itm,
215 (ProjectBrowserSimpleDirectoryItem,
216 ProjectBrowserDirectoryItem)
217 ):
218 self.renameFileAct.setEnabled(False)
219 else:
220 self.vcsHelper.showContextMenu(menu, self.menuActions)
221
222 def _editPixmap(self):
223 """
224 Protected slot to handle the open in icon editor popup menu entry.
225 """
226 itmList = self.getSelectedItems()
227
228 for itm in itmList:
229 if (
230 isinstance(itm, ProjectBrowserFileItem) and
231 itm.isPixmapFile()
232 ):
233 self.pixmapEditFile.emit(itm.fileName())
234
235 def _openHexEditor(self):
236 """
237 Protected slot to handle the open in hex editor popup menu entry.
238 """
239 itmList = self.getSelectedItems()
240
241 for itm in itmList:
242 if isinstance(itm, ProjectBrowserFileItem):
243 self.binaryFile.emit(itm.fileName())
244
245 def _openItem(self):
246 """
247 Protected slot to handle the open popup menu entry.
248 """
249 itmList = self.getSelectedItems()
250
251 for itm in itmList:
252 if isinstance(itm, ProjectBrowserFileItem):
253 if itm.isSvgFile():
254 self.svgFile.emit(itm.fileName())
255 elif itm.isPixmapFile():
256 self.pixmapFile.emit(itm.fileName())
257 elif itm.isEricGraphicsFile():
258 self.umlFile.emit(itm.fileName())
259 else:
260 if Utilities.MimeTypes.isTextFile(itm.fileName()):
261 self.sourceFile.emit(itm.fileName())
262 else:
263 QDesktopServices.openUrl(QUrl(itm.fileName()))
264
265 def __showMimeType(self):
266 """
267 Private slot to show the mime type of the selected entry.
268 """
269 itmList = self.getSelectedItems()
270 if itmList:
271 mimetype = Utilities.MimeTypes.mimeType(itmList[0].fileName())
272 if mimetype is None:
273 E5MessageBox.warning(
274 self,
275 self.tr("Show Mime-Type"),
276 self.tr("""The mime type of the file could not be"""
277 """ determined."""))
278 elif mimetype.split("/")[0] == "text":
279 E5MessageBox.information(
280 self,
281 self.tr("Show Mime-Type"),
282 self.tr("""The file has the mime type <b>{0}</b>.""")
283 .format(mimetype))
284 else:
285 textMimeTypesList = Preferences.getUI("TextMimeTypes")
286 if mimetype in textMimeTypesList:
287 E5MessageBox.information(
288 self,
289 self.tr("Show Mime-Type"),
290 self.tr("""The file has the mime type <b>{0}</b>.""")
291 .format(mimetype))
292 else:
293 ok = E5MessageBox.yesNo(
294 self,
295 self.tr("Show Mime-Type"),
296 self.tr("""The file has the mime type <b>{0}</b>."""
297 """<br/> Shall it be added to the list of"""
298 """ text mime types?""").format(mimetype))
299 if ok:
300 textMimeTypesList.append(mimetype)
301 Preferences.setUI("TextMimeTypes", textMimeTypesList)
302
303 def __removeItem(self):
304 """
305 Private slot to remove the selected entry from the OTHERS project
306 data area.
307 """
308 itmList = self.getSelectedItems()
309
310 for itm in itmList[:]:
311 if isinstance(itm, ProjectBrowserFileItem):
312 fn = itm.fileName()
313 self.closeSourceWindow.emit(fn)
314 self.project.removeFile(fn)
315 else:
316 dn = itm.dirName()
317 self.project.removeDirectory(dn)
318
319 def __deleteItem(self):
320 """
321 Private method to delete the selected entry from the OTHERS project
322 data area.
323 """
324 itmList = self.getSelectedItems()
325
326 items = []
327 names = []
328 fullNames = []
329 dirItems = []
330 dirNames = []
331 dirFullNames = []
332 for itm in itmList:
333 if isinstance(itm, ProjectBrowserFileItem):
334 fn2 = itm.fileName()
335 fn = self.project.getRelativePath(fn2)
336 items.append(itm)
337 fullNames.append(fn2)
338 names.append(fn)
339 else:
340 dn2 = itm.dirName()
341 dn = self.project.getRelativePath(dn2)
342 dirItems.append(itm)
343 dirFullNames.append(dn2)
344 dirNames.append(dn)
345 items.extend(dirItems)
346 fullNames.extend(dirFullNames)
347 names.extend(dirNames)
348 del itmList
349 del dirFullNames
350 del dirNames
351
352 from UI.DeleteFilesConfirmationDialog import (
353 DeleteFilesConfirmationDialog
354 )
355 dlg = DeleteFilesConfirmationDialog(
356 self.parent(),
357 self.tr("Delete files/directories"),
358 self.tr(
359 "Do you really want to delete these entries from the"
360 " project?"),
361 names)
362
363 if dlg.exec() == QDialog.DialogCode.Accepted:
364 for itm, fn2, fn in zip(items[:], fullNames, names):
365 if isinstance(itm, ProjectBrowserFileItem):
366 self.closeSourceWindow.emit(fn2)
367 self.project.deleteFile(fn)
368 elif isinstance(itm, ProjectBrowserDirectoryItem):
369 self.project.deleteDirectory(fn2)
370
371 def __refreshItem(self):
372 """
373 Private slot to refresh (repopulate) an item.
374 """
375 itm = self.model().item(self.currentIndex())
376 if isinstance(itm, ProjectBrowserFileItem):
377 name = itm.fileName()
378 self.project.repopulateItem(name)
379 elif isinstance(itm, ProjectBrowserDirectoryItem):
380 name = itm.dirName()
381 self._model.directoryChanged(name)
382 else:
383 name = ''
384
385 self._resizeColumns(QModelIndex())

eric ide

mercurial