| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 1 | #!/usr/bin/env python | 
 | 2 | # | 
 | 3 | # BitBake Graphical GTK User Interface | 
 | 4 | # | 
 | 5 | # Copyright (C) 2012        Intel Corporation | 
 | 6 | # | 
 | 7 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | 
 | 8 | # Authored by Shane Wang <shane.wang@intel.com> | 
 | 9 | # | 
 | 10 | # This program is free software; you can redistribute it and/or modify | 
 | 11 | # it under the terms of the GNU General Public License version 2 as | 
 | 12 | # published by the Free Software Foundation. | 
 | 13 | # | 
 | 14 | # This program is distributed in the hope that it will be useful, | 
 | 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 17 | # GNU General Public License for more details. | 
 | 18 | # | 
 | 19 | # You should have received a copy of the GNU General Public License along | 
 | 20 | # with this program; if not, write to the Free Software Foundation, Inc., | 
 | 21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 
 | 22 |  | 
 | 23 | import gtk | 
 | 24 | import glib | 
 | 25 | import re | 
 | 26 | from bb.ui.crumbs.progressbar import HobProgressBar | 
 | 27 | from bb.ui.crumbs.hobcolor import HobColors | 
 | 28 | from bb.ui.crumbs.hobwidget import hic, HobImageButton, HobInfoButton, HobAltButton, HobButton | 
 | 29 | from bb.ui.crumbs.hoblistmodel import RecipeListModel | 
 | 30 | from bb.ui.crumbs.hobpages import HobPage | 
 | 31 | from bb.ui.crumbs.hig.retrieveimagedialog import RetrieveImageDialog | 
 | 32 |  | 
 | 33 | # | 
 | 34 | # ImageConfigurationPage | 
 | 35 | # | 
 | 36 | class ImageConfigurationPage (HobPage): | 
 | 37 |  | 
 | 38 |     __dummy_machine__ = "--select a machine--" | 
 | 39 |     __dummy_image__   = "--select an image recipe--" | 
 | 40 |     __custom_image__  = "Select from my image recipes" | 
 | 41 |  | 
 | 42 |     def __init__(self, builder): | 
 | 43 |         super(ImageConfigurationPage, self).__init__(builder, "Image configuration") | 
 | 44 |  | 
 | 45 |         self.image_combo_id = None | 
 | 46 |         # we use machine_combo_changed_by_manual to identify the machine is changed by code | 
 | 47 |         # or by manual. If by manual, all user's recipe selection and package selection are | 
 | 48 |         # cleared. | 
 | 49 |         self.machine_combo_changed_by_manual = True | 
 | 50 |         self.stopping = False | 
 | 51 |         self.warning_shift = 0 | 
 | 52 |         self.custom_image_selected = None | 
 | 53 |         self.create_visual_elements() | 
 | 54 |  | 
 | 55 |     def create_visual_elements(self): | 
 | 56 |         # create visual elements | 
 | 57 |         self.toolbar = gtk.Toolbar() | 
 | 58 |         self.toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL) | 
 | 59 |         self.toolbar.set_style(gtk.TOOLBAR_BOTH) | 
 | 60 |  | 
 | 61 |         my_images_button = self.append_toolbar_button(self.toolbar, | 
 | 62 |             "Images", | 
 | 63 |             hic.ICON_IMAGES_DISPLAY_FILE, | 
 | 64 |             hic.ICON_IMAGES_HOVER_FILE, | 
 | 65 |             "Open previously built images", | 
 | 66 |             self.my_images_button_clicked_cb) | 
 | 67 |         settings_button = self.append_toolbar_button(self.toolbar, | 
 | 68 |             "Settings", | 
 | 69 |             hic.ICON_SETTINGS_DISPLAY_FILE, | 
 | 70 |             hic.ICON_SETTINGS_HOVER_FILE, | 
 | 71 |             "View additional build settings", | 
 | 72 |             self.settings_button_clicked_cb) | 
 | 73 |  | 
 | 74 |         self.config_top_button = self.add_onto_top_bar(self.toolbar) | 
 | 75 |  | 
 | 76 |         self.gtable = gtk.Table(40, 40, True) | 
 | 77 |         self.create_config_machine() | 
 | 78 |         self.create_config_baseimg() | 
 | 79 |         self.config_build_button = self.create_config_build_button() | 
 | 80 |  | 
 | 81 |     def _remove_all_widget(self): | 
 | 82 |         children = self.gtable.get_children() or [] | 
 | 83 |         for child in children: | 
 | 84 |             self.gtable.remove(child) | 
 | 85 |         children = self.box_group_area.get_children() or [] | 
 | 86 |         for child in children: | 
 | 87 |             self.box_group_area.remove(child) | 
 | 88 |         children = self.get_children() or [] | 
 | 89 |         for child in children: | 
 | 90 |             self.remove(child) | 
 | 91 |  | 
 | 92 |     def _pack_components(self, pack_config_build_button = False): | 
 | 93 |         self._remove_all_widget() | 
 | 94 |         self.pack_start(self.config_top_button, expand=False, fill=False) | 
 | 95 |         self.pack_start(self.group_align, expand=True, fill=True) | 
 | 96 |  | 
 | 97 |         self.box_group_area.pack_start(self.gtable, expand=True, fill=True) | 
 | 98 |         if pack_config_build_button: | 
 | 99 |             self.box_group_area.pack_end(self.config_build_button, expand=False, fill=False) | 
 | 100 |         else: | 
 | 101 |             box = gtk.HBox(False, 6) | 
 | 102 |             box.show() | 
 | 103 |             subbox = gtk.HBox(False, 0) | 
 | 104 |             subbox.set_size_request(205, 49) | 
 | 105 |             subbox.show() | 
 | 106 |             box.add(subbox) | 
 | 107 |             self.box_group_area.pack_end(box, False, False) | 
 | 108 |  | 
 | 109 |     def show_machine(self): | 
 | 110 |         self.progress_bar.reset() | 
 | 111 |         self._pack_components(pack_config_build_button = False) | 
 | 112 |         self.set_config_machine_layout(show_progress_bar = False) | 
 | 113 |         self.show_all() | 
 | 114 |  | 
 | 115 |     def update_progress_bar(self, title, fraction, status=None): | 
 | 116 |         if self.stopping == False: | 
 | 117 |             self.progress_bar.update(fraction) | 
 | 118 |             self.progress_bar.set_text(title) | 
 | 119 |             self.progress_bar.set_rcstyle(status) | 
 | 120 |  | 
 | 121 |     def show_info_populating(self): | 
 | 122 |         self._pack_components(pack_config_build_button = False) | 
 | 123 |         self.set_config_machine_layout(show_progress_bar = True) | 
 | 124 |         self.show_all() | 
 | 125 |  | 
 | 126 |     def show_info_populated(self): | 
 | 127 |         self.progress_bar.reset() | 
 | 128 |         self._pack_components(pack_config_build_button = False) | 
 | 129 |         self.set_config_machine_layout(show_progress_bar = False) | 
 | 130 |         self.set_config_baseimg_layout() | 
 | 131 |         self.show_all() | 
 | 132 |  | 
 | 133 |     def show_baseimg_selected(self): | 
 | 134 |         self.progress_bar.reset() | 
 | 135 |         self._pack_components(pack_config_build_button = True) | 
 | 136 |         self.set_config_machine_layout(show_progress_bar = False) | 
 | 137 |         self.set_config_baseimg_layout() | 
 | 138 |         self.show_all() | 
 | 139 |         if self.builder.recipe_model.get_selected_image() == self.builder.recipe_model.__custom_image__: | 
 | 140 |             self.just_bake_button.hide() | 
 | 141 |  | 
 | 142 |     def add_warnings_bar(self): | 
 | 143 |         #create the warnings bar shown when recipes parsing generates warnings | 
 | 144 |         color = HobColors.KHAKI | 
 | 145 |         warnings_bar = gtk.EventBox() | 
 | 146 |         warnings_bar.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) | 
 | 147 |         warnings_bar.set_flags(gtk.CAN_DEFAULT) | 
 | 148 |         warnings_bar.grab_default() | 
 | 149 |  | 
 | 150 |         build_stop_tab = gtk.Table(10, 20, True) | 
 | 151 |         warnings_bar.add(build_stop_tab) | 
 | 152 |  | 
 | 153 |         icon = gtk.Image() | 
 | 154 |         icon_pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_INDI_ALERT_FILE) | 
 | 155 |         icon.set_from_pixbuf(icon_pix_buffer) | 
 | 156 |         build_stop_tab.attach(icon, 0, 2, 0, 10) | 
 | 157 |  | 
 | 158 |         label = gtk.Label() | 
 | 159 |         label.set_alignment(0.0, 0.5) | 
 | 160 |         warnings_nb = len(self.builder.parsing_warnings) | 
 | 161 |         if warnings_nb == 1: | 
 | 162 |             label.set_markup("<span size='x-large'><b>1 recipe parsing warning</b></span>") | 
 | 163 |         else: | 
 | 164 |             label.set_markup("<span size='x-large'><b>%s recipe parsing warnings</b></span>" % warnings_nb) | 
 | 165 |         build_stop_tab.attach(label, 2, 12, 0, 10) | 
 | 166 |  | 
 | 167 |         view_warnings_button = HobButton("View warnings") | 
 | 168 |         view_warnings_button.connect('clicked', self.view_warnings_button_clicked_cb) | 
 | 169 |         build_stop_tab.attach(view_warnings_button, 15, 19, 1, 9) | 
 | 170 |  | 
 | 171 |         return warnings_bar | 
 | 172 |  | 
 | 173 |     def disable_warnings_bar(self): | 
 | 174 |         if self.builder.parsing_warnings: | 
 | 175 |             if hasattr(self, 'warnings_bar'): | 
 | 176 |                 self.warnings_bar.hide_all() | 
 | 177 |             self.builder.parsing_warnings = [] | 
 | 178 |  | 
 | 179 |     def create_config_machine(self): | 
 | 180 |         self.machine_title = gtk.Label() | 
 | 181 |         self.machine_title.set_alignment(0.0, 0.5) | 
 | 182 |         mark = "<span %s>Select a machine</span>" % self.span_tag('x-large', 'bold') | 
 | 183 |         self.machine_title.set_markup(mark) | 
 | 184 |  | 
 | 185 |         self.machine_title_desc = gtk.Label() | 
 | 186 |         self.machine_title_desc.set_alignment(0.0, 0.5) | 
 | 187 |         mark = ("<span %s>Your selection is the profile of the target machine for which you" | 
 | 188 |         " are building the image.\n</span>") % (self.span_tag('medium')) | 
 | 189 |         self.machine_title_desc.set_markup(mark) | 
 | 190 |  | 
 | 191 |         self.machine_combo = gtk.combo_box_new_text() | 
 | 192 |         self.machine_combo.connect("changed", self.machine_combo_changed_cb) | 
 | 193 |  | 
 | 194 |         icon_file = hic.ICON_LAYERS_DISPLAY_FILE | 
 | 195 |         hover_file = hic.ICON_LAYERS_HOVER_FILE | 
 | 196 |         self.layer_button = HobImageButton("Layers", "Add support for machines, software, etc.", | 
 | 197 |                                 icon_file, hover_file) | 
 | 198 |         self.layer_button.connect("clicked", self.layer_button_clicked_cb) | 
 | 199 |  | 
 | 200 |         markup = "Layers are a powerful mechanism to extend the Yocto Project " | 
 | 201 |         markup += "with your own functionality.\n" | 
 | 202 |         markup += "For more on layers, check the <a href=\"" | 
 | 203 |         markup += "http://www.yoctoproject.org/docs/current/dev-manual/" | 
 | 204 |         markup += "dev-manual.html#understanding-and-using-layers\">reference manual</a>." | 
 | 205 |         self.layer_info_icon = HobInfoButton("<b>Layers</b>" + "*" + markup, self.get_parent()) | 
 | 206 |         self.progress_bar = HobProgressBar() | 
 | 207 |         self.stop_button = HobAltButton("Stop") | 
 | 208 |         self.stop_button.connect("clicked", self.stop_button_clicked_cb) | 
 | 209 |         self.machine_separator = gtk.HSeparator() | 
 | 210 |  | 
 | 211 |     def set_config_machine_layout(self, show_progress_bar = False): | 
 | 212 |         self.gtable.attach(self.machine_title, 0, 40, 0, 4) | 
 | 213 |         self.gtable.attach(self.machine_title_desc, 0, 40, 4, 6) | 
 | 214 |         self.gtable.attach(self.machine_combo, 0, 12, 7, 10) | 
 | 215 |         self.gtable.attach(self.layer_button, 14, 36, 7, 12) | 
 | 216 |         self.gtable.attach(self.layer_info_icon, 36, 40, 7, 11) | 
 | 217 |         if show_progress_bar: | 
 | 218 |             #self.gtable.attach(self.progress_box, 0, 40, 15, 18) | 
 | 219 |             self.gtable.attach(self.progress_bar, 0, 37, 15, 18) | 
 | 220 |             self.gtable.attach(self.stop_button, 37, 40, 15, 18, 0, 0) | 
 | 221 |         if self.builder.parsing_warnings: | 
 | 222 |             self.warnings_bar = self.add_warnings_bar() | 
 | 223 |             self.gtable.attach(self.warnings_bar, 0, 40, 14, 18) | 
 | 224 |             self.warning_shift = 4 | 
 | 225 |         else: | 
 | 226 |             self.warning_shift = 0 | 
 | 227 |         self.gtable.attach(self.machine_separator, 0, 40, 13, 14) | 
 | 228 |  | 
 | 229 |     def create_config_baseimg(self): | 
 | 230 |         self.image_title = gtk.Label() | 
 | 231 |         self.image_title.set_alignment(0, 1.0) | 
 | 232 |         mark = "<span %s>Select an image recipe</span>" % self.span_tag('x-large', 'bold') | 
 | 233 |         self.image_title.set_markup(mark) | 
 | 234 |  | 
 | 235 |         self.image_title_desc = gtk.Label() | 
 | 236 |         self.image_title_desc.set_alignment(0, 0.5) | 
 | 237 |  | 
 | 238 |         mark = ("<span %s>Image recipes are a starting point for the type of image you want. " | 
 | 239 |                 "You can build them as \n" | 
 | 240 |                 "they are or edit them to suit your needs.\n</span>") % self.span_tag('medium') | 
 | 241 |         self.image_title_desc.set_markup(mark) | 
 | 242 |  | 
 | 243 |         self.image_combo = gtk.combo_box_new_text() | 
 | 244 |         self.image_combo.set_row_separator_func(self.combo_separator_func, None) | 
 | 245 |         self.image_combo_id = self.image_combo.connect("changed", self.image_combo_changed_cb) | 
 | 246 |  | 
 | 247 |         self.image_desc = gtk.Label() | 
 | 248 |         self.image_desc.set_alignment(0.0, 0.5) | 
 | 249 |         self.image_desc.set_size_request(256, -1) | 
 | 250 |         self.image_desc.set_justify(gtk.JUSTIFY_LEFT) | 
 | 251 |         self.image_desc.set_line_wrap(True) | 
 | 252 |  | 
 | 253 |         # button to view recipes | 
 | 254 |         icon_file = hic.ICON_RCIPE_DISPLAY_FILE | 
 | 255 |         hover_file = hic.ICON_RCIPE_HOVER_FILE | 
 | 256 |         self.view_adv_configuration_button = HobImageButton("Advanced configuration", | 
 | 257 |                                                                  "Select image types, package formats, etc", | 
 | 258 |                                                                  icon_file, hover_file)         | 
 | 259 |         self.view_adv_configuration_button.connect("clicked", self.view_adv_configuration_button_clicked_cb) | 
 | 260 |  | 
 | 261 |         self.image_separator = gtk.HSeparator() | 
 | 262 |  | 
 | 263 |     def combo_separator_func(self, model, iter, user_data): | 
 | 264 |         name = model.get_value(iter, 0) | 
 | 265 |         if name == "--Separator--": | 
 | 266 |             return True | 
 | 267 |  | 
 | 268 |     def set_config_baseimg_layout(self): | 
 | 269 |         self.gtable.attach(self.image_title, 0, 40, 15+self.warning_shift, 17+self.warning_shift) | 
 | 270 |         self.gtable.attach(self.image_title_desc, 0, 40, 18+self.warning_shift, 22+self.warning_shift) | 
 | 271 |         self.gtable.attach(self.image_combo, 0, 12, 23+self.warning_shift, 26+self.warning_shift) | 
 | 272 |         self.gtable.attach(self.image_desc, 0, 12, 27+self.warning_shift, 33+self.warning_shift) | 
 | 273 |         self.gtable.attach(self.view_adv_configuration_button, 14, 36, 23+self.warning_shift, 28+self.warning_shift) | 
 | 274 |         self.gtable.attach(self.image_separator, 0, 40, 35+self.warning_shift, 36+self.warning_shift) | 
 | 275 |  | 
 | 276 |     def create_config_build_button(self): | 
 | 277 |         # Create the "Build packages" and "Build image" buttons at the bottom | 
 | 278 |         button_box = gtk.HBox(False, 6) | 
 | 279 |  | 
 | 280 |         # create button "Build image" | 
 | 281 |         self.just_bake_button = HobButton("Build image") | 
 | 282 |         self.just_bake_button.set_tooltip_text("Build the image recipe as it is") | 
 | 283 |         self.just_bake_button.connect("clicked", self.just_bake_button_clicked_cb) | 
 | 284 |         button_box.pack_end(self.just_bake_button, expand=False, fill=False) | 
 | 285 |  | 
 | 286 |         # create button "Edit image recipe" | 
 | 287 |         self.edit_image_button = HobAltButton("Edit image recipe") | 
 | 288 |         self.edit_image_button.set_tooltip_text("Customize the recipes and packages to be included in your image") | 
 | 289 |         self.edit_image_button.connect("clicked", self.edit_image_button_clicked_cb) | 
 | 290 |         button_box.pack_end(self.edit_image_button, expand=False, fill=False) | 
 | 291 |  | 
 | 292 |         return button_box | 
 | 293 |  | 
 | 294 |     def stop_button_clicked_cb(self, button): | 
 | 295 |         self.stopping = True | 
 | 296 |         self.progress_bar.set_text("Stopping recipe parsing") | 
 | 297 |         self.progress_bar.set_rcstyle("stop") | 
 | 298 |         self.builder.cancel_parse_sync() | 
 | 299 |  | 
 | 300 |     def view_warnings_button_clicked_cb(self, button): | 
 | 301 |         self.builder.show_warning_dialog() | 
 | 302 |  | 
 | 303 |     def machine_combo_changed_idle_cb(self): | 
 | 304 |         self.builder.window.set_cursor(None) | 
 | 305 |  | 
 | 306 |     def machine_combo_changed_cb(self, machine_combo): | 
 | 307 |         self.stopping = False | 
 | 308 |         self.builder.parsing_warnings = [] | 
 | 309 |         combo_item = machine_combo.get_active_text() | 
 | 310 |         if not combo_item or combo_item == self.__dummy_machine__: | 
 | 311 |             return | 
 | 312 |  | 
 | 313 |         self.builder.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) | 
 | 314 |         self.builder.wait(0.1) #wait for combo and cursor to update | 
 | 315 |  | 
 | 316 |         # remove __dummy_machine__ item from the store list after first user selection | 
 | 317 |         # because it is no longer valid | 
 | 318 |         combo_store = machine_combo.get_model() | 
 | 319 |         if len(combo_store) and (combo_store[0][0] == self.__dummy_machine__): | 
 | 320 |             machine_combo.remove_text(0) | 
 | 321 |  | 
 | 322 |         self.builder.configuration.curr_mach = combo_item | 
 | 323 |         if self.machine_combo_changed_by_manual: | 
 | 324 |             self.builder.configuration.clear_selection() | 
 | 325 |         # reset machine_combo_changed_by_manual | 
 | 326 |         self.machine_combo_changed_by_manual = True | 
 | 327 |  | 
 | 328 |         self.builder.configuration.selected_image = None | 
 | 329 |  | 
 | 330 |         # Do reparse recipes | 
 | 331 |         self.builder.populate_recipe_package_info_async() | 
 | 332 |  | 
 | 333 |         glib.idle_add(self.machine_combo_changed_idle_cb) | 
 | 334 |  | 
 | 335 |     def update_machine_combo(self): | 
 | 336 |         self.disable_warnings_bar() | 
 | 337 |         all_machines = [self.__dummy_machine__] + self.builder.parameters.all_machines | 
 | 338 |  | 
 | 339 |         model = self.machine_combo.get_model() | 
 | 340 |         model.clear() | 
 | 341 |         for machine in all_machines: | 
 | 342 |             self.machine_combo.append_text(machine) | 
 | 343 |         self.machine_combo.set_active(0) | 
 | 344 |  | 
 | 345 |     def switch_machine_combo(self): | 
 | 346 |         self.disable_warnings_bar() | 
 | 347 |         self.machine_combo_changed_by_manual = False | 
 | 348 |         model = self.machine_combo.get_model() | 
 | 349 |         active = 0 | 
 | 350 |         while active < len(model): | 
 | 351 |             if model[active][0] == self.builder.configuration.curr_mach: | 
 | 352 |                 self.machine_combo.set_active(active) | 
 | 353 |                 return | 
 | 354 |             active += 1 | 
 | 355 |  | 
 | 356 |         if model[0][0] != self.__dummy_machine__: | 
 | 357 |             self.machine_combo.insert_text(0, self.__dummy_machine__) | 
 | 358 |  | 
 | 359 |         self.machine_combo.set_active(0) | 
 | 360 |  | 
 | 361 |     def update_image_desc(self): | 
 | 362 |         desc = "" | 
 | 363 |         selected_image = self.image_combo.get_active_text() | 
 | 364 |         if selected_image and selected_image in self.builder.recipe_model.pn_path.keys(): | 
 | 365 |             image_path = self.builder.recipe_model.pn_path[selected_image] | 
 | 366 |             image_iter = self.builder.recipe_model.get_iter(image_path) | 
 | 367 |             desc = self.builder.recipe_model.get_value(image_iter, self.builder.recipe_model.COL_DESC) | 
 | 368 |  | 
 | 369 |         mark = ("<span %s>%s</span>\n") % (self.span_tag('small'), desc) | 
 | 370 |         self.image_desc.set_markup(mark) | 
 | 371 |  | 
 | 372 |     def image_combo_changed_idle_cb(self, selected_image, selected_recipes, selected_packages): | 
 | 373 |         self.builder.update_recipe_model(selected_image, selected_recipes) | 
 | 374 |         self.builder.update_package_model(selected_packages) | 
 | 375 |         self.builder.window_sensitive(True) | 
 | 376 |  | 
 | 377 |     def image_combo_changed_cb(self, combo): | 
 | 378 |         self.builder.window_sensitive(False) | 
 | 379 |         selected_image = self.image_combo.get_active_text() | 
 | 380 |         if selected_image == self.__custom_image__: | 
 | 381 |             topdir = self.builder.get_topdir() | 
 | 382 |             images_dir = topdir + "/recipes/images/custom/" | 
 | 383 |             self.builder.ensure_dir(images_dir) | 
 | 384 |  | 
 | 385 |             dialog = RetrieveImageDialog(images_dir, "Select from my image recipes", | 
 | 386 |                             self.builder, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) | 
 | 387 |             response = dialog.run() | 
 | 388 |             if response == gtk.RESPONSE_OK: | 
 | 389 |                 image_name = dialog.get_filename() | 
 | 390 |                 head, tail = os.path.split(image_name) | 
 | 391 |                 selected_image = os.path.splitext(tail)[0] | 
 | 392 |                 self.custom_image_selected = selected_image | 
 | 393 |                 self.update_image_combo(self.builder.recipe_model, selected_image) | 
 | 394 |             else: | 
 | 395 |                 selected_image = self.__dummy_image__ | 
 | 396 |                 self.update_image_combo(self.builder.recipe_model, None) | 
 | 397 |             dialog.destroy() | 
 | 398 |         else: | 
 | 399 |             if self.custom_image_selected: | 
 | 400 |                 self.custom_image_selected = None | 
 | 401 |                 self.update_image_combo(self.builder.recipe_model, selected_image) | 
 | 402 |  | 
 | 403 |         if not selected_image or (selected_image == self.__dummy_image__): | 
 | 404 |             self.builder.window_sensitive(True) | 
 | 405 |             self.just_bake_button.hide() | 
 | 406 |             self.edit_image_button.hide() | 
 | 407 |             return | 
 | 408 |  | 
 | 409 |         # remove __dummy_image__ item from the store list after first user selection | 
 | 410 |         # because it is no longer valid | 
 | 411 |         combo_store = combo.get_model() | 
 | 412 |         if len(combo_store) and (combo_store[0][0] == self.__dummy_image__): | 
 | 413 |             combo.remove_text(0) | 
 | 414 |  | 
 | 415 |         self.builder.customized = False | 
 | 416 |  | 
 | 417 |         selected_recipes = [] | 
 | 418 |  | 
 | 419 |         image_path = self.builder.recipe_model.pn_path[selected_image] | 
 | 420 |         image_iter = self.builder.recipe_model.get_iter(image_path) | 
 | 421 |         selected_packages = self.builder.recipe_model.get_value(image_iter, self.builder.recipe_model.COL_INSTALL).split() | 
 | 422 |         self.update_image_desc() | 
 | 423 |  | 
 | 424 |         self.builder.recipe_model.reset() | 
 | 425 |         self.builder.package_model.reset() | 
 | 426 |  | 
 | 427 |         self.show_baseimg_selected() | 
 | 428 |  | 
 | 429 |         if selected_image == self.builder.recipe_model.__custom_image__: | 
 | 430 |             self.just_bake_button.hide() | 
 | 431 |  | 
 | 432 |         glib.idle_add(self.image_combo_changed_idle_cb, selected_image, selected_recipes, selected_packages) | 
 | 433 |  | 
 | 434 |     def _image_combo_connect_signal(self): | 
 | 435 |         if not self.image_combo_id: | 
 | 436 |             self.image_combo_id = self.image_combo.connect("changed", self.image_combo_changed_cb) | 
 | 437 |  | 
 | 438 |     def _image_combo_disconnect_signal(self): | 
 | 439 |         if self.image_combo_id: | 
 | 440 |             self.image_combo.disconnect(self.image_combo_id) | 
 | 441 |             self.image_combo_id = None | 
 | 442 |  | 
 | 443 |     def update_image_combo(self, recipe_model, selected_image): | 
 | 444 |         # Update the image combo according to the images in the recipe_model | 
 | 445 |         # populate image combo | 
 | 446 |         filter = {RecipeListModel.COL_TYPE : ['image']} | 
 | 447 |         image_model = recipe_model.tree_model(filter) | 
 | 448 |         image_model.set_sort_column_id(recipe_model.COL_NAME, gtk.SORT_ASCENDING) | 
 | 449 |         active = 0 | 
 | 450 |         cnt = 0 | 
 | 451 |  | 
 | 452 |         white_pattern = [] | 
 | 453 |         if self.builder.parameters.image_white_pattern: | 
 | 454 |             for i in self.builder.parameters.image_white_pattern.split(): | 
 | 455 |                 white_pattern.append(re.compile(i)) | 
 | 456 |  | 
 | 457 |         black_pattern = [] | 
 | 458 |         if self.builder.parameters.image_black_pattern: | 
 | 459 |             for i in self.builder.parameters.image_black_pattern.split(): | 
 | 460 |                 black_pattern.append(re.compile(i)) | 
 | 461 |         black_pattern.append(re.compile("hob-image")) | 
 | 462 |         black_pattern.append(re.compile("edited(-[0-9]*)*.bb$")) | 
 | 463 |  | 
 | 464 |         it = image_model.get_iter_first() | 
 | 465 |         self._image_combo_disconnect_signal() | 
 | 466 |         model = self.image_combo.get_model() | 
 | 467 |         model.clear() | 
 | 468 |         # Set a indicator text to combo store when first open | 
 | 469 |         if not selected_image: | 
 | 470 |             self.image_combo.append_text(self.__dummy_image__) | 
 | 471 |             cnt = cnt + 1 | 
 | 472 |  | 
 | 473 |         self.image_combo.append_text(self.__custom_image__) | 
 | 474 |         self.image_combo.append_text("--Separator--") | 
 | 475 |         cnt = cnt + 2 | 
 | 476 |  | 
 | 477 |         topdir = self.builder.get_topdir() | 
 | 478 |         # append and set active | 
 | 479 |         while it: | 
 | 480 |             path = image_model.get_path(it) | 
 | 481 |             it = image_model.iter_next(it) | 
 | 482 |             image_name = image_model[path][recipe_model.COL_NAME] | 
 | 483 |             if image_name == self.builder.recipe_model.__custom_image__: | 
 | 484 |                 continue | 
 | 485 |  | 
 | 486 |             if black_pattern: | 
 | 487 |                 allow = True | 
 | 488 |                 for pattern in black_pattern: | 
 | 489 |                     if pattern.search(image_name): | 
 | 490 |                         allow = False | 
 | 491 |                         break | 
 | 492 |             elif white_pattern: | 
 | 493 |                 allow = False | 
 | 494 |                 for pattern in white_pattern: | 
 | 495 |                     if pattern.search(image_name): | 
 | 496 |                         allow = True | 
 | 497 |                         break | 
 | 498 |             else: | 
 | 499 |                 allow = True | 
 | 500 |  | 
 | 501 |             file_name = image_model[path][recipe_model.COL_FILE] | 
 | 502 |             if file_name and topdir in file_name: | 
 | 503 |                 allow = False | 
 | 504 |  | 
 | 505 |             if allow: | 
 | 506 |                 self.image_combo.append_text(image_name) | 
 | 507 |                 if image_name == selected_image: | 
 | 508 |                     active = cnt | 
 | 509 |                 cnt = cnt + 1 | 
 | 510 |         self.image_combo.append_text(self.builder.recipe_model.__custom_image__) | 
 | 511 |  | 
 | 512 |         if selected_image == self.builder.recipe_model.__custom_image__: | 
 | 513 |             active = cnt | 
 | 514 |  | 
 | 515 |         if self.custom_image_selected: | 
 | 516 |             self.image_combo.append_text("--Separator--") | 
 | 517 |             self.image_combo.append_text(self.custom_image_selected) | 
 | 518 |             cnt = cnt + 2 | 
 | 519 |             if self.custom_image_selected == selected_image: | 
 | 520 |                 active = cnt | 
 | 521 |  | 
 | 522 |         self.image_combo.set_active(active) | 
 | 523 |  | 
 | 524 |         if active != 0: | 
 | 525 |             self.show_baseimg_selected() | 
 | 526 |  | 
 | 527 |         self._image_combo_connect_signal() | 
 | 528 |  | 
 | 529 |     def layer_button_clicked_cb(self, button): | 
 | 530 |         # Create a layer selection dialog | 
 | 531 |         self.builder.show_layer_selection_dialog() | 
 | 532 |  | 
 | 533 |     def view_adv_configuration_button_clicked_cb(self, button): | 
 | 534 |         # Create an advanced settings dialog | 
 | 535 |         response, settings_changed = self.builder.show_adv_settings_dialog() | 
 | 536 |         if not response: | 
 | 537 |             return | 
 | 538 |         if settings_changed: | 
 | 539 |             self.builder.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) | 
 | 540 |             self.builder.wait(0.1) #wait for adv_settings_dialog to terminate | 
 | 541 |             self.builder.reparse_post_adv_settings() | 
 | 542 |             self.builder.window.set_cursor(None) | 
 | 543 |  | 
 | 544 |     def just_bake_button_clicked_cb(self, button): | 
 | 545 |         self.builder.parsing_warnings = [] | 
 | 546 |         self.builder.just_bake() | 
 | 547 |  | 
 | 548 |     def edit_image_button_clicked_cb(self, button): | 
 | 549 |         self.builder.set_base_image() | 
 | 550 |         self.builder.show_recipes() | 
 | 551 |  | 
 | 552 |     def my_images_button_clicked_cb(self, button): | 
 | 553 |         self.builder.show_load_my_images_dialog() | 
 | 554 |  | 
 | 555 |     def settings_button_clicked_cb(self, button): | 
 | 556 |         # Create an advanced settings dialog | 
 | 557 |         response, settings_changed = self.builder.show_simple_settings_dialog() | 
 | 558 |         if not response: | 
 | 559 |             return | 
 | 560 |         if settings_changed: | 
 | 561 |             self.builder.reparse_post_adv_settings() |