9 |
9 |
10 from __future__ import unicode_literals |
10 from __future__ import unicode_literals |
11 |
11 |
12 import os |
12 import os |
13 import shutil |
13 import shutil |
14 import time |
|
15 |
14 |
16 from PyQt5.QtCore import pyqtSlot, Qt, QPoint |
15 from PyQt5.QtCore import pyqtSlot, Qt, QPoint |
17 from PyQt5.QtWidgets import ( |
16 from PyQt5.QtWidgets import ( |
18 QWidget, QTreeWidgetItem, QHeaderView, QMenu, QInputDialog, QLineEdit, |
17 QWidget, QTreeWidgetItem, QHeaderView, QMenu, QInputDialog, QLineEdit, |
19 QDialog |
18 QDialog |
114 self.__localDelDirTreeAct = self.__localMenu.addAction( |
113 self.__localDelDirTreeAct = self.__localMenu.addAction( |
115 self.tr("Delete Directory Tree"), self.__deleteLocalDirectoryTree) |
114 self.tr("Delete Directory Tree"), self.__deleteLocalDirectoryTree) |
116 self.__localMenu.addSeparator() |
115 self.__localMenu.addSeparator() |
117 self.__localDelFileAct = self.__localMenu.addAction( |
116 self.__localDelFileAct = self.__localMenu.addAction( |
118 self.tr("Delete File"), self.__deleteLocalFile) |
117 self.tr("Delete File"), self.__deleteLocalFile) |
119 self.__localMenu.addSeparator() |
|
120 self.__localMenu.addAction( |
|
121 self.tr("Show Time"), self.__showLocalTime) |
|
122 |
118 |
123 self.__deviceMenu = QMenu(self) |
119 self.__deviceMenu = QMenu(self) |
124 if not self.__repl.isMicrobit(): |
120 if not self.__repl.isMicrobit(): |
125 self.__deviceMenu.addAction( |
121 self.__deviceMenu.addAction( |
126 self.tr("Change Directory"), self.__changeDeviceDirectory) |
122 self.tr("Change Directory"), self.__changeDeviceDirectory) |
127 self.__deviceMenu.addAction( |
123 self.__deviceMenu.addAction( |
128 self.tr("Create Directory"), self.__createDeviceDirectory) |
124 self.tr("Create Directory"), self.__createDeviceDirectory) |
129 self.__devDelDirAct = self.__deviceMenu.addAction( |
125 if not self.__deviceWithLocalAccess: |
130 self.tr("Delete Directory"), self.__deleteDeviceDirectory) |
126 self.__devDelDirAct = self.__deviceMenu.addAction( |
|
127 self.tr("Delete Directory"), self.__deleteDeviceDirectory) |
131 self.__devDelDirTreeAct = self.__deviceMenu.addAction( |
128 self.__devDelDirTreeAct = self.__deviceMenu.addAction( |
132 self.tr("Delete Directory Tree"), |
129 self.tr("Delete Directory Tree"), |
133 self.__deleteDeviceDirectoryTree) |
130 self.__deleteDeviceDirectoryTree) |
134 self.__deviceMenu.addSeparator() |
131 self.__deviceMenu.addSeparator() |
135 self.__devDelFileAct = self.__deviceMenu.addAction( |
132 self.__devDelFileAct = self.__deviceMenu.addAction( |
296 Private slot to reload the local list. |
293 Private slot to reload the local list. |
297 """ |
294 """ |
298 dirname = self.localCwd.text() |
295 dirname = self.localCwd.text() |
299 self.__listLocalFiles(dirname) |
296 self.__listLocalFiles(dirname) |
300 |
297 |
301 # TODO: |
|
302 @pyqtSlot(QTreeWidgetItem, int) |
298 @pyqtSlot(QTreeWidgetItem, int) |
303 def on_deviceFileTreeWidget_itemActivated(self, item, column): |
299 def on_deviceFileTreeWidget_itemActivated(self, item, column): |
304 """ |
300 """ |
305 Private slot to handle the activation of a device item. |
301 Private slot to handle the activation of a device item. |
306 |
302 |
311 @type QTreeWidgetItem |
307 @type QTreeWidgetItem |
312 @param column column of the activation |
308 @param column column of the activation |
313 @type int |
309 @type int |
314 """ |
310 """ |
315 name = os.path.join(self.deviceCwd.text(), item.text(0)) |
311 name = os.path.join(self.deviceCwd.text(), item.text(0)) |
316 if name.endswith("/"): |
312 if self.__deviceWithLocalAccess: |
317 # directory names end with a '/' |
313 if name.endswith("/"): |
318 self.__fileManager.cd(name[:-1]) |
314 # directory names end with a '/' |
|
315 self.__listLocalFiles(name[:-1], True) |
|
316 elif Utilities.MimeTypes.isTextFile(name): |
|
317 e5App().getObject("ViewManager").getEditor(name) |
|
318 else: |
|
319 if name.endswith("/"): |
|
320 # directory names end with a '/' |
|
321 self.__fileManager.cd(name[:-1]) |
319 |
322 |
320 @pyqtSlot() |
323 @pyqtSlot() |
321 def on_deviceFileTreeWidget_itemSelectionChanged(self): |
324 def on_deviceFileTreeWidget_itemSelectionChanged(self): |
322 """ |
325 """ |
323 Private slot handling a change of selection in the local pane. |
326 Private slot handling a change of selection in the local pane. |
328 self.deviceFileTreeWidget.selectedItems()[0].text(0) |
331 self.deviceFileTreeWidget.selectedItems()[0].text(0) |
329 .endswith("/")) |
332 .endswith("/")) |
330 self.getButton.setEnabled(enable) |
333 self.getButton.setEnabled(enable) |
331 self.getAsButton.setEnabled(enable) |
334 self.getAsButton.setEnabled(enable) |
332 |
335 |
333 # TODO: |
|
334 @pyqtSlot() |
336 @pyqtSlot() |
335 def on_deviceUpButton_clicked(self): |
337 def on_deviceUpButton_clicked(self): |
336 """ |
338 """ |
337 Private slot to go up one directory level on the device. |
339 Private slot to go up one directory level on the device. |
338 """ |
340 """ |
339 cwd = self.deviceCwd.text() |
341 cwd = self.deviceCwd.text() |
340 dirname = os.path.dirname(cwd) |
342 dirname = os.path.dirname(cwd) |
341 self.__fileManager.cd(dirname) |
343 if self.__deviceWithLocalAccess: |
342 |
344 self.__listLocalFiles(dirname, True) |
343 # TODO: |
345 else: |
|
346 self.__fileManager.cd(dirname) |
|
347 |
344 @pyqtSlot() |
348 @pyqtSlot() |
345 def on_deviceReloadButton_clicked(self): |
349 def on_deviceReloadButton_clicked(self): |
346 """ |
350 """ |
347 Private slot to reload the device list. |
351 Private slot to reload the device list. |
348 """ |
352 """ |
349 dirname = self.deviceCwd.text() |
353 dirname = self.deviceCwd.text() |
350 if dirname: |
354 if self.__deviceWithLocalAccess: |
351 self.__fileManager.lls(dirname) |
355 self.__listLocalFiles(dirname, True) |
352 else: |
356 else: |
353 self.__fileManager.pwd() |
357 if dirname: |
|
358 self.__fileManager.lls(dirname) |
|
359 else: |
|
360 self.__fileManager.pwd() |
354 |
361 |
355 def __isFileInList(self, filename, treeWidget): |
362 def __isFileInList(self, filename, treeWidget): |
356 """ |
363 """ |
357 Private method to check, if a file name is contained in a tree widget. |
364 Private method to check, if a file name is contained in a tree widget. |
358 |
365 |
407 if action == "cancel": |
413 if action == "cancel": |
408 return |
414 return |
409 elif action == "rename": |
415 elif action == "rename": |
410 deviceFilename = os.path.basename(resultFilename) |
416 deviceFilename = os.path.basename(resultFilename) |
411 |
417 |
412 deviceCwd = self.deviceCwd.text() |
418 if self.__deviceWithLocalAccess: |
413 if deviceCwd: |
419 shutil.copy2( |
414 deviceFilename = deviceCwd + "/" + deviceFilename |
420 os.path.join(self.localCwd.text(), filename), |
415 self.__fileManager.put( |
421 os.path.join(self.deviceCwd.text(), deviceFilename) |
416 os.path.join(self.localCwd.text(), filename), |
422 ) |
417 deviceFilename |
423 self.__listLocalFiles(self.deviceCwd.text(), |
418 ) |
424 localDevice=True) |
|
425 else: |
|
426 deviceCwd = self.deviceCwd.text() |
|
427 if deviceCwd and deviceCwd != "/": |
|
428 deviceFilename = deviceCwd + "/" + deviceFilename |
|
429 self.__fileManager.put( |
|
430 os.path.join(self.localCwd.text(), filename), |
|
431 deviceFilename |
|
432 ) |
419 |
433 |
420 @pyqtSlot() |
434 @pyqtSlot() |
421 def on_putAsButton_clicked(self): |
435 def on_putAsButton_clicked(self): |
422 """ |
436 """ |
423 Private slot to copy the selected file to the connected device |
437 Private slot to copy the selected file to the connected device |
424 with a different name. |
438 with a different name. |
425 """ |
439 """ |
426 self.on_putButton_clicked(putAs=True) |
440 self.on_putButton_clicked(putAs=True) |
427 |
441 |
428 # TODO: |
|
429 @pyqtSlot() |
442 @pyqtSlot() |
430 def on_getButton_clicked(self, getAs=False): |
443 def on_getButton_clicked(self, getAs=False): |
431 """ |
444 """ |
432 Private slot to copy the selected file from the connected device. |
445 Private slot to copy the selected file from the connected device. |
433 |
446 |
461 if action == "cancel": |
474 if action == "cancel": |
462 return |
475 return |
463 elif action == "rename": |
476 elif action == "rename": |
464 localFilename = resultFilename |
477 localFilename = resultFilename |
465 |
478 |
466 deviceCwd = self.deviceCwd.text() |
479 if self.__deviceWithLocalAccess: |
467 if deviceCwd: |
480 shutil.copy2( |
468 filename = deviceCwd + "/" + filename |
481 os.path.join(self.deviceCwd.text(), filename), |
469 if not os.path.isabs(localFilename): |
482 os.path.join(self.localCwd.text(), localFilename) |
470 localFilename = os.path.join(self.localCwd.text(), |
483 ) |
471 localFilename) |
484 self.__listLocalFiles(self.localCwd.text()) |
472 self.__fileManager.get( |
485 else: |
473 filename, |
486 deviceCwd = self.deviceCwd.text() |
474 localFilename |
487 if deviceCwd: |
475 ) |
488 filename = deviceCwd + "/" + filename |
|
489 self.__fileManager.get( |
|
490 filename, |
|
491 os.path.join(self.localCwd.text(), localFilename) |
|
492 ) |
476 |
493 |
477 @pyqtSlot() |
494 @pyqtSlot() |
478 def on_getAsButton_clicked(self): |
495 def on_getAsButton_clicked(self): |
479 """ |
496 """ |
480 Private slot to copy the selected file from the connected device |
497 Private slot to copy the selected file from the connected device |
492 @param localFile name of the local file |
509 @param localFile name of the local file |
493 @type str |
510 @type str |
494 """ |
511 """ |
495 self.__listLocalFiles(self.localCwd.text()) |
512 self.__listLocalFiles(self.localCwd.text()) |
496 |
513 |
497 # TODO: |
|
498 @pyqtSlot() |
514 @pyqtSlot() |
499 def on_syncButton_clicked(self): |
515 def on_syncButton_clicked(self): |
500 """ |
516 """ |
501 Private slot to synchronize the local directory to the device. |
517 Private slot to synchronize the local directory to the device. |
502 """ |
518 """ |
503 self.__fileManager.rsync( |
519 self.__fileManager.rsync( |
504 self.localCwd.text(), |
520 self.localCwd.text(), |
505 self.deviceCwd.text(), |
521 self.deviceCwd.text(), |
506 mirror=True |
522 mirror=True, |
|
523 localDevice=self.__deviceWithLocalAccess, |
507 ) |
524 ) |
508 |
525 |
509 @pyqtSlot(str, str) |
526 @pyqtSlot(str, str) |
510 def __handleRsyncDone(self, localDir, deviceDir): |
527 def __handleRsyncDone(self, localDir, deviceDir): |
511 """ |
528 """ |
673 self.tr("""<p>The directory <b>{0}</b> could not be""" |
690 self.tr("""<p>The directory <b>{0}</b> could not be""" |
674 """ deleted.</p><p>Reason: {1}</p>""").format( |
691 """ deleted.</p><p>Reason: {1}</p>""").format( |
675 dirname, str(exc)) |
692 dirname, str(exc)) |
676 ) |
693 ) |
677 |
694 |
678 # TODO: |
695 @pyqtSlot() |
679 @pyqtSlot() |
696 def __deleteLocalFile(self, localDevice=False): |
680 def __deleteLocalFile(self): |
|
681 """ |
697 """ |
682 Private slot to delete a local file. |
698 Private slot to delete a local file. |
683 """ |
699 |
684 if bool(len(self.localFileTreeWidget.selectedItems())): |
700 @param localDevice flag indicating device access via local file system |
685 name = self.localFileTreeWidget.selectedItems()[0].text(0) |
701 @type bool |
686 filename = os.path.join(self.localCwd.text(), name) |
702 """ |
|
703 if localDevice: |
|
704 cwdWidget = self.deviceCwd |
|
705 fileTreeWidget = self.deviceFileTreeWidget |
|
706 else: |
|
707 cwdWidget = self.localCwd |
|
708 fileTreeWidget = self.localFileTreeWidget |
|
709 |
|
710 if bool(len(fileTreeWidget.selectedItems())): |
|
711 name = fileTreeWidget.selectedItems()[0].text(0) |
|
712 filename = os.path.join(cwdWidget.text(), name) |
687 dlg = DeleteFilesConfirmationDialog( |
713 dlg = DeleteFilesConfirmationDialog( |
688 self, |
714 self, |
689 self.tr("Delete File"), |
715 self.tr("Delete File"), |
690 self.tr( |
716 self.tr( |
691 "Do you really want to delete this file?"), |
717 "Do you really want to delete this file?"), |
692 [filename]) |
718 [filename]) |
693 if dlg.exec_() == QDialog.Accepted: |
719 if dlg.exec_() == QDialog.Accepted: |
694 try: |
720 try: |
695 os.remove(filename) |
721 os.remove(filename) |
696 self.__listLocalFiles(self.localCwd.text()) |
722 self.__listLocalFiles(cwdWidget.text(), |
|
723 localDevice=localDevice) |
697 except (OSError, IOError) as exc: |
724 except (OSError, IOError) as exc: |
698 E5MessageBox.critical( |
725 E5MessageBox.critical( |
699 self, |
726 self, |
700 self.tr("Delete File"), |
727 self.tr("Delete File"), |
701 self.tr("""<p>The file <b>{0}</b> could not be""" |
728 self.tr("""<p>The file <b>{0}</b> could not be""" |
702 """ deleted.</p><p>Reason: {1}</p>""").format( |
729 """ deleted.</p><p>Reason: {1}</p>""").format( |
703 filename, str(exc)) |
730 filename, str(exc)) |
704 ) |
731 ) |
705 |
732 |
706 # TODO: move to repl widget super menu |
|
707 @pyqtSlot() |
|
708 def __showLocalTime(self): |
|
709 """ |
|
710 Private slot to show the local date and time. |
|
711 """ |
|
712 localdatetime = time.localtime() |
|
713 loacldate = time.strftime('%Y-%m-%d', localdatetime) |
|
714 localtime = time.strftime('%H:%M:%S', localdatetime) |
|
715 E5MessageBox.information( |
|
716 self, |
|
717 self.tr("Local Date and Time"), |
|
718 self.tr("<h3>Local Date and Time</h3>" |
|
719 "<table>" |
|
720 "<tr><td><b>Date</b></td><td>{0}</td></tr>" |
|
721 "<tr><td><b>Time</b></td><td>{1}</td></tr>" |
|
722 "</table>" |
|
723 ).format(loacldate, localtime) |
|
724 ) |
|
725 |
|
726 ################################################################## |
733 ################################################################## |
727 ## Context menu methods for the device files below |
734 ## Context menu methods for the device files below |
728 ################################################################## |
735 ################################################################## |
729 |
736 |
730 @pyqtSlot(QPoint) |
737 @pyqtSlot(QPoint) |
796 if self.__deviceWithLocalAccess: |
804 if self.__deviceWithLocalAccess: |
797 self.__deleteLocalDirectoryTree(True) |
805 self.__deleteLocalDirectoryTree(True) |
798 else: |
806 else: |
799 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
807 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
800 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
808 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
801 dirname = self.deviceCwd.text() + "/" + name[:-1] |
809 cwd = self.deviceCwd.text() |
|
810 if cwd and cwd != "/": |
|
811 dirname = cwd + "/" + name[:-1] |
|
812 else: |
|
813 dirname = "/" + name[:-1] |
802 dlg = DeleteFilesConfirmationDialog( |
814 dlg = DeleteFilesConfirmationDialog( |
803 self, |
815 self, |
804 self.tr("Delete Directory"), |
816 self.tr("Delete Directory"), |
805 self.tr( |
817 self.tr( |
806 "Do you really want to delete this directory?"), |
818 "Do you really want to delete this directory?"), |
817 if self.__deviceWithLocalAccess: |
829 if self.__deviceWithLocalAccess: |
818 self.__deleteLocalDirectoryTree(True) |
830 self.__deleteLocalDirectoryTree(True) |
819 else: |
831 else: |
820 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
832 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
821 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
833 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
822 dirname = self.deviceCwd.text() + "/" + name[:-1] |
834 cwd = self.deviceCwd.text() |
|
835 if cwd and cwd != "/": |
|
836 dirname = cwd + "/" + name[:-1] |
|
837 else: |
|
838 dirname = "/" + name[:-1] |
823 dlg = DeleteFilesConfirmationDialog( |
839 dlg = DeleteFilesConfirmationDialog( |
824 self, |
840 self, |
825 self.tr("Delete Directory Tree"), |
841 self.tr("Delete Directory Tree"), |
826 self.tr( |
842 self.tr( |
827 "Do you really want to delete this directory tree?"), |
843 "Do you really want to delete this directory tree?"), |
828 [dirname]) |
844 [dirname]) |
829 if dlg.exec_() == QDialog.Accepted: |
845 if dlg.exec_() == QDialog.Accepted: |
830 self.__fileManager.rmdir(dirname, recursive=True) |
846 self.__fileManager.rmdir(dirname, recursive=True) |
831 |
847 |
832 # TODO: |
|
833 @pyqtSlot() |
848 @pyqtSlot() |
834 def __deleteDeviceFile(self): |
849 def __deleteDeviceFile(self): |
835 """ |
850 """ |
836 Private slot to delete a file. |
851 Private slot to delete a file. |
837 """ |
852 """ |
838 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
853 if self.__deviceWithLocalAccess: |
839 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
854 self.__deleteLocalFile(True) |
840 dirname = self.deviceCwd.text() |
855 else: |
841 if dirname: |
856 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
842 filename = dirname + "/" + name |
857 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
843 else: |
858 dirname = self.deviceCwd.text() |
844 filename = name |
859 if dirname and dirname != "/": |
845 dlg = DeleteFilesConfirmationDialog( |
860 filename = dirname + "/" + name |
846 self, |
861 else: |
847 self.tr("Delete File"), |
862 filename = "/" + name |
848 self.tr( |
863 dlg = DeleteFilesConfirmationDialog( |
849 "Do you really want to delete this file?"), |
864 self, |
850 [filename]) |
865 self.tr("Delete File"), |
851 if dlg.exec_() == QDialog.Accepted: |
866 self.tr( |
852 self.__fileManager.delete(filename) |
867 "Do you really want to delete this file?"), |
|
868 [filename]) |
|
869 if dlg.exec_() == QDialog.Accepted: |
|
870 self.__fileManager.delete(filename) |
853 |
871 |
854 @pyqtSlot() |
872 @pyqtSlot() |
855 def __showFileSystemInfo(self): |
873 def __showFileSystemInfo(self): |
856 """ |
874 """ |
857 Private slot to show some file system information. |
875 Private slot to show some file system information. |