diff -r 217862c28319 -r 3eddfc540614 eric6/MicroPython/MicroPythonFileManagerWidget.py --- a/eric6/MicroPython/MicroPythonFileManagerWidget.py Thu Jul 25 19:55:40 2019 +0200 +++ b/eric6/MicroPython/MicroPythonFileManagerWidget.py Fri Jul 26 20:05:49 2019 +0200 @@ -10,10 +10,13 @@ from __future__ import unicode_literals import os +import shutil +import time from PyQt5.QtCore import pyqtSlot, Qt, QPoint from PyQt5.QtWidgets import ( - QWidget, QTreeWidgetItem, QHeaderView, QMenu, QInputDialog, QLineEdit + QWidget, QTreeWidgetItem, QHeaderView, QMenu, QInputDialog, QLineEdit, + QDialog ) from E5Gui import E5MessageBox, E5PathPickerDialog @@ -28,6 +31,8 @@ mtime2string, mode2string, decoratedName, listdirStat ) +from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog + import UI.PixmapCache import Preferences import Utilities @@ -53,7 +58,9 @@ self.putButton.setIcon(UI.PixmapCache.getIcon("1rightarrow")) self.getButton.setIcon(UI.PixmapCache.getIcon("1leftarrow")) self.localUpButton.setIcon(UI.PixmapCache.getIcon("1uparrow")) + self.localReloadButton.setIcon(UI.PixmapCache.getIcon("reload")) self.deviceUpButton.setIcon(UI.PixmapCache.getIcon("1uparrow")) + self.deviceReloadButton.setIcon(UI.PixmapCache.getIcon("reload")) self.putButton.setEnabled(False) self.getButton.setEnabled(False) @@ -72,7 +79,6 @@ self.__fileManager.putFileDone.connect(self.__newDeviceList) self.__fileManager.getFileDone.connect(self.__handleGetDone) self.__fileManager.rsyncDone.connect(self.__handleRsyncDone) - self.__fileManager.rsyncMessages.connect(self.__handleRsyncMessages) self.__fileManager.rsyncProgressMessage.connect( self.__handleRsyncProgressMessage) self.__fileManager.removeDirectoryDone.connect(self.__newDeviceList) @@ -93,8 +99,16 @@ self.__localMenu = QMenu(self) self.__localMenu.addAction(self.tr("Change Directory"), self.__changeLocalDirectory) - # TODO: add some more local entries - # TODO: add entry to reload + self.__localMenu.addAction( + self.tr("Create Directory"), self.__createLocalDirectory) + self.__localDelDirTreeAct = self.__localMenu.addAction( + self.tr("Delete Directory Tree"), self.__deleteLocalDirectoryTree) + self.__localMenu.addSeparator() + self.__localDelFileAct = self.__localMenu.addAction( + self.tr("Delete File"), self.__deleteLocalFile) + self.__localMenu.addSeparator() + self.__localMenu.addAction( + self.tr("Show Time"), self.__showLocalTime) self.__deviceMenu = QMenu(self) self.__deviceMenu.addAction( @@ -109,8 +123,6 @@ self.__devDelFileAct = self.__deviceMenu.addAction( self.tr("Delete File"), self.__deleteDeviceFile) self.__deviceMenu.addSeparator() - # TODO: add entry to reload - self.__deviceMenu.addSeparator() self.__deviceMenu.addAction( self.tr("Synchronize Time"), self.__synchronizeTime) self.__deviceMenu.addAction( @@ -181,9 +193,9 @@ @type tuple of (str, str, str, str) """ self.deviceFileTreeWidget.clear() - for name, mode, size, time in filesList: + for name, mode, size, dateTime in filesList: itm = QTreeWidgetItem(self.deviceFileTreeWidget, - [name, mode, size, time]) + [name, mode, size, dateTime]) itm.setTextAlignment(1, Qt.AlignHCenter) itm.setTextAlignment(2, Qt.AlignRight) self.deviceFileTreeWidget.header().resizeSections( @@ -258,6 +270,14 @@ dirname = os.path.dirname(cwd) self.__listLocalFiles(dirname) + @pyqtSlot() + def on_localReloadButton_clicked(self): + """ + Private slot to reload the local list. + """ + dirname = self.localCwd.text() + self.__listLocalFiles(dirname) + @pyqtSlot(QTreeWidgetItem, int) def on_deviceFileTreeWidget_itemActivated(self, item, column): """ @@ -297,6 +317,17 @@ dirname = os.path.dirname(cwd) self.__fileManager.cd(dirname) + @pyqtSlot() + def on_deviceReloadButton_clicked(self): + """ + Private slot to reload the device list. + """ + dirname = self.deviceCwd.text() + if dirname: + self.__fileManager.lls(dirname) + else: + self.__fileManager.pwd() + def __isFileInList(self, filename, treeWidget): """ Private method to check, if a file name is contained in a tree widget. @@ -327,7 +358,6 @@ # it is really a file if self.__isFileInList(filename, self.deviceFileTreeWidget): # ask for overwrite permission - # TODO: test this action, resultFilename = confirmOverwrite( filename, self.tr("Copy File to Device"), self.tr("The given file exists already" @@ -359,7 +389,6 @@ # it is really a file if self.__isFileInList(filename, self.localFileTreeWidget): # ask for overwrite permission - # TODO: test this action, resultFilename = confirmOverwrite( filename, self.tr("Copy File from Device"), self.tr("The given file exists already."), @@ -393,7 +422,6 @@ """ self.__listLocalFiles(self.localCwd.text()) - # TODO: test this @pyqtSlot() def on_syncButton_clicked(self): """ @@ -418,32 +446,31 @@ self.__listLocalFiles(self.localCwd.text()) self.__fileManager.lls(self.deviceCwd.text()) - @pyqtSlot(list) - def __handleRsyncMessages(self, messages): - """ - Private slot to handle messages from the rsync operation. - - @param messages list of message generated by the rsync operation - @type list - """ - E5MessageBox.information( - self, - self.tr("rsync Messages"), - self.tr("""<p>rsync gave the following messages</p>""" - """<ul><li>{0}</li></ul>""").format( - "</li><li>".join(messages) - ) - ) - @pyqtSlot(str) def __handleRsyncProgressMessage(self, message): """ Private slot handling progress messages sent by the file manager. + + @param message message to be shown + @type str """ - # TODO: not implemented yet - # create and open the info dialog, if it is None - # connect to the dialog finished(int) signal to set the memeber variable to None - # add messages to dialog + if self.__progressInfoDialog is None: + from .MicroPythonProgressInfoDialog import ( + MicroPythonProgressInfoDialog + ) + self.__progressInfoDialog = MicroPythonProgressInfoDialog(self) + self.__progressInfoDialog.finished.connect( + self.__progressInfoDialogFinished) + self.__progressInfoDialog.show() + self.__progressInfoDialog.addMessage(message) + + @pyqtSlot() + def __progressInfoDialogFinished(self): + """ + Private slot handling the closing of the progress info dialog. + """ + self.__progressInfoDialog.deleteLater() + self.__progressInfoDialog = None @pyqtSlot() def __newDeviceList(self): @@ -464,6 +491,17 @@ @param pos position to show the menu at @type QPoint """ + hasSelection = bool(len(self.localFileTreeWidget.selectedItems())) + if hasSelection: + name = self.localFileTreeWidget.selectedItems()[0].text(0) + isDir = name.endswith("/") + isFile = not isDir + else: + isDir = False + isFile = False + self.__localDelDirTreeAct.setEnabled(isDir) + self.__localDelFileAct.setEnabled(isFile) + self.__localMenu.exec_(self.localFileTreeWidget.mapToGlobal(pos)) @pyqtSlot() @@ -484,6 +522,104 @@ self.localCwd.setText(dirPath) self.__listLocalFiles(dirPath) + # TODO: test this + @pyqtSlot() + def __createLocalDirectory(self): + """ + Private slot to create a local directory. + """ + dirPath, ok = QInputDialog.getText( + self, + self.tr("Create Directory"), + self.tr("Enter directory name:"), + QLineEdit.Normal) + if ok and dirPath: + dirPath = os.path.join(self.localCwd.text(), dirPath) + try: + os.mkdir(dirPath) + except (OSError, IOError) as exc: + E5MessageBox.critical( + self, + self.tr("Create Directory"), + self.tr("""<p>The directory <b>{0}</b> could not be""" + """ created.</p><p>Reason: {1}</p>""").format( + dirPath, str(exc)) + ) + + # TODO: test this + @pyqtSlot() + def __deleteLocalDirectoryTree(self): + """ + Private slot to delete a local directory tree. + """ + if bool(len(self.localFileTreeWidget.selectedItems())): + name = self.localFileTreeWidget.selectedItems()[0].text(0) + dirname = os.path.join(self.localCwd.text(), name[:-1]) + dlg = DeleteFilesConfirmationDialog( + self, + self.tr("Delete Directory Tree"), + self.tr( + "Do you really want to delete this directory tree?"), + [dirname]) + if dlg.exec_() == QDialog.Accepted: + try: + shutil.rmtree(dirname) + except Exception as exc: + E5MessageBox.critical( + self, + self.tr("Delete Directory Tree"), + self.tr("""<p>The directory <b>{0}</b> could not be""" + """ deleted.</p><p>Reason: {1}</p>""").format( + dirname, str(exc)) + ) + + # TODO: test this + @pyqtSlot() + def __deleteLocalFile(self): + """ + Private slot to delete a local file. + """ + if bool(len(self.localFileTreeWidget.selectedItems())): + name = self.localFileTreeWidget.selectedItems()[0].text(0) + filename = os.path.join(self.localCwd.text(), name) + dlg = DeleteFilesConfirmationDialog( + self, + self.tr("Delete File"), + self.tr( + "Do you really want to delete this file?"), + [filename]) + if dlg.exec_() == QDialog.Accepted: + try: + os.remove(filename) + except (OSError, IOError) as exc: + E5MessageBox.critical( + self, + self.tr("Delete File"), + self.tr("""<p>The file <b>{0}</b> could not be""" + """ deleted.</p><p>Reason: {1}</p>""").format( + filename, str(exc)) + ) + + # TODO: test this + @pyqtSlot() + def __showLocalTime(self): + """ + Private slot to show the local date and time. + """ + localdatetime = time.localtime() + loacldate = time.strftime('%Y-%m-%d', localdatetime) + localtime = time.strftime('%H:%M:%S', localdatetime) + E5MessageBox.information( + self, + self.tr("Local Date and Time"), + self.tr("<h3>Local Date and Time</h3>" + "<table>" + "<tr><td><b>Date</b></td><td>{0}</td></tr>" + "<tr><td><b>Time</b></td><td>{1}</td></tr>" + "</table>" + ).format(loacldate, localtime) + ) + ################################################################## ## Context menu methods for the device files below ################################################################## @@ -552,8 +688,14 @@ if bool(len(self.deviceFileTreeWidget.selectedItems())): name = self.deviceFileTreeWidget.selectedItems()[0].text(0) dirname = self.deviceCwd.text() + "/" + name[:-1] - # TODO: add confirmation - self.__fileManager.rmdir(dirname) + dlg = DeleteFilesConfirmationDialog( + self, + self.tr("Delete Directory"), + self.tr( + "Do you really want to delete this directory?"), + [dirname]) + if dlg.exec_() == QDialog.Accepted: + self.__fileManager.rmdir(dirname) @pyqtSlot() def __deleteDeviceDirectoryTree(self): @@ -564,19 +706,31 @@ if bool(len(self.deviceFileTreeWidget.selectedItems())): name = self.deviceFileTreeWidget.selectedItems()[0].text(0) dirname = self.deviceCwd.text() + "/" + name[:-1] - # TODO: add confirmation - self.__fileManager.rmdir(dirname, recursive=True) + dlg = DeleteFilesConfirmationDialog( + self, + self.tr("Delete Directory Tree"), + self.tr( + "Do you really want to delete this directory tree?"), + [dirname]) + if dlg.exec_() == QDialog.Accepted: + self.__fileManager.rmdir(dirname, recursive=True) @pyqtSlot() def __deleteDeviceFile(self): """ - Private slot to delete a file + Private slot to delete a file. """ if bool(len(self.deviceFileTreeWidget.selectedItems())): name = self.deviceFileTreeWidget.selectedItems()[0].text(0) filename = self.deviceCwd.text() + "/" + name - # TODO: add confirmation - self.__fileManager.delete(filename) + dlg = DeleteFilesConfirmationDialog( + self, + self.tr("Delete File"), + self.tr( + "Do you really want to delete this file?"), + [filename]) + if dlg.exec_() == QDialog.Accepted: + self.__fileManager.delete(filename) @pyqtSlot() def __synchronizeTime(self):