summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/ui/crumbs/hoblistmodel.py
diff options
context:
space:
mode:
authorbavery <brian.avery@intel.com>2016-02-29 10:26:02 -0800
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-03-02 22:41:23 +0000
commita9dc72f08bf5bdd898fba429729acee0e7305838 (patch)
treefa1e320398a1939df372363fbbfd79a5e58ae933 /bitbake/lib/bb/ui/crumbs/hoblistmodel.py
parent27468dbc3aa4ed71a20f706d4a65dfa29c4dd733 (diff)
downloadpoky-a9dc72f08bf5bdd898fba429729acee0e7305838.tar.gz
bitbake: hob: removal of hob ui and associated ui files
We've been gearing up the Toaster web UI to replace the Hob (GTK+ based) UI for some time now; Hob has basically been on life support for the past few releases. As of late last month in master, Toaster has the capability to select the packages in an image, removing the last thing that Hob could do that Toaster couldn't. To recap, the reasons why Hob is being removed include: - The code is tightly woven into BitBake, making it fragile. This means it needs significant QA and maintenance on an ongoing basis. - Some of the implementation is not ideal; we'll be able to remove some cruft from BitBake and OE-Core at the same time. - It's GTK+ 2 based, not the current GTK+ 3. - Toaster is now a much more capable UI and is being actively maintained The discussion about removing hob can be found at: http://lists.openembedded.org/pipermail/openembedded-architecture/2016-February/000082.html (Bitbake rev: be2cceea159c6ca9111eff3df87b98513eab6d72) Signed-off-by: bavery <brian.avery@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/hoblistmodel.py')
-rw-r--r--bitbake/lib/bb/ui/crumbs/hoblistmodel.py903
1 files changed, 0 insertions, 903 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/hoblistmodel.py b/bitbake/lib/bb/ui/crumbs/hoblistmodel.py
deleted file mode 100644
index 50df156f4d..0000000000
--- a/bitbake/lib/bb/ui/crumbs/hoblistmodel.py
+++ /dev/null
@@ -1,903 +0,0 @@
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
23import gtk
24import gobject
25from bb.ui.crumbs.hobpages import HobPage
26
27#
28# PackageListModel
29#
30class PackageListModel(gtk.ListStore):
31 """
32 This class defines an gtk.ListStore subclass which will convert the output
33 of the bb.event.TargetsTreeGenerated event into a gtk.ListStore whilst also
34 providing convenience functions to access gtk.TreeModel subclasses which
35 provide filtered views of the data.
36 """
37
38 (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)
39
40 __gsignals__ = {
41 "package-selection-changed" : (gobject.SIGNAL_RUN_LAST,
42 gobject.TYPE_NONE,
43 ()),
44 }
45
46 __toolchain_required_packages__ = ["packagegroup-core-standalone-sdk-target", "packagegroup-core-standalone-sdk-target-dbg"]
47
48 def __init__(self):
49 self.rprov_pkg = {}
50 gtk.ListStore.__init__ (self,
51 gobject.TYPE_STRING,
52 gobject.TYPE_STRING,
53 gobject.TYPE_STRING,
54 gobject.TYPE_STRING,
55 gobject.TYPE_STRING,
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_BOOLEAN,
63 gobject.TYPE_BOOLEAN,
64 gobject.TYPE_STRING,
65 gobject.TYPE_STRING)
66 self.sort_column_id, self.sort_order = PackageListModel.COL_NAME, gtk.SORT_ASCENDING
67
68 """
69 Find the model path for the item_name
70 Returns the path in the model or None
71 """
72 def find_path_for_item(self, item_name):
73 pkg = item_name
74 if item_name not in self.pn_path.keys():
75 if item_name not in self.rprov_pkg.keys():
76 return None
77 pkg = self.rprov_pkg[item_name]
78 if pkg not in self.pn_path.keys():
79 return None
80
81 return self.pn_path[pkg]
82
83 def find_item_for_path(self, item_path):
84 return self[item_path][self.COL_NAME]
85
86 """
87 Helper function to determine whether an item is an item specified by filter
88 """
89 def tree_model_filter(self, model, it, filter):
90 name = model.get_value(it, self.COL_NAME)
91
92 for key in filter.keys():
93 if key == self.COL_NAME:
94 if filter[key] != 'Search packages by name':
95 if name and filter[key] not in name:
96 return False
97 else:
98 if model.get_value(it, key) not in filter[key]:
99 return False
100 self.filtered_nb += 1
101 return True
102
103 """
104 Create, if required, and return a filtered gtk.TreeModelSort
105 containing only the items specified by filter
106 """
107 def tree_model(self, filter, excluded_items_ahead=False, included_items_ahead=False, search_data=None, initial=False):
108 model = self.filter_new()
109 self.filtered_nb = 0
110 model.set_visible_func(self.tree_model_filter, filter)
111
112 sort = gtk.TreeModelSort(model)
113 sort.connect ('sort-column-changed', self.sort_column_changed_cb)
114 if initial:
115 sort.set_sort_column_id(PackageListModel.COL_NAME, gtk.SORT_ASCENDING)
116 sort.set_default_sort_func(None)
117 elif excluded_items_ahead:
118 sort.set_default_sort_func(self.exclude_item_sort_func, search_data)
119 elif included_items_ahead:
120 sort.set_default_sort_func(self.include_item_sort_func, search_data)
121 else:
122 if search_data and search_data!='Search recipes by name' and search_data!='Search package groups by name':
123 sort.set_default_sort_func(self.sort_func, search_data)
124 else:
125 sort.set_sort_column_id(self.sort_column_id, self.sort_order)
126 sort.set_default_sort_func(None)
127
128 sort.set_sort_func(PackageListModel.COL_INC, self.sort_column, PackageListModel.COL_INC)
129 sort.set_sort_func(PackageListModel.COL_SIZE, self.sort_column, PackageListModel.COL_SIZE)
130 sort.set_sort_func(PackageListModel.COL_BINB, self.sort_binb_column)
131 sort.set_sort_func(PackageListModel.COL_RCP, self.sort_column, PackageListModel.COL_RCP)
132 return sort
133
134 def sort_column_changed_cb (self, data):
135 self.sort_column_id, self.sort_order = data.get_sort_column_id ()
136
137 def sort_column(self, model, row1, row2, col):
138 value1 = model.get_value(row1, col)
139 value2 = model.get_value(row2, col)
140 if col==PackageListModel.COL_SIZE:
141 value1 = HobPage._string_to_size(value1)
142 value2 = HobPage._string_to_size(value2)
143
144 cmp_res = cmp(value1, value2)
145 if cmp_res!=0:
146 if col==PackageListModel.COL_INC:
147 return -cmp_res
148 else:
149 return cmp_res
150 else:
151 name1 = model.get_value(row1, PackageListModel.COL_NAME)
152 name2 = model.get_value(row2, PackageListModel.COL_NAME)
153 return cmp(name1,name2)
154
155 def sort_binb_column(self, model, row1, row2):
156 value1 = model.get_value(row1, PackageListModel.COL_BINB)
157 value2 = model.get_value(row2, PackageListModel.COL_BINB)
158 value1_list = value1.split(', ')
159 value2_list = value2.split(', ')
160
161 value1 = value1_list[0]
162 value2 = value2_list[0]
163
164 cmp_res = cmp(value1, value2)
165 if cmp_res==0:
166 cmp_size = cmp(len(value1_list), len(value2_list))
167 if cmp_size==0:
168 name1 = model.get_value(row1, PackageListModel.COL_NAME)
169 name2 = model.get_value(row2, PackageListModel.COL_NAME)
170 return cmp(name1,name2)
171 else:
172 return cmp_size
173 else:
174 return cmp_res
175
176 def exclude_item_sort_func(self, model, iter1, iter2, user_data=None):
177 if user_data:
178 val1 = model.get_value(iter1, PackageListModel.COL_NAME)
179 val2 = model.get_value(iter2, PackageListModel.COL_NAME)
180 return self.cmp_vals(val1, val2, user_data)
181 else:
182 val1 = model.get_value(iter1, PackageListModel.COL_FADE_INC)
183 val2 = model.get_value(iter2, PackageListModel.COL_INC)
184 return ((val1 == True) and (val2 == False))
185
186 def include_item_sort_func(self, model, iter1, iter2, user_data=None):
187 if user_data:
188 val1 = model.get_value(iter1, PackageListModel.COL_NAME)
189 val2 = model.get_value(iter2, PackageListModel.COL_NAME)
190 return self.cmp_vals(val1, val2, user_data)
191 else:
192 val1 = model.get_value(iter1, PackageListModel.COL_INC)
193 val2 = model.get_value(iter2, PackageListModel.COL_INC)
194 return ((val1 == False) and (val2 == True))
195
196 def sort_func(self, model, iter1, iter2, user_data):
197 val1 = model.get_value(iter1, PackageListModel.COL_NAME)
198 val2 = model.get_value(iter2, PackageListModel.COL_NAME)
199 return self.cmp_vals(val1, val2, user_data)
200
201 def cmp_vals(self, val1, val2, user_data):
202 if val1 is None or val2 is None:
203 return 0
204 elif val1.startswith(user_data) and not val2.startswith(user_data):
205 return -1
206 elif not val1.startswith(user_data) and val2.startswith(user_data):
207 return 1
208 else:
209 return cmp(val1, val2)
210
211 def convert_vpath_to_path(self, view_model, view_path):
212 # view_model is the model sorted
213 # get the path of the model filtered
214 filtered_model_path = view_model.convert_path_to_child_path(view_path)
215 # get the model filtered
216 filtered_model = view_model.get_model()
217 # get the path of the original model
218 path = filtered_model.convert_path_to_child_path(filtered_model_path)
219 return path
220
221 def convert_path_to_vpath(self, view_model, path):
222 it = view_model.get_iter_first()
223 while it:
224 name = self.find_item_for_path(path)
225 view_name = view_model.get_value(it, PackageListModel.COL_NAME)
226 if view_name == name:
227 view_path = view_model.get_path(it)
228 return view_path
229 it = view_model.iter_next(it)
230 return None
231
232 """
233 The populate() function takes as input the data from a
234 bb.event.PackageInfo event and populates the package list.
235 """
236 def populate(self, pkginfolist):
237 # First clear the model, in case repopulating
238 self.clear()
239
240 def getpkgvalue(pkgdict, key, pkgname, defaultval = None):
241 value = pkgdict.get('%s_%s' % (key, pkgname), None)
242 if not value:
243 value = pkgdict.get(key, defaultval)
244 return value
245
246 for pkginfo in pkginfolist:
247 pn = pkginfo['PN']
248 pv = pkginfo['PV']
249 pr = pkginfo['PR']
250 pkg = pkginfo['PKG']
251 pkgv = getpkgvalue(pkginfo, 'PKGV', pkg)
252 pkgr = getpkgvalue(pkginfo, 'PKGR', pkg)
253 # PKGSIZE is artificial, will always be overridden with the package name if present
254 pkgsize = int(pkginfo.get('PKGSIZE_%s' % pkg, "0"))
255 # PKG_%s is the renamed version
256 pkg_rename = pkginfo.get('PKG_%s' % pkg, "")
257 # The rest may be overridden or not
258 section = getpkgvalue(pkginfo, 'SECTION', pkg, "")
259 summary = getpkgvalue(pkginfo, 'SUMMARY', pkg, "")
260 rdep = getpkgvalue(pkginfo, 'RDEPENDS', pkg, "")
261 rrec = getpkgvalue(pkginfo, 'RRECOMMENDS', pkg, "")
262 rprov = getpkgvalue(pkginfo, 'RPROVIDES', pkg, "")
263 files_list = getpkgvalue(pkginfo, 'FILES_INFO', pkg, "")
264 for i in rprov.split():
265 self.rprov_pkg[i] = pkg
266
267 recipe = pn + '-' + pv + '-' + pr
268
269 allow_empty = getpkgvalue(pkginfo, 'ALLOW_EMPTY', pkg, "")
270
271 if pkgsize == 0 and not allow_empty:
272 continue
273
274 size = HobPage._size_to_string(pkgsize)
275 self.set(self.append(), self.COL_NAME, pkg, self.COL_VER, pkgv,
276 self.COL_REV, pkgr, self.COL_RNM, pkg_rename,
277 self.COL_SEC, section, self.COL_SUM, summary,
278 self.COL_RDEP, rdep + ' ' + rrec,
279 self.COL_RPROV, rprov, self.COL_SIZE, size,
280 self.COL_RCP, recipe, self.COL_BINB, "",
281 self.COL_INC, False, self.COL_FONT, '10', self.COL_FLIST, files_list)
282
283 self.pn_path = {}
284 it = self.get_iter_first()
285 while it:
286 pn = self.get_value(it, self.COL_NAME)
287 path = self.get_path(it)
288 self.pn_path[pn] = path
289 it = self.iter_next(it)
290
291 """
292 Update the model, send out the notification.
293 """
294 def selection_change_notification(self):
295 self.emit("package-selection-changed")
296
297 """
298 Check whether the item at item_path is included or not
299 """
300 def path_included(self, item_path):
301 return self[item_path][self.COL_INC]
302
303 """
304 Add this item, and any of its dependencies, to the image contents
305 """
306 def include_item(self, item_path, binb=""):
307 if self.path_included(item_path):
308 return
309
310 item_name = self[item_path][self.COL_NAME]
311 item_deps = self[item_path][self.COL_RDEP]
312
313 self[item_path][self.COL_INC] = True
314
315 item_bin = self[item_path][self.COL_BINB].split(', ')
316 if binb and not binb in item_bin:
317 item_bin.append(binb)
318 self[item_path][self.COL_BINB] = ', '.join(item_bin).lstrip(', ')
319
320 if item_deps:
321 # Ensure all of the items deps are included and, where appropriate,
322 # add this item to their COL_BINB
323 for dep in item_deps.split(" "):
324 if dep.startswith('('):
325 continue
326 # If the contents model doesn't already contain dep, add it
327 dep_path = self.find_path_for_item(dep)
328 if not dep_path:
329 continue
330 dep_included = self.path_included(dep_path)
331
332 if dep_included and not dep in item_bin:
333 # don't set the COL_BINB to this item if the target is an
334 # item in our own COL_BINB
335 dep_bin = self[dep_path][self.COL_BINB].split(', ')
336 if not item_name in dep_bin:
337 dep_bin.append(item_name)
338 self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ')
339 elif not dep_included:
340 self.include_item(dep_path, binb=item_name)
341
342 def exclude_item(self, item_path):
343 if not self.path_included(item_path):
344 return
345
346 self[item_path][self.COL_INC] = False
347
348 item_name = self[item_path][self.COL_NAME]
349 item_deps = self[item_path][self.COL_RDEP]
350 if item_deps:
351 for dep in item_deps.split(" "):
352 if dep.startswith('('):
353 continue
354 dep_path = self.find_path_for_item(dep)
355 if not dep_path:
356 continue
357 dep_bin = self[dep_path][self.COL_BINB].split(', ')
358 if item_name in dep_bin:
359 dep_bin.remove(item_name)
360 self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ')
361
362 item_bin = self[item_path][self.COL_BINB].split(', ')
363 if item_bin:
364 for binb in item_bin:
365 binb_path = self.find_path_for_item(binb)
366 if not binb_path:
367 continue
368 self.exclude_item(binb_path)
369
370 """
371 Empty self.contents by setting the include of each entry to None
372 """
373 def reset(self):
374 it = self.get_iter_first()
375 while it:
376 self.set(it,
377 self.COL_INC, False,
378 self.COL_BINB, "")
379 it = self.iter_next(it)
380
381 self.selection_change_notification()
382
383 def get_selected_packages(self):
384 packagelist = []
385
386 it = self.get_iter_first()
387 while it:
388 if self.get_value(it, self.COL_INC):
389 name = self.get_value(it, self.COL_NAME)
390 packagelist.append(name)
391 it = self.iter_next(it)
392
393 return packagelist
394
395 def get_user_selected_packages(self):
396 packagelist = []
397
398 it = self.get_iter_first()
399 while it:
400 if self.get_value(it, self.COL_INC):
401 binb = self.get_value(it, self.COL_BINB)
402 if binb == "User Selected":
403 name = self.get_value(it, self.COL_NAME)
404 packagelist.append(name)
405 it = self.iter_next(it)
406
407 return packagelist
408
409 def get_selected_packages_toolchain(self):
410 packagelist = []
411
412 it = self.get_iter_first()
413 while it:
414 if self.get_value(it, self.COL_INC):
415 name = self.get_value(it, self.COL_NAME)
416 if name.endswith("-dev") or name.endswith("-dbg"):
417 packagelist.append(name)
418 it = self.iter_next(it)
419
420 return list(set(packagelist + self.__toolchain_required_packages__));
421
422 """
423 Package model may be incomplete, therefore when calling the
424 set_selected_packages(), some packages will not be set included.
425 Return the un-set packages list.
426 """
427 def set_selected_packages(self, packagelist, user_selected=False):
428 left = []
429 binb = 'User Selected' if user_selected else ''
430 for pn in packagelist:
431 if pn in self.pn_path.keys():
432 path = self.pn_path[pn]
433 self.include_item(item_path=path, binb=binb)
434 else:
435 left.append(pn)
436
437 self.selection_change_notification()
438 return left
439
440 """
441 Return the selected package size, unit is B.
442 """
443 def get_packages_size(self):
444 packages_size = 0
445 it = self.get_iter_first()
446 while it:
447 if self.get_value(it, self.COL_INC):
448 str_size = self.get_value(it, self.COL_SIZE)
449 if not str_size:
450 continue
451
452 packages_size += HobPage._string_to_size(str_size)
453
454 it = self.iter_next(it)
455 return packages_size
456
457 """
458 Resync the state of included items to a backup column before performing the fadeout visible effect
459 """
460 def resync_fadeout_column(self, model_first_iter=None):
461 it = model_first_iter
462 while it:
463 active = self.get_value(it, self.COL_INC)
464 self.set(it, self.COL_FADE_INC, active)
465 it = self.iter_next(it)
466
467#
468# RecipeListModel
469#
470class RecipeListModel(gtk.ListStore):
471 """
472 This class defines an gtk.ListStore subclass which will convert the output
473 of the bb.event.TargetsTreeGenerated event into a gtk.ListStore whilst also
474 providing convenience functions to access gtk.TreeModel subclasses which
475 provide filtered views of the data.
476 """
477 (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,
478 COL_REVISION, COL_HOMEPAGE, COL_BUGTRACKER, COL_FILE) = range(18)
479
480 __custom_image__ = "Start with an empty image recipe"
481
482 __gsignals__ = {
483 "recipe-selection-changed" : (gobject.SIGNAL_RUN_LAST,
484 gobject.TYPE_NONE,
485 ()),
486 }
487
488 """
489 """
490 def __init__(self):
491 gtk.ListStore.__init__ (self,
492 gobject.TYPE_STRING,
493 gobject.TYPE_STRING,
494 gobject.TYPE_STRING,
495 gobject.TYPE_STRING,
496 gobject.TYPE_STRING,
497 gobject.TYPE_STRING,
498 gobject.TYPE_STRING,
499 gobject.TYPE_BOOLEAN,
500 gobject.TYPE_BOOLEAN,
501 gobject.TYPE_STRING,
502 gobject.TYPE_STRING,
503 gobject.TYPE_BOOLEAN,
504 gobject.TYPE_STRING,
505 gobject.TYPE_STRING,
506 gobject.TYPE_STRING,
507 gobject.TYPE_STRING,
508 gobject.TYPE_STRING,
509 gobject.TYPE_STRING)
510 self.sort_column_id, self.sort_order = RecipeListModel.COL_NAME, gtk.SORT_ASCENDING
511
512 """
513 Find the model path for the item_name
514 Returns the path in the model or None
515 """
516 def find_path_for_item(self, item_name):
517 if self.non_target_name(item_name) or item_name not in self.pn_path.keys():
518 return None
519 else:
520 return self.pn_path[item_name]
521
522 def find_item_for_path(self, item_path):
523 return self[item_path][self.COL_NAME]
524
525 """
526 Helper method to determine whether name is a target pn
527 """
528 def non_target_name(self, name):
529 if name and ('-native' in name):
530 return True
531 return False
532
533 """
534 Helper function to determine whether an item is an item specified by filter
535 """
536 def tree_model_filter(self, model, it, filter):
537 name = model.get_value(it, self.COL_NAME)
538 if self.non_target_name(name):
539 return False
540
541 for key in filter.keys():
542 if key == self.COL_NAME:
543 if filter[key] != 'Search recipes by name' and filter[key] != 'Search package groups by name':
544 if filter[key] not in name:
545 return False
546 else:
547 if model.get_value(it, key) not in filter[key]:
548 return False
549 self.filtered_nb += 1
550
551 return True
552
553 def exclude_item_sort_func(self, model, iter1, iter2, user_data=None):
554 if user_data:
555 val1 = model.get_value(iter1, RecipeListModel.COL_NAME)
556 val2 = model.get_value(iter2, RecipeListModel.COL_NAME)
557 return self.cmp_vals(val1, val2, user_data)
558 else:
559 val1 = model.get_value(iter1, RecipeListModel.COL_FADE_INC)
560 val2 = model.get_value(iter2, RecipeListModel.COL_INC)
561 return ((val1 == True) and (val2 == False))
562
563 def include_item_sort_func(self, model, iter1, iter2, user_data=None):
564 if user_data:
565 val1 = model.get_value(iter1, RecipeListModel.COL_NAME)
566 val2 = model.get_value(iter2, RecipeListModel.COL_NAME)
567 return self.cmp_vals(val1, val2, user_data)
568 else:
569 val1 = model.get_value(iter1, RecipeListModel.COL_INC)
570 val2 = model.get_value(iter2, RecipeListModel.COL_INC)
571 return ((val1 == False) and (val2 == True))
572
573 def sort_func(self, model, iter1, iter2, user_data):
574 val1 = model.get_value(iter1, RecipeListModel.COL_NAME)
575 val2 = model.get_value(iter2, RecipeListModel.COL_NAME)
576 return self.cmp_vals(val1, val2, user_data)
577
578 def cmp_vals(self, val1, val2, user_data):
579 if val1 is None or val2 is None:
580 return 0
581 elif val1.startswith(user_data) and not val2.startswith(user_data):
582 return -1
583 elif not val1.startswith(user_data) and val2.startswith(user_data):
584 return 1
585 else:
586 return cmp(val1, val2)
587
588 """
589 Create, if required, and return a filtered gtk.TreeModelSort
590 containing only the items specified by filter
591 """
592 def tree_model(self, filter, excluded_items_ahead=False, included_items_ahead=False, search_data=None, initial=False):
593 model = self.filter_new()
594 self.filtered_nb = 0
595 model.set_visible_func(self.tree_model_filter, filter)
596
597 sort = gtk.TreeModelSort(model)
598 sort.connect ('sort-column-changed', self.sort_column_changed_cb)
599 if initial:
600 sort.set_sort_column_id(RecipeListModel.COL_NAME, gtk.SORT_ASCENDING)
601 sort.set_default_sort_func(None)
602 elif excluded_items_ahead:
603 sort.set_default_sort_func(self.exclude_item_sort_func, search_data)
604 elif included_items_ahead:
605 sort.set_default_sort_func(self.include_item_sort_func, search_data)
606 else:
607 if search_data and search_data!='Search recipes by name' and search_data!='Search package groups by name':
608 sort.set_default_sort_func(self.sort_func, search_data)
609 else:
610 sort.set_sort_column_id(self.sort_column_id, self.sort_order)
611 sort.set_default_sort_func(None)
612
613 sort.set_sort_func(RecipeListModel.COL_INC, self.sort_column, RecipeListModel.COL_INC)
614 sort.set_sort_func(RecipeListModel.COL_GROUP, self.sort_column, RecipeListModel.COL_GROUP)
615 sort.set_sort_func(RecipeListModel.COL_BINB, self.sort_binb_column)
616 sort.set_sort_func(RecipeListModel.COL_LIC, self.sort_column, RecipeListModel.COL_LIC)
617 return sort
618
619 def sort_column_changed_cb (self, data):
620 self.sort_column_id, self.sort_order = data.get_sort_column_id ()
621
622 def sort_column(self, model, row1, row2, col):
623 value1 = model.get_value(row1, col)
624 value2 = model.get_value(row2, col)
625 cmp_res = cmp(value1, value2)
626 if cmp_res!=0:
627 if col==RecipeListModel.COL_INC:
628 return -cmp_res
629 else:
630 return cmp_res
631 else:
632 name1 = model.get_value(row1, RecipeListModel.COL_NAME)
633 name2 = model.get_value(row2, RecipeListModel.COL_NAME)
634 return cmp(name1,name2)
635
636 def sort_binb_column(self, model, row1, row2):
637 value1 = model.get_value(row1, RecipeListModel.COL_BINB)
638 value2 = model.get_value(row2, RecipeListModel.COL_BINB)
639 value1_list = value1.split(', ')
640 value2_list = value2.split(', ')
641
642 value1 = value1_list[0]
643 value2 = value2_list[0]
644
645 cmp_res = cmp(value1, value2)
646 if cmp_res==0:
647 cmp_size = cmp(len(value1_list), len(value2_list))
648 if cmp_size==0:
649 name1 = model.get_value(row1, RecipeListModel.COL_NAME)
650 name2 = model.get_value(row2, RecipeListModel.COL_NAME)
651 return cmp(name1,name2)
652 else:
653 return cmp_size
654 else:
655 return cmp_res
656
657 def convert_vpath_to_path(self, view_model, view_path):
658 filtered_model_path = view_model.convert_path_to_child_path(view_path)
659 filtered_model = view_model.get_model()
660
661 # get the path of the original model
662 path = filtered_model.convert_path_to_child_path(filtered_model_path)
663 return path
664
665 def convert_path_to_vpath(self, view_model, path):
666 it = view_model.get_iter_first()
667 while it:
668 name = self.find_item_for_path(path)
669 view_name = view_model.get_value(it, RecipeListModel.COL_NAME)
670 if view_name == name:
671 view_path = view_model.get_path(it)
672 return view_path
673 it = view_model.iter_next(it)
674 return None
675
676 """
677 The populate() function takes as input the data from a
678 bb.event.TargetsTreeGenerated event and populates the RecipeList.
679 """
680 def populate(self, event_model):
681 # First clear the model, in case repopulating
682 self.clear()
683
684 # dummy image for prompt
685 self.set_in_list(self.__custom_image__, "Use 'Edit image recipe' to customize recipes and packages " \
686 "to be included in your image ")
687
688 for item in event_model["pn"]:
689 name = item
690 desc = event_model["pn"][item]["description"]
691 lic = event_model["pn"][item]["license"]
692 group = event_model["pn"][item]["section"]
693 inherits = event_model["pn"][item]["inherits"]
694 summary = event_model["pn"][item]["summary"]
695 version = event_model["pn"][item]["version"]
696 revision = event_model["pn"][item]["prevision"]
697 homepage = event_model["pn"][item]["homepage"]
698 bugtracker = event_model["pn"][item]["bugtracker"]
699 filename = event_model["pn"][item]["filename"]
700 install = []
701
702 depends = event_model["depends"].get(item, []) + event_model["rdepends-pn"].get(item, [])
703
704 if ('packagegroup.bbclass' in " ".join(inherits)):
705 atype = 'packagegroup'
706 elif ('/image.bbclass' in " ".join(inherits)):
707 if "edited" not in name:
708 atype = 'image'
709 install = event_model["rdepends-pkg"].get(item, []) + event_model["rrecs-pkg"].get(item, [])
710 elif ('meta-' in name):
711 atype = 'toolchain'
712 elif (name == 'dummy-image' or name == 'dummy-toolchain'):
713 atype = 'dummy'
714 else:
715 atype = 'recipe'
716
717 self.set(self.append(), self.COL_NAME, item, self.COL_DESC, desc,
718 self.COL_LIC, lic, self.COL_GROUP, group,
719 self.COL_DEPS, " ".join(depends), self.COL_BINB, "",
720 self.COL_TYPE, atype, self.COL_INC, False,
721 self.COL_IMG, False, self.COL_INSTALL, " ".join(install), self.COL_PN, item,
722 self.COL_SUMMARY, summary, self.COL_VERSION, version, self.COL_REVISION, revision,
723 self.COL_HOMEPAGE, homepage, self.COL_BUGTRACKER, bugtracker,
724 self.COL_FILE, filename)
725
726 self.pn_path = {}
727 it = self.get_iter_first()
728 while it:
729 pn = self.get_value(it, self.COL_NAME)
730 path = self.get_path(it)
731 self.pn_path[pn] = path
732 it = self.iter_next(it)
733
734 def set_in_list(self, item, desc):
735 self.set(self.append(), self.COL_NAME, item,
736 self.COL_DESC, desc,
737 self.COL_LIC, "", self.COL_GROUP, "",
738 self.COL_DEPS, "", self.COL_BINB, "",
739 self.COL_TYPE, "image", self.COL_INC, False,
740 self.COL_IMG, False, self.COL_INSTALL, "", self.COL_PN, item,
741 self.COL_SUMMARY, "", self.COL_VERSION, "", self.COL_REVISION, "",
742 self.COL_HOMEPAGE, "", self.COL_BUGTRACKER, "")
743 self.pn_path = {}
744 it = self.get_iter_first()
745 while it:
746 pn = self.get_value(it, self.COL_NAME)
747 path = self.get_path(it)
748 self.pn_path[pn] = path
749 it = self.iter_next(it)
750
751 """
752 Update the model, send out the notification.
753 """
754 def selection_change_notification(self):
755 self.emit("recipe-selection-changed")
756
757 def path_included(self, item_path):
758 return self[item_path][self.COL_INC]
759
760 """
761 Add this item, and any of its dependencies, to the image contents
762 """
763 def include_item(self, item_path, binb="", image_contents=False):
764 if self.path_included(item_path):
765 return
766
767 item_name = self[item_path][self.COL_NAME]
768 item_deps = self[item_path][self.COL_DEPS]
769
770 self[item_path][self.COL_INC] = True
771
772 item_bin = self[item_path][self.COL_BINB].split(', ')
773 if binb and not binb in item_bin:
774 item_bin.append(binb)
775 self[item_path][self.COL_BINB] = ', '.join(item_bin).lstrip(', ')
776
777 # We want to do some magic with things which are brought in by the
778 # base image so tag them as so
779 if image_contents:
780 self[item_path][self.COL_IMG] = True
781
782 if item_deps:
783 # Ensure all of the items deps are included and, where appropriate,
784 # add this item to their COL_BINB
785 for dep in item_deps.split(" "):
786 # If the contents model doesn't already contain dep, add it
787 dep_path = self.find_path_for_item(dep)
788 if not dep_path:
789 continue
790 dep_included = self.path_included(dep_path)
791
792 if dep_included and not dep in item_bin:
793 # don't set the COL_BINB to this item if the target is an
794 # item in our own COL_BINB
795 dep_bin = self[dep_path][self.COL_BINB].split(', ')
796 if not item_name in dep_bin:
797 dep_bin.append(item_name)
798 self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ')
799 elif not dep_included:
800 self.include_item(dep_path, binb=item_name, image_contents=image_contents)
801 dep_bin = self[item_path][self.COL_BINB].split(', ')
802 if self[item_path][self.COL_NAME] in dep_bin:
803 dep_bin.remove(self[item_path][self.COL_NAME])
804 self[item_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ')
805
806 def exclude_item(self, item_path):
807 if not self.path_included(item_path):
808 return
809
810 self[item_path][self.COL_INC] = False
811
812 item_name = self[item_path][self.COL_NAME]
813 item_deps = self[item_path][self.COL_DEPS]
814 if item_deps:
815 for dep in item_deps.split(" "):
816 dep_path = self.find_path_for_item(dep)
817 if not dep_path:
818 continue
819 dep_bin = self[dep_path][self.COL_BINB].split(', ')
820 if item_name in dep_bin:
821 dep_bin.remove(item_name)
822 self[dep_path][self.COL_BINB] = ', '.join(dep_bin).lstrip(', ')
823
824 item_bin = self[item_path][self.COL_BINB].split(', ')
825 if item_bin:
826 for binb in item_bin:
827 binb_path = self.find_path_for_item(binb)
828 if not binb_path:
829 continue
830 self.exclude_item(binb_path)
831
832 def reset(self):
833 it = self.get_iter_first()
834 while it:
835 self.set(it,
836 self.COL_INC, False,
837 self.COL_BINB, "",
838 self.COL_IMG, False)
839 it = self.iter_next(it)
840
841 self.selection_change_notification()
842
843 """
844 Returns two lists. One of user selected recipes and the other containing
845 all selected recipes
846 """
847 def get_selected_recipes(self):
848 allrecipes = []
849 userrecipes = []
850
851 it = self.get_iter_first()
852 while it:
853 if self.get_value(it, self.COL_INC):
854 name = self.get_value(it, self.COL_PN)
855 type = self.get_value(it, self.COL_TYPE)
856 if type != "image":
857 allrecipes.append(name)
858 sel = "User Selected" in self.get_value(it, self.COL_BINB)
859 if sel:
860 userrecipes.append(name)
861 it = self.iter_next(it)
862
863 return list(set(userrecipes)), list(set(allrecipes))
864
865 def set_selected_recipes(self, recipelist):
866 for pn in recipelist:
867 if pn in self.pn_path.keys():
868 path = self.pn_path[pn]
869 self.include_item(item_path=path,
870 binb="User Selected")
871 self.selection_change_notification()
872
873 def get_selected_image(self):
874 it = self.get_iter_first()
875 while it:
876 if self.get_value(it, self.COL_INC):
877 name = self.get_value(it, self.COL_PN)
878 type = self.get_value(it, self.COL_TYPE)
879 if type == "image":
880 sel = "User Selected" in self.get_value(it, self.COL_BINB)
881 if sel:
882 return name
883 it = self.iter_next(it)
884 return None
885
886 def set_selected_image(self, img):
887 if not img:
888 return
889 self.reset()
890 path = self.find_path_for_item(img)
891 self.include_item(item_path=path,
892 binb="User Selected",
893 image_contents=True)
894 self.selection_change_notification()
895
896 def set_custom_image_version(self, version):
897 self.custom_image_version = version
898
899 def get_custom_image_version(self):
900 return self.custom_image_version
901
902 def is_custom_image(self):
903 return self.get_selected_image() == self.__custom_image__