summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Lock <josh@linux.intel.com>2011-01-12 12:24:04 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2011-02-24 15:54:52 +0000
commit9b43eaff99615d8bd58b2f3a54c280e5470d3a9c (patch)
tree1aa1ee1e41d269887e1dc80f0e751237ccc85074
parenta13304e1c6500db95823961a5a34849db46037e3 (diff)
downloadpoky-9b43eaff99615d8bd58b2f3a54c280e5470d3a9c.tar.gz
bitbake: introduce crumbs.TaskListModel a gtk.ListStore subclass
Provide a gtk.ListStore subclass which includes a function, populate(), which takes as input the data emitted by bb.event.TargetsTreeGenerated and fills the ListStore model appropriately. Furthermore convenience functions are provided by which the caller can get gtk.TreeModel subclasses which provide filtered views of the data. Signed-off-by: Joshua Lock <josh@linux.intel.com>
-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