|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a dialog to enter the firmware flashing data. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 import os |
|
13 |
|
14 from PyQt5.QtCore import pyqtSlot |
|
15 from PyQt5.QtWidgets import QDialog, QDialogButtonBox |
|
16 |
|
17 from E5Gui.E5PathPicker import E5PathPickerModes |
|
18 from E5Gui import E5MessageBox |
|
19 |
|
20 from .Ui_CircuitPythonFirmwareSelectionDialog import ( |
|
21 Ui_CircuitPythonFirmwareSelectionDialog |
|
22 ) |
|
23 |
|
24 import Utilities |
|
25 import UI.PixmapCache |
|
26 |
|
27 |
|
28 class CircuitPythonFirmwareSelectionDialog( |
|
29 QDialog, Ui_CircuitPythonFirmwareSelectionDialog): |
|
30 """ |
|
31 Class implementing a dialog to enter the firmware flashing data. |
|
32 """ |
|
33 def __init__(self, parent=None): |
|
34 """ |
|
35 Constructor |
|
36 |
|
37 @param parent reference to the parent widget |
|
38 @type QWidget |
|
39 """ |
|
40 super(CircuitPythonFirmwareSelectionDialog, self).__init__(parent) |
|
41 self.setupUi(self) |
|
42 |
|
43 self.retestButton.setIcon(UI.PixmapCache.getIcon("rescan")) |
|
44 |
|
45 self.firmwarePicker.setMode(E5PathPickerModes.OpenFileMode) |
|
46 self.firmwarePicker.setFilters( |
|
47 self.tr("CircuitPython Firmware Files (*.uf2);;" |
|
48 "All Files (*)")) |
|
49 |
|
50 self.bootPicker.setMode(E5PathPickerModes.DirectoryShowFilesMode) |
|
51 |
|
52 boards = ( |
|
53 ("", ""), # indicator for no selection |
|
54 |
|
55 ("Circuit Playground Express", "CPLAYBOOT"), |
|
56 ("Feather M0 Express", "FEATHERBOOT"), |
|
57 ("Feather M4 Express", "FEATHERBOOT"), |
|
58 ("Gemma M0", "GEMMABOOT"), |
|
59 ("Grand Central M4 Express", "GCM4BOOT"), |
|
60 ("ItsyBitsy M0 Express", "ITSYBOOT"), |
|
61 ("ItsyBitsy M4 Express", "ITSYM4BOOT"), |
|
62 ("Metro M0 Express", "METROBOOT"), |
|
63 ("Metro M4 Express", "METROM4BOOT"), |
|
64 ("NeoTrelis M4 Express", "TRELM4BOOT"), |
|
65 ("Trinket M0", "TRINKETBOOT"), |
|
66 |
|
67 ("Manual Select", "<manual>"), |
|
68 ) |
|
69 for boardName, bootVolume in boards: |
|
70 self.boardComboBox.addItem(boardName, bootVolume) |
|
71 |
|
72 msh = self.minimumSizeHint() |
|
73 self.resize(max(self.width(), msh.width()), msh.height()) |
|
74 |
|
75 def __updateOkButton(self): |
|
76 """ |
|
77 Private method to update the state of the OK button and the retest |
|
78 button. |
|
79 """ |
|
80 firmwareFile = self.firmwarePicker.text() |
|
81 self.retestButton.setEnabled(bool(firmwareFile) and |
|
82 os.path.exists(firmwareFile)) |
|
83 |
|
84 if not bool(firmwareFile) or not os.path.exists(firmwareFile): |
|
85 enable = False |
|
86 else: |
|
87 volumeName = self.boardComboBox.currentData() |
|
88 if volumeName and volumeName != "<manual>": |
|
89 # check if the user selected a board and the board is in |
|
90 # bootloader mode |
|
91 deviceDirectory = Utilities.findVolume(volumeName) |
|
92 if deviceDirectory: |
|
93 self.bootPicker.setText(deviceDirectory) |
|
94 enable = True |
|
95 else: |
|
96 enable = False |
|
97 E5MessageBox.warning( |
|
98 self, |
|
99 self.tr("Select Path to Device"), |
|
100 self.tr("""<p>The device volume <b>{0}</b> could not""" |
|
101 """ be found. Is the device in 'bootloader'""" |
|
102 """ mode and mounted?</p> <p>Alternatively""" |
|
103 """ select the Manual Select" entry and""" |
|
104 """ enter the path to the device below.</p>""") |
|
105 .format(volumeName) |
|
106 ) |
|
107 |
|
108 elif volumeName == "<manual>": |
|
109 # select the device path manually |
|
110 deviceDirectory = self.bootPicker.text() |
|
111 enable = (bool(deviceDirectory) and |
|
112 os.path.exists(deviceDirectory)) |
|
113 |
|
114 else: |
|
115 # illegal entry |
|
116 enable = False |
|
117 |
|
118 self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable) |
|
119 |
|
120 @pyqtSlot(str) |
|
121 def on_firmwarePicker_textChanged(self, firmware): |
|
122 """ |
|
123 Private slot handling a change of the firmware path. |
|
124 |
|
125 @param firmware path to the firmware |
|
126 @type str |
|
127 """ |
|
128 self.__updateOkButton() |
|
129 |
|
130 @pyqtSlot(int) |
|
131 def on_boardComboBox_currentIndexChanged(self, index): |
|
132 """ |
|
133 Private slot to handle the selection of a board type. |
|
134 |
|
135 @param index index of the selected board type |
|
136 @type int |
|
137 """ |
|
138 if self.boardComboBox.itemData(index) == "<manual>": |
|
139 self.bootPicker.clear() |
|
140 self.bootPicker.setEnabled(True) |
|
141 else: |
|
142 self.bootPicker.setEnabled(False) |
|
143 |
|
144 self.__updateOkButton() |
|
145 |
|
146 @pyqtSlot() |
|
147 def on_retestButton_clicked(self): |
|
148 """ |
|
149 Private slot to research for the selected volume. |
|
150 """ |
|
151 self.__updateOkButton() |
|
152 |
|
153 @pyqtSlot(str) |
|
154 def on_bootPicker_textChanged(self, devicePath): |
|
155 """ |
|
156 Private slot handling a change of the device path. |
|
157 |
|
158 @param devicePath path to the device |
|
159 @type str |
|
160 """ |
|
161 self.__updateOkButton() |
|
162 |
|
163 def getData(self): |
|
164 """ |
|
165 Public method to obtain the entered data. |
|
166 |
|
167 @return tuple containing the path to the CircuitPython firmware file |
|
168 and the path to the device |
|
169 @rtype tuple of (str, str) |
|
170 """ |
|
171 return self.firmwarePicker.text(), self.bootPicker.text() |