16 QWidget, QTreeWidgetItem, QHeaderView, QMenu, QInputDialog, QLineEdit |
16 QWidget, QTreeWidgetItem, QHeaderView, QMenu, QInputDialog, QLineEdit |
17 ) |
17 ) |
18 |
18 |
19 from E5Gui import E5MessageBox, E5PathPickerDialog |
19 from E5Gui import E5MessageBox, E5PathPickerDialog |
20 from E5Gui.E5PathPicker import E5PathPickerModes |
20 from E5Gui.E5PathPicker import E5PathPickerModes |
|
21 from E5Gui.E5FileSaveConfirmDialog import confirmOverwrite |
21 from E5Gui.E5Application import e5App |
22 from E5Gui.E5Application import e5App |
22 |
23 |
23 from .Ui_MicroPythonFileManagerWidget import Ui_MicroPythonFileManagerWidget |
24 from .Ui_MicroPythonFileManagerWidget import Ui_MicroPythonFileManagerWidget |
24 |
25 |
25 from .MicroPythonFileSystem import MicroPythonFileManager |
26 from .MicroPythonFileSystem import MicroPythonFileManager |
60 self.localFileTreeWidget.header().setSortIndicator( |
61 self.localFileTreeWidget.header().setSortIndicator( |
61 0, Qt.AscendingOrder) |
62 0, Qt.AscendingOrder) |
62 self.deviceFileTreeWidget.header().setSortIndicator( |
63 self.deviceFileTreeWidget.header().setSortIndicator( |
63 0, Qt.AscendingOrder) |
64 0, Qt.AscendingOrder) |
64 |
65 |
|
66 self.__progressInfoDialog = None |
65 self.__fileManager = MicroPythonFileManager(port, self) |
67 self.__fileManager = MicroPythonFileManager(port, self) |
66 |
68 |
67 self.__fileManager.longListFiles.connect(self.__handleLongListFiles) |
69 self.__fileManager.longListFiles.connect(self.__handleLongListFiles) |
68 self.__fileManager.currentDir.connect(self.__handleCurrentDir) |
70 self.__fileManager.currentDir.connect(self.__handleCurrentDir) |
69 self.__fileManager.currentDirChanged.connect(self.__handleCurrentDir) |
71 self.__fileManager.currentDirChanged.connect(self.__handleCurrentDir) |
70 self.__fileManager.putFileDone.connect(self.__newDeviceList) |
72 self.__fileManager.putFileDone.connect(self.__newDeviceList) |
71 self.__fileManager.getFileDone.connect(self.__handleGetDone) |
73 self.__fileManager.getFileDone.connect(self.__handleGetDone) |
72 self.__fileManager.rsyncDone.connect(self.__handleRsyncDone) |
74 self.__fileManager.rsyncDone.connect(self.__handleRsyncDone) |
73 self.__fileManager.rsyncMessages.connect(self.__handleRsyncMessages) |
75 self.__fileManager.rsyncMessages.connect(self.__handleRsyncMessages) |
|
76 self.__fileManager.rsyncProgressMessage.connect( |
|
77 self.__handleRsyncProgressMessage) |
74 self.__fileManager.removeDirectoryDone.connect(self.__newDeviceList) |
78 self.__fileManager.removeDirectoryDone.connect(self.__newDeviceList) |
75 self.__fileManager.createDirectoryDone.connect(self.__newDeviceList) |
79 self.__fileManager.createDirectoryDone.connect(self.__newDeviceList) |
76 self.__fileManager.deleteFileDone.connect(self.__newDeviceList) |
80 self.__fileManager.deleteFileDone.connect(self.__newDeviceList) |
77 self.__fileManager.synchTimeDone.connect(self.__timeSynchronized) |
81 self.__fileManager.synchTimeDone.connect(self.__timeSynchronized) |
78 self.__fileManager.showTimeDone.connect(self.__deviceTimeReceived) |
82 self.__fileManager.showTimeDone.connect(self.__deviceTimeReceived) |
87 self.__showDeviceContextMenu) |
91 self.__showDeviceContextMenu) |
88 |
92 |
89 self.__localMenu = QMenu(self) |
93 self.__localMenu = QMenu(self) |
90 self.__localMenu.addAction(self.tr("Change Directory"), |
94 self.__localMenu.addAction(self.tr("Change Directory"), |
91 self.__changeLocalDirectory) |
95 self.__changeLocalDirectory) |
|
96 # TODO: add some more local entries |
|
97 # TODO: add entry to reload |
92 |
98 |
93 self.__deviceMenu = QMenu(self) |
99 self.__deviceMenu = QMenu(self) |
94 self.__deviceMenu.addAction( |
100 self.__deviceMenu.addAction( |
95 self.tr("Change Directory"), self.__changeDeviceDirectory) |
101 self.tr("Change Directory"), self.__changeDeviceDirectory) |
96 self.__deviceMenu.addAction( |
102 self.__deviceMenu.addAction( |
101 self.tr("Delete Directory Tree"), self.__deleteDeviceDirectoryTree) |
107 self.tr("Delete Directory Tree"), self.__deleteDeviceDirectoryTree) |
102 self.__deviceMenu.addSeparator() |
108 self.__deviceMenu.addSeparator() |
103 self.__devDelFileAct = self.__deviceMenu.addAction( |
109 self.__devDelFileAct = self.__deviceMenu.addAction( |
104 self.tr("Delete File"), self.__deleteDeviceFile) |
110 self.tr("Delete File"), self.__deleteDeviceFile) |
105 self.__deviceMenu.addSeparator() |
111 self.__deviceMenu.addSeparator() |
|
112 # TODO: add entry to reload |
|
113 self.__deviceMenu.addSeparator() |
106 self.__deviceMenu.addAction( |
114 self.__deviceMenu.addAction( |
107 self.tr("Synchronize Time"), self.__synchronizeTime) |
115 self.tr("Synchronize Time"), self.__synchronizeTime) |
108 self.__deviceMenu.addAction( |
116 self.__deviceMenu.addAction( |
109 self.tr("Show Time"), self.__showDeviceTime) |
117 self.tr("Show Time"), self.__showDeviceTime) |
110 self.__deviceMenu.addSeparator() |
118 self.__deviceMenu.addSeparator() |
317 filename = selectedItems[0].text(0).strip() |
325 filename = selectedItems[0].text(0).strip() |
318 if not filename.endswith("/"): |
326 if not filename.endswith("/"): |
319 # it is really a file |
327 # it is really a file |
320 if self.__isFileInList(filename, self.deviceFileTreeWidget): |
328 if self.__isFileInList(filename, self.deviceFileTreeWidget): |
321 # ask for overwrite permission |
329 # ask for overwrite permission |
322 ok = E5MessageBox.yesNo( |
330 # TODO: test this |
323 self, |
331 action, resultFilename = confirmOverwrite( |
324 self.tr("Copy File to Device"), |
332 filename, self.tr("Copy File to Device"), |
325 self.tr("<p>The file <b>{0}</b> exists on the" |
333 self.tr("The given file exists already" |
326 " connected device. Overwrite it?</p>") |
334 " (Enter file name only)."), |
327 .format(filename) |
335 False, self) |
328 ) |
336 if action == "cancel": |
329 if ok: |
337 return |
|
338 elif action == "rename": |
|
339 deviceFilename = os.path.basename(resultFilename) |
|
340 else: |
330 deviceFilename = filename |
341 deviceFilename = filename |
331 else: |
|
332 deviceFilename, ok = QInputDialog.getText( |
|
333 self, |
|
334 self.tr("Copy File to Device"), |
|
335 self.tr("Enter a new name:"), |
|
336 QLineEdit.Normal, |
|
337 filename) |
|
338 if not ok or not bool(deviceFilename): |
|
339 return |
|
340 else: |
342 else: |
341 deviceFilename = filename |
343 deviceFilename = filename |
342 |
344 |
343 self.__fileManager.put( |
345 self.__fileManager.put( |
344 os.path.join(self.localCwd.text(), filename), |
346 os.path.join(self.localCwd.text(), filename), |
355 filename = selectedItems[0].text(0).strip() |
357 filename = selectedItems[0].text(0).strip() |
356 if not filename.endswith("/"): |
358 if not filename.endswith("/"): |
357 # it is really a file |
359 # it is really a file |
358 if self.__isFileInList(filename, self.localFileTreeWidget): |
360 if self.__isFileInList(filename, self.localFileTreeWidget): |
359 # ask for overwrite permission |
361 # ask for overwrite permission |
360 ok = E5MessageBox.yesNo( |
362 # TODO: test this |
361 self, |
363 action, resultFilename = confirmOverwrite( |
362 self.tr("Copy File from Device"), |
364 filename, self.tr("Copy File from Device"), |
363 self.tr("<p>The file <b>{0}</b> exists locally." |
365 self.tr("The given file exists already."), |
364 " Overwrite it?</p>") |
366 True, self) |
365 .format(filename) |
367 if action == "cancel": |
366 ) |
368 return |
367 if ok: |
369 elif action == "rename": |
|
370 localFilename = resultFilename |
|
371 else: |
368 localFilename = filename |
372 localFilename = filename |
369 else: |
|
370 localFilename, ok = QInputDialog.getText( |
|
371 self, |
|
372 self.tr("Copy File from Device"), |
|
373 self.tr("Enter a new name:"), |
|
374 QLineEdit.Normal, |
|
375 filename) |
|
376 if not ok or not bool(localFilename): |
|
377 return |
|
378 else: |
373 else: |
379 localFilename = filename |
374 localFilename = filename |
380 |
375 |
|
376 if not os.path.isabs(localFilename): |
|
377 localFilename = os.path.join(self.localCwd.text(), |
|
378 localFilename) |
381 self.__fileManager.get( |
379 self.__fileManager.get( |
382 os.path.join(self.deviceCwd.text(), filename), |
380 os.path.join(self.deviceCwd.text(), filename), |
383 os.path.join(self.localCwd.text(), localFilename) |
381 localFilename |
384 ) |
382 ) |
385 |
383 |
386 @pyqtSlot(str, str) |
384 @pyqtSlot(str, str) |
387 def __handleGetDone(self, deviceFile, localFile): |
385 def __handleGetDone(self, deviceFile, localFile): |
388 """ |
386 """ |
434 """<ul><li>{0}</li></ul>""").format( |
433 """<ul><li>{0}</li></ul>""").format( |
435 "</li><li>".join(messages) |
434 "</li><li>".join(messages) |
436 ) |
435 ) |
437 ) |
436 ) |
438 |
437 |
|
438 @pyqtSlot(str) |
|
439 def __handleRsyncProgressMessage(self, message): |
|
440 """ |
|
441 Private slot handling progress messages sent by the file manager. |
|
442 """ |
|
443 # TODO: not implemented yet |
|
444 # create and open the info dialog, if it is None |
|
445 # connect to the dialog finished(int) signal to set the memeber variable to None |
|
446 # add messages to dialog |
|
447 |
439 @pyqtSlot() |
448 @pyqtSlot() |
440 def __newDeviceList(self): |
449 def __newDeviceList(self): |
441 """ |
450 """ |
442 Private slot to initiate a new long list of the device directory. |
451 Private slot to initiate a new long list of the device directory. |
443 """ |
452 """ |
460 @pyqtSlot() |
469 @pyqtSlot() |
461 def __changeLocalDirectory(self): |
470 def __changeLocalDirectory(self): |
462 """ |
471 """ |
463 Private slot to change the local directory. |
472 Private slot to change the local directory. |
464 """ |
473 """ |
465 path, ok = E5PathPickerDialog.getPath( |
474 dirPath, ok = E5PathPickerDialog.getPath( |
466 self, |
475 self, |
467 self.tr("Change Directory"), |
476 self.tr("Change Directory"), |
468 self.tr("Select Directory"), |
477 self.tr("Select Directory"), |
469 E5PathPickerModes.DirectoryShowFilesMode, |
478 E5PathPickerModes.DirectoryShowFilesMode, |
470 defaultDirectory=self.localCwd.text(), |
479 defaultDirectory=self.localCwd.text(), |
471 ) |
480 ) |
472 if ok and path: |
481 if ok and dirPath: |
473 self.localCwd.setText(path) |
482 if not os.path.isabs(dirPath): |
474 self.__listLocalFiles(path) |
483 dirPath = os.path.join(self.localCwd.text(), dirPath) |
|
484 self.localCwd.setText(dirPath) |
|
485 self.__listLocalFiles(dirPath) |
475 |
486 |
476 ################################################################## |
487 ################################################################## |
477 ## Context menu methods for the device files below |
488 ## Context menu methods for the device files below |
478 ################################################################## |
489 ################################################################## |
479 |
490 |
508 current directory. |
519 current directory. |
509 """ |
520 """ |
510 dirPath, ok = QInputDialog.getText( |
521 dirPath, ok = QInputDialog.getText( |
511 self, |
522 self, |
512 self.tr("Change Directory"), |
523 self.tr("Change Directory"), |
513 self.tr("Enter the full directory path on the device:"), |
524 self.tr("Enter the directory path on the device:"), |
514 QLineEdit.Normal, |
525 QLineEdit.Normal, |
515 self.deviceCwd.text()) |
526 self.deviceCwd.text()) |
516 if ok and dirPath: |
527 if ok and dirPath: |
|
528 if not dirPath.startswith("/"): |
|
529 dirPath = self.deviceCwd.text() + "/" + dirPath |
517 self.__fileManager.cd(dirPath) |
530 self.__fileManager.cd(dirPath) |
518 |
531 |
|
532 # TODO: test this |
519 @pyqtSlot() |
533 @pyqtSlot() |
520 def __createDeviceDirectory(self): |
534 def __createDeviceDirectory(self): |
521 """ |
535 """ |
522 Private slot to create a directory on the device. |
536 Private slot to create a directory on the device. |
523 """ |
537 """ |
527 self.tr("Enter directory name:"), |
541 self.tr("Enter directory name:"), |
528 QLineEdit.Normal) |
542 QLineEdit.Normal) |
529 if ok and dirPath: |
543 if ok and dirPath: |
530 self.__fileManager.mkdir(dirPath) |
544 self.__fileManager.mkdir(dirPath) |
531 |
545 |
|
546 # TODO: test this |
532 @pyqtSlot() |
547 @pyqtSlot() |
533 def __deleteDeviceDirectory(self): |
548 def __deleteDeviceDirectory(self): |
534 """ |
549 """ |
535 Private slot to delete an empty directory on the device. |
550 Private slot to delete an empty directory on the device. |
536 """ |
551 """ |
537 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
552 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
538 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
553 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
539 dirname = self.deviceCwd.text() + "/" + name[:-1] |
554 dirname = self.deviceCwd.text() + "/" + name[:-1] |
|
555 # TODO: add confirmation |
540 self.__fileManager.rmdir(dirname) |
556 self.__fileManager.rmdir(dirname) |
541 |
557 |
542 @pyqtSlot() |
558 @pyqtSlot() |
543 def __deleteDeviceDirectoryTree(self): |
559 def __deleteDeviceDirectoryTree(self): |
544 """ |
560 """ |
546 recursively. |
562 recursively. |
547 """ |
563 """ |
548 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
564 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
549 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
565 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
550 dirname = self.deviceCwd.text() + "/" + name[:-1] |
566 dirname = self.deviceCwd.text() + "/" + name[:-1] |
|
567 # TODO: add confirmation |
551 self.__fileManager.rmdir(dirname, recursive=True) |
568 self.__fileManager.rmdir(dirname, recursive=True) |
552 |
569 |
553 @pyqtSlot() |
570 @pyqtSlot() |
554 def __deleteDeviceFile(self): |
571 def __deleteDeviceFile(self): |
555 """ |
572 """ |
556 Private slot to delete a file |
573 Private slot to delete a file |
557 """ |
574 """ |
558 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
575 if bool(len(self.deviceFileTreeWidget.selectedItems())): |
559 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
576 name = self.deviceFileTreeWidget.selectedItems()[0].text(0) |
560 filename = self.deviceCwd.text() + "/" + name |
577 filename = self.deviceCwd.text() + "/" + name |
|
578 # TODO: add confirmation |
561 self.__fileManager.delete(filename) |
579 self.__fileManager.delete(filename) |
562 |
580 |
563 @pyqtSlot() |
581 @pyqtSlot() |
564 def __synchronizeTime(self): |
582 def __synchronizeTime(self): |
565 """ |
583 """ |
632 "<h3>Device Version Information</h3>" |
650 "<h3>Device Version Information</h3>" |
633 ) |
651 ) |
634 msg += "<table>" |
652 msg += "<table>" |
635 for key, value in versionInfo.items(): |
653 for key, value in versionInfo.items(): |
636 msg += "<tr><td><b>{0}</b></td><td>{1}</td></tr>".format( |
654 msg += "<tr><td><b>{0}</b></td><td>{1}</td></tr>".format( |
637 key, value) |
655 key.capitalize(), value) |
638 msg += "</table>" |
656 msg += "</table>" |
639 else: |
657 else: |
640 msg = self.tr("No version information available.") |
658 msg = self.tr("No version information available.") |
641 E5MessageBox.information( |
659 E5MessageBox.information( |
642 self, |
660 self, |