From 656f9a07588cc00704825a78de9649ca4a1552b8 Mon Sep 17 00:00:00 2001 From: Dongxiao Xu Date: Mon, 28 Nov 2011 14:32:40 +0800 Subject: 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 Signed-off-by: Shane Wang Signed-off-by: Liming An Signed-off-by: Fengxia Hua Designed-by: Belen Barros Pena Signed-off-by: Richard Purdie --- bitbake/lib/bb/ui/crumbs/hig.py | 589 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 586 insertions(+), 3 deletions(-) (limited to 'bitbake/lib/bb/ui/crumbs/hig.py') 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 @@ # # BitBake Graphical GTK User Interface # -# Copyright (C) 2011 Intel Corporation +# Copyright (C) 2011-2012 Intel Corporation # # Authored by Joshua Lock +# Authored by Dongxiao Xu +# Authored by Shane Wang # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as @@ -18,21 +20,33 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -import gobject import gtk +import gobject +import hashlib +import os +import re +import subprocess +import shlex +from bb.ui.crumbs.hobcolor import HobColors +from bb.ui.crumbs.hobwidget import HobWidget +from bb.ui.crumbs.progressbar import HobProgressBar + """ The following are convenience classes for implementing GNOME HIG compliant BitBake GUI's In summary: spacing = 12px, border-width = 6px """ +# +# CrumbsDialog +# class CrumbsDialog(gtk.Dialog): """ A GNOME HIG compliant dialog widget. Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons """ def __init__(self, parent=None, label="", icon=gtk.STOCK_INFO): - gtk.Dialog.__init__(self, "", parent, gtk.DIALOG_DESTROY_WITH_PARENT) + super(CrumbsDialog, self).__init__("", parent, gtk.DIALOG_DESTROY_WITH_PARENT) #self.set_property("has-separator", False) # note: deprecated in 2.22 @@ -59,3 +73,572 @@ class CrumbsDialog(gtk.Dialog): self.label.set_property("yalign", 0.00) self.label.show() first_row.add(self.label) + +# +# Brought-in-by Dialog +# +class BinbDialog(gtk.Dialog): + """ + A dialog widget to show "brought in by" info when a recipe/package is clicked. + """ + + def __init__(self, title, content, parent=None): + super(BinbDialog, self).__init__(title, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, None) + + self.set_position(gtk.WIN_POS_MOUSE) + self.set_resizable(False) + self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(HobColors.DARK)) + + hbox = gtk.HBox(False, 0) + self.vbox.pack_start(hbox, expand=False, fill=False, padding=10) + + label = gtk.Label(content) + label.set_alignment(0, 0) + label.set_line_wrap(True) + label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.Color(HobColors.WHITE)) + + hbox.pack_start(label, expand=False, fill=False, padding=10) + self.vbox.show_all() + +# +# AdvancedSettings Dialog +# +class AdvancedSettingDialog (gtk.Dialog): + + def __init__(self, title, configuration, all_image_types, + all_package_formats, all_distros, all_sdk_machines, + max_threads, split_model, parent, flags, buttons): + super(AdvancedSettingDialog, self).__init__(title, parent, flags, buttons) + + # class members from other objects + # bitbake settings from Builder.Configuration + self.configuration = configuration + self.image_types = all_image_types + self.all_package_formats = all_package_formats + self.all_distros = all_distros + self.all_sdk_machines = all_sdk_machines + self.max_threads = max_threads + self.split_model = split_model + + # class members for internal use + self.pkgfmt_store = None + self.distro_combo = None + self.dldir_text = None + self.sstatedir_text = None + self.sstatemirror_text = None + self.bb_spinner = None + self.pmake_spinner = None + self.rootfs_size_spinner = None + self.extra_size_spinner = None + self.gplv3_checkbox = None + self.toolchain_checkbox = None + self.setting_store = None + self.image_types_checkbuttons = {} + + self.variables = {} + self.variables["PACKAGE_FORMAT"] = self.configuration.curr_package_format + self.variables["INCOMPATIBLE_LICENSE"] = self.configuration.incompat_license + self.variables["IMAGE_FSTYPES"] = self.configuration.image_fstypes + self.md5 = hashlib.md5(str(sorted(self.variables.items()))).hexdigest() + self.settings_changed = False + + # create visual elements on the dialog + self.create_visual_elements() + self.connect("response", self.response_cb) + + def create_visual_elements(self): + self.set_size_request(500, 500) + + self.nb = gtk.Notebook() + self.nb.set_show_tabs(True) + self.nb.append_page(self.create_image_types_page(), gtk.Label("Image types")) + self.nb.append_page(self.create_output_page(), gtk.Label("Output")) + self.nb.append_page(self.create_build_environment_page(), gtk.Label("Build environment")) + self.nb.append_page(self.create_others_page(), gtk.Label("Others")) + self.nb.set_current_page(0) + self.vbox.pack_start(self.nb, expand=True, fill=True) + self.vbox.pack_end(gtk.HSeparator(), expand=True, fill=True) + + self.show_all() + + def create_image_types_page(self): + advanced_vbox = gtk.VBox(False, 15) + advanced_vbox.set_border_width(20) + + rows = (len(self.image_types)+1)/2 + table = gtk.Table(rows + 1, 10, True) + advanced_vbox.pack_start(table, expand=False, fill=False) + + tooltip = "Select image file system types that will be used." + image = gtk.Image() + image.show() + image.set_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON) + image.set_tooltip_text(tooltip) + label = HobWidget.gen_label_widget("Select image types:") + table.attach(label, 0, 9, 0, 1) + table.attach(image, 9, 10, 0, 1) + + i = 1 + j = 1 + for image_type in self.image_types: + self.image_types_checkbuttons[image_type] = gtk.CheckButton(image_type) + self.image_types_checkbuttons[image_type].set_tooltip_text("Build an %s image" % image_type) + table.attach(self.image_types_checkbuttons[image_type], j, j + 4, i, i + 1) + if image_type in self.configuration.image_fstypes: + self.image_types_checkbuttons[image_type].set_active(True) + i += 1 + if i > rows: + i = 1 + j = j + 4 + + return advanced_vbox + + def create_output_page(self): + advanced_vbox = gtk.VBox(False, 15) + advanced_vbox.set_border_width(20) + + sub_vbox = gtk.VBox(False, 5) + advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) + label = HobWidget.gen_label_widget("Packaging Format:") + tooltip = "Select package formats that will be used. " + tooltip += "The first format will be used for final image" + pkgfmt_widget, self.pkgfmt_store = HobWidget.gen_pkgfmt_widget(self.configuration.curr_package_format, self.all_package_formats, tooltip) + sub_vbox.pack_start(label, expand=False, fill=False) + sub_vbox.pack_start(pkgfmt_widget, expand=False, fill=False) + + sub_vbox = gtk.VBox(False, 5) + advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) + label = HobWidget.gen_label_widget("Image Rootfs Size: (MB)") + 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\"." + rootfs_size_widget, self.rootfs_size_spinner = HobWidget.gen_spinner_widget(int(self.configuration.image_rootfs_size*1.0/1024), 0, 1024, tooltip) + sub_vbox.pack_start(label, expand=False, fill=False) + sub_vbox.pack_start(rootfs_size_widget, expand=False, fill=False) + + sub_vbox = gtk.VBox(False, 5) + advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) + label = HobWidget.gen_label_widget("Image Extra Size: (MB)") + 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." + extra_size_widget, self.extra_size_spinner = HobWidget.gen_spinner_widget(int(self.configuration.image_extra_size*1.0/1024), 0, 1024, tooltip) + sub_vbox.pack_start(label, expand=False, fill=False) + sub_vbox.pack_start(extra_size_widget, expand=False, fill=False) + + self.gplv3_checkbox = gtk.CheckButton("Exclude GPLv3 packages") + self.gplv3_checkbox.set_tooltip_text("Check this box to prevent GPLv3 packages from being included in your image") + if "GPLv3" in self.configuration.incompat_license.split(): + self.gplv3_checkbox.set_active(True) + else: + self.gplv3_checkbox.set_active(False) + advanced_vbox.pack_start(self.gplv3_checkbox, expand=False, fill=False) + + sub_hbox = gtk.HBox(False, 5) + advanced_vbox.pack_start(sub_hbox, expand=False, fill=False) + self.toolchain_checkbox = gtk.CheckButton("Build Toolchain") + self.toolchain_checkbox.set_tooltip_text("Check this box to build the related toolchain with your image") + self.toolchain_checkbox.set_active(self.configuration.toolchain_build) + sub_hbox.pack_start(self.toolchain_checkbox, expand=False, fill=False) + + tooltip = "This is the Host platform you would like to run the toolchain" + sdk_machine_widget, self.sdk_machine_combo = HobWidget.gen_combo_widget(self.configuration.curr_sdk_machine, self.all_sdk_machines, tooltip) + sub_hbox.pack_start(sdk_machine_widget, expand=False, fill=False) + + return advanced_vbox + + def create_build_environment_page(self): + advanced_vbox = gtk.VBox(False, 15) + advanced_vbox.set_border_width(20) + + sub_vbox = gtk.VBox(False, 5) + advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) + label = HobWidget.gen_label_widget("Select Distro:") + tooltip = "This is the Yocto distribution you would like to use" + distro_widget, self.distro_combo = HobWidget.gen_combo_widget(self.configuration.curr_distro, self.all_distros, tooltip) + sub_vbox.pack_start(label, expand=False, fill=False) + sub_vbox.pack_start(distro_widget, expand=False, fill=False) + + sub_vbox = gtk.VBox(False, 5) + advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) + label = HobWidget.gen_label_widget("BB_NUMBER_THREADS:") + tooltip = "Sets the number of threads that bitbake tasks can run simultaneously" + bbthread_widget, self.bb_spinner = HobWidget.gen_spinner_widget(self.configuration.bbthread, 1, self.max_threads, tooltip) + sub_vbox.pack_start(label, expand=False, fill=False) + sub_vbox.pack_start(bbthread_widget, expand=False, fill=False) + + sub_vbox = gtk.VBox(False, 5) + advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) + label = HobWidget.gen_label_widget("PARALLEL_MAKE:") + tooltip = "Sets the make parallism, as known as 'make -j'" + pmake_widget, self.pmake_spinner = HobWidget.gen_spinner_widget(self.configuration.pmake, 1, self.max_threads, tooltip) + sub_vbox.pack_start(label, expand=False, fill=False) + sub_vbox.pack_start(pmake_widget, expand=False, fill=False) + + sub_vbox = gtk.VBox(False, 5) + advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) + label = HobWidget.gen_label_widget("Set Download Directory:") + tooltip = "Select a folder that caches the upstream project source code" + dldir_widget, self.dldir_text = HobWidget.gen_entry_widget(self.split_model, self.configuration.dldir, self, tooltip) + sub_vbox.pack_start(label, expand=False, fill=False) + sub_vbox.pack_start(dldir_widget, expand=False, fill=False) + + sub_vbox = gtk.VBox(False, 5) + advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) + label = HobWidget.gen_label_widget("Select SSTATE Directory:") + tooltip = "Select a folder that caches your prebuilt results" + sstatedir_widget, self.sstatedir_text = HobWidget.gen_entry_widget(self.split_model, self.configuration.sstatedir, self, tooltip) + sub_vbox.pack_start(label, expand=False, fill=False) + sub_vbox.pack_start(sstatedir_widget, expand=False, fill=False) + + sub_vbox = gtk.VBox(False, 5) + advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) + label = HobWidget.gen_label_widget("Select SSTATE Mirror:") + tooltip = "Select the prebuilt mirror that will fasten your build speed" + sstatemirror_widget, self.sstatemirror_text = HobWidget.gen_entry_widget(self.split_model, self.configuration.sstatemirror, self, tooltip) + sub_vbox.pack_start(label, expand=False, fill=False) + sub_vbox.pack_start(sstatemirror_widget, expand=False, fill=False) + + return advanced_vbox + + def create_others_page(self): + advanced_vbox = gtk.VBox(False, 15) + advanced_vbox.set_border_width(20) + + sub_vbox = gtk.VBox(False, 5) + advanced_vbox.pack_start(sub_vbox, expand=True, fill=True) + label = HobWidget.gen_label_widget("Add your own variables:") + tooltip = "This is the key/value pair for your extra settings" + setting_widget, self.setting_store = HobWidget.gen_editable_settings(self.configuration.extra_setting, tooltip) + sub_vbox.pack_start(label, expand=False, fill=False) + sub_vbox.pack_start(setting_widget, expand=True, fill=True) + + return advanced_vbox + + def response_cb(self, dialog, response_id): + self.variables = {} + + self.configuration.curr_package_format = "" + it = self.pkgfmt_store.get_iter_first() + while it: + value = self.pkgfmt_store.get_value(it, 2) + if value: + self.configuration.curr_package_format += (self.pkgfmt_store.get_value(it, 1) + " ") + it = self.pkgfmt_store.iter_next(it) + self.configuration.curr_package_format = self.configuration.curr_package_format.strip() + self.variables["PACKAGE_FORMAT"] = self.configuration.curr_package_format + + self.configuration.curr_distro = self.distro_combo.get_active_text() + self.configuration.dldir = self.dldir_text.get_text() + self.configuration.sstatedir = self.sstatedir_text.get_text() + self.configuration.sstatemirror = self.sstatemirror_text.get_text() + self.configuration.bbthread = self.bb_spinner.get_value_as_int() + self.configuration.pmake = self.pmake_spinner.get_value_as_int() + self.configuration.image_rootfs_size = self.rootfs_size_spinner.get_value_as_int() * 1024 + self.configuration.image_extra_size = self.extra_size_spinner.get_value_as_int() * 1024 + + self.configuration.image_fstypes = [] + for image_type in self.image_types: + if self.image_types_checkbuttons[image_type].get_active(): + self.configuration.image_fstypes.append(image_type) + self.variables["IMAGE_FSTYPES"] = self.configuration.image_fstypes + + if self.gplv3_checkbox.get_active(): + if "GPLv3" not in self.configuration.incompat_license.split(): + self.configuration.incompat_license += " GPLv3" + else: + if "GPLv3" in self.configuration.incompat_license.split(): + self.configuration.incompat_license = self.configuration.incompat_license.split().remove("GPLv3") + self.configuration.incompat_license = " ".join(self.configuration.incompat_license or []) + self.configuration.incompat_license = self.configuration.incompat_license.strip() + self.variables["INCOMPATIBLE_LICENSE"] = self.configuration.incompat_license + + self.configuration.toolchain_build = self.toolchain_checkbox.get_active() + + self.configuration.extra_setting = {} + it = self.setting_store.get_iter_first() + while it: + key = self.setting_store.get_value(it, 0) + value = self.setting_store.get_value(it, 1) + self.configuration.extra_setting[key] = value + self.variables[key] = value + it = self.setting_store.iter_next(it) + + md5 = hashlib.md5(str(sorted(self.variables.items()))).hexdigest() + self.settings_changed = (self.md5 != md5) + +# +# DeployImageDialog +# +class DeployImageDialog (gtk.Dialog): + + __dummy_usb__ = "--select a usb drive--" + + def __init__(self, title, image_path, parent, flags, buttons): + super(DeployImageDialog, self).__init__(title, parent, flags, buttons) + + self.image_path = image_path + + self.create_visual_elements() + self.connect("response", self.response_cb) + + def create_visual_elements(self): + self.set_border_width(20) + self.set_default_size(500, 250) + + label = gtk.Label() + label.set_alignment(0.0, 0.5) + markup = "The image to be written into usb drive:" + label.set_markup(markup) + self.vbox.pack_start(label, expand=False, fill=False, padding=2) + + scroll = gtk.ScrolledWindow() + scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + scroll.set_shadow_type(gtk.SHADOW_IN) + tv = gtk.TextView() + tv.set_editable(False) + tv.set_wrap_mode(gtk.WRAP_WORD) + tv.set_cursor_visible(False) + buf = gtk.TextBuffer() + buf.set_text(self.image_path) + tv.set_buffer(buf) + scroll.add(tv) + self.vbox.pack_start(scroll, expand=True, fill=True) + + self.usb_desc = gtk.Label() + self.usb_desc.set_alignment(0.0, 0.5) + markup = "You haven't chosen any USB drive." + self.usb_desc.set_markup(markup) + + self.usb_combo = gtk.combo_box_new_text() + self.usb_combo.connect("changed", self.usb_combo_changed_cb) + model = self.usb_combo.get_model() + model.clear() + self.usb_combo.append_text(self.__dummy_usb__) + for usb in self.find_all_usb_devices(): + self.usb_combo.append_text("/dev/" + usb) + self.usb_combo.set_active(0) + self.vbox.pack_start(self.usb_combo, expand=True, fill=True) + self.vbox.pack_start(self.usb_desc, expand=False, fill=False, padding=2) + + self.progress_bar = HobProgressBar() + self.vbox.pack_start(self.progress_bar, expand=False, fill=False) + separator = gtk.HSeparator() + self.vbox.pack_start(separator, expand=False, fill=True, padding=10) + + self.vbox.show_all() + self.progress_bar.hide() + + def popen_read(self, cmd): + return os.popen("%s 2>/dev/null" % cmd).read().strip() + + def find_all_usb_devices(self): + usb_devs = [ os.readlink(u) + for u in self.popen_read('ls /dev/disk/by-id/usb*').split() + if not re.search(r'part\d+', u) ] + return [ '%s' % u[u.rfind('/')+1:] for u in usb_devs ] + + def get_usb_info(self, dev): + return "%s %s" % \ + (self.popen_read('cat /sys/class/block/%s/device/vendor' % dev), + self.popen_read('cat /sys/class/block/%s/device/model' % dev)) + + def usb_combo_changed_cb(self, usb_combo): + combo_item = self.usb_combo.get_active_text() + if not combo_item or combo_item == self.__dummy_usb__: + markup = "You haven't chosen any USB drive." + self.usb_desc.set_markup(markup) + else: + markup = "" + self.get_usb_info(combo_item.lstrip("/dev/")) + "" + self.usb_desc.set_markup(markup) + + def response_cb(self, dialog, response_id): + if response_id == gtk.RESPONSE_YES: + combo_item = self.usb_combo.get_active_text() + if combo_item and combo_item != self.__dummy_usb__: + cmdline = "/usr/bin/xterm -e " + cmdline += "\"sudo dd if=" + self.image_path + " of=" + combo_item + "; bash\"" + subprocess.Popen(args=shlex.split(cmdline)) + + def update_progress_bar(self, title, fraction, status=True): + self.progress_bar.update(fraction) + self.progress_bar.set_title(title) + self.progress_bar.set_rcstyle(status) + + def write_file(self, ifile, ofile): + self.progress_bar.reset() + self.progress_bar.show() + + f_from = os.open(ifile, os.O_RDONLY) + f_to = os.open(ofile, os.O_WRONLY) + + total_size = os.stat(ifile).st_size + written_size = 0 + + while True: + buf = os.read(f_from, 1024*1024) + if not buf: + break + os.write(f_to, buf) + written_size += 1024*1024 + self.update_progress_bar("Writing to usb:", written_size * 1.0/total_size) + + self.update_progress_bar("Writing completed:", 1.0) + os.close(f_from) + os.close(f_to) + self.progress_bar.hide() +# +# LayerSelectionDialog +# +class LayerSelectionDialog (gtk.Dialog): + + def __init__(self, title, layers, all_layers, split_model, + parent, flags, buttons): + super(LayerSelectionDialog, self).__init__(title, parent, flags, buttons) + + # class members from other objects + self.layers = layers + self.all_layers = all_layers + self.split_model = split_model + self.layers_changed = False + + # class members for internal use + self.layer_store = None + + # create visual elements on the dialog + self.create_visual_elements() + self.connect("response", self.response_cb) + + def create_visual_elements(self): + self.set_border_width(20) + self.set_default_size(400, 250) + + hbox_top = gtk.HBox() + self.set_border_width(12) + self.vbox.pack_start(hbox_top, expand=False, fill=False) + + if self.split_model: + label = HobWidget.gen_label_widget("Select Layers:\n(Available layers under '${COREBASE}/layers/' directory)") + else: + label = HobWidget.gen_label_widget("Select Layers:") + hbox_top.pack_start(label, expand=False, fill=False) + + tooltip = "Layer is a collection of bb files and conf files" + image = gtk.Image() + image.set_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON) + image.set_tooltip_text(tooltip) + hbox_top.pack_end(image, expand=False, fill=False) + + layer_widget, self.layer_store = HobWidget.gen_layer_widget(self.split_model, self.layers, self.all_layers, self, None) + + self.vbox.pack_start(layer_widget, expand=True, fill=True) + + separator = gtk.HSeparator() + self.vbox.pack_start(separator, False, True, 5) + separator.show() + + hbox_button = gtk.HBox() + self.vbox.pack_end(hbox_button, expand=False, fill=False) + hbox_button.show() + + label = HobWidget.gen_label_widget("'meta' is Core layer for Yocto images\n" + "Please do not remove it") + hbox_button.pack_start(label, expand=False, fill=False) + + self.show_all() + + def response_cb(self, dialog, response_id): + model = self.layer_store + it = model.get_iter_first() + layers = [] + while it: + if self.split_model: + inc = model.get_value(it, 1) + if inc: + layers.append(model.get_value(it, 0)) + else: + layers.append(model.get_value(it, 0)) + it = model.iter_next(it) + + self.layers_changed = (self.layers != layers) + self.layers = layers + +class ImageSelectionDialog (gtk.Dialog): + + def __init__(self, image_folder, image_types, title, parent, flags, buttons): + super(ImageSelectionDialog, self).__init__(title, parent, flags, buttons) + self.connect("response", self.response_cb) + + self.image_folder = image_folder + self.image_types = image_types + self.image_names = [] + + # create visual elements on the dialog + self.create_visual_elements() + + self.image_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN) + self.fill_image_store() + + def create_visual_elements(self): + self.set_border_width(20) + self.set_default_size(600, 300) + self.vbox.set_spacing(10) + + hbox = gtk.HBox(False, 10) + self.vbox.pack_start(hbox, expand=False, fill=False) + + entry = gtk.Entry() + entry.set_text(self.image_folder) + table = gtk.Table(1, 10, True) + table.set_size_request(560, -1) + hbox.pack_start(table, expand=False, fill=False) + table.attach(entry, 0, 9, 0, 1) + image = gtk.Image() + image.set_from_stock(gtk.STOCK_OPEN,gtk.ICON_SIZE_BUTTON) + open_button = gtk.Button() + open_button.set_image(image) + open_button.connect("clicked", self.select_path_cb, self, entry) + table.attach(open_button, 9, 10, 0, 1) + + imgtv_widget, self.imgsel_tv = HobWidget.gen_imgtv_widget(400, 160) + self.vbox.pack_start(imgtv_widget, expand=True, fill=True) + + self.show_all() + + def select_path_cb(self, action, parent, entry): + dialog = gtk.FileChooserDialog("", parent, + gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, + (gtk.STOCK_OK, gtk.RESPONSE_YES, + gtk.STOCK_CANCEL, gtk.RESPONSE_NO)) + response = dialog.run() + if response == gtk.RESPONSE_YES: + path = dialog.get_filename() + entry.set_text(path) + self.image_folder = path + self.fill_image_store() + + dialog.destroy() + + def fill_image_store(self): + self.image_store.clear() + imageset = set() + for root, dirs, files in os.walk(self.image_folder): + for f in files: + for image_type in self.image_types: + if f.endswith('.' + image_type): + imageset.add(f.rsplit('.' + image_type)[0]) + + for image in imageset: + self.image_store.set(self.image_store.append(), 0, image, 1, False) + + self.imgsel_tv.set_model(self.image_store) + + def response_cb(self, dialog, response_id): + self.image_names = [] + if response_id == gtk.RESPONSE_YES: + iter = self.image_store.get_iter_first() + while iter: + path = self.image_store.get_path(iter) + if self.image_store[path][1]: + for root, dirs, files in os.walk(self.image_folder): + for f in files: + if f.startswith(self.image_store[path][0] + '.'): + self.image_names.append(f) + break + iter = self.image_store.iter_next(iter) -- cgit v1.2.3-54-g00ecf