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/imageconfigurationpage.py | 358 +++++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 bitbake/lib/bb/ui/crumbs/imageconfigurationpage.py (limited to 'bitbake/lib/bb/ui/crumbs/imageconfigurationpage.py') diff --git a/bitbake/lib/bb/ui/crumbs/imageconfigurationpage.py b/bitbake/lib/bb/ui/crumbs/imageconfigurationpage.py new file mode 100644 index 0000000000..d3a9ffd710 --- /dev/null +++ b/bitbake/lib/bb/ui/crumbs/imageconfigurationpage.py @@ -0,0 +1,358 @@ +#!/usr/bin/env python +# +# BitBake Graphical GTK User Interface +# +# Copyright (C) 2012 Intel Corporation +# +# 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 +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import gtk +import glib +from bb.ui.crumbs.progressbar import HobProgressBar +from bb.ui.crumbs.hobcolor import HobColors +from bb.ui.crumbs.hobwidget import hic, HobXpmLabelButtonBox +from bb.ui.crumbs.hoblistmodel import RecipeListModel +from bb.ui.crumbs.hobpages import HobPage + +from bb.ui.crumbs.hig import CrumbsDialog, BinbDialog, \ + AdvancedSettingDialog, LayerSelectionDialog + +# +# ImageConfigurationPage +# +class ImageConfigurationPage (HobPage): + + __dummy_machine__ = "--select a machine--" + + def __init__(self, builder): + super(ImageConfigurationPage, self).__init__(builder, "Image configuration") + + self.image_combo_id = None + self.create_visual_elements() + + def create_visual_elements(self): + # create visual elements + self.toolbar = gtk.Toolbar() + self.toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL) + self.toolbar.set_style(gtk.TOOLBAR_BOTH) + + _, template_button = self.append_toolbar_button(self.toolbar, + "Template", + hic.ICON_TEMPLATES_DISPLAY_FILE, + hic.ICON_TEMPLATES_HOVER_FILE, + "Load a hob building template saved before", + self.template_button_clicked_cb) + _, my_images_button = self.append_toolbar_button(self.toolbar, + "My images", + hic.ICON_IMAGES_DISPLAY_FILE, + hic.ICON_IMAGES_HOVER_FILE, + "Open images built out previously for running or deployment", + self.my_images_button_clicked_cb) + _, settings_button = self.append_toolbar_button(self.toolbar, + "Settings", + hic.ICON_SETTINGS_DISPLAY_FILE, + hic.ICON_SETTINGS_HOVER_FILE, + "Other advanced settings for build", + self.settings_button_clicked_cb) + + self.config_top_button = self.add_onto_top_bar(self.toolbar) + + self.gtable = gtk.Table(40, 40, True) + self.create_config_machine() + self.create_config_baseimg() + self.config_build_button = self.create_config_build_button() + + def _remove_all_widget(self): + children = self.gtable.get_children() or [] + for child in children: + self.gtable.remove(child) + children = self.box_group_area.get_children() or [] + for child in children: + self.box_group_area.remove(child) + children = self.get_children() or [] + for child in children: + self.remove(child) + + def _pack_components(self): + self._remove_all_widget() + self.pack_start(self.config_top_button, expand=False, fill=False) + self.pack_start(self.group_align, expand=True, fill=True) + + self.box_group_area.pack_start(self.gtable, expand=True, fill=True) + self.box_group_area.pack_end(self.config_build_button, expand=False, fill=False) + + def show_machine(self): + self._pack_components() + self.set_config_machine_layout() + self.show_all() + self.progress_bar.reset() + self.progress_bar.hide() + self.config_build_button.hide_all() + + 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 show_info_populating(self): + self._pack_components() + self.set_config_machine_layout() + self.show_all() + self.config_build_button.hide_all() + + def show_info_populated(self): + self._pack_components() + self.set_config_machine_layout() + self.set_config_baseimg_layout() + self.show_all() + self.progress_bar.reset() + self.progress_bar.hide() + + def create_config_machine(self): + self.machine_title = gtk.Label() + self.machine_title.set_alignment(0.0, 0.5) + mark = "Select a machine" % self.span_tag('24px', 'bold') + self.machine_title.set_markup(mark) + + self.machine_title_desc = gtk.Label() + self.machine_title_desc.set_alignment(0, 0.5) + mark = ("This is the profile of the target machine for which you" + " are building the image.\n") % (self.span_tag(px='14px')) + self.machine_title_desc.set_markup(mark) + + self.machine_combo = gtk.combo_box_new_text() + self.machine_combo.connect("changed", self.machine_combo_changed_cb) + + icon_file = hic.ICON_LAYERS_DISPLAY_FILE + hover_file = hic.ICON_LAYERS_HOVER_FILE + self.layer_button = HobXpmLabelButtonBox(icon_file, hover_file, + "Layers", "Add support for machines, software, etc") + self.layer_button.connect("button-release-event", self.layer_button_clicked_cb) + + icon_file = hic.ICON_INFO_DISPLAY_FILE + self.layer_info_icon = gtk.Image() + pix_buffer = gtk.gdk.pixbuf_new_from_file(icon_file) + self.layer_info_icon.set_from_pixbuf(pix_buffer) + markup = "Layers are a powerful mechanism to extend the Yocto Project " + markup += "with your own functionality.\n" + markup += "For more on layers, check:\n" + markup += "http://www.yoctoproject.org/docs/current/poky-ref-manual/" + markup += "poky-ref-manual.html#usingpoky-changes-layers." + self.layer_info_icon.set_tooltip_markup(markup) + + self.progress_bar = HobProgressBar() + self.machine_separator = gtk.HSeparator() + + def set_config_machine_layout(self): + self.gtable.attach(self.machine_title, 0, 40, 0, 4) + self.gtable.attach(self.machine_title_desc, 0, 40, 4, 6) + self.gtable.attach(self.machine_combo, 0, 12, 6, 9) + self.gtable.attach(self.layer_button, 12, 36, 6, 10) + self.gtable.attach(self.layer_info_icon, 36, 40, 6, 9) + self.gtable.attach(self.progress_bar, 0, 40, 13, 17) + self.gtable.attach(self.machine_separator, 0, 40, 12, 13) + + def create_config_baseimg(self): + self.image_title = gtk.Label() + self.image_title.set_alignment(0, 1.0) + mark = "Select a base image" % self.span_tag('24px', 'bold') + self.image_title.set_markup(mark) + + self.image_title_desc = gtk.Label() + self.image_title_desc.set_alignment(0, 0.5) + mark = ("Base images are a starting point for the type of image you want. " + "You can build them as \n" + "they are or customize them to your specific needs.\n") % self.span_tag('14px') + self.image_title_desc.set_markup(mark) + + self.image_combo = gtk.combo_box_new_text() + self.image_combo_id = self.image_combo.connect("changed", self.image_combo_changed_cb) + + self.image_desc = gtk.Label() + self.image_desc.set_alignment(0, 0) + self.image_desc.set_line_wrap(True) + + # button to view recipes + icon_file = hic.ICON_RCIPE_DISPLAY_FILE + hover_file = hic.ICON_RCIPE_HOVER_FILE + self.view_recipes_button = HobXpmLabelButtonBox(icon_file, hover_file, + "View Recipes", "Add/remove recipes and collections") + self.view_recipes_button.connect("button-release-event", self.view_recipes_button_clicked_cb) + + # button to view packages + icon_file = hic.ICON_PACKAGES_DISPLAY_FILE + hover_file = hic.ICON_PACKAGES_HOVER_FILE + self.view_packages_button = HobXpmLabelButtonBox(icon_file, hover_file, + "View Packages", "Add/remove packages") + self.view_packages_button.connect("button-release-event", self.view_packages_button_clicked_cb) + + self.image_separator = gtk.HSeparator() + + def set_config_baseimg_layout(self): + self.gtable.attach(self.image_title, 0, 40, 13, 17) + self.gtable.attach(self.image_title_desc, 0, 40, 17, 22) + self.gtable.attach(self.image_combo, 0, 12, 22, 25) + self.gtable.attach(self.image_desc, 14, 38, 22, 27) + self.gtable.attach(self.view_recipes_button, 0, 20, 28, 32) + self.gtable.attach(self.view_packages_button, 20, 40, 28, 32) + self.gtable.attach(self.image_separator, 0, 40, 35, 36) + + def create_config_build_button(self): + # Create the "Build packages" and "Just bake" buttons at the bottom + button_box = gtk.HBox(False, 5) + + # create button "Just bake" + just_bake_button = gtk.Button() + label = gtk.Label() + mark = "Just bake" % self.span_tag('24px', 'bold') + label.set_markup(mark) + + just_bake_button.set_image(label) + just_bake_button.set_size_request(205, 49) + just_bake_button.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(HobColors.ORANGE)) + just_bake_button.modify_bg(gtk.STATE_PRELIGHT, gtk.gdk.Color(HobColors.ORANGE)) + just_bake_button.modify_bg(gtk.STATE_SELECTED, gtk.gdk.Color(HobColors.ORANGE)) + just_bake_button.set_tooltip_text("Build image to get your target image") + just_bake_button.set_flags(gtk.CAN_DEFAULT) + just_bake_button.grab_default() + just_bake_button.connect("clicked", self.just_bake_button_clicked_cb) + button_box.pack_end(just_bake_button, expand=False, fill=False) + + label = gtk.Label(" or ") + button_box.pack_end(label, expand=False, fill=False) + + # create button "Build Packages" + build_packages_button = gtk.LinkButton("Build packages first based on recipe selection " + "for late customization on packages for the target image", "Build Packages") + build_packages_button.connect("clicked", self.build_packages_button_clicked_cb) + button_box.pack_end(build_packages_button, expand=False, fill=False) + + return button_box + + def machine_combo_changed_cb(self, machine_combo): + combo_item = machine_combo.get_active_text() + if not combo_item or combo_item == self.__dummy_machine__: + self.builder.switch_page(self.builder.MACHINE_SELECTION) + else: + self.builder.configuration.curr_mach = combo_item + # Do reparse recipes + self.builder.switch_page(self.builder.RCPPKGINFO_POPULATING) + + def update_machine_combo(self): + all_machines = [self.__dummy_machine__] + self.builder.parameters.all_machines + + model = self.machine_combo.get_model() + model.clear() + for machine in all_machines: + self.machine_combo.append_text(machine) + self.machine_combo.set_active(0) + + def switch_machine_combo(self): + model = self.machine_combo.get_model() + active = 0 + while active < len(model): + if model[active][0] == self.builder.configuration.curr_mach: + self.machine_combo.set_active(active) + return + active += 1 + self.machine_combo.set_active(0) + + def image_combo_changed_idle_cb(self, selected_image, selected_recipes, selected_packages): + self.builder.update_recipe_model(selected_image, selected_recipes) + self.builder.update_package_model(selected_packages) + self.builder.window_sensitive(True) + + def image_combo_changed_cb(self, combo): + self.builder.window_sensitive(False) + selected_image = self.image_combo.get_active_text() + if not selected_image: + return + + selected_recipes = [] + + image_path = self.builder.recipe_model.pn_path[selected_image] + image_iter = self.builder.recipe_model.get_iter(image_path) + selected_packages = self.builder.recipe_model.get_value(image_iter, self.builder.recipe_model.COL_INSTALL).split() + + mark = ("%s\n") % (self.span_tag('14px'), self.builder.recipe_model.get_value(image_iter, self.builder.recipe_model.COL_DESC)) + self.image_desc.set_markup(mark) + + self.builder.recipe_model.reset() + self.builder.package_model.reset() + + glib.idle_add(self.image_combo_changed_idle_cb, selected_image, selected_recipes, selected_packages) + + def _image_combo_connect_signal(self): + if not self.image_combo_id: + self.image_combo_id = self.image_combo.connect("changed", self.image_combo_changed_cb) + + def _image_combo_disconnect_signal(self): + if self.image_combo_id: + self.image_combo.disconnect(self.image_combo_id) + self.image_combo_id = None + + def update_image_combo(self, recipe_model, selected_image): + # Update the image combo according to the images in the recipe_model + # populate image combo + filter = {RecipeListModel.COL_TYPE : ['image']} + image_model = recipe_model.tree_model(filter) + active = 0 + cnt = 0 + + it = image_model.get_iter_first() + self._image_combo_disconnect_signal() + model = self.image_combo.get_model() + model.clear() + # append and set active + while it: + path = image_model.get_path(it) + image_name = image_model[path][recipe_model.COL_NAME] + self.image_combo.append_text(image_name) + if image_name == selected_image: + active = cnt + it = image_model.iter_next(it) + cnt = cnt + 1 + self._image_combo_connect_signal() + + self.image_combo.set_active(-1) + self.image_combo.set_active(active) + + def layer_button_clicked_cb(self, event, data): + # Create a layer selection dialog + self.builder.show_layer_selection_dialog() + + def view_recipes_button_clicked_cb(self, event, data): + self.builder.show_recipes() + + def view_packages_button_clicked_cb(self, event, data): + self.builder.show_packages() + + def just_bake_button_clicked_cb(self, button): + self.builder.just_bake() + + def build_packages_button_clicked_cb(self, button): + self.builder.build_packages() + + def template_button_clicked_cb(self, button): + self.builder.show_load_template_dialog() + + def my_images_button_clicked_cb(self, button): + self.builder.show_load_my_images_dialog() + + def settings_button_clicked_cb(self, button): + # Create an advanced settings dialog + self.builder.show_adv_settings_dialog() -- cgit v1.2.3-54-g00ecf