diff options
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/hoblistmodel.py')
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hoblistmodel.py | 903 |
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 | |||
23 | import gtk | ||
24 | import gobject | ||
25 | from bb.ui.crumbs.hobpages import HobPage | ||
26 | |||
27 | # | ||
28 | # PackageListModel | ||
29 | # | ||
30 | class 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 | # | ||
470 | class 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__ | ||