# # BitBake Graphical GTK User Interface # # Copyright (C) 2011 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 # 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 gobject from bb.ui.crumbs.hobpages import HobPage # # PackageListModel # class PackageListModel(gtk.ListStore): """ This class defines an gtk.ListStore subclass which will convert the output of the bb.event.TargetsTreeGenerated event into a gtk.ListStore whilst also providing convenience functions to access gtk.TreeModel subclasses which provide filtered views of the data. """ (COL_NAME, COL_VER, COL_REV, COL_RNM, COL_SEC, COL_SUM, COL_RDEP, COL_RPROV, COL_SIZE, COL_RCP, COL_BINB, COL_INC, COL_FADE_INC, COL_FONT, COL_FLIST) = range(15) __gsignals__ = { "package-selection-changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } __toolchain_required_packages__ = ["packagegroup-core-standalone-sdk-target", "packagegroup-core-standalone-sdk-target-dbg"] def __init__(self): self.rprov_pkg = {} gtk.ListStore.__init__ (self, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_STRING) self.sort_column_id, self.sort_order = PackageListModel.COL_NAME, gtk.SORT_ASCENDING """ Find the model path for the item_name Returns the path in the model or None """ def find_path_for_item(self, item_name): pkg = item_name if item_name not in self.pn_path.keys(): if item_name not in self.rprov_pkg.keys(): return None pkg = self.rprov_pkg[item_name] if pkg not in self.pn_path.keys(): return None return self.pn_path[pkg] def find_item_for_path(self, item_path): return self[item_path][self.COL_NAME] """ Helper function to determine whether an item is an item specified by filter """ def tree_model_filter(self, model, it, filter): name = model.get_value(it, self.COL_NAME) for key in filter.keys(): if key == self.COL_NAME: if filter[key] != 'Search packages by name': if name and filter[key] not in name: return False else: if model.get_value(it, key) not in filter[key]: return False self.filtered_nb += 1 return True """ Create, if required, and return a filtered gtk.TreeModelSort containing only the items specified by filter """ def tree_model(self, filter, excluded_items_ahead=False, included_items_ahead=False, search_data=None, initial=False): model = self.filter_new() self.filtered_nb = 0 model.set_visible_func(self.tree_model_filter, filter) sort = gtk.TreeModelSort(model) sort.connect ('sort-column-changed', self.sort_column_changed_cb) if initial: sort.set_sort_column_id(PackageListModel.COL_NAME, gtk.SORT_ASCENDING) sort.set_default_sort_func(None) elif excluded_items_ahead: sort.set_default_sort_func(self.exclude_item_sort_func, search_data) elif included_items_ahead: sort.set_default_sort_func(self.include_item_sort_func, search_data) else: if search_data and search_data!='Search recipes by name' and search_data!='Search package groups by name': sort.set_default_sort_func(self.sort_func, search_data) else: sort.set_sort_column_id(self.sort_column_id, self.sort_order) sort.set_default_sort_func(None) sort.set_sort_func(PackageListModel.COL_INC, self.sort_column, PackageListModel.COL_INC) sort.set_sort_func(PackageListModel.COL_SIZE, self.sort_column, PackageListModel.COL_SIZE) sort.set_sort_func(PackageListModel.COL_BINB, self.sort_binb_column) sort.set_sort_func(PackageListModel.COL_RCP, self.sort_column, PackageListModel.COL_RCP) return sort def sort_column_changed_cb (self, data): self.sort_column_id, self.sort_order = data.get_sort_column_id () def sort_column(self, model, row1, row2, col): value1 = model.get_value(row1, col) value2 = model.get_value(row2, col) if col==PackageListModel.COL_SIZE: value1 = HobPage._string_to_size(value1) value2 = HobPage._string_to_size(value2) cmp_res = cmp(value1, value2) if cmp_res!=0: if col==PackageListModel.COL_INC: return -cmp_res else: return cmp_res else: name1 = model.get_value(row1, PackageListModel.COL_NAME) name2 = model.get_value(row2, PackageListModel.COL_NAME) return cmp(name1,name2) def sort_binb_column(self, model, row1, row2): value1 = model.get_value(row1, PackageListModel.COL_BINB) value2 = model.get_value(row2, PackageListModel.COL_BINB) value1_list = value1.split(', ') value2_list = value2.split(', ') value1 = value1_list[0] value2 = value2_list[0] cmp_res = cmp(value1, value2) if cmp_res==0: cmp_size = cmp(len(value1_list), len(value2_list)) if cmp_size==0: name1 = model.get_value(row1, PackageListModel.COL_NAME) name2 = model.get_value(row2, PackageListModel.COL_NAME) return cmp(name1,name2) else: return cmp_size else: return cmp_res def exclude_item_sort_func(self, model, iter1, iter2, user_data=None): if user_data: val1 = model.get_value(iter1, PackageListModel.COL_NAME) val2 = model.get_value(iter2, PackageListModel.COL_NAME) return self.cmp_vals(val1, val2, user_data) else: val1 = model.get_value(iter1, PackageListModel.COL_FADE_INC) val2 = model.get_value(iter2, PackageListModel.COL_INC) return ((val1 == True) and (val2 == False)) def include_item_sort_func(self, model, iter1, iter2, user_data=None): if user_data: val1 = model.get_value(iter1, PackageListModel.COL_NAME) val2 = model.get_value(iter2, PackageListModel.COL_NAME) return self.cmp_vals(val1, val2, user_data) else: val1 = model.get_value(iter1, PackageListModel.COL_INC) val2 = model.get_value(iter2, PackageListModel.COL_INC) return ((val1 == False) and (val2 == True)) def sort_func(self, model, iter1, iter2, user_data): val1 = model.get_value(iter1, PackageListModel.COL_NAME) val2 = model.get_value(iter2, PackageListModel.COL_NAME) return self.cmp_vals(val1, val2, user_data) def cmp_vals(self, val1, val2, user_data): if val1 is None or val2 is None: return 0 elif val1.startswith(user_data) and not val2.startswith(user_data): return -1 elif not val1.startswith(user_data) and val2.startswith(user_data): return 1 else: return cmp(val1, val2) def convert_vpath_to_path(self, view_model, view_path): # view_model is the model sorted # get the path of the model filtered filtered_model_path = view_model.convert_path_to_child_path(view_path) # get the model filtered filtered_model = view_model.get_model() # get the path of the original model path = filtered_model.convert_path_to_child_path(filtered_model_path) return path def convert_path_to_vpath(self, view_model, path): it = view_model.get_iter_first() while it: name = self.find_item_for_path(path) view_name = view_model.get_value(it, PackageListModel.COL_NAME) if view_name == name: view_path = view_model.get_path(it) return view_path it = view_model.iter_next(it) return None """ The populate() function takes as input the data from a bb.event.PackageInfo event and populates the package list. """ def populate(self, pkginfolist): # First clear the model, in case repopulating self.clear() def getpkgvalue(pkgdict, key, pkgname, defaultval = None): value = pkgdict.get('%s_%s' % (key, pkgname), None) if not value: value = pkgdict.get(key, defaultval) return value for pkginfo in pkginfolist: pn = pkginfo['PN'] pv = pkginfo['PV'] pr = pkginfo['PR'] pkg = pkginfo['PKG'] pkgv = getpkgvalue(pkginfo, 'PKGV', pkg) pkgr = getpkgvalue(pkginfo, 'PKGR', pkg) # PKGSIZE is artificial, will always be overridden with the package name if present pkgsize = int(pkginfo.get('PKGSIZE_%s' % pkg, "0")) # PKG_%s is the renamed version pkg_rename = pkginfo.get('PKG_%s' % pkg, "") # The rest may be overridden or not section = getpkgvalue(pkginfo, 'SECTION', pkg, "") summary = getpkgvalue(pkginfo, 'SUMMARY', pkg, "") rdep = getpkgvalue(pkginfo, 'RDEPENDS', pkg, "") rrec = getpkgvalue(pkginfo, 'RRECOMMENDS', pkg, "") rprov = getpkgvalue(pkginfo, 'RPROVIDES', pkg, "") files_list = getpkgvalue(pkginfo, 'FILES_INFO', pkg, "") for i in rprov.split(): self.rprov_pkg[i] = pkg recipe = pn + '-' + pv + '-' + pr allow_empty = getpkgvalue(pkginfo, 'ALLOW_EMPTY', pkg, "") if pkgsize == 0 and not allow_empty: continue size = HobPage._size_to_string(pkgsize) self.set(self.append(), self.COL_NAME, pkg, self.COL_VER, pkgv, self.COL_REV, pkgr, self.COL_RNM, pkg_rename, self.COL_SEC, section, self.COL_SUM, summary, self.COL_RDEP, rdep + ' ' + rrec, self.COL_RPROV, rprov, self.COL_SIZE, size, self.COL_RCP, recipe, self.COL_BINB, "", self.COL_INC, False, self.COL_FONT, '10', self.COL_FLIST, files_list) self.pn_path = {} it = self.get_iter_first() while it: pn = self.get_value(it, self.COL_NAME) path = self.get_path(it) self.pn_path[pn] = path it = self.iter_next(it) """ Update the model, send out the notification. """ def selection_change_notification(self): self.emit("package-selection-changed") """ Check whether the item at item_path is included or not """ def path_included(self, item_path): return self[item_path][self.COL_INC] """ Add this item, and any of its dependencies, to the image contents """ def include_item(self, item_path, binb=""): if self.path_included(item_path): return item_name = self[item_path][self.COL_NAME] item_deps = self[item_path][self.COL_RDEP] self[item_path][self.COL_INC] = True item_bin = self[item_path][self.COL_BINB].split(', ') if binb and not binb in item_bin: item_bin.append(binb) self[item_path][self.COL_BINB] = ', '.join(item_bin).lstrip(', ') if item_deps: # Ensure all of the items deps are included and, where appropriate, # add this item to their COL_BINB for dep in item_deps.split(" "): if dep.startswith('('): continue # If the contents model doesn't already contain dep, add it dep_path = self.find_path_for_item(dep) if not dep_path: continue dep_included = self.path_included(dep_path) if dep_included and not dep in item_bin: # don't set the COL_BINB to this item if the target is an # item in our own COL_BINB dep_bin = self[dep_path][self.COL_BINB].split(', ') if not item_name in dep_bin: dep_bin.append(item_name) self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ') elif not dep_included: self.include_item(dep_path, binb=item_name) def exclude_item(self, item_path): if not self.path_included(item_path): return self[item_path][self.COL_INC] = False item_name = self[item_path][self.COL_NAME] item_deps = self[item_path][self.COL_RDEP] if item_deps: for dep in item_deps.split(" "): if dep.startswith('('): continue dep_path = self.find_path_for_item(dep) if not dep_path: continue dep_bin = self[dep_path][self.COL_BINB].split(', ') if item_name in dep_bin: dep_bin.remove(item_name) self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ') item_bin = self[item_path][self.COL_BINB].split(', ') if item_bin: for binb in item_bin: binb_path = self.find_path_for_item(binb) if not binb_path: continue self.exclude_item(binb_path) """ Empty self.contents by setting the include of each entry to None """ def reset(self): it = self.get_iter_first() while it: self.set(it, self.COL_INC, False, self.COL_BINB, "") it = self.iter_next(it) self.selection_change_notification() def get_selected_packages(self): packagelist = [] it = self.get_iter_first() while it: if self.get_value(it, self.COL_INC): name = self.get_value(it, self.COL_NAME) packagelist.append(name) it = self.iter_next(it) return packagelist def get_user_selected_packages(self): packagelist = [] it = self.get_iter_first() while it: if self.get_value(it, self.COL_INC): binb = self.get_value(it, self.COL_BINB) if binb == "User Selected": name = self.get_value(it, self.COL_NAME) packagelist.append(name) it = self.iter_next(it) return packagelist def get_selected_packages_toolchain(self): packagelist = [] it = self.get_iter_first() while it: if self.get_value(it, self.COL_INC): name = self.get_value(it, self.COL_NAME) if name.endswith("-dev") or name.endswith("-dbg"): packagelist.append(name) it = self.iter_next(it) return list(set(packagelist + self.__toolchain_required_packages__)); """ Package model may be incomplete, therefore when calling the set_selected_packages(), some packages will not be set included. Return the un-set packages list. """ def set_selected_packages(self, packagelist, user_selected=False): left = [] binb = 'User Selected' if user_selected else '' for pn in packagelist: if pn in self.pn_path.keys(): path = self.pn_path[pn] self.include_item(item_path=path, binb=binb) else: left.append(pn) self.selection_change_notification() return left """ Return the selected package size, unit is B. """ def get_packages_size(self): packages_size = 0 it = self.get_iter_first() while it: if self.get_value(it, self.COL_INC): str_size = self.get_value(it, self.COL_SIZE) if not str_size: continue packages_size += HobPage._string_to_size(str_size) it = self.iter_next(it) return packages_size """ Resync the state of included items to a backup column before performing the fadeout visible effect """ def resync_fadeout_column(self, model_first_iter=None): it = model_first_iter while it: active = self.get_value(it, self.COL_INC) self.set(it, self.COL_FADE_INC, active) it = self.iter_next(it) # # RecipeListModel # class RecipeListModel(gtk.ListStore): """ This class defines an gtk.ListStore subclass which will convert the output of the bb.event.TargetsTreeGenerated event into a gtk.ListStore whilst also providing convenience functions to access gtk.TreeModel subclasses which provide filtered views of the data. """ (COL_NAME, COL_DESC, COL_LIC, COL_GROUP, COL_DEPS, COL_BINB, COL_TYPE, COL_INC, COL_IMG, COL_INSTALL, COL_PN, COL_FADE_INC, COL_SUMMARY, COL_VERSION, COL_REVISION, COL_HOMEPAGE, COL_BUGTRACKER, COL_FILE) = range(18) __custom_image__ = "Start with an empty image recipe" __gsignals__ = { "recipe-selection-changed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } """ """ def __init__(self): gtk.ListStore.__init__ (self, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING) self.sort_column_id, self.sort_order = RecipeListModel.COL_NAME, gtk.SORT_ASCENDING """ Find the model path for the item_name Returns the path in the model or None """ def find_path_for_item(self, item_name): if self.non_target_name(item_name) or item_name not in self.pn_path.keys(): return None else: return self.pn_path[item_name] def find_item_for_path(self, item_path): return self[item_path][self.COL_NAME] """ Helper method to determine whether name is a target pn """ def non_target_name(self, name): if name and ('-native' in name): return True return False """ Helper function to determine whether an item is an item specified by filter """ def tree_model_filter(self, model, it, filter): name = model.get_value(it, self.COL_NAME) if self.non_target_name(name): return False for key in filter.keys(): if key == self.COL_NAME: if filter[key] != 'Search recipes by name' and filter[key] != 'Search package groups by name': if filter[key] not in name: return False else: if model.get_value(it, key) not in filter[key]: return False self.filtered_nb += 1 return True def exclude_item_sort_func(self, model, iter1, iter2, user_data=None): if user_data: val1 = model.get_value(iter1, RecipeListModel.COL_NAME) val2 = model.get_value(iter2, RecipeListModel.COL_NAME) return self.cmp_vals(val1, val2, user_data) else: val1 = model.get_value(iter1, RecipeListModel.COL_FADE_INC) val2 = model.get_value(iter2, RecipeListModel.COL_INC) return ((val1 == True) and (val2 == False)) def include_item_sort_func(self, model, iter1, iter2, user_data=None): if user_data: val1 = model.get_value(iter1, RecipeListModel.COL_NAME) val2 = model.get_value(iter2, RecipeListModel.COL_NAME) return self.cmp_vals(val1, val2, user_data) else: val1 = model.get_value(iter1, RecipeListModel.COL_INC) val2 = model.get_value(iter2, RecipeListModel.COL_INC) return ((val1 == False) and (val2 == True)) def sort_func(self, model, iter1, iter2, user_data): val1 = model.get_value(iter1, RecipeListModel.COL_NAME) val2 = model.get_value(iter2, RecipeListModel.COL_NAME) return self.cmp_vals(val1, val2, user_data) def cmp_vals(self, val1, val2, user_data): if val1 is None or val2 is None: return 0 elif val1.startswith(user_data) and not val2.startswith(user_data): return -1 elif not val1.startswith(user_data) and val2.startswith(user_data): return 1 else: return cmp(val1, val2) """ Create, if required, and return a filtered gtk.TreeModelSort containing only the items specified by filter """ def tree_model(self, filter, excluded_items_ahead=False, included_items_ahead=False, search_data=None, initial=False): model = self.filter_new() self.filtered_nb = 0 model.set_visible_func(self.tree_model_filter, filter) sort = gtk.TreeModelSort(model) sort.connect ('sort-column-changed', self.sort_column_changed_cb) if initial: sort.set_sort_column_id(RecipeListModel.COL_NAME, gtk.SORT_ASCENDING) sort.set_default_sort_func(None) elif excluded_items_ahead: sort.set_default_sort_func(self.exclude_item_sort_func, search_data) elif included_items_ahead: sort.set_default_sort_func(self.include_item_sort_func, search_data) else: if search_data and search_data!='Search recipes by name' and search_data!='Search package groups by name': sort.set_default_sort_func(self.sort_func, search_data) else: sort.set_sort_column_id(self.sort_column_id, self.sort_order) sort.set_default_sort_func(None) sort.set_sort_func(RecipeListModel.COL_INC, self.sort_column, RecipeListModel.COL_INC) sort.set_sort_func(RecipeListModel.COL_GROUP, self.sort_column, RecipeListModel.COL_GROUP) sort.set_sort_func(RecipeListModel.COL_BINB, self.sort_binb_column) sort.set_sort_func(RecipeListModel.COL_LIC, self.sort_column, RecipeListModel.COL_LIC) return sort def sort_column_changed_cb (self, data): self.sort_column_id, self.sort_order = data.get_sort_column_id () def sort_column(self, model, row1, row2, col): value1 = model.get_value(row1, col) value2 = model.get_value(row2, col) cmp_res = cmp(value1, value2) if cmp_res!=0: if col==RecipeListModel.COL_INC: return -cmp_res else: return cmp_res else: name1 = model.get_value(row1, RecipeListModel.COL_NAME) name2 = model.get_value(row2, RecipeListModel.COL_NAME) return cmp(name1,name2) def sort_binb_column(self, model, row1, row2): value1 = model.get_value(row1, RecipeListModel.COL_BINB) value2 = model.get_value(row2, RecipeListModel.COL_BINB) value1_list = value1.split(', ') value2_list = value2.split(', ') value1 = value1_list[0] value2 = value2_list[0] cmp_res = cmp(value1, value2) if cmp_res==0: cmp_size = cmp(len(value1_list), len(value2_list)) if cmp_size==0: name1 = model.get_value(row1, RecipeListModel.COL_NAME) name2 = model.get_value(row2, RecipeListModel.COL_NAME) return cmp(name1,name2) else: return cmp_size else: return cmp_res def convert_vpath_to_path(self, view_model, view_path): filtered_model_path = view_model.convert_path_to_child_path(view_path) filtered_model = view_model.get_model() # get the path of the original model path = filtered_model.convert_path_to_child_path(filtered_model_path) return path def convert_path_to_vpath(self, view_model, path): it = view_model.get_iter_first() while it: name = self.find_item_for_path(path) view_name = view_model.get_value(it, RecipeListModel.COL_NAME) if view_name == name: view_path = view_model.get_path(it) return view_path it = view_model.iter_next(it) return None """ The populate() function takes as input the data from a bb.event.TargetsTreeGenerated event and populates the RecipeList. """ def populate(self, event_model): # First clear the model, in case repopulating self.clear() # dummy image for prompt self.set_in_list(self.__custom_image__, "Use 'Edit image recipe' to customize recipes and packages " \ "to be included in your image ") for item in event_model["pn"]: name = item desc = event_model["pn"][item]["description"] lic = event_model["pn"][item]["license"] group = event_model["pn"][item]["section"] inherits = event_model["pn"][item]["inherits"] summary = event_model["pn"][item]["summary"] version = event_model["pn"][item]["version"] revision = event_model["pn"][item]["prevision"] homepage = event_model["pn"][item]["homepage"] bugtracker = event_model["pn"][item]["bugtracker"] filename = event_model["pn"][item]["filename"] install = [] depends = event_model["depends"].get(item, []) + event_model["rdepends-pn"].get(item, []) if ('packagegroup.bbclass' in " ".join(inherits)): atype = 'packagegroup' elif ('/image.bbclass' in " ".join(inherits)): if "edited" not in name: atype = 'image' install = event_model["rdepends-pkg"].get(item, []) + event_model["rrecs-pkg"].get(item, []) elif ('meta-' in name): atype = 'toolchain' elif (name == 'dummy-image' or name == 'dummy-toolchain'): atype = 'dummy' else: atype = 'recipe' self.set(self.append(), self.COL_NAME, item, self.COL_DESC, desc, self.COL_LIC, lic, self.COL_GROUP, group, self.COL_DEPS, " ".join(depends), self.COL_BINB, "", self.COL_TYPE, atype, self.COL_INC, False, self.COL_IMG, False, self.COL_INSTALL, " ".join(install), self.COL_PN, item, self.COL_SUMMARY, summary, self.COL_VERSION, version, self.COL_REVISION, revision, self.COL_HOMEPAGE, homepage, self.COL_BUGTRACKER, bugtracker, self.COL_FILE, filename) self.pn_path = {} it = self.get_iter_first() while it: pn = self.get_value(it, self.COL_NAME) path = self.get_path(it) self.pn_path[pn] = path it = self.iter_next(it) def set_in_list(self, item, desc): self.set(self.append(), self.COL_NAME, item, self.COL_DESC, desc, self.COL_LIC, "", self.COL_GROUP, "", self.COL_DEPS, "", self.COL_BINB, "", self.COL_TYPE, "image", self.COL_INC, False, self.COL_IMG, False, self.COL_INSTALL, "", self.COL_PN, item, self.COL_SUMMARY, "", self.COL_VERSION, "", self.COL_REVISION, "", self.COL_HOMEPAGE, "", self.COL_BUGTRACKER, "") self.pn_path = {} it = self.get_iter_first() while it: pn = self.get_value(it, self.COL_NAME) path = self.get_path(it) self.pn_path[pn] = path it = self.iter_next(it) """ Update the model, send out the notification. """ def selection_change_notification(self): self.emit("recipe-selection-changed") def path_included(self, item_path): return self[item_path][self.COL_INC] """ Add this item, and any of its dependencies, to the image contents """ def include_item(self, item_path, binb="", image_contents=False): if self.path_included(item_path): return item_name = self[item_path][self.COL_NAME] item_deps = self[item_path][self.COL_DEPS] self[item_path][self.COL_INC] = True item_bin = self[item_path][self.COL_BINB].split(', ') if binb and not binb in item_bin: item_bin.append(binb) self[item_path][self.COL_BINB] = ', '.join(item_bin).lstrip(', ') # We want to do some magic with things which are brought in by the # base image so tag them as so if image_contents: self[item_path][self.COL_IMG] = True if item_deps: # Ensure all of the items deps are included and, where appropriate, # add this item to their COL_BINB for dep in item_deps.split(" "): # If the contents model doesn't already contain dep, add it dep_path = self.find_path_for_item(dep) if not dep_path: continue dep_included = self.path_included(dep_path) if dep_included and not dep in item_bin: # don't set the COL_BINB to this item if the target is an # item in our own COL_BINB dep_bin = self[dep_path][self.COL_BINB].split(', ') if not item_name in dep_bin: dep_bin.append(item_name) self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ') elif not dep_included: self.include_item(dep_path, binb=item_name, image_contents=image_contents) dep_bin = self[item_path][self.COL_BINB].split(', ') if self[item_path][self.COL_NAME] in dep_bin: dep_bin.remove(self[item_path][self.COL_NAME]) self[item_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ') def exclude_item(self, item_path): if not self.path_included(item_path): return self[item_path][self.COL_INC] = False item_name = self[item_path][self.COL_NAME] item_deps = self[item_path][self.COL_DEPS] if item_deps: for dep in item_deps.split(" "): dep_path = self.find_path_for_item(dep) if not dep_path: continue dep_bin = self[dep_path][self.COL_BINB].split(', ') if item_name in dep_bin: dep_bin.remove(item_name) self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ') item_bin = self[item_path][self.COL_BINB].split(', ') if item_bin: for binb in item_bin: binb_path = self.find_path_for_item(binb) if not binb_path: continue self.exclude_item(binb_path) def reset(self): it = self.get_iter_first() while it: self.set(it, self.COL_INC, False, self.COL_BINB, "", self.COL_IMG, False) it = self.iter_next(it) self.selection_change_notification() """ Returns two lists. One of user selected recipes and the other containing all selected recipes """ def get_selected_recipes(self): allrecipes = [] userrecipes = [] it = self.get_iter_first() while it: if self.get_value(it, self.COL_INC): name = self.get_value(it, self.COL_PN) type = self.get_value(it, self.COL_TYPE) if type != "image": allrecipes.append(name) sel = "User Selected" in self.get_value(it, self.COL_BINB) if sel: userrecipes.append(name) it = self.iter_next(it) return list(set(userrecipes)), list(set(allrecipes)) def set_selected_recipes(self, recipelist): for pn in recipelist: if pn in self.pn_path.keys(): path = self.pn_path[pn] self.include_item(item_path=path, binb="User Selected") self.selection_change_notification() def get_selected_image(self): it = self.get_iter_first() while it: if self.get_value(it, self.COL_INC): name = self.get_value(it, self.COL_PN) type = self.get_value(it, self.COL_TYPE) if type == "image": sel = "User Selected" in self.get_value(it, self.COL_BINB) if sel: return name it = self.iter_next(it) return None def set_selected_image(self, img): if not img: return self.reset() path = self.find_path_for_item(img) self.include_item(item_path=path, binb="User Selected", image_contents=True) self.selection_change_notification() def set_custom_image_version(self, version): self.custom_image_version = version def get_custom_image_version(self): return self.custom_image_version def is_custom_image(self): return self.get_selected_image() == self.__custom_image__