summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bitbake/lib/bb/ui/crumbs/tasklistmodel.py346
1 files changed, 346 insertions, 0 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/tasklistmodel.py b/bitbake/lib/bb/ui/crumbs/tasklistmodel.py
new file mode 100644
index 0000000000..a83a176ddc
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/tasklistmodel.py
@@ -0,0 +1,346 @@
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#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21import gtk
22import gobject
23
24class TaskListModel(gtk.ListStore):
25 """
26 This class defines an gtk.ListStore subclass which will convert the output
27 of the bb.event.TargetsTreeGenerated event into a gtk.ListStore whilst also
28 providing convenience functions to access gtk.TreeModel subclasses which
29 provide filtered views of the data.
30 """
31 (COL_NAME, COL_DESC, COL_LIC, COL_GROUP, COL_DEPS, COL_BINB, COL_TYPE, COL_INC) = range(8)
32
33 __gsignals__ = {
34 "tasklist-populated" : (gobject.SIGNAL_RUN_LAST,
35 gobject.TYPE_NONE,
36 ())
37 }
38
39 """
40 """
41 def __init__(self):
42 self.contents = None
43 self.tasks = None
44 self.packages = None
45 self.images = None
46
47 gtk.ListStore.__init__ (self,
48 gobject.TYPE_STRING,
49 gobject.TYPE_STRING,
50 gobject.TYPE_STRING,
51 gobject.TYPE_STRING,
52 gobject.TYPE_STRING,
53 gobject.TYPE_STRING,
54 gobject.TYPE_STRING,
55 gobject.TYPE_BOOLEAN)
56
57 """
58 Create, if required, and return a filtered gtk.TreeModel
59 containing only the items which are to be included in the
60 image
61 """
62 def contents_model(self):
63 if not self.contents:
64 self.contents = self.filter_new()
65 self.contents.set_visible_column(self.COL_INC)
66 return self.contents
67
68 """
69 Helper function to determine whether an item is a task
70 """
71 def task_model_filter(self, model, it):
72 if model.get_value(it, self.COL_TYPE) == 'task':
73 return True
74 else:
75 return False
76
77 """
78 Create, if required, and return a filtered gtk.TreeModel
79 containing only the items which are tasks
80 """
81 def tasks_model(self):
82 if not self.tasks:
83 self.tasks = self.filter_new()
84 self.tasks.set_visible_func(self.task_model_filter)
85 return self.tasks
86
87 """
88 Helper function to determine whether an item is an image
89 """
90 def image_model_filter(self, model, it):
91 if model.get_value(it, self.COL_TYPE) == 'image':
92 return True
93 else:
94 return False
95
96 """
97 Create, if required, and return a filtered gtk.TreeModel
98 containing only the items which are images
99 """
100 def images_model(self):
101 if not self.images:
102 self.images = self.filter_new()
103 self.images.set_visible_func(self.image_model_filter)
104 return self.images
105
106 """
107 Helper function to determine whether an item is a package
108 """
109 def package_model_filter(self, model, it):
110 if model.get_value(it, self.COL_TYPE) == 'package':
111 return True
112 else:
113 return False
114
115 """
116 Create, if required, and return a filtered gtk.TreeModel
117 containing only the items which are packages
118 """
119 def packages_model(self):
120 if not self.packages:
121 self.packages = self.filter_new()
122 self.packages.set_visible_func(self.package_model_filter)
123 return self.packages
124
125 """
126 The populate() function takes as input the data from a
127 bb.event.TargetsTreeGenerated event and populates the TaskList.
128 Once the population is done it emits gsignal tasklist-populated
129 to notify any listeners that the model is ready
130 """
131 def populate(self, event_model):
132 for item in event_model["pn"]:
133 atype = 'package'
134 name = item
135 summary = event_model["pn"][item]["summary"]
136 license = event_model["pn"][item]["license"]
137 group = event_model["pn"][item]["section"]
138
139 depends = event_model["depends"].get(item, "")
140 rdepends = event_model["rdepends-pn"].get(item, "")
141 depends = depends + rdepends
142 self.squish(depends)
143 deps = " ".join(depends)
144
145 if name.count('task-') > 0:
146 atype = 'task'
147 elif name.count('-image-') > 0:
148 atype = 'image'
149
150 self.set(self.append(), self.COL_NAME, name, self.COL_DESC, summary,
151 self.COL_LIC, license, self.COL_GROUP, group,
152 self.COL_DEPS, deps, self.COL_BINB, "",
153 self.COL_TYPE, atype, self.COL_INC, False)
154
155 self.emit("tasklist-populated")
156
157 """
158 squish lst so that it doesn't contain any duplicates
159 """
160 def squish(self, lst):
161 seen = {}
162 for l in lst:
163 seen[l] = 1
164 return seen.keys()
165
166 """
167 Mark the item at path as not included
168 NOTE:
169 path should be a gtk.TreeModelPath into self (not a filtered model)
170 """
171 def remove_item_path(self, path):
172 self[path][self.COL_BINB] = ""
173 self[path][self.COL_INC] = False
174
175 """
176 """
177 def mark(self, path):
178 name = self[path][self.COL_NAME]
179 it = self.get_iter_first()
180 removals = []
181 #print("Removing %s" % name)
182
183 self.remove_item_path(path)
184
185 # Remove all dependent packages, update binb
186 while it:
187 path = self.get_path(it)
188 # FIXME: need to ensure partial name matching doesn't happen, regexp?
189 if self[path][self.COL_INC] and self[path][self.COL_DEPS].count(name):
190 #print("%s depended on %s, marking for removal" % (self[path][self.COL_NAME], name))
191 # found a dependency, remove it
192 self.mark(path)
193 if self[path][self.COL_INC] and self[path][self.COL_BINB].count(name):
194 binb = self.find_alt_dependency(self[path][self.COL_NAME])
195 #print("%s was brought in by %s, binb set to %s" % (self[path][self.COL_NAME], name, binb))
196 self[path][self.COL_BINB] = binb
197 it = self.iter_next(it)
198
199 """
200 """
201 def sweep_up(self):
202 removals = []
203 it = self.get_iter_first()
204
205 while it:
206 path = self.get_path(it)
207 binb = self[path][self.COL_BINB]
208 if binb == "" or binb is None:
209 #print("Sweeping up %s" % self[path][self.COL_NAME])
210 if not path in removals:
211 removals.extend(path)
212 it = self.iter_next(it)
213
214 while removals:
215 path = removals.pop()
216 self.mark(path)
217
218 """
219 Remove an item from the contents
220 """
221 def remove_item(self, path):
222 self.mark(path)
223 self.sweep_up()
224
225 """
226 Find the name of an item in the image contents which depends on the item
227 at contents_path returns either an item name (str) or None
228 NOTE:
229 contents_path must be a path in the self.contents gtk.TreeModel
230 """
231 def find_alt_dependency(self, name):
232 it = self.get_iter_first()
233 while it:
234 # iterate all items in the model
235 path = self.get_path(it)
236 deps = self[path][self.COL_DEPS]
237 itname = self[path][self.COL_NAME]
238 inc = self[path][self.COL_INC]
239 if itname != name and inc and deps.count(name) > 0:
240 # if this item depends on the item, return this items name
241 #print("%s depends on %s" % (itname, name))
242 return itname
243 it = self.iter_next(it)
244 return ""
245
246 """
247 Convert a path in self to a path in the filtered contents model
248 """
249 def contents_path_for_path(self, path):
250 return self.contents.convert_child_path_to_path(path)
251
252 """
253 Check the self.contents gtk.TreeModel for an item
254 where COL_NAME matches item_name
255 Returns True if a match is found, False otherwise
256 """
257 def contents_includes_name(self, item_name):
258 it = self.contents.get_iter_first()
259 while it:
260 path = self.contents.get_path(it)
261 if self.contents[path][self.COL_NAME] == item_name:
262 return True
263 it = self.contents.iter_next(it)
264 return False
265
266 """
267 Add this item, and any of its dependencies, to the image contents
268 """
269 def include_item(self, item_path, binb=""):
270 name = self[item_path][self.COL_NAME]
271 deps = self[item_path][self.COL_DEPS]
272 cur_inc = self[item_path][self.COL_INC]
273 #print("Adding %s for %s dependency" % (name, binb))
274 if not cur_inc:
275 self[item_path][self.COL_INC] = True
276 self[item_path][self.COL_BINB] = binb
277 if deps:
278 #print("Dependencies of %s are %s" % (name, deps))
279 # add all of the deps and set their binb to this item
280 for dep in deps.split(" "):
281 # FIXME: this skipping virtuals can't be right? Unless we choose only to show target
282 # packages? In which case we should handle this server side...
283 # If the contents model doesn't already contain dep, add it
284 if not dep.startswith("virtual") and not self.contents_includes_name(dep):
285 path = self.find_path_for_item(dep)
286 if path:
287 self.include_item(path, name)
288 else:
289 pass
290
291 """
292 Find the model path for the item_name
293 Returns the path in the model or None
294 """
295 def find_path_for_item(self, item_name):
296 it = self.get_iter_first()
297 path = None
298 while it:
299 path = self.get_path(it)
300 if (self[path][self.COL_NAME] == item_name):
301 return path
302 else:
303 it = self.iter_next(it)
304 return None
305
306 """
307 Empty self.contents by setting the include of each entry to None
308 """
309 def reset(self):
310 it = self.contents.get_iter_first()
311 while it:
312 path = self.contents.get_path(it)
313 opath = self.contents.convert_path_to_child_path(path)
314 self[opath][self.COL_INC] = False
315 self[opath][self.COL_BINB] = ""
316 # As we've just removed the first item...
317 it = self.contents.get_iter_first()
318
319 """
320 Returns True if one of the selected tasks is an image, False otherwise
321 """
322 def targets_contains_image(self):
323 it = self.images.get_iter_first()
324 while it:
325 path = self.images.get_path(it)
326 inc = self.images[path][self.COL_INC]
327 if inc:
328 return True
329 it = self.images.iter_next(it)
330 return False
331
332 """
333 Return a list of all selected items which are not -native or -cross
334 """
335 def get_targets(self):
336 tasks = []
337
338 it = self.contents.get_iter_first()
339 while it:
340 path = self.contents.get_path(it)
341 name = self.contents[path][self.COL_NAME]
342 stype = self.contents[path][self.COL_TYPE]
343 if not name.count('-native') and not name.count('-cross'):
344 tasks.append(name)
345 it = self.contents.iter_next(it)
346 return tasks