eric6/MicroPython/MicroPythonFileManagerWidget.py

branch
micropython
changeset 7130
6014d37d9683
parent 7126
376deb7fefe7
child 7131
f75e990caf99
equal deleted inserted replaced
7129:3cc19aec959a 7130:6014d37d9683
41 41
42 class MicroPythonFileManagerWidget(QWidget, Ui_MicroPythonFileManagerWidget): 42 class MicroPythonFileManagerWidget(QWidget, Ui_MicroPythonFileManagerWidget):
43 """ 43 """
44 Class implementing a file manager for MicroPython devices. 44 Class implementing a file manager for MicroPython devices.
45 """ 45 """
46 def __init__(self, commandsInterface, parent=None): 46 def __init__(self, commandsInterface, deviceWithLocalAccess, parent=None):
47 """ 47 """
48 Constructor 48 Constructor
49 49
50 @param commandsInterface reference to the commands interface object 50 @param commandsInterface reference to the commands interface object
51 @type MicroPythonCommandsInterface 51 @type MicroPythonCommandsInterface
52 @param deviceWithLocalAccess flag indicating the device supports file
53 access via a local directory
54 @type bool
52 @param parent reference to the parent widget 55 @param parent reference to the parent widget
53 @type QWidget 56 @type QWidget
54 """ 57 """
55 super(MicroPythonFileManagerWidget, self).__init__(parent) 58 super(MicroPythonFileManagerWidget, self).__init__(parent)
56 self.setupUi(self) 59 self.setupUi(self)
57 60
58 self.__repl = parent 61 self.__repl = parent
62 self.__deviceWithLocalAccess = deviceWithLocalAccess
59 63
60 self.syncButton.setIcon(UI.PixmapCache.getIcon("2rightarrow")) 64 self.syncButton.setIcon(UI.PixmapCache.getIcon("2rightarrow"))
61 self.putButton.setIcon(UI.PixmapCache.getIcon("1rightarrow")) 65 self.putButton.setIcon(UI.PixmapCache.getIcon("1rightarrow"))
62 self.putAsButton.setIcon(UI.PixmapCache.getIcon("putAs")) 66 self.putAsButton.setIcon(UI.PixmapCache.getIcon("putAs"))
63 self.getButton.setIcon(UI.PixmapCache.getIcon("1leftarrow")) 67 self.getButton.setIcon(UI.PixmapCache.getIcon("1leftarrow"))
147 if not dirname: 151 if not dirname:
148 dirname = (Preferences.getMultiProject("Workspace") or 152 dirname = (Preferences.getMultiProject("Workspace") or
149 os.path.expanduser("~")) 153 os.path.expanduser("~"))
150 self.__listLocalFiles(dirname) 154 self.__listLocalFiles(dirname)
151 155
152 self.__fileManager.pwd() 156 if self.__deviceWithLocalAccess:
157 dirname = self.__repl.getDeviceWorkspace()
158 if dirname:
159 self.__listLocalFiles(dirname, True)
160 else:
161 self.__fileManager.pwd()
153 162
154 def stop(self): 163 def stop(self):
155 """ 164 """
156 Public method to stop the widget. 165 Public method to stop the widget.
157 """ 166 """
201 itm.setTextAlignment(1, Qt.AlignHCenter) 210 itm.setTextAlignment(1, Qt.AlignHCenter)
202 itm.setTextAlignment(2, Qt.AlignRight) 211 itm.setTextAlignment(2, Qt.AlignRight)
203 self.deviceFileTreeWidget.header().resizeSections( 212 self.deviceFileTreeWidget.header().resizeSections(
204 QHeaderView.ResizeToContents) 213 QHeaderView.ResizeToContents)
205 214
206 def __listLocalFiles(self, dirname=""): 215 def __listLocalFiles(self, dirname="", localDevice=False):
207 """ 216 """
208 Private method to populate the local files list. 217 Private method to populate the local files list.
209 218
210 @param dirname name of the local directory to be listed 219 @param dirname name of the local directory to be listed
211 @type str 220 @type str
212 """ # __IGNORE_WARNING_D234__ 221 @param localDevice flag indicating device access via local file system
213 222 @type bool
223 """
214 if not dirname: 224 if not dirname:
215 dirname = os.getcwd() 225 dirname = os.getcwd()
216 if dirname.endswith(os.sep): 226 if dirname.endswith(os.sep):
217 dirname = dirname[:-1] 227 dirname = dirname[:-1]
218 self.localCwd.setText(dirname) 228 if localDevice:
229 self.deviceCwd.setText(dirname)
230 else:
231 self.localCwd.setText(dirname)
219 232
220 filesStatList = listdirStat(dirname) 233 filesStatList = listdirStat(dirname)
221 filesList = [( 234 filesList = [(
222 decoratedName(f, s[0], os.path.isdir(os.path.join(dirname, f))), 235 decoratedName(f, s[0], os.path.isdir(os.path.join(dirname, f))),
223 mode2string(s[0]), 236 mode2string(s[0]),
224 str(s[6]), 237 str(s[6]),
225 mtime2string(s[8])) for f, s in filesStatList] 238 mtime2string(s[8])) for f, s in filesStatList]
226 self.localFileTreeWidget.clear() 239 if localDevice:
240 fileTreeWidget = self.deviceFileTreeWidget
241 else:
242 fileTreeWidget = self.localFileTreeWidget
243 fileTreeWidget.clear()
227 for item in filesList: 244 for item in filesList:
228 itm = QTreeWidgetItem(self.localFileTreeWidget, item) 245 itm = QTreeWidgetItem(fileTreeWidget, item)
229 itm.setTextAlignment(1, Qt.AlignHCenter) 246 itm.setTextAlignment(1, Qt.AlignHCenter)
230 itm.setTextAlignment(2, Qt.AlignRight) 247 itm.setTextAlignment(2, Qt.AlignRight)
231 self.localFileTreeWidget.header().resizeSections( 248 fileTreeWidget.header().resizeSections(
232 QHeaderView.ResizeToContents) 249 QHeaderView.ResizeToContents)
233 250
234 @pyqtSlot(QTreeWidgetItem, int) 251 @pyqtSlot(QTreeWidgetItem, int)
235 def on_localFileTreeWidget_itemActivated(self, item, column): 252 def on_localFileTreeWidget_itemActivated(self, item, column):
236 """ 253 """
279 Private slot to reload the local list. 296 Private slot to reload the local list.
280 """ 297 """
281 dirname = self.localCwd.text() 298 dirname = self.localCwd.text()
282 self.__listLocalFiles(dirname) 299 self.__listLocalFiles(dirname)
283 300
301 # TODO:
284 @pyqtSlot(QTreeWidgetItem, int) 302 @pyqtSlot(QTreeWidgetItem, int)
285 def on_deviceFileTreeWidget_itemActivated(self, item, column): 303 def on_deviceFileTreeWidget_itemActivated(self, item, column):
286 """ 304 """
287 Private slot to handle the activation of a device item. 305 Private slot to handle the activation of a device item.
288 306
310 self.deviceFileTreeWidget.selectedItems()[0].text(0) 328 self.deviceFileTreeWidget.selectedItems()[0].text(0)
311 .endswith("/")) 329 .endswith("/"))
312 self.getButton.setEnabled(enable) 330 self.getButton.setEnabled(enable)
313 self.getAsButton.setEnabled(enable) 331 self.getAsButton.setEnabled(enable)
314 332
333 # TODO:
315 @pyqtSlot() 334 @pyqtSlot()
316 def on_deviceUpButton_clicked(self): 335 def on_deviceUpButton_clicked(self):
317 """ 336 """
318 Private slot to go up one directory level on the device. 337 Private slot to go up one directory level on the device.
319 """ 338 """
320 cwd = self.deviceCwd.text() 339 cwd = self.deviceCwd.text()
321 dirname = os.path.dirname(cwd) 340 dirname = os.path.dirname(cwd)
322 self.__fileManager.cd(dirname) 341 self.__fileManager.cd(dirname)
323 342
343 # TODO:
324 @pyqtSlot() 344 @pyqtSlot()
325 def on_deviceReloadButton_clicked(self): 345 def on_deviceReloadButton_clicked(self):
326 """ 346 """
327 Private slot to reload the device list. 347 Private slot to reload the device list.
328 """ 348 """
348 if treeWidget.topLevelItem(row).text(0) == filename: 368 if treeWidget.topLevelItem(row).text(0) == filename:
349 return True 369 return True
350 370
351 return False 371 return False
352 372
373 # TODO:
353 @pyqtSlot() 374 @pyqtSlot()
354 def on_putButton_clicked(self, putAs=False): 375 def on_putButton_clicked(self, putAs=False):
355 """ 376 """
356 Private slot to copy the selected file to the connected device. 377 Private slot to copy the selected file to the connected device.
357 378
402 Private slot to copy the selected file to the connected device 423 Private slot to copy the selected file to the connected device
403 with a different name. 424 with a different name.
404 """ 425 """
405 self.on_putButton_clicked(putAs=True) 426 self.on_putButton_clicked(putAs=True)
406 427
428 # TODO:
407 @pyqtSlot() 429 @pyqtSlot()
408 def on_getButton_clicked(self, getAs=False): 430 def on_getButton_clicked(self, getAs=False):
409 """ 431 """
410 Private slot to copy the selected file from the connected device. 432 Private slot to copy the selected file from the connected device.
411 433
470 @param localFile name of the local file 492 @param localFile name of the local file
471 @type str 493 @type str
472 """ 494 """
473 self.__listLocalFiles(self.localCwd.text()) 495 self.__listLocalFiles(self.localCwd.text())
474 496
497 # TODO:
475 @pyqtSlot() 498 @pyqtSlot()
476 def on_syncButton_clicked(self): 499 def on_syncButton_clicked(self):
477 """ 500 """
478 Private slot to synchronize the local directory to the device. 501 Private slot to synchronize the local directory to the device.
479 """ 502 """
553 self.__localDelFileAct.setEnabled(isFile) 576 self.__localDelFileAct.setEnabled(isFile)
554 577
555 self.__localMenu.exec_(self.localFileTreeWidget.mapToGlobal(pos)) 578 self.__localMenu.exec_(self.localFileTreeWidget.mapToGlobal(pos))
556 579
557 @pyqtSlot() 580 @pyqtSlot()
558 def __changeLocalDirectory(self): 581 def __changeLocalDirectory(self, localDevice=False):
559 """ 582 """
560 Private slot to change the local directory. 583 Private slot to change the local directory.
561 """ 584
585 @param localDevice flag indicating device access via local file system
586 @type bool
587 """
588 if localDevice:
589 cwdWidget = self.deviceCwd
590 else:
591 cwdWidget = self.localCwd
592
562 dirPath, ok = E5PathPickerDialog.getPath( 593 dirPath, ok = E5PathPickerDialog.getPath(
563 self, 594 self,
564 self.tr("Change Directory"), 595 self.tr("Change Directory"),
565 self.tr("Select Directory"), 596 self.tr("Select Directory"),
566 E5PathPickerModes.DirectoryShowFilesMode, 597 E5PathPickerModes.DirectoryShowFilesMode,
567 defaultDirectory=self.localCwd.text(), 598 path=cwdWidget.text(),
599 defaultDirectory=cwdWidget.text(),
568 ) 600 )
569 if ok and dirPath: 601 if ok and dirPath:
570 if not os.path.isabs(dirPath): 602 if not os.path.isabs(dirPath):
571 dirPath = os.path.join(self.localCwd.text(), dirPath) 603 dirPath = os.path.join(cwdWidget.text(), dirPath)
572 self.localCwd.setText(dirPath) 604 cwdWidget.setText(dirPath)
573 self.__listLocalFiles(dirPath) 605 self.__listLocalFiles(dirPath, localDevice=localDevice)
574 606
575 @pyqtSlot() 607 @pyqtSlot()
576 def __createLocalDirectory(self): 608 def __createLocalDirectory(self, localDevice=False):
577 """ 609 """
578 Private slot to create a local directory. 610 Private slot to create a local directory.
579 """ 611
612 @param localDevice flag indicating device access via local file system
613 @type bool
614 """
615 if localDevice:
616 cwdWidget = self.deviceCwd
617 else:
618 cwdWidget = self.localCwd
619
580 dirPath, ok = QInputDialog.getText( 620 dirPath, ok = QInputDialog.getText(
581 self, 621 self,
582 self.tr("Create Directory"), 622 self.tr("Create Directory"),
583 self.tr("Enter directory name:"), 623 self.tr("Enter directory name:"),
584 QLineEdit.Normal) 624 QLineEdit.Normal)
585 if ok and dirPath: 625 if ok and dirPath:
586 dirPath = os.path.join(self.localCwd.text(), dirPath) 626 dirPath = os.path.join(cwdWidget.text(), dirPath)
587 try: 627 try:
588 os.mkdir(dirPath) 628 os.mkdir(dirPath)
589 self.__listLocalFiles(self.localCwd.text()) 629 self.__listLocalFiles(cwdWidget.text(),
630 localDevice=localDevice)
590 except (OSError, IOError) as exc: 631 except (OSError, IOError) as exc:
591 E5MessageBox.critical( 632 E5MessageBox.critical(
592 self, 633 self,
593 self.tr("Create Directory"), 634 self.tr("Create Directory"),
594 self.tr("""<p>The directory <b>{0}</b> could not be""" 635 self.tr("""<p>The directory <b>{0}</b> could not be"""
595 """ created.</p><p>Reason: {1}</p>""").format( 636 """ created.</p><p>Reason: {1}</p>""").format(
596 dirPath, str(exc)) 637 dirPath, str(exc))
597 ) 638 )
598 639
599 @pyqtSlot() 640 @pyqtSlot()
600 def __deleteLocalDirectoryTree(self): 641 def __deleteLocalDirectoryTree(self, localDevice=False):
601 """ 642 """
602 Private slot to delete a local directory tree. 643 Private slot to delete a local directory tree.
603 """ 644
604 if bool(len(self.localFileTreeWidget.selectedItems())): 645 @param localDevice flag indicating device access via local file system
605 name = self.localFileTreeWidget.selectedItems()[0].text(0) 646 @type bool
606 dirname = os.path.join(self.localCwd.text(), name[:-1]) 647 """
648 if localDevice:
649 cwdWidget = self.deviceCwd
650 fileTreeWidget = self.deviceFileTreeWidget
651 else:
652 cwdWidget = self.localCwd
653 fileTreeWidget = self.localFileTreeWidget
654
655 if bool(len(fileTreeWidget.selectedItems())):
656 name = fileTreeWidget.selectedItems()[0].text(0)
657 dirname = os.path.join(cwdWidget.text(), name[:-1])
607 dlg = DeleteFilesConfirmationDialog( 658 dlg = DeleteFilesConfirmationDialog(
608 self, 659 self,
609 self.tr("Delete Directory Tree"), 660 self.tr("Delete Directory Tree"),
610 self.tr( 661 self.tr(
611 "Do you really want to delete this directory tree?"), 662 "Do you really want to delete this directory tree?"),
612 [dirname]) 663 [dirname])
613 if dlg.exec_() == QDialog.Accepted: 664 if dlg.exec_() == QDialog.Accepted:
614 try: 665 try:
615 shutil.rmtree(dirname) 666 shutil.rmtree(dirname)
616 self.__listLocalFiles(self.localCwd.text()) 667 self.__listLocalFiles(cwdWidget.text(),
668 localDevice=localDevice)
617 except Exception as exc: 669 except Exception as exc:
618 E5MessageBox.critical( 670 E5MessageBox.critical(
619 self, 671 self,
620 self.tr("Delete Directory Tree"), 672 self.tr("Delete Directory Tree"),
621 self.tr("""<p>The directory <b>{0}</b> could not be""" 673 self.tr("""<p>The directory <b>{0}</b> could not be"""
622 """ deleted.</p><p>Reason: {1}</p>""").format( 674 """ deleted.</p><p>Reason: {1}</p>""").format(
623 dirname, str(exc)) 675 dirname, str(exc))
624 ) 676 )
625 677
678 # TODO:
626 @pyqtSlot() 679 @pyqtSlot()
627 def __deleteLocalFile(self): 680 def __deleteLocalFile(self):
628 """ 681 """
629 Private slot to delete a local file. 682 Private slot to delete a local file.
630 """ 683 """
647 self.tr("Delete File"), 700 self.tr("Delete File"),
648 self.tr("""<p>The file <b>{0}</b> could not be""" 701 self.tr("""<p>The file <b>{0}</b> could not be"""
649 """ deleted.</p><p>Reason: {1}</p>""").format( 702 """ deleted.</p><p>Reason: {1}</p>""").format(
650 filename, str(exc)) 703 filename, str(exc))
651 ) 704 )
652 705
706 # TODO: move to repl widget super menu
653 @pyqtSlot() 707 @pyqtSlot()
654 def __showLocalTime(self): 708 def __showLocalTime(self):
655 """ 709 """
656 Private slot to show the local date and time. 710 Private slot to show the local date and time.
657 """ 711 """
702 Private slot to change the current directory of the device. 756 Private slot to change the current directory of the device.
703 757
704 Note: This triggers a re-population of the device list for the new 758 Note: This triggers a re-population of the device list for the new
705 current directory. 759 current directory.
706 """ 760 """
707 dirPath, ok = QInputDialog.getText( 761 if self.__deviceWithLocalAccess:
708 self, 762 self.__changeLocalDirectory(True)
709 self.tr("Change Directory"), 763 else:
710 self.tr("Enter the directory path on the device:"), 764 dirPath, ok = QInputDialog.getText(
711 QLineEdit.Normal, 765 self,
712 self.deviceCwd.text()) 766 self.tr("Change Directory"),
713 if ok and dirPath: 767 self.tr("Enter the directory path on the device:"),
714 if not dirPath.startswith("/"): 768 QLineEdit.Normal,
715 dirPath = self.deviceCwd.text() + "/" + dirPath 769 self.deviceCwd.text())
716 self.__fileManager.cd(dirPath) 770 if ok and dirPath:
771 if not dirPath.startswith("/"):
772 dirPath = self.deviceCwd.text() + "/" + dirPath
773 self.__fileManager.cd(dirPath)
717 774
718 @pyqtSlot() 775 @pyqtSlot()
719 def __createDeviceDirectory(self): 776 def __createDeviceDirectory(self):
720 """ 777 """
721 Private slot to create a directory on the device. 778 Private slot to create a directory on the device.
722 """ 779 """
723 dirPath, ok = QInputDialog.getText( 780 if self.__deviceWithLocalAccess:
724 self, 781 self.__createLocalDirectory(True)
725 self.tr("Create Directory"), 782 else:
726 self.tr("Enter directory name:"), 783 dirPath, ok = QInputDialog.getText(
727 QLineEdit.Normal) 784 self,
728 if ok and dirPath: 785 self.tr("Create Directory"),
729 self.__fileManager.mkdir(dirPath) 786 self.tr("Enter directory name:"),
787 QLineEdit.Normal)
788 if ok and dirPath:
789 self.__fileManager.mkdir(dirPath)
730 790
731 @pyqtSlot() 791 @pyqtSlot()
732 def __deleteDeviceDirectory(self): 792 def __deleteDeviceDirectory(self):
733 """ 793 """
734 Private slot to delete an empty directory on the device. 794 Private slot to delete an empty directory on the device.
735 """ 795 """
736 if bool(len(self.deviceFileTreeWidget.selectedItems())): 796 if self.__deviceWithLocalAccess:
737 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) 797 self.__deleteLocalDirectoryTree(True)
738 dirname = self.deviceCwd.text() + "/" + name[:-1] 798 else:
739 dlg = DeleteFilesConfirmationDialog( 799 if bool(len(self.deviceFileTreeWidget.selectedItems())):
740 self, 800 name = self.deviceFileTreeWidget.selectedItems()[0].text(0)
741 self.tr("Delete Directory"), 801 dirname = self.deviceCwd.text() + "/" + name[:-1]
742 self.tr( 802 dlg = DeleteFilesConfirmationDialog(
743 "Do you really want to delete this directory?"), 803 self,
744 [dirname]) 804 self.tr("Delete Directory"),
745 if dlg.exec_() == QDialog.Accepted: 805 self.tr(
746 self.__fileManager.rmdir(dirname) 806 "Do you really want to delete this directory?"),
807 [dirname])
808 if dlg.exec_() == QDialog.Accepted:
809 self.__fileManager.rmdir(dirname)
747 810
748 @pyqtSlot() 811 @pyqtSlot()
749 def __deleteDeviceDirectoryTree(self): 812 def __deleteDeviceDirectoryTree(self):
750 """ 813 """
751 Private slot to delete a directory and all its subdirectories 814 Private slot to delete a directory and all its subdirectories
752 recursively. 815 recursively.
753 """ 816 """
754 if bool(len(self.deviceFileTreeWidget.selectedItems())): 817 if self.__deviceWithLocalAccess:
755 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) 818 self.__deleteLocalDirectoryTree(True)
756 dirname = self.deviceCwd.text() + "/" + name[:-1] 819 else:
757 dlg = DeleteFilesConfirmationDialog( 820 if bool(len(self.deviceFileTreeWidget.selectedItems())):
758 self, 821 name = self.deviceFileTreeWidget.selectedItems()[0].text(0)
759 self.tr("Delete Directory Tree"), 822 dirname = self.deviceCwd.text() + "/" + name[:-1]
760 self.tr( 823 dlg = DeleteFilesConfirmationDialog(
761 "Do you really want to delete this directory tree?"), 824 self,
762 [dirname]) 825 self.tr("Delete Directory Tree"),
763 if dlg.exec_() == QDialog.Accepted: 826 self.tr(
764 self.__fileManager.rmdir(dirname, recursive=True) 827 "Do you really want to delete this directory tree?"),
765 828 [dirname])
829 if dlg.exec_() == QDialog.Accepted:
830 self.__fileManager.rmdir(dirname, recursive=True)
831
832 # TODO:
766 @pyqtSlot() 833 @pyqtSlot()
767 def __deleteDeviceFile(self): 834 def __deleteDeviceFile(self):
768 """ 835 """
769 Private slot to delete a file. 836 Private slot to delete a file.
770 """ 837 """

eric ide

mercurial