eric6/UI/Browser.py

changeset 8114
b7abbf3f82a3
parent 8109
486984bb52e3
child 8143
2c730d5fd177
equal deleted inserted replaced
8113:d2ff62484a9e 8114:b7abbf3f82a3
6 """ 6 """
7 Module implementing a browser with class browsing capabilities. 7 Module implementing a browser with class browsing capabilities.
8 """ 8 """
9 9
10 import os 10 import os
11 import shutil
11 12
12 from PyQt5.QtCore import ( 13 from PyQt5.QtCore import (
13 pyqtSignal, pyqtSlot, Qt, QUrl, QCoreApplication, QItemSelectionModel, 14 pyqtSignal, pyqtSlot, Qt, QUrl, QCoreApplication, QItemSelectionModel,
14 QModelIndex, QElapsedTimer 15 QModelIndex, QElapsedTimer
15 ) 16 )
16 from PyQt5.QtGui import QDesktopServices 17 from PyQt5.QtGui import QDesktopServices
17 from PyQt5.QtWidgets import ( 18 from PyQt5.QtWidgets import (
18 QTreeView, QApplication, QMenu, QAbstractItemView, QAction 19 QTreeView, QApplication, QMenu, QAbstractItemView, QAction, QInputDialog,
20 QLineEdit, QDialog
19 ) 21 )
20 22
21 from E5Gui.E5Application import e5App 23 from E5Gui.E5Application import e5App
22 from E5Gui import E5FileDialog, E5MessageBox 24 from E5Gui import E5FileDialog, E5MessageBox
23 25
24 from Project.ProjectBrowserModel import ProjectBrowserSimpleDirectoryItem 26 from Project.ProjectBrowserModel import ProjectBrowserSimpleDirectoryItem
25 from .BrowserModel import ( 27 from .BrowserModel import (
26 BrowserModel, BrowserDirectoryItem, BrowserFileItem, BrowserClassItem, 28 BrowserModel, BrowserDirectoryItem, BrowserFileItem, BrowserClassItem,
27 BrowserMethodItem, BrowserClassAttributeItem, BrowserImportItem, 29 BrowserMethodItem, BrowserClassAttributeItem, BrowserImportItem,
28 BrowserImportsItem, BrowserSysPathItem, BrowserGlobalsItem 30 BrowserImportsItem, BrowserSysPathItem, BrowserGlobalsItem,
31 BrowserItemDirectory
29 ) 32 )
30 from .BrowserSortFilterProxyModel import BrowserSortFilterProxyModel 33 from .BrowserSortFilterProxyModel import BrowserSortFilterProxyModel
31 34
32 import UI.PixmapCache 35 import UI.PixmapCache
33 import Preferences 36 import Preferences
211 self.showHiddenFilesAct.setCheckable(True) 214 self.showHiddenFilesAct.setCheckable(True)
212 self.showHiddenFilesAct.toggled.connect(self._showHidden) 215 self.showHiddenFilesAct.toggled.connect(self._showHidden)
213 self.showHiddenFilesAct.setChecked( 216 self.showHiddenFilesAct.setChecked(
214 Preferences.getUI("BrowsersListHiddenFiles")) 217 Preferences.getUI("BrowsersListHiddenFiles"))
215 218
219 self.__newMenu = QMenu(QCoreApplication.translate('Browser', "New"),
220 self)
221 self.__newMenu.addAction(
222 QCoreApplication.translate('Browser', 'Directory'),
223 self._newDirectory)
224 self.__newMenu.addAction(
225 QCoreApplication.translate('Browser', 'File'), self._newFile)
226
216 # create the popup menu for source files 227 # create the popup menu for source files
217 self.sourceMenu = QMenu(self) 228 self.sourceMenu = QMenu(self)
218 self.sourceMenu.addAction( 229 self.sourceMenu.addAction(
219 QCoreApplication.translate('Browser', 'Open'), self._openItem) 230 QCoreApplication.translate('Browser', 'Open'), self._openItem)
220 self.unittestAct = self.sourceMenu.addAction( 231 self.unittestAct = self.sourceMenu.addAction(
232 self.sourceMenu.addAction( 243 self.sourceMenu.addAction(
233 QCoreApplication.translate('Browser', 'Copy Path to Clipboard'), 244 QCoreApplication.translate('Browser', 'Copy Path to Clipboard'),
234 self._copyToClipboard) 245 self._copyToClipboard)
235 self.sourceMenu.addSeparator() 246 self.sourceMenu.addSeparator()
236 self.sourceMenu.addAction(self.showHiddenFilesAct) 247 self.sourceMenu.addAction(self.showHiddenFilesAct)
248 self.sourceMenu.addSeparator()
249 self.sourceMenu.addMenu(self.__newMenu)
250 self.sourceMenu.addAction(
251 QCoreApplication.translate('Browser', 'Delete'),
252 self._deleteFileOrDirectory)
237 253
238 # create the popup menu for general use 254 # create the popup menu for general use
239 self.menu = QMenu(self) 255 self.menu = QMenu(self)
240 self.menu.addAction( 256 self.menu.addAction(
241 QCoreApplication.translate('Browser', 'Open'), self._openItem) 257 QCoreApplication.translate('Browser', 'Open'), self._openItem)
253 self.menu.addAction( 269 self.menu.addAction(
254 QCoreApplication.translate('Browser', 'Copy Path to Clipboard'), 270 QCoreApplication.translate('Browser', 'Copy Path to Clipboard'),
255 self._copyToClipboard) 271 self._copyToClipboard)
256 self.menu.addSeparator() 272 self.menu.addSeparator()
257 self.menu.addAction(self.showHiddenFilesAct) 273 self.menu.addAction(self.showHiddenFilesAct)
274 self.menu.addSeparator()
275 self.menu.addMenu(self.__newMenu)
276 self.menu.addAction(
277 QCoreApplication.translate('Browser', 'Delete'),
278 self._deleteFileOrDirectory)
258 279
259 # create the menu for multiple selected files 280 # create the menu for multiple selected files
260 self.multiMenu = QMenu(self) 281 self.multiMenu = QMenu(self)
261 self.multiMenu.addAction( 282 self.multiMenu.addAction(
262 QCoreApplication.translate('Browser', 'Open'), self._openItem) 283 QCoreApplication.translate('Browser', 'Open'), self._openItem)
263 self.multiMenu.addSeparator() 284 self.multiMenu.addSeparator()
264 self.multiMenu.addAction(self.showHiddenFilesAct) 285 self.multiMenu.addAction(self.showHiddenFilesAct)
286 self.multiMenu.addSeparator()
287 self.multiMenu.addAction(
288 QCoreApplication.translate('Browser', 'Delete'),
289 self.__deleteMultiple)
265 290
266 # create the directory menu 291 # create the directory menu
267 self.dirMenu = QMenu(self) 292 self.dirMenu = QMenu(self)
268 self.dirMenu.addAction( 293 self.dirMenu.addAction(
269 QCoreApplication.translate('Browser', 'New toplevel directory...'), 294 QCoreApplication.translate('Browser', 'New toplevel directory...'),
289 self.dirMenu.addAction( 314 self.dirMenu.addAction(
290 QCoreApplication.translate('Browser', 'Copy Path to Clipboard'), 315 QCoreApplication.translate('Browser', 'Copy Path to Clipboard'),
291 self._copyToClipboard) 316 self._copyToClipboard)
292 self.dirMenu.addSeparator() 317 self.dirMenu.addSeparator()
293 self.dirMenu.addAction(self.showHiddenFilesAct) 318 self.dirMenu.addAction(self.showHiddenFilesAct)
319 self.dirMenu.addSeparator()
320 self.dirMenu.addMenu(self.__newMenu)
321 self.dirMenu.addAction(
322 QCoreApplication.translate('Browser', 'Delete'),
323 self._deleteFileOrDirectory)
294 324
295 # create the attribute menu 325 # create the attribute menu
296 self.gotoMenu = QMenu(QCoreApplication.translate('Browser', "Goto"), 326 self.gotoMenu = QMenu(QCoreApplication.translate('Browser', "Goto"),
297 self) 327 self)
298 self.gotoMenu.aboutToShow.connect(self._showGotoMenu) 328 self.gotoMenu.aboutToShow.connect(self._showGotoMenu)
696 def getSelectedItems(self, filterList=None): 726 def getSelectedItems(self, filterList=None):
697 """ 727 """
698 Public method to get the selected items. 728 Public method to get the selected items.
699 729
700 @param filterList list of classes to check against 730 @param filterList list of classes to check against
701 @return list of selected items (list of BroweserItem) 731 @return list of selected items (list of BrowserItem)
702 """ 732 """
703 selectedItems = [] 733 selectedItems = []
704 indexes = self.selectedIndexes() 734 indexes = self.selectedIndexes()
705 for index in indexes: 735 for index in indexes:
706 if index.column() == 0: 736 if index.column() == 0:
817 @return flag indicating a correct type 847 @return flag indicating a correct type
818 @rtype bool 848 @rtype bool
819 """ 849 """
820 return isinstance( 850 return isinstance(
821 item, (BrowserDirectoryItem, BrowserFileItem, BrowserSysPathItem)) 851 item, (BrowserDirectoryItem, BrowserFileItem, BrowserSysPathItem))
852
853 @pyqtSlot()
854 def _newDirectory(self):
855 """
856 Protected slot to create a new directory.
857 """
858 index = self.currentIndex()
859 if index.isValid():
860 dname = self.model().item(index).dirName()
861 newName, ok = QInputDialog.getText(
862 self,
863 self.tr("New Directory"),
864 self.tr("Name for new directory:"),
865 QLineEdit.Normal)
866 if ok and bool(newName):
867 dirpath = os.path.join(dname, newName)
868 if os.path.exists(dirpath):
869 E5MessageBox.warning(
870 self,
871 self.tr("New Directory"),
872 self.tr("A file or directory named <b>{0}</b> exists"
873 " already. Aborting...")
874 .format(newName))
875 else:
876 try:
877 os.mkdir(dirpath, mode=0o751)
878 except OSError as err:
879 E5MessageBox.critical(
880 self,
881 self.tr("New Directory"),
882 self.tr("<p>The directory <b>{0}</b> could not be"
883 " created.</p><p>Reason: {1}</p>")
884 .format(newName, str(err)))
885
886 @pyqtSlot()
887 def _newFile(self):
888 """
889 Protected slot to create a new file.
890 """
891 index = self.currentIndex()
892 if index.isValid():
893 dname = self.model().item(index).dirName()
894 fname, ok = QInputDialog.getText(
895 self,
896 self.tr("New File"),
897 self.tr("Name for new file:"),
898 QLineEdit.Normal)
899 if ok and bool(fname):
900 filepath = os.path.join(dname, fname)
901 if os.path.exists(filepath):
902 E5MessageBox.warning(
903 self,
904 self.tr("New File"),
905 self.tr("A file or directory named <b>{0}</b> exists"
906 " already. Aborting...")
907 .format(fname))
908 else:
909 try:
910 f = open(filepath, "w")
911 f.close()
912 except OSError as err:
913 E5MessageBox.critical(
914 self,
915 self.tr("New File"),
916 self.tr("<p>The file <b>{0}</b> could not be"
917 " created.</p><p>Reason: {1}</p>")
918 .format(fname, str(err)))
919
920 @pyqtSlot()
921 def _deleteFileOrDirectory(self):
922 """
923 Protected slot to delete a directory or file.
924 """
925 index = self.currentIndex()
926 if index.isValid():
927 itm = self.model().item(index)
928 if itm.type() == BrowserItemDirectory:
929 self.__deleteDirectory(itm.dirName())
930 else:
931 self.__deleteFile(itm.fileName())
932
933 def __deleteFile(self, fn):
934 """
935 Private method to delete a file.
936
937 @param fn filename to be deleted
938 @type str
939 """
940 try:
941 from ThirdParty.Send2Trash.send2trash import send2trash as s2t
942 trashMsg = self.tr("Do you really want to move this file to the"
943 " trash?")
944 except ImportError:
945 s2t = os.remove
946 trashMsg = self.tr("Do you really want to delete this file?")
947
948 from UI.DeleteFilesConfirmationDialog import (
949 DeleteFilesConfirmationDialog
950 )
951 dlg = DeleteFilesConfirmationDialog(
952 self.parent(),
953 self.tr("Delete File"),
954 trashMsg,
955 [fn])
956 if dlg.exec() == QDialog.Accepted:
957 try:
958 s2t(fn)
959 except OSError as err:
960 E5MessageBox.critical(
961 self.ui,
962 self.tr("Delete File"),
963 self.tr(
964 "<p>The selected file <b>{0}</b> could not be"
965 " deleted.</p><p>Reason: {1}</p>")
966 .format(fn, str(err))
967 )
968
969 def __deleteDirectory(self, dn):
970 """
971 Private method to delete a directory.
972
973 @param dn directory name to be removed from the project
974 @type str
975 """
976 try:
977 from ThirdParty.Send2Trash.send2trash import send2trash
978 s2tAvailable = True
979 trashMsg = self.tr("Do you really want to move this directory to"
980 " the trash?")
981 except ImportError:
982 s2tAvailable = False
983 trashMsg = self.tr("Do you really want to delete this directory?")
984
985 from UI.DeleteFilesConfirmationDialog import (
986 DeleteFilesConfirmationDialog
987 )
988 dlg = DeleteFilesConfirmationDialog(
989 self.parent(),
990 self.tr("Delete Directory"),
991 trashMsg,
992 [dn])
993 if dlg.exec() == QDialog.Accepted:
994 try:
995 if s2tAvailable:
996 send2trash(dn)
997 else:
998 shutil.rmtree(dn, True)
999 except OSError as err:
1000 E5MessageBox.critical(
1001 self.ui,
1002 self.tr("Delete Directory"),
1003 self.tr(
1004 "<p>The selected directory <b>{0}</b> could not be"
1005 " deleted.</p><p>Reason: {1}</p>")
1006 .format(dn, str(err))
1007 )
1008
1009 @pyqtSlot()
1010 def __deleteMultiple(self):
1011 """
1012 Private slot to delete multiple directories and files.
1013
1014 Note: The context menu for multi selection is only shown for file
1015 items.
1016 """
1017 fileNames = []
1018 for itm in self.getSelectedItems():
1019 fileNames.append(itm.fileName())
1020
1021 try:
1022 from ThirdParty.Send2Trash.send2trash import send2trash as s2t
1023 trashMsg = self.tr("Do you really want to move these files to the"
1024 " trash?")
1025 except ImportError:
1026 s2t = os.remove
1027 trashMsg = self.tr("Do you really want to delete these files?")
1028
1029 from UI.DeleteFilesConfirmationDialog import (
1030 DeleteFilesConfirmationDialog
1031 )
1032 dlg = DeleteFilesConfirmationDialog(
1033 self.parent(),
1034 self.tr("Delete Files"),
1035 trashMsg,
1036 sorted(fileNames)
1037 )
1038 if dlg.exec() == QDialog.Accepted:
1039 for fn in fileNames:
1040 try:
1041 s2t(fn)
1042 except OSError as err:
1043 E5MessageBox.critical(
1044 self.ui,
1045 self.tr("Delete File"),
1046 self.tr(
1047 "<p>The selected file <b>{0}</b> could not be"
1048 " deleted.</p><p>Reason: {1}</p>")
1049 .format(fn, str(err))
1050 )

eric ide

mercurial