diff options
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/hoblistmodel.py')
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hoblistmodel.py | 765 |
1 files changed, 765 insertions, 0 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/hoblistmodel.py b/bitbake/lib/bb/ui/crumbs/hoblistmodel.py new file mode 100644 index 0000000000..227ae4b5de --- /dev/null +++ b/bitbake/lib/bb/ui/crumbs/hoblistmodel.py | |||
@@ -0,0 +1,765 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011 Intel Corporation | ||
5 | # | ||
6 | # Authored by Joshua Lock <josh@linux.intel.com> | ||
7 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | ||
8 | # Authored by Shane Wang <shane.wang@intel.com> | ||
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 gobject | ||
25 | |||
26 | # | ||
27 | # PackageListModel | ||
28 | # | ||
29 | class PackageListModel(gtk.TreeStore): | ||
30 | """ | ||
31 | This class defines an gtk.TreeStore subclass which will convert the output | ||
32 | of the bb.event.TargetsTreeGenerated event into a gtk.TreeStore whilst also | ||
33 | providing convenience functions to access gtk.TreeModel subclasses which | ||
34 | provide filtered views of the data. | ||
35 | """ | ||
36 | (COL_NAME, COL_VER, COL_REV, COL_RNM, COL_SEC, COL_SUM, COL_RDEP, COL_RPROV, COL_SIZE, COL_BINB, COL_INC) = range(11) | ||
37 | |||
38 | __gsignals__ = { | ||
39 | "packagelist-populated" : (gobject.SIGNAL_RUN_LAST, | ||
40 | gobject.TYPE_NONE, | ||
41 | ()), | ||
42 | "package-selection-changed" : (gobject.SIGNAL_RUN_LAST, | ||
43 | gobject.TYPE_NONE, | ||
44 | ()), | ||
45 | } | ||
46 | |||
47 | def __init__(self): | ||
48 | |||
49 | self.contents = None | ||
50 | self.images = None | ||
51 | self.pkgs_size = 0 | ||
52 | self.pn_path = {} | ||
53 | self.pkg_path = {} | ||
54 | |||
55 | gtk.TreeStore.__init__ (self, | ||
56 | gobject.TYPE_STRING, | ||
57 | gobject.TYPE_STRING, | ||
58 | gobject.TYPE_STRING, | ||
59 | gobject.TYPE_STRING, | ||
60 | gobject.TYPE_STRING, | ||
61 | gobject.TYPE_STRING, | ||
62 | gobject.TYPE_STRING, | ||
63 | gobject.TYPE_STRING, | ||
64 | gobject.TYPE_STRING, | ||
65 | gobject.TYPE_STRING, | ||
66 | gobject.TYPE_BOOLEAN) | ||
67 | |||
68 | |||
69 | """ | ||
70 | Find the model path for the item_name | ||
71 | Returns the path in the model or None | ||
72 | """ | ||
73 | def find_path_for_item(self, item_name): | ||
74 | if item_name not in self.pkg_path.keys(): | ||
75 | return None | ||
76 | else: | ||
77 | return self.pkg_path[item_name] | ||
78 | |||
79 | def find_item_for_path(self, item_path): | ||
80 | return self[item_path][self.COL_NAME] | ||
81 | |||
82 | """ | ||
83 | Helper function to determine whether an item is an item specified by filter | ||
84 | """ | ||
85 | def tree_model_filter(self, model, it, filter): | ||
86 | for key in filter.keys(): | ||
87 | if model.get_value(it, key) not in filter[key]: | ||
88 | return False | ||
89 | |||
90 | return True | ||
91 | |||
92 | """ | ||
93 | Create, if required, and return a filtered gtk.TreeModelSort | ||
94 | containing only the items specified by filter | ||
95 | """ | ||
96 | def tree_model(self, filter): | ||
97 | model = self.filter_new() | ||
98 | model.set_visible_func(self.tree_model_filter, filter) | ||
99 | |||
100 | sort = gtk.TreeModelSort(model) | ||
101 | sort.set_sort_column_id(PackageListModel.COL_NAME, gtk.SORT_ASCENDING) | ||
102 | sort.set_default_sort_func(None) | ||
103 | return sort | ||
104 | |||
105 | def convert_vpath_to_path(self, view_model, view_path): | ||
106 | # view_model is the model sorted | ||
107 | # get the path of the model filtered | ||
108 | filtered_model_path = view_model.convert_path_to_child_path(view_path) | ||
109 | # get the model filtered | ||
110 | filtered_model = view_model.get_model() | ||
111 | # get the path of the original model | ||
112 | path = filtered_model.convert_path_to_child_path(filtered_model_path) | ||
113 | return path | ||
114 | |||
115 | def convert_path_to_vpath(self, view_model, path): | ||
116 | name = self.find_item_for_path(path) | ||
117 | it = view_model.get_iter_first() | ||
118 | while it: | ||
119 | child_it = view_model.iter_children(it) | ||
120 | while child_it: | ||
121 | view_name = view_model.get_value(child_it, self.COL_NAME) | ||
122 | if view_name == name: | ||
123 | view_path = view_model.get_path(child_it) | ||
124 | return view_path | ||
125 | child_it = view_model.iter_next(child_it) | ||
126 | it = view_model.iter_next(it) | ||
127 | return None | ||
128 | |||
129 | """ | ||
130 | The populate() function takes as input the data from a | ||
131 | bb.event.PackageInfo event and populates the package list. | ||
132 | Once the population is done it emits gsignal packagelist-populated | ||
133 | to notify any listeners that the model is ready | ||
134 | """ | ||
135 | def populate(self, pkginfolist): | ||
136 | self.clear() | ||
137 | self.pkgs_size = 0 | ||
138 | self.pn_path = {} | ||
139 | self.pkg_path = {} | ||
140 | |||
141 | for pkginfo in pkginfolist: | ||
142 | pn = pkginfo['PN'] | ||
143 | pv = pkginfo['PV'] | ||
144 | pr = pkginfo['PR'] | ||
145 | if pn in self.pn_path.keys(): | ||
146 | pniter = self.get_iter(self.pn_path[pn]) | ||
147 | else: | ||
148 | pniter = self.append(None) | ||
149 | self.set(pniter, self.COL_NAME, pn + '-' + pv + '-' + pr, | ||
150 | self.COL_INC, False) | ||
151 | self.pn_path[pn] = self.get_path(pniter) | ||
152 | |||
153 | pkg = pkginfo['PKG'] | ||
154 | pkgv = pkginfo['PKGV'] | ||
155 | pkgr = pkginfo['PKGR'] | ||
156 | pkgsize = pkginfo['PKGSIZE_%s' % pkg] if 'PKGSIZE_%s' % pkg in pkginfo.keys() else "0" | ||
157 | pkg_rename = pkginfo['PKG_%s' % pkg] if 'PKG_%s' % pkg in pkginfo.keys() else "" | ||
158 | section = pkginfo['SECTION_%s' % pkg] if 'SECTION_%s' % pkg in pkginfo.keys() else "" | ||
159 | summary = pkginfo['SUMMARY_%s' % pkg] if 'SUMMARY_%s' % pkg in pkginfo.keys() else "" | ||
160 | rdep = pkginfo['RDEPENDS_%s' % pkg] if 'RDEPENDS_%s' % pkg in pkginfo.keys() else "" | ||
161 | rrec = pkginfo['RRECOMMENDS_%s' % pkg] if 'RRECOMMENDS_%s' % pkg in pkginfo.keys() else "" | ||
162 | rprov = pkginfo['RPROVIDES_%s' % pkg] if 'RPROVIDES_%s' % pkg in pkginfo.keys() else "" | ||
163 | |||
164 | if 'ALLOW_EMPTY_%s' % pkg in pkginfo.keys(): | ||
165 | allow_empty = pkginfo['ALLOW_EMPTY_%s' % pkg] | ||
166 | elif 'ALLOW_EMPTY' in pkginfo.keys(): | ||
167 | allow_empty = pkginfo['ALLOW_EMPTY'] | ||
168 | else: | ||
169 | allow_empty = "" | ||
170 | |||
171 | if pkgsize == "0" and not allow_empty: | ||
172 | continue | ||
173 | |||
174 | if len(pkgsize) > 3: | ||
175 | size = '%.1f' % (int(pkgsize)*1.0/1024) + ' MB' | ||
176 | else: | ||
177 | size = pkgsize + ' KB' | ||
178 | |||
179 | it = self.append(pniter) | ||
180 | self.pkg_path[pkg] = self.get_path(it) | ||
181 | self.set(it, self.COL_NAME, pkg, self.COL_VER, pkgv, | ||
182 | self.COL_REV, pkgr, self.COL_RNM, pkg_rename, | ||
183 | self.COL_SEC, section, self.COL_SUM, summary, | ||
184 | self.COL_RDEP, rdep + ' ' + rrec, | ||
185 | self.COL_RPROV, rprov, self.COL_SIZE, size, | ||
186 | self.COL_BINB, "", self.COL_INC, False) | ||
187 | |||
188 | self.emit("packagelist-populated") | ||
189 | |||
190 | """ | ||
191 | Check whether the item at item_path is included or not | ||
192 | """ | ||
193 | def path_included(self, item_path): | ||
194 | return self[item_path][self.COL_INC] | ||
195 | |||
196 | """ | ||
197 | Update the model, send out the notification. | ||
198 | """ | ||
199 | def selection_change_notification(self): | ||
200 | self.emit("package-selection-changed") | ||
201 | |||
202 | """ | ||
203 | Mark a certain package as selected. | ||
204 | All its dependencies are marked as selected. | ||
205 | The recipe provides the package is marked as selected. | ||
206 | If user explicitly selects a recipe, all its providing packages are selected | ||
207 | """ | ||
208 | def include_item(self, item_path, binb=""): | ||
209 | if self.path_included(item_path): | ||
210 | return | ||
211 | |||
212 | item_name = self[item_path][self.COL_NAME] | ||
213 | item_rdep = self[item_path][self.COL_RDEP] | ||
214 | |||
215 | self[item_path][self.COL_INC] = True | ||
216 | |||
217 | self.selection_change_notification() | ||
218 | |||
219 | it = self.get_iter(item_path) | ||
220 | |||
221 | # If user explicitly selects a recipe, all its providing packages are selected. | ||
222 | if not self[item_path][self.COL_VER] and binb == "User Selected": | ||
223 | child_it = self.iter_children(it) | ||
224 | while child_it: | ||
225 | child_path = self.get_path(child_it) | ||
226 | child_included = self.path_included(child_path) | ||
227 | if not child_included: | ||
228 | self.include_item(child_path, binb="User Selected") | ||
229 | child_it = self.iter_next(child_it) | ||
230 | return | ||
231 | |||
232 | # The recipe provides the package is also marked as selected | ||
233 | parent_it = self.iter_parent(it) | ||
234 | if parent_it: | ||
235 | parent_path = self.get_path(parent_it) | ||
236 | self[parent_path][self.COL_INC] = True | ||
237 | |||
238 | item_bin = self[item_path][self.COL_BINB].split(', ') | ||
239 | if binb and not binb in item_bin: | ||
240 | item_bin.append(binb) | ||
241 | self[item_path][self.COL_BINB] = ', '.join(item_bin).lstrip(', ') | ||
242 | |||
243 | if item_rdep: | ||
244 | # Ensure all of the items deps are included and, where appropriate, | ||
245 | # add this item to their COL_BINB | ||
246 | for dep in item_rdep.split(" "): | ||
247 | if dep.startswith('('): | ||
248 | continue | ||
249 | # If the contents model doesn't already contain dep, add it | ||
250 | dep_path = self.find_path_for_item(dep) | ||
251 | if not dep_path: | ||
252 | continue | ||
253 | dep_included = self.path_included(dep_path) | ||
254 | |||
255 | if dep_included and not dep in item_bin: | ||
256 | # don't set the COL_BINB to this item if the target is an | ||
257 | # item in our own COL_BINB | ||
258 | dep_bin = self[dep_path][self.COL_BINB].split(', ') | ||
259 | if not item_name in dep_bin: | ||
260 | dep_bin.append(item_name) | ||
261 | self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ') | ||
262 | elif not dep_included: | ||
263 | self.include_item(dep_path, binb=item_name) | ||
264 | |||
265 | """ | ||
266 | Mark a certain package as de-selected. | ||
267 | All other packages that depends on this package are marked as de-selected. | ||
268 | If none of the packages provided by the recipe, the recipe should be marked as de-selected. | ||
269 | If user explicitly de-select a recipe, all its providing packages are de-selected. | ||
270 | """ | ||
271 | def exclude_item(self, item_path): | ||
272 | if not self.path_included(item_path): | ||
273 | return | ||
274 | |||
275 | self[item_path][self.COL_INC] = False | ||
276 | |||
277 | self.selection_change_notification() | ||
278 | |||
279 | item_name = self[item_path][self.COL_NAME] | ||
280 | item_rdep = self[item_path][self.COL_RDEP] | ||
281 | it = self.get_iter(item_path) | ||
282 | |||
283 | # If user explicitly de-select a recipe, all its providing packages are de-selected. | ||
284 | if not self[item_path][self.COL_VER]: | ||
285 | child_it = self.iter_children(it) | ||
286 | while child_it: | ||
287 | child_path = self.get_path(child_it) | ||
288 | child_included = self[child_path][self.COL_INC] | ||
289 | if child_included: | ||
290 | self.exclude_item(child_path) | ||
291 | child_it = self.iter_next(child_it) | ||
292 | return | ||
293 | |||
294 | # If none of the packages provided by the recipe, the recipe should be marked as de-selected. | ||
295 | parent_it = self.iter_parent(it) | ||
296 | peer_iter = self.iter_children(parent_it) | ||
297 | enabled = 0 | ||
298 | while peer_iter: | ||
299 | peer_path = self.get_path(peer_iter) | ||
300 | if self[peer_path][self.COL_INC]: | ||
301 | enabled = 1 | ||
302 | break | ||
303 | peer_iter = self.iter_next(peer_iter) | ||
304 | if not enabled: | ||
305 | parent_path = self.get_path(parent_it) | ||
306 | self[parent_path][self.COL_INC] = False | ||
307 | |||
308 | # All packages that depends on this package are de-selected. | ||
309 | if item_rdep: | ||
310 | for dep in item_rdep.split(" "): | ||
311 | if dep.startswith('('): | ||
312 | continue | ||
313 | dep_path = self.find_path_for_item(dep) | ||
314 | if not dep_path: | ||
315 | continue | ||
316 | dep_bin = self[dep_path][self.COL_BINB].split(', ') | ||
317 | if item_name in dep_bin: | ||
318 | dep_bin.remove(item_name) | ||
319 | self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ') | ||
320 | |||
321 | item_bin = self[item_path][self.COL_BINB].split(', ') | ||
322 | if item_bin: | ||
323 | for binb in item_bin: | ||
324 | binb_path = self.find_path_for_item(binb) | ||
325 | if not binb_path: | ||
326 | continue | ||
327 | self.exclude_item(binb_path) | ||
328 | |||
329 | """ | ||
330 | Package model may be incomplete, therefore when calling the | ||
331 | set_selected_packages(), some packages will not be set included. | ||
332 | Return the un-set packages list. | ||
333 | """ | ||
334 | def set_selected_packages(self, packagelist): | ||
335 | left = [] | ||
336 | for pn in packagelist: | ||
337 | if pn in self.pkg_path.keys(): | ||
338 | path = self.pkg_path[pn] | ||
339 | self.include_item(item_path=path, | ||
340 | binb="User Selected") | ||
341 | else: | ||
342 | left.append(pn) | ||
343 | |||
344 | return left | ||
345 | |||
346 | def get_selected_packages(self): | ||
347 | packagelist = [] | ||
348 | |||
349 | it = self.get_iter_first() | ||
350 | while it: | ||
351 | child_it = self.iter_children(it) | ||
352 | while child_it: | ||
353 | if self.get_value(child_it, self.COL_INC): | ||
354 | name = self.get_value(child_it, self.COL_NAME) | ||
355 | packagelist.append(name) | ||
356 | child_it = self.iter_next(child_it) | ||
357 | it = self.iter_next(it) | ||
358 | |||
359 | return packagelist | ||
360 | |||
361 | """ | ||
362 | Return the selected package size, unit is KB. | ||
363 | """ | ||
364 | def get_packages_size(self): | ||
365 | packages_size = 0 | ||
366 | it = self.get_iter_first() | ||
367 | while it: | ||
368 | child_it = self.iter_children(it) | ||
369 | while child_it: | ||
370 | if self.get_value(child_it, self.COL_INC): | ||
371 | str_size = self.get_value(child_it, self.COL_SIZE) | ||
372 | if not str_size: | ||
373 | continue | ||
374 | |||
375 | unit = str_size.split() | ||
376 | if unit[1] == 'MB': | ||
377 | size = float(unit[0])*1024 | ||
378 | else: | ||
379 | size = float(unit[0]) | ||
380 | packages_size += size | ||
381 | |||
382 | child_it = self.iter_next(child_it) | ||
383 | it = self.iter_next(it) | ||
384 | return "%f" % packages_size | ||
385 | |||
386 | """ | ||
387 | Empty self.contents by setting the include of each entry to None | ||
388 | """ | ||
389 | def reset(self): | ||
390 | self.pkgs_size = 0 | ||
391 | it = self.get_iter_first() | ||
392 | while it: | ||
393 | self.set(it, self.COL_INC, False) | ||
394 | child_it = self.iter_children(it) | ||
395 | while child_it: | ||
396 | self.set(child_it, | ||
397 | self.COL_INC, False, | ||
398 | self.COL_BINB, "") | ||
399 | child_it = self.iter_next(child_it) | ||
400 | it = self.iter_next(it) | ||
401 | |||
402 | self.selection_change_notification() | ||
403 | |||
404 | # | ||
405 | # RecipeListModel | ||
406 | # | ||
407 | class RecipeListModel(gtk.ListStore): | ||
408 | """ | ||
409 | This class defines an gtk.ListStore subclass which will convert the output | ||
410 | of the bb.event.TargetsTreeGenerated event into a gtk.ListStore whilst also | ||
411 | providing convenience functions to access gtk.TreeModel subclasses which | ||
412 | provide filtered views of the data. | ||
413 | """ | ||
414 | (COL_NAME, COL_DESC, COL_LIC, COL_GROUP, COL_DEPS, COL_BINB, COL_TYPE, COL_INC, COL_IMG, COL_INSTALL, COL_PN) = range(11) | ||
415 | |||
416 | __dummy_image__ = "--select a base image--" | ||
417 | |||
418 | __gsignals__ = { | ||
419 | "recipelist-populated" : (gobject.SIGNAL_RUN_LAST, | ||
420 | gobject.TYPE_NONE, | ||
421 | ()), | ||
422 | "recipe-selection-changed" : (gobject.SIGNAL_RUN_LAST, | ||
423 | gobject.TYPE_NONE, | ||
424 | ()), | ||
425 | } | ||
426 | |||
427 | """ | ||
428 | """ | ||
429 | def __init__(self): | ||
430 | gtk.ListStore.__init__ (self, | ||
431 | gobject.TYPE_STRING, | ||
432 | gobject.TYPE_STRING, | ||
433 | gobject.TYPE_STRING, | ||
434 | gobject.TYPE_STRING, | ||
435 | gobject.TYPE_STRING, | ||
436 | gobject.TYPE_STRING, | ||
437 | gobject.TYPE_STRING, | ||
438 | gobject.TYPE_BOOLEAN, | ||
439 | gobject.TYPE_BOOLEAN, | ||
440 | gobject.TYPE_STRING, | ||
441 | gobject.TYPE_STRING, | ||
442 | gobject.TYPE_STRING) | ||
443 | |||
444 | """ | ||
445 | Find the model path for the item_name | ||
446 | Returns the path in the model or None | ||
447 | """ | ||
448 | def find_path_for_item(self, item_name): | ||
449 | if self.non_target_name(item_name) or item_name not in self.pn_path.keys(): | ||
450 | return None | ||
451 | else: | ||
452 | return self.pn_path[item_name] | ||
453 | |||
454 | def find_item_for_path(self, item_path): | ||
455 | return self[item_path][self.COL_NAME] | ||
456 | |||
457 | """ | ||
458 | Helper method to determine whether name is a target pn | ||
459 | """ | ||
460 | def non_target_name(self, name): | ||
461 | if name and ('-native' in name): | ||
462 | return True | ||
463 | return False | ||
464 | |||
465 | """ | ||
466 | Helper function to determine whether an item is an item specified by filter | ||
467 | """ | ||
468 | def tree_model_filter(self, model, it, filter): | ||
469 | name = model.get_value(it, self.COL_NAME) | ||
470 | if self.non_target_name(name): | ||
471 | return False | ||
472 | |||
473 | for key in filter.keys(): | ||
474 | if model.get_value(it, key) not in filter[key]: | ||
475 | return False | ||
476 | |||
477 | return True | ||
478 | |||
479 | def sort_func(self, model, iter1, iter2): | ||
480 | val1 = model.get_value(iter1, RecipeListModel.COL_NAME) | ||
481 | val2 = model.get_value(iter2, RecipeListModel.COL_NAME) | ||
482 | return val1 > val2 | ||
483 | |||
484 | """ | ||
485 | Create, if required, and return a filtered gtk.TreeModelSort | ||
486 | containing only the items which are items specified by filter | ||
487 | """ | ||
488 | def tree_model(self, filter): | ||
489 | model = self.filter_new() | ||
490 | model.set_visible_func(self.tree_model_filter, filter) | ||
491 | |||
492 | sort = gtk.TreeModelSort(model) | ||
493 | sort.set_default_sort_func(self.sort_func) | ||
494 | return sort | ||
495 | |||
496 | def convert_vpath_to_path(self, view_model, view_path): | ||
497 | filtered_model_path = view_model.convert_path_to_child_path(view_path) | ||
498 | filtered_model = view_model.get_model() | ||
499 | |||
500 | # get the path of the original model | ||
501 | path = filtered_model.convert_path_to_child_path(filtered_model_path) | ||
502 | return path | ||
503 | |||
504 | def convert_path_to_vpath(self, view_model, path): | ||
505 | it = view_model.get_iter_first() | ||
506 | while it: | ||
507 | name = self.find_item_for_path(path) | ||
508 | view_name = view_model.get_value(it, RecipeListModel.COL_NAME) | ||
509 | if view_name == name: | ||
510 | view_path = view_model.get_path(it) | ||
511 | return view_path | ||
512 | it = view_model.iter_next(it) | ||
513 | return None | ||
514 | |||
515 | def map_runtime(self, event_model, runtime, rdep_type, name): | ||
516 | if rdep_type not in ['pkg', 'pn'] or runtime not in ['rdepends', 'rrecs']: | ||
517 | return | ||
518 | package_depends = event_model["%s-%s" % (runtime, rdep_type)].get(name, []) | ||
519 | pn_depends = [] | ||
520 | for package_depend in package_depends: | ||
521 | if 'task-' not in package_depend and package_depend in event_model["packages"].keys(): | ||
522 | pn_depends.append(event_model["packages"][package_depend]["pn"]) | ||
523 | else: | ||
524 | pn_depends.append(package_depend) | ||
525 | return list(set(pn_depends)) | ||
526 | |||
527 | def subpkg_populate(self, event_model, pkg, desc, lic, group, atype, pn): | ||
528 | pn_depends = self.map_runtime(event_model, "rdepends", "pkg", pkg) | ||
529 | pn_depends += self.map_runtime(event_model, "rrecs", "pkg", pkg) | ||
530 | self.set(self.append(), self.COL_NAME, pkg, self.COL_DESC, desc, | ||
531 | self.COL_LIC, lic, self.COL_GROUP, group, | ||
532 | self.COL_DEPS, " ".join(pn_depends), self.COL_BINB, "", | ||
533 | self.COL_TYPE, atype, self.COL_INC, False, | ||
534 | self.COL_IMG, False, self.COL_INSTALL, "", self.COL_PN, pn) | ||
535 | |||
536 | """ | ||
537 | The populate() function takes as input the data from a | ||
538 | bb.event.TargetsTreeGenerated event and populates the RecipeList. | ||
539 | Once the population is done it emits gsignal recipelist-populated | ||
540 | to notify any listeners that the model is ready | ||
541 | """ | ||
542 | def populate(self, event_model): | ||
543 | # First clear the model, in case repopulating | ||
544 | self.clear() | ||
545 | |||
546 | # dummy image for prompt | ||
547 | self.set(self.append(), self.COL_NAME, self.__dummy_image__, | ||
548 | self.COL_DESC, "", | ||
549 | self.COL_LIC, "", self.COL_GROUP, "", | ||
550 | self.COL_DEPS, "", self.COL_BINB, "", | ||
551 | self.COL_TYPE, "image", self.COL_INC, False, | ||
552 | self.COL_IMG, False, self.COL_INSTALL, "", self.COL_PN, self.__dummy_image__) | ||
553 | |||
554 | for item in event_model["pn"]: | ||
555 | name = item | ||
556 | desc = event_model["pn"][item]["description"] | ||
557 | lic = event_model["pn"][item]["license"] | ||
558 | group = event_model["pn"][item]["section"] | ||
559 | install = [] | ||
560 | |||
561 | if ('task-' in name): | ||
562 | if ('lib32-' in name or 'lib64-' in name): | ||
563 | atype = 'mltask' | ||
564 | else: | ||
565 | atype = 'task' | ||
566 | for pkg in event_model["pn"][name]["packages"]: | ||
567 | self.subpkg_populate(event_model, pkg, desc, lic, group, atype, name) | ||
568 | continue | ||
569 | |||
570 | elif ('-image-' in name): | ||
571 | atype = 'image' | ||
572 | depends = event_model["depends"].get(item, []) | ||
573 | rdepends = self.map_runtime(event_model, 'rdepends', 'pn', name) | ||
574 | depends = depends + rdepends | ||
575 | install = event_model["rdepends-pn"].get(item, []) | ||
576 | |||
577 | elif ('meta-' in name): | ||
578 | atype = 'toolchain' | ||
579 | |||
580 | elif (name == 'dummy-image' or name == 'dummy-toolchain'): | ||
581 | atype = 'dummy' | ||
582 | |||
583 | else: | ||
584 | if ('lib32-' in name or 'lib64-' in name): | ||
585 | atype = 'mlrecipe' | ||
586 | else: | ||
587 | atype = 'recipe' | ||
588 | depends = event_model["depends"].get(item, []) | ||
589 | depends += self.map_runtime(event_model, 'rdepends', 'pn', item) | ||
590 | for pkg in event_model["pn"][name]["packages"]: | ||
591 | depends += self.map_runtime(event_model, 'rdepends', 'pkg', item) | ||
592 | depends += self.map_runtime(event_model, 'rrecs', 'pkg', item) | ||
593 | |||
594 | self.set(self.append(), self.COL_NAME, item, self.COL_DESC, desc, | ||
595 | self.COL_LIC, lic, self.COL_GROUP, group, | ||
596 | self.COL_DEPS, " ".join(depends), self.COL_BINB, "", | ||
597 | self.COL_TYPE, atype, self.COL_INC, False, | ||
598 | self.COL_IMG, False, self.COL_INSTALL, " ".join(install), self.COL_PN, item) | ||
599 | |||
600 | self.pn_path = {} | ||
601 | it = self.get_iter_first() | ||
602 | while it: | ||
603 | pn = self.get_value(it, self.COL_NAME) | ||
604 | path = self.get_path(it) | ||
605 | self.pn_path[pn] = path | ||
606 | it = self.iter_next(it) | ||
607 | |||
608 | self.emit("recipelist-populated") | ||
609 | |||
610 | """ | ||
611 | Update the model, send out the notification. | ||
612 | """ | ||
613 | def selection_change_notification(self): | ||
614 | self.emit("recipe-selection-changed") | ||
615 | |||
616 | def path_included(self, item_path): | ||
617 | return self[item_path][self.COL_INC] | ||
618 | |||
619 | """ | ||
620 | Append a certain image into the combobox | ||
621 | """ | ||
622 | def image_list_append(self, name, deps, install): | ||
623 | # check whether a certain image is there | ||
624 | if not name or self.find_path_for_item(name): | ||
625 | return | ||
626 | it = self.append() | ||
627 | self.set(it, self.COL_NAME, name, self.COL_DESC, "", | ||
628 | self.COL_LIC, "", self.COL_GROUP, "", | ||
629 | self.COL_DEPS, deps, self.COL_BINB, "", | ||
630 | self.COL_TYPE, "image", self.COL_INC, False, | ||
631 | self.COL_IMG, False, self.COL_INSTALL, install, | ||
632 | self.COL_PN, name) | ||
633 | self.pn_path[name] = self.get_path(it) | ||
634 | |||
635 | """ | ||
636 | Add this item, and any of its dependencies, to the image contents | ||
637 | """ | ||
638 | def include_item(self, item_path, binb="", image_contents=False): | ||
639 | if self.path_included(item_path): | ||
640 | return | ||
641 | |||
642 | item_name = self[item_path][self.COL_NAME] | ||
643 | item_deps = self[item_path][self.COL_DEPS] | ||
644 | |||
645 | self[item_path][self.COL_INC] = True | ||
646 | self.selection_change_notification() | ||
647 | |||
648 | item_bin = self[item_path][self.COL_BINB].split(', ') | ||
649 | if binb and not binb in item_bin: | ||
650 | item_bin.append(binb) | ||
651 | self[item_path][self.COL_BINB] = ', '.join(item_bin).lstrip(', ') | ||
652 | |||
653 | # We want to do some magic with things which are brought in by the | ||
654 | # base image so tag them as so | ||
655 | if image_contents: | ||
656 | self[item_path][self.COL_IMG] = True | ||
657 | |||
658 | if item_deps: | ||
659 | # Ensure all of the items deps are included and, where appropriate, | ||
660 | # add this item to their COL_BINB | ||
661 | for dep in item_deps.split(" "): | ||
662 | # If the contents model doesn't already contain dep, add it | ||
663 | dep_path = self.find_path_for_item(dep) | ||
664 | if not dep_path: | ||
665 | continue | ||
666 | dep_included = self.path_included(dep_path) | ||
667 | |||
668 | if dep_included and not dep in item_bin: | ||
669 | # don't set the COL_BINB to this item if the target is an | ||
670 | # item in our own COL_BINB | ||
671 | dep_bin = self[dep_path][self.COL_BINB].split(', ') | ||
672 | if not item_name in dep_bin: | ||
673 | dep_bin.append(item_name) | ||
674 | self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ') | ||
675 | elif not dep_included: | ||
676 | self.include_item(dep_path, binb=item_name, image_contents=image_contents) | ||
677 | |||
678 | def exclude_item(self, item_path): | ||
679 | if not self.path_included(item_path): | ||
680 | return | ||
681 | |||
682 | self[item_path][self.COL_INC] = False | ||
683 | |||
684 | self.selection_change_notification() | ||
685 | |||
686 | item_name = self[item_path][self.COL_NAME] | ||
687 | item_deps = self[item_path][self.COL_DEPS] | ||
688 | if item_deps: | ||
689 | for dep in item_deps.split(" "): | ||
690 | dep_path = self.find_path_for_item(dep) | ||
691 | if not dep_path: | ||
692 | continue | ||
693 | dep_bin = self[dep_path][self.COL_BINB].split(', ') | ||
694 | if item_name in dep_bin: | ||
695 | dep_bin.remove(item_name) | ||
696 | self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ') | ||
697 | |||
698 | item_bin = self[item_path][self.COL_BINB].split(', ') | ||
699 | if item_bin: | ||
700 | for binb in item_bin: | ||
701 | binb_path = self.find_path_for_item(binb) | ||
702 | if not binb_path: | ||
703 | continue | ||
704 | self.exclude_item(binb_path) | ||
705 | |||
706 | def reset(self): | ||
707 | it = self.get_iter_first() | ||
708 | while it: | ||
709 | self.set(it, | ||
710 | self.COL_INC, False, | ||
711 | self.COL_BINB, "", | ||
712 | self.COL_IMG, False) | ||
713 | it = self.iter_next(it) | ||
714 | |||
715 | self.selection_change_notification() | ||
716 | |||
717 | """ | ||
718 | Returns two lists. One of user selected recipes and the other containing | ||
719 | all selected recipes | ||
720 | """ | ||
721 | def get_selected_recipes(self): | ||
722 | allrecipes = [] | ||
723 | userrecipes = [] | ||
724 | |||
725 | it = self.get_iter_first() | ||
726 | while it: | ||
727 | if self.get_value(it, self.COL_INC): | ||
728 | name = self.get_value(it, self.COL_PN) | ||
729 | type = self.get_value(it, self.COL_TYPE) | ||
730 | if type != "image": | ||
731 | allrecipes.append(name) | ||
732 | sel = "User Selected" in self.get_value(it, self.COL_BINB) | ||
733 | if sel: | ||
734 | userrecipes.append(name) | ||
735 | it = self.iter_next(it) | ||
736 | |||
737 | return list(set(userrecipes)), list(set(allrecipes)) | ||
738 | |||
739 | def set_selected_recipes(self, recipelist): | ||
740 | for pn in recipelist: | ||
741 | if pn in self.pn_path.keys(): | ||
742 | path = self.pn_path[pn] | ||
743 | self.include_item(item_path=path, | ||
744 | binb="User Selected") | ||
745 | |||
746 | def get_selected_image(self): | ||
747 | it = self.get_iter_first() | ||
748 | while it: | ||
749 | if self.get_value(it, self.COL_INC): | ||
750 | name = self.get_value(it, self.COL_PN) | ||
751 | type = self.get_value(it, self.COL_TYPE) | ||
752 | if type == "image": | ||
753 | sel = "User Selected" in self.get_value(it, self.COL_BINB) | ||
754 | if sel: | ||
755 | return name | ||
756 | it = self.iter_next(it) | ||
757 | return None | ||
758 | |||
759 | def set_selected_image(self, img): | ||
760 | if img == None: | ||
761 | return | ||
762 | path = self.find_path_for_item(img) | ||
763 | self.include_item(item_path=path, | ||
764 | binb="User Selected", | ||
765 | image_contents=True) | ||