diff options
author | Dongxiao Xu <dongxiao.xu@intel.com> | 2011-11-28 14:32:40 +0800 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2012-02-24 18:04:27 +0000 |
commit | 656f9a07588cc00704825a78de9649ca4a1552b8 (patch) | |
tree | 653c7941689599994d5876162c540fb7ee22736e /bitbake/lib/bb/ui/crumbs/hig.py | |
parent | 14df6d53b6856ec78322b9c0ef01e26c0406fe28 (diff) | |
download | poky-656f9a07588cc00704825a78de9649ca4a1552b8.tar.gz |
Hob: A new implemetation (v2)
This commit implements a new design for hob
Some of the new features:
- Friendly new designed GUI. Quick response to user actions.
- Two step builds support package generation and image generation.
- Support running GUI seprarately from bitbake server.
- Recipe/package selection and deselection.
- Accurate customization for image contents and size.
- Progress bars showing the parsing and build status.
- Load/save user configurations from/into templates.
(Bitbake rev: 4dacd29f9c957d20f4583330b51e5420f9c3338d)
Signed-off-by: Dongxiao Xu <dongxiao.xu@intel.com>
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Liming An <limingx.l.an@intel.com>
Signed-off-by: Fengxia Hua <fengxia.hua@intel.com>
Designed-by: Belen Barros Pena <belen.barros.pena@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/hig.py')
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig.py | 589 |
1 files changed, 586 insertions, 3 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/hig.py b/bitbake/lib/bb/ui/crumbs/hig.py index b3b3c7a72e..89dfe03608 100644 --- a/bitbake/lib/bb/ui/crumbs/hig.py +++ b/bitbake/lib/bb/ui/crumbs/hig.py | |||
@@ -1,9 +1,11 @@ | |||
1 | # | 1 | # |
2 | # BitBake Graphical GTK User Interface | 2 | # BitBake Graphical GTK User Interface |
3 | # | 3 | # |
4 | # Copyright (C) 2011 Intel Corporation | 4 | # Copyright (C) 2011-2012 Intel Corporation |
5 | # | 5 | # |
6 | # Authored by Joshua Lock <josh@linux.intel.com> | 6 | # Authored by Joshua Lock <josh@linux.intel.com> |
7 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | ||
8 | # Authored by Shane Wang <shane.wang@intel.com> | ||
7 | # | 9 | # |
8 | # This program is free software; you can redistribute it and/or modify | 10 | # This program is free software; you can redistribute it and/or modify |
9 | # it under the terms of the GNU General Public License version 2 as | 11 | # it under the terms of the GNU General Public License version 2 as |
@@ -18,21 +20,33 @@ | |||
18 | # with this program; if not, write to the Free Software Foundation, Inc., | 20 | # with this program; if not, write to the Free Software Foundation, Inc., |
19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
20 | 22 | ||
21 | import gobject | ||
22 | import gtk | 23 | import gtk |
24 | import gobject | ||
25 | import hashlib | ||
26 | import os | ||
27 | import re | ||
28 | import subprocess | ||
29 | import shlex | ||
30 | from bb.ui.crumbs.hobcolor import HobColors | ||
31 | from bb.ui.crumbs.hobwidget import HobWidget | ||
32 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
33 | |||
23 | """ | 34 | """ |
24 | The following are convenience classes for implementing GNOME HIG compliant | 35 | The following are convenience classes for implementing GNOME HIG compliant |
25 | BitBake GUI's | 36 | BitBake GUI's |
26 | In summary: spacing = 12px, border-width = 6px | 37 | In summary: spacing = 12px, border-width = 6px |
27 | """ | 38 | """ |
28 | 39 | ||
40 | # | ||
41 | # CrumbsDialog | ||
42 | # | ||
29 | class CrumbsDialog(gtk.Dialog): | 43 | class CrumbsDialog(gtk.Dialog): |
30 | """ | 44 | """ |
31 | A GNOME HIG compliant dialog widget. | 45 | A GNOME HIG compliant dialog widget. |
32 | Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons | 46 | Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons |
33 | """ | 47 | """ |
34 | def __init__(self, parent=None, label="", icon=gtk.STOCK_INFO): | 48 | def __init__(self, parent=None, label="", icon=gtk.STOCK_INFO): |
35 | gtk.Dialog.__init__(self, "", parent, gtk.DIALOG_DESTROY_WITH_PARENT) | 49 | super(CrumbsDialog, self).__init__("", parent, gtk.DIALOG_DESTROY_WITH_PARENT) |
36 | 50 | ||
37 | #self.set_property("has-separator", False) # note: deprecated in 2.22 | 51 | #self.set_property("has-separator", False) # note: deprecated in 2.22 |
38 | 52 | ||
@@ -59,3 +73,572 @@ class CrumbsDialog(gtk.Dialog): | |||
59 | self.label.set_property("yalign", 0.00) | 73 | self.label.set_property("yalign", 0.00) |
60 | self.label.show() | 74 | self.label.show() |
61 | first_row.add(self.label) | 75 | first_row.add(self.label) |
76 | |||
77 | # | ||
78 | # Brought-in-by Dialog | ||
79 | # | ||
80 | class BinbDialog(gtk.Dialog): | ||
81 | """ | ||
82 | A dialog widget to show "brought in by" info when a recipe/package is clicked. | ||
83 | """ | ||
84 | |||
85 | def __init__(self, title, content, parent=None): | ||
86 | super(BinbDialog, self).__init__(title, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, None) | ||
87 | |||
88 | self.set_position(gtk.WIN_POS_MOUSE) | ||
89 | self.set_resizable(False) | ||
90 | self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(HobColors.DARK)) | ||
91 | |||
92 | hbox = gtk.HBox(False, 0) | ||
93 | self.vbox.pack_start(hbox, expand=False, fill=False, padding=10) | ||
94 | |||
95 | label = gtk.Label(content) | ||
96 | label.set_alignment(0, 0) | ||
97 | label.set_line_wrap(True) | ||
98 | label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.Color(HobColors.WHITE)) | ||
99 | |||
100 | hbox.pack_start(label, expand=False, fill=False, padding=10) | ||
101 | self.vbox.show_all() | ||
102 | |||
103 | # | ||
104 | # AdvancedSettings Dialog | ||
105 | # | ||
106 | class AdvancedSettingDialog (gtk.Dialog): | ||
107 | |||
108 | def __init__(self, title, configuration, all_image_types, | ||
109 | all_package_formats, all_distros, all_sdk_machines, | ||
110 | max_threads, split_model, parent, flags, buttons): | ||
111 | super(AdvancedSettingDialog, self).__init__(title, parent, flags, buttons) | ||
112 | |||
113 | # class members from other objects | ||
114 | # bitbake settings from Builder.Configuration | ||
115 | self.configuration = configuration | ||
116 | self.image_types = all_image_types | ||
117 | self.all_package_formats = all_package_formats | ||
118 | self.all_distros = all_distros | ||
119 | self.all_sdk_machines = all_sdk_machines | ||
120 | self.max_threads = max_threads | ||
121 | self.split_model = split_model | ||
122 | |||
123 | # class members for internal use | ||
124 | self.pkgfmt_store = None | ||
125 | self.distro_combo = None | ||
126 | self.dldir_text = None | ||
127 | self.sstatedir_text = None | ||
128 | self.sstatemirror_text = None | ||
129 | self.bb_spinner = None | ||
130 | self.pmake_spinner = None | ||
131 | self.rootfs_size_spinner = None | ||
132 | self.extra_size_spinner = None | ||
133 | self.gplv3_checkbox = None | ||
134 | self.toolchain_checkbox = None | ||
135 | self.setting_store = None | ||
136 | self.image_types_checkbuttons = {} | ||
137 | |||
138 | self.variables = {} | ||
139 | self.variables["PACKAGE_FORMAT"] = self.configuration.curr_package_format | ||
140 | self.variables["INCOMPATIBLE_LICENSE"] = self.configuration.incompat_license | ||
141 | self.variables["IMAGE_FSTYPES"] = self.configuration.image_fstypes | ||
142 | self.md5 = hashlib.md5(str(sorted(self.variables.items()))).hexdigest() | ||
143 | self.settings_changed = False | ||
144 | |||
145 | # create visual elements on the dialog | ||
146 | self.create_visual_elements() | ||
147 | self.connect("response", self.response_cb) | ||
148 | |||
149 | def create_visual_elements(self): | ||
150 | self.set_size_request(500, 500) | ||
151 | |||
152 | self.nb = gtk.Notebook() | ||
153 | self.nb.set_show_tabs(True) | ||
154 | self.nb.append_page(self.create_image_types_page(), gtk.Label("Image types")) | ||
155 | self.nb.append_page(self.create_output_page(), gtk.Label("Output")) | ||
156 | self.nb.append_page(self.create_build_environment_page(), gtk.Label("Build environment")) | ||
157 | self.nb.append_page(self.create_others_page(), gtk.Label("Others")) | ||
158 | self.nb.set_current_page(0) | ||
159 | self.vbox.pack_start(self.nb, expand=True, fill=True) | ||
160 | self.vbox.pack_end(gtk.HSeparator(), expand=True, fill=True) | ||
161 | |||
162 | self.show_all() | ||
163 | |||
164 | def create_image_types_page(self): | ||
165 | advanced_vbox = gtk.VBox(False, 15) | ||
166 | advanced_vbox.set_border_width(20) | ||
167 | |||
168 | rows = (len(self.image_types)+1)/2 | ||
169 | table = gtk.Table(rows + 1, 10, True) | ||
170 | advanced_vbox.pack_start(table, expand=False, fill=False) | ||
171 | |||
172 | tooltip = "Select image file system types that will be used." | ||
173 | image = gtk.Image() | ||
174 | image.show() | ||
175 | image.set_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON) | ||
176 | image.set_tooltip_text(tooltip) | ||
177 | label = HobWidget.gen_label_widget("<span weight=\"bold\">Select image types:</span>") | ||
178 | table.attach(label, 0, 9, 0, 1) | ||
179 | table.attach(image, 9, 10, 0, 1) | ||
180 | |||
181 | i = 1 | ||
182 | j = 1 | ||
183 | for image_type in self.image_types: | ||
184 | self.image_types_checkbuttons[image_type] = gtk.CheckButton(image_type) | ||
185 | self.image_types_checkbuttons[image_type].set_tooltip_text("Build an %s image" % image_type) | ||
186 | table.attach(self.image_types_checkbuttons[image_type], j, j + 4, i, i + 1) | ||
187 | if image_type in self.configuration.image_fstypes: | ||
188 | self.image_types_checkbuttons[image_type].set_active(True) | ||
189 | i += 1 | ||
190 | if i > rows: | ||
191 | i = 1 | ||
192 | j = j + 4 | ||
193 | |||
194 | return advanced_vbox | ||
195 | |||
196 | def create_output_page(self): | ||
197 | advanced_vbox = gtk.VBox(False, 15) | ||
198 | advanced_vbox.set_border_width(20) | ||
199 | |||
200 | sub_vbox = gtk.VBox(False, 5) | ||
201 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
202 | label = HobWidget.gen_label_widget("<span weight=\"bold\">Packaging Format:</span>") | ||
203 | tooltip = "Select package formats that will be used. " | ||
204 | tooltip += "The first format will be used for final image" | ||
205 | pkgfmt_widget, self.pkgfmt_store = HobWidget.gen_pkgfmt_widget(self.configuration.curr_package_format, self.all_package_formats, tooltip) | ||
206 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
207 | sub_vbox.pack_start(pkgfmt_widget, expand=False, fill=False) | ||
208 | |||
209 | sub_vbox = gtk.VBox(False, 5) | ||
210 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
211 | label = HobWidget.gen_label_widget("<span weight=\"bold\">Image Rootfs Size: (MB)</span>") | ||
212 | tooltip = "Sets the size of your target image.\nThis is the basic size of your target image, unless your selected package size exceeds this value, or you set value to \"Image Extra Size\"." | ||
213 | rootfs_size_widget, self.rootfs_size_spinner = HobWidget.gen_spinner_widget(int(self.configuration.image_rootfs_size*1.0/1024), 0, 1024, tooltip) | ||
214 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
215 | sub_vbox.pack_start(rootfs_size_widget, expand=False, fill=False) | ||
216 | |||
217 | sub_vbox = gtk.VBox(False, 5) | ||
218 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
219 | label = HobWidget.gen_label_widget("<span weight=\"bold\">Image Extra Size: (MB)</span>") | ||
220 | tooltip = "Sets the extra free space of your target image.\nDefaultly, system will reserve 30% of your image size as your free space. If your image contains zypper, it will bring in 50MB more space. The maximum free space is 1024MB." | ||
221 | extra_size_widget, self.extra_size_spinner = HobWidget.gen_spinner_widget(int(self.configuration.image_extra_size*1.0/1024), 0, 1024, tooltip) | ||
222 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
223 | sub_vbox.pack_start(extra_size_widget, expand=False, fill=False) | ||
224 | |||
225 | self.gplv3_checkbox = gtk.CheckButton("Exclude GPLv3 packages") | ||
226 | self.gplv3_checkbox.set_tooltip_text("Check this box to prevent GPLv3 packages from being included in your image") | ||
227 | if "GPLv3" in self.configuration.incompat_license.split(): | ||
228 | self.gplv3_checkbox.set_active(True) | ||
229 | else: | ||
230 | self.gplv3_checkbox.set_active(False) | ||
231 | advanced_vbox.pack_start(self.gplv3_checkbox, expand=False, fill=False) | ||
232 | |||
233 | sub_hbox = gtk.HBox(False, 5) | ||
234 | advanced_vbox.pack_start(sub_hbox, expand=False, fill=False) | ||
235 | self.toolchain_checkbox = gtk.CheckButton("Build Toolchain") | ||
236 | self.toolchain_checkbox.set_tooltip_text("Check this box to build the related toolchain with your image") | ||
237 | self.toolchain_checkbox.set_active(self.configuration.toolchain_build) | ||
238 | sub_hbox.pack_start(self.toolchain_checkbox, expand=False, fill=False) | ||
239 | |||
240 | tooltip = "This is the Host platform you would like to run the toolchain" | ||
241 | sdk_machine_widget, self.sdk_machine_combo = HobWidget.gen_combo_widget(self.configuration.curr_sdk_machine, self.all_sdk_machines, tooltip) | ||
242 | sub_hbox.pack_start(sdk_machine_widget, expand=False, fill=False) | ||
243 | |||
244 | return advanced_vbox | ||
245 | |||
246 | def create_build_environment_page(self): | ||
247 | advanced_vbox = gtk.VBox(False, 15) | ||
248 | advanced_vbox.set_border_width(20) | ||
249 | |||
250 | sub_vbox = gtk.VBox(False, 5) | ||
251 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
252 | label = HobWidget.gen_label_widget("<span weight=\"bold\">Select Distro:</span>") | ||
253 | tooltip = "This is the Yocto distribution you would like to use" | ||
254 | distro_widget, self.distro_combo = HobWidget.gen_combo_widget(self.configuration.curr_distro, self.all_distros, tooltip) | ||
255 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
256 | sub_vbox.pack_start(distro_widget, expand=False, fill=False) | ||
257 | |||
258 | sub_vbox = gtk.VBox(False, 5) | ||
259 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
260 | label = HobWidget.gen_label_widget("<span weight=\"bold\">BB_NUMBER_THREADS:</span>") | ||
261 | tooltip = "Sets the number of threads that bitbake tasks can run simultaneously" | ||
262 | bbthread_widget, self.bb_spinner = HobWidget.gen_spinner_widget(self.configuration.bbthread, 1, self.max_threads, tooltip) | ||
263 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
264 | sub_vbox.pack_start(bbthread_widget, expand=False, fill=False) | ||
265 | |||
266 | sub_vbox = gtk.VBox(False, 5) | ||
267 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
268 | label = HobWidget.gen_label_widget("<span weight=\"bold\">PARALLEL_MAKE:</span>") | ||
269 | tooltip = "Sets the make parallism, as known as 'make -j'" | ||
270 | pmake_widget, self.pmake_spinner = HobWidget.gen_spinner_widget(self.configuration.pmake, 1, self.max_threads, tooltip) | ||
271 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
272 | sub_vbox.pack_start(pmake_widget, expand=False, fill=False) | ||
273 | |||
274 | sub_vbox = gtk.VBox(False, 5) | ||
275 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
276 | label = HobWidget.gen_label_widget("<span weight=\"bold\">Set Download Directory:</span>") | ||
277 | tooltip = "Select a folder that caches the upstream project source code" | ||
278 | dldir_widget, self.dldir_text = HobWidget.gen_entry_widget(self.split_model, self.configuration.dldir, self, tooltip) | ||
279 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
280 | sub_vbox.pack_start(dldir_widget, expand=False, fill=False) | ||
281 | |||
282 | sub_vbox = gtk.VBox(False, 5) | ||
283 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
284 | label = HobWidget.gen_label_widget("<span weight=\"bold\">Select SSTATE Directory:</span>") | ||
285 | tooltip = "Select a folder that caches your prebuilt results" | ||
286 | sstatedir_widget, self.sstatedir_text = HobWidget.gen_entry_widget(self.split_model, self.configuration.sstatedir, self, tooltip) | ||
287 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
288 | sub_vbox.pack_start(sstatedir_widget, expand=False, fill=False) | ||
289 | |||
290 | sub_vbox = gtk.VBox(False, 5) | ||
291 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
292 | label = HobWidget.gen_label_widget("<span weight=\"bold\">Select SSTATE Mirror:</span>") | ||
293 | tooltip = "Select the prebuilt mirror that will fasten your build speed" | ||
294 | sstatemirror_widget, self.sstatemirror_text = HobWidget.gen_entry_widget(self.split_model, self.configuration.sstatemirror, self, tooltip) | ||
295 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
296 | sub_vbox.pack_start(sstatemirror_widget, expand=False, fill=False) | ||
297 | |||
298 | return advanced_vbox | ||
299 | |||
300 | def create_others_page(self): | ||
301 | advanced_vbox = gtk.VBox(False, 15) | ||
302 | advanced_vbox.set_border_width(20) | ||
303 | |||
304 | sub_vbox = gtk.VBox(False, 5) | ||
305 | advanced_vbox.pack_start(sub_vbox, expand=True, fill=True) | ||
306 | label = HobWidget.gen_label_widget("<span weight=\"bold\">Add your own variables:</span>") | ||
307 | tooltip = "This is the key/value pair for your extra settings" | ||
308 | setting_widget, self.setting_store = HobWidget.gen_editable_settings(self.configuration.extra_setting, tooltip) | ||
309 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
310 | sub_vbox.pack_start(setting_widget, expand=True, fill=True) | ||
311 | |||
312 | return advanced_vbox | ||
313 | |||
314 | def response_cb(self, dialog, response_id): | ||
315 | self.variables = {} | ||
316 | |||
317 | self.configuration.curr_package_format = "" | ||
318 | it = self.pkgfmt_store.get_iter_first() | ||
319 | while it: | ||
320 | value = self.pkgfmt_store.get_value(it, 2) | ||
321 | if value: | ||
322 | self.configuration.curr_package_format += (self.pkgfmt_store.get_value(it, 1) + " ") | ||
323 | it = self.pkgfmt_store.iter_next(it) | ||
324 | self.configuration.curr_package_format = self.configuration.curr_package_format.strip() | ||
325 | self.variables["PACKAGE_FORMAT"] = self.configuration.curr_package_format | ||
326 | |||
327 | self.configuration.curr_distro = self.distro_combo.get_active_text() | ||
328 | self.configuration.dldir = self.dldir_text.get_text() | ||
329 | self.configuration.sstatedir = self.sstatedir_text.get_text() | ||
330 | self.configuration.sstatemirror = self.sstatemirror_text.get_text() | ||
331 | self.configuration.bbthread = self.bb_spinner.get_value_as_int() | ||
332 | self.configuration.pmake = self.pmake_spinner.get_value_as_int() | ||
333 | self.configuration.image_rootfs_size = self.rootfs_size_spinner.get_value_as_int() * 1024 | ||
334 | self.configuration.image_extra_size = self.extra_size_spinner.get_value_as_int() * 1024 | ||
335 | |||
336 | self.configuration.image_fstypes = [] | ||
337 | for image_type in self.image_types: | ||
338 | if self.image_types_checkbuttons[image_type].get_active(): | ||
339 | self.configuration.image_fstypes.append(image_type) | ||
340 | self.variables["IMAGE_FSTYPES"] = self.configuration.image_fstypes | ||
341 | |||
342 | if self.gplv3_checkbox.get_active(): | ||
343 | if "GPLv3" not in self.configuration.incompat_license.split(): | ||
344 | self.configuration.incompat_license += " GPLv3" | ||
345 | else: | ||
346 | if "GPLv3" in self.configuration.incompat_license.split(): | ||
347 | self.configuration.incompat_license = self.configuration.incompat_license.split().remove("GPLv3") | ||
348 | self.configuration.incompat_license = " ".join(self.configuration.incompat_license or []) | ||
349 | self.configuration.incompat_license = self.configuration.incompat_license.strip() | ||
350 | self.variables["INCOMPATIBLE_LICENSE"] = self.configuration.incompat_license | ||
351 | |||
352 | self.configuration.toolchain_build = self.toolchain_checkbox.get_active() | ||
353 | |||
354 | self.configuration.extra_setting = {} | ||
355 | it = self.setting_store.get_iter_first() | ||
356 | while it: | ||
357 | key = self.setting_store.get_value(it, 0) | ||
358 | value = self.setting_store.get_value(it, 1) | ||
359 | self.configuration.extra_setting[key] = value | ||
360 | self.variables[key] = value | ||
361 | it = self.setting_store.iter_next(it) | ||
362 | |||
363 | md5 = hashlib.md5(str(sorted(self.variables.items()))).hexdigest() | ||
364 | self.settings_changed = (self.md5 != md5) | ||
365 | |||
366 | # | ||
367 | # DeployImageDialog | ||
368 | # | ||
369 | class DeployImageDialog (gtk.Dialog): | ||
370 | |||
371 | __dummy_usb__ = "--select a usb drive--" | ||
372 | |||
373 | def __init__(self, title, image_path, parent, flags, buttons): | ||
374 | super(DeployImageDialog, self).__init__(title, parent, flags, buttons) | ||
375 | |||
376 | self.image_path = image_path | ||
377 | |||
378 | self.create_visual_elements() | ||
379 | self.connect("response", self.response_cb) | ||
380 | |||
381 | def create_visual_elements(self): | ||
382 | self.set_border_width(20) | ||
383 | self.set_default_size(500, 250) | ||
384 | |||
385 | label = gtk.Label() | ||
386 | label.set_alignment(0.0, 0.5) | ||
387 | markup = "<span font_desc='12'>The image to be written into usb drive:</span>" | ||
388 | label.set_markup(markup) | ||
389 | self.vbox.pack_start(label, expand=False, fill=False, padding=2) | ||
390 | |||
391 | scroll = gtk.ScrolledWindow() | ||
392 | scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) | ||
393 | scroll.set_shadow_type(gtk.SHADOW_IN) | ||
394 | tv = gtk.TextView() | ||
395 | tv.set_editable(False) | ||
396 | tv.set_wrap_mode(gtk.WRAP_WORD) | ||
397 | tv.set_cursor_visible(False) | ||
398 | buf = gtk.TextBuffer() | ||
399 | buf.set_text(self.image_path) | ||
400 | tv.set_buffer(buf) | ||
401 | scroll.add(tv) | ||
402 | self.vbox.pack_start(scroll, expand=True, fill=True) | ||
403 | |||
404 | self.usb_desc = gtk.Label() | ||
405 | self.usb_desc.set_alignment(0.0, 0.5) | ||
406 | markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>" | ||
407 | self.usb_desc.set_markup(markup) | ||
408 | |||
409 | self.usb_combo = gtk.combo_box_new_text() | ||
410 | self.usb_combo.connect("changed", self.usb_combo_changed_cb) | ||
411 | model = self.usb_combo.get_model() | ||
412 | model.clear() | ||
413 | self.usb_combo.append_text(self.__dummy_usb__) | ||
414 | for usb in self.find_all_usb_devices(): | ||
415 | self.usb_combo.append_text("/dev/" + usb) | ||
416 | self.usb_combo.set_active(0) | ||
417 | self.vbox.pack_start(self.usb_combo, expand=True, fill=True) | ||
418 | self.vbox.pack_start(self.usb_desc, expand=False, fill=False, padding=2) | ||
419 | |||
420 | self.progress_bar = HobProgressBar() | ||
421 | self.vbox.pack_start(self.progress_bar, expand=False, fill=False) | ||
422 | separator = gtk.HSeparator() | ||
423 | self.vbox.pack_start(separator, expand=False, fill=True, padding=10) | ||
424 | |||
425 | self.vbox.show_all() | ||
426 | self.progress_bar.hide() | ||
427 | |||
428 | def popen_read(self, cmd): | ||
429 | return os.popen("%s 2>/dev/null" % cmd).read().strip() | ||
430 | |||
431 | def find_all_usb_devices(self): | ||
432 | usb_devs = [ os.readlink(u) | ||
433 | for u in self.popen_read('ls /dev/disk/by-id/usb*').split() | ||
434 | if not re.search(r'part\d+', u) ] | ||
435 | return [ '%s' % u[u.rfind('/')+1:] for u in usb_devs ] | ||
436 | |||
437 | def get_usb_info(self, dev): | ||
438 | return "%s %s" % \ | ||
439 | (self.popen_read('cat /sys/class/block/%s/device/vendor' % dev), | ||
440 | self.popen_read('cat /sys/class/block/%s/device/model' % dev)) | ||
441 | |||
442 | def usb_combo_changed_cb(self, usb_combo): | ||
443 | combo_item = self.usb_combo.get_active_text() | ||
444 | if not combo_item or combo_item == self.__dummy_usb__: | ||
445 | markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>" | ||
446 | self.usb_desc.set_markup(markup) | ||
447 | else: | ||
448 | markup = "<span font_desc='12'>" + self.get_usb_info(combo_item.lstrip("/dev/")) + "</span>" | ||
449 | self.usb_desc.set_markup(markup) | ||
450 | |||
451 | def response_cb(self, dialog, response_id): | ||
452 | if response_id == gtk.RESPONSE_YES: | ||
453 | combo_item = self.usb_combo.get_active_text() | ||
454 | if combo_item and combo_item != self.__dummy_usb__: | ||
455 | cmdline = "/usr/bin/xterm -e " | ||
456 | cmdline += "\"sudo dd if=" + self.image_path + " of=" + combo_item + "; bash\"" | ||
457 | subprocess.Popen(args=shlex.split(cmdline)) | ||
458 | |||
459 | def update_progress_bar(self, title, fraction, status=True): | ||
460 | self.progress_bar.update(fraction) | ||
461 | self.progress_bar.set_title(title) | ||
462 | self.progress_bar.set_rcstyle(status) | ||
463 | |||
464 | def write_file(self, ifile, ofile): | ||
465 | self.progress_bar.reset() | ||
466 | self.progress_bar.show() | ||
467 | |||
468 | f_from = os.open(ifile, os.O_RDONLY) | ||
469 | f_to = os.open(ofile, os.O_WRONLY) | ||
470 | |||
471 | total_size = os.stat(ifile).st_size | ||
472 | written_size = 0 | ||
473 | |||
474 | while True: | ||
475 | buf = os.read(f_from, 1024*1024) | ||
476 | if not buf: | ||
477 | break | ||
478 | os.write(f_to, buf) | ||
479 | written_size += 1024*1024 | ||
480 | self.update_progress_bar("Writing to usb:", written_size * 1.0/total_size) | ||
481 | |||
482 | self.update_progress_bar("Writing completed:", 1.0) | ||
483 | os.close(f_from) | ||
484 | os.close(f_to) | ||
485 | self.progress_bar.hide() | ||
486 | # | ||
487 | # LayerSelectionDialog | ||
488 | # | ||
489 | class LayerSelectionDialog (gtk.Dialog): | ||
490 | |||
491 | def __init__(self, title, layers, all_layers, split_model, | ||
492 | parent, flags, buttons): | ||
493 | super(LayerSelectionDialog, self).__init__(title, parent, flags, buttons) | ||
494 | |||
495 | # class members from other objects | ||
496 | self.layers = layers | ||
497 | self.all_layers = all_layers | ||
498 | self.split_model = split_model | ||
499 | self.layers_changed = False | ||
500 | |||
501 | # class members for internal use | ||
502 | self.layer_store = None | ||
503 | |||
504 | # create visual elements on the dialog | ||
505 | self.create_visual_elements() | ||
506 | self.connect("response", self.response_cb) | ||
507 | |||
508 | def create_visual_elements(self): | ||
509 | self.set_border_width(20) | ||
510 | self.set_default_size(400, 250) | ||
511 | |||
512 | hbox_top = gtk.HBox() | ||
513 | self.set_border_width(12) | ||
514 | self.vbox.pack_start(hbox_top, expand=False, fill=False) | ||
515 | |||
516 | if self.split_model: | ||
517 | label = HobWidget.gen_label_widget("<span weight=\"bold\" font_desc='12'>Select Layers:</span>\n(Available layers under '${COREBASE}/layers/' directory)") | ||
518 | else: | ||
519 | label = HobWidget.gen_label_widget("<span weight=\"bold\" font_desc='12'>Select Layers:</span>") | ||
520 | hbox_top.pack_start(label, expand=False, fill=False) | ||
521 | |||
522 | tooltip = "Layer is a collection of bb files and conf files" | ||
523 | image = gtk.Image() | ||
524 | image.set_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON) | ||
525 | image.set_tooltip_text(tooltip) | ||
526 | hbox_top.pack_end(image, expand=False, fill=False) | ||
527 | |||
528 | layer_widget, self.layer_store = HobWidget.gen_layer_widget(self.split_model, self.layers, self.all_layers, self, None) | ||
529 | |||
530 | self.vbox.pack_start(layer_widget, expand=True, fill=True) | ||
531 | |||
532 | separator = gtk.HSeparator() | ||
533 | self.vbox.pack_start(separator, False, True, 5) | ||
534 | separator.show() | ||
535 | |||
536 | hbox_button = gtk.HBox() | ||
537 | self.vbox.pack_end(hbox_button, expand=False, fill=False) | ||
538 | hbox_button.show() | ||
539 | |||
540 | label = HobWidget.gen_label_widget("<i>'meta' is Core layer for Yocto images</i>\n" | ||
541 | "<span weight=\"bold\">Please do not remove it</span>") | ||
542 | hbox_button.pack_start(label, expand=False, fill=False) | ||
543 | |||
544 | self.show_all() | ||
545 | |||
546 | def response_cb(self, dialog, response_id): | ||
547 | model = self.layer_store | ||
548 | it = model.get_iter_first() | ||
549 | layers = [] | ||
550 | while it: | ||
551 | if self.split_model: | ||
552 | inc = model.get_value(it, 1) | ||
553 | if inc: | ||
554 | layers.append(model.get_value(it, 0)) | ||
555 | else: | ||
556 | layers.append(model.get_value(it, 0)) | ||
557 | it = model.iter_next(it) | ||
558 | |||
559 | self.layers_changed = (self.layers != layers) | ||
560 | self.layers = layers | ||
561 | |||
562 | class ImageSelectionDialog (gtk.Dialog): | ||
563 | |||
564 | def __init__(self, image_folder, image_types, title, parent, flags, buttons): | ||
565 | super(ImageSelectionDialog, self).__init__(title, parent, flags, buttons) | ||
566 | self.connect("response", self.response_cb) | ||
567 | |||
568 | self.image_folder = image_folder | ||
569 | self.image_types = image_types | ||
570 | self.image_names = [] | ||
571 | |||
572 | # create visual elements on the dialog | ||
573 | self.create_visual_elements() | ||
574 | |||
575 | self.image_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN) | ||
576 | self.fill_image_store() | ||
577 | |||
578 | def create_visual_elements(self): | ||
579 | self.set_border_width(20) | ||
580 | self.set_default_size(600, 300) | ||
581 | self.vbox.set_spacing(10) | ||
582 | |||
583 | hbox = gtk.HBox(False, 10) | ||
584 | self.vbox.pack_start(hbox, expand=False, fill=False) | ||
585 | |||
586 | entry = gtk.Entry() | ||
587 | entry.set_text(self.image_folder) | ||
588 | table = gtk.Table(1, 10, True) | ||
589 | table.set_size_request(560, -1) | ||
590 | hbox.pack_start(table, expand=False, fill=False) | ||
591 | table.attach(entry, 0, 9, 0, 1) | ||
592 | image = gtk.Image() | ||
593 | image.set_from_stock(gtk.STOCK_OPEN,gtk.ICON_SIZE_BUTTON) | ||
594 | open_button = gtk.Button() | ||
595 | open_button.set_image(image) | ||
596 | open_button.connect("clicked", self.select_path_cb, self, entry) | ||
597 | table.attach(open_button, 9, 10, 0, 1) | ||
598 | |||
599 | imgtv_widget, self.imgsel_tv = HobWidget.gen_imgtv_widget(400, 160) | ||
600 | self.vbox.pack_start(imgtv_widget, expand=True, fill=True) | ||
601 | |||
602 | self.show_all() | ||
603 | |||
604 | def select_path_cb(self, action, parent, entry): | ||
605 | dialog = gtk.FileChooserDialog("", parent, | ||
606 | gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, | ||
607 | (gtk.STOCK_OK, gtk.RESPONSE_YES, | ||
608 | gtk.STOCK_CANCEL, gtk.RESPONSE_NO)) | ||
609 | response = dialog.run() | ||
610 | if response == gtk.RESPONSE_YES: | ||
611 | path = dialog.get_filename() | ||
612 | entry.set_text(path) | ||
613 | self.image_folder = path | ||
614 | self.fill_image_store() | ||
615 | |||
616 | dialog.destroy() | ||
617 | |||
618 | def fill_image_store(self): | ||
619 | self.image_store.clear() | ||
620 | imageset = set() | ||
621 | for root, dirs, files in os.walk(self.image_folder): | ||
622 | for f in files: | ||
623 | for image_type in self.image_types: | ||
624 | if f.endswith('.' + image_type): | ||
625 | imageset.add(f.rsplit('.' + image_type)[0]) | ||
626 | |||
627 | for image in imageset: | ||
628 | self.image_store.set(self.image_store.append(), 0, image, 1, False) | ||
629 | |||
630 | self.imgsel_tv.set_model(self.image_store) | ||
631 | |||
632 | def response_cb(self, dialog, response_id): | ||
633 | self.image_names = [] | ||
634 | if response_id == gtk.RESPONSE_YES: | ||
635 | iter = self.image_store.get_iter_first() | ||
636 | while iter: | ||
637 | path = self.image_store.get_path(iter) | ||
638 | if self.image_store[path][1]: | ||
639 | for root, dirs, files in os.walk(self.image_folder): | ||
640 | for f in files: | ||
641 | if f.startswith(self.image_store[path][0] + '.'): | ||
642 | self.image_names.append(f) | ||
643 | break | ||
644 | iter = self.image_store.iter_next(iter) | ||