diff options
author | bavery <brian.avery@intel.com> | 2016-02-29 10:26:02 -0800 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-03-02 22:41:23 +0000 |
commit | a9dc72f08bf5bdd898fba429729acee0e7305838 (patch) | |
tree | fa1e320398a1939df372363fbbfd79a5e58ae933 /bitbake/lib/bb | |
parent | 27468dbc3aa4ed71a20f706d4a65dfa29c4dd733 (diff) | |
download | poky-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')
-rwxr-xr-x | bitbake/lib/bb/ui/crumbs/builddetailspage.py | 437 | ||||
-rwxr-xr-x | bitbake/lib/bb/ui/crumbs/builder.py | 1534 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/advancedsettingsdialog.py | 341 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/parsingwarningsdialog.py | 163 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py | 90 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/retrieveimagedialog.py | 51 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/saveimagedialog.py | 159 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/simplesettingsdialog.py | 891 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hobeventhandler.py | 645 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hoblistmodel.py | 903 | ||||
-rwxr-xr-x | bitbake/lib/bb/ui/crumbs/hobpages.py | 128 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/imageconfigurationpage.py | 561 | ||||
-rwxr-xr-x | bitbake/lib/bb/ui/crumbs/imagedetailspage.py | 705 | ||||
-rwxr-xr-x | bitbake/lib/bb/ui/crumbs/packageselectionpage.py | 355 | ||||
-rwxr-xr-x | bitbake/lib/bb/ui/crumbs/recipeselectionpage.py | 335 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/sanitycheckpage.py | 85 | ||||
-rwxr-xr-x | bitbake/lib/bb/ui/hob.py | 109 |
17 files changed, 0 insertions, 7492 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/builddetailspage.py b/bitbake/lib/bb/ui/crumbs/builddetailspage.py deleted file mode 100755 index 7fc690e2fa..0000000000 --- a/bitbake/lib/bb/ui/crumbs/builddetailspage.py +++ /dev/null | |||
@@ -1,437 +0,0 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # | ||
3 | # BitBake Graphical GTK User Interface | ||
4 | # | ||
5 | # Copyright (C) 2012 Intel Corporation | ||
6 | # | ||
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 pango | ||
25 | import gobject | ||
26 | import bb.process | ||
27 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
28 | from bb.ui.crumbs.hobwidget import hic, HobNotebook, HobAltButton, HobWarpCellRendererText, HobButton, HobInfoButton | ||
29 | from bb.ui.crumbs.runningbuild import RunningBuildTreeView | ||
30 | from bb.ui.crumbs.runningbuild import BuildFailureTreeView | ||
31 | from bb.ui.crumbs.hobpages import HobPage | ||
32 | from bb.ui.crumbs.hobcolor import HobColors | ||
33 | |||
34 | class BuildConfigurationTreeView(gtk.TreeView): | ||
35 | def __init__ (self): | ||
36 | gtk.TreeView.__init__(self) | ||
37 | self.set_rules_hint(False) | ||
38 | self.set_headers_visible(False) | ||
39 | self.set_property("hover-expand", True) | ||
40 | self.get_selection().set_mode(gtk.SELECTION_SINGLE) | ||
41 | |||
42 | # The icon that indicates whether we're building or failed. | ||
43 | renderer0 = gtk.CellRendererText() | ||
44 | renderer0.set_property('font-desc', pango.FontDescription('courier bold 12')) | ||
45 | col0 = gtk.TreeViewColumn ("Name", renderer0, text=0) | ||
46 | self.append_column (col0) | ||
47 | |||
48 | # The message of configuration. | ||
49 | renderer1 = HobWarpCellRendererText(col_number=1) | ||
50 | col1 = gtk.TreeViewColumn ("Values", renderer1, text=1) | ||
51 | self.append_column (col1) | ||
52 | |||
53 | def set_vars(self, key="", var=[""]): | ||
54 | d = {} | ||
55 | if type(var) == str: | ||
56 | d = {key: [var]} | ||
57 | elif type(var) == list and len(var) > 1: | ||
58 | #create the sub item line | ||
59 | l = [] | ||
60 | text = "" | ||
61 | for item in var: | ||
62 | text = " - " + item | ||
63 | l.append(text) | ||
64 | d = {key: var} | ||
65 | |||
66 | return d | ||
67 | |||
68 | def set_config_model(self, show_vars): | ||
69 | listmodel = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING) | ||
70 | parent = None | ||
71 | for var in show_vars: | ||
72 | for subitem in var.items(): | ||
73 | name = subitem[0] | ||
74 | is_parent = True | ||
75 | for value in subitem[1]: | ||
76 | if is_parent: | ||
77 | parent = listmodel.append(parent, (name, value)) | ||
78 | is_parent = False | ||
79 | else: | ||
80 | listmodel.append(parent, (None, value)) | ||
81 | name = " - " | ||
82 | parent = None | ||
83 | # renew the tree model after get the configuration messages | ||
84 | self.set_model(listmodel) | ||
85 | |||
86 | def show(self, src_config_info, src_params): | ||
87 | vars = [] | ||
88 | vars.append(self.set_vars("BB version:", src_params.bb_version)) | ||
89 | vars.append(self.set_vars("Target arch:", src_params.target_arch)) | ||
90 | vars.append(self.set_vars("Target OS:", src_params.target_os)) | ||
91 | vars.append(self.set_vars("Machine:", src_config_info.curr_mach)) | ||
92 | vars.append(self.set_vars("Distro:", src_config_info.curr_distro)) | ||
93 | vars.append(self.set_vars("Distro version:", src_params.distro_version)) | ||
94 | vars.append(self.set_vars("SDK machine:", src_config_info.curr_sdk_machine)) | ||
95 | vars.append(self.set_vars("Tune features:", src_params.tune_pkgarch)) | ||
96 | vars.append(self.set_vars("Layers:", src_config_info.layers)) | ||
97 | |||
98 | for path in src_config_info.layers: | ||
99 | import os, os.path | ||
100 | if os.path.exists(path): | ||
101 | branch = bb.process.run('cd %s; git branch | grep "^* " | tr -d "* "' % path)[0] | ||
102 | if branch.startswith("fatal:"): | ||
103 | branch = "(unknown)" | ||
104 | if branch: | ||
105 | branch = branch.strip('\n') | ||
106 | vars.append(self.set_vars("Branch:", branch)) | ||
107 | break | ||
108 | |||
109 | self.set_config_model(vars) | ||
110 | |||
111 | def reset(self): | ||
112 | self.set_model(None) | ||
113 | |||
114 | # | ||
115 | # BuildDetailsPage | ||
116 | # | ||
117 | |||
118 | class BuildDetailsPage (HobPage): | ||
119 | |||
120 | def __init__(self, builder): | ||
121 | super(BuildDetailsPage, self).__init__(builder, "Building ...") | ||
122 | |||
123 | self.num_of_issues = 0 | ||
124 | self.endpath = (0,) | ||
125 | # create visual elements | ||
126 | self.create_visual_elements() | ||
127 | |||
128 | def create_visual_elements(self): | ||
129 | # create visual elements | ||
130 | self.vbox = gtk.VBox(False, 12) | ||
131 | |||
132 | self.progress_box = gtk.VBox(False, 12) | ||
133 | self.task_status = gtk.Label("\n") # to ensure layout is correct | ||
134 | self.task_status.set_alignment(0.0, 0.5) | ||
135 | self.progress_box.pack_start(self.task_status, expand=False, fill=False) | ||
136 | self.progress_hbox = gtk.HBox(False, 6) | ||
137 | self.progress_box.pack_end(self.progress_hbox, expand=True, fill=True) | ||
138 | self.progress_bar = HobProgressBar() | ||
139 | self.progress_hbox.pack_start(self.progress_bar, expand=True, fill=True) | ||
140 | self.stop_button = HobAltButton("Stop") | ||
141 | self.stop_button.connect("clicked", self.stop_button_clicked_cb) | ||
142 | self.stop_button.set_sensitive(False) | ||
143 | self.progress_hbox.pack_end(self.stop_button, expand=False, fill=False) | ||
144 | |||
145 | self.notebook = HobNotebook() | ||
146 | self.config_tv = BuildConfigurationTreeView() | ||
147 | self.scrolled_view_config = gtk.ScrolledWindow () | ||
148 | self.scrolled_view_config.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) | ||
149 | self.scrolled_view_config.add(self.config_tv) | ||
150 | self.notebook.append_page(self.scrolled_view_config, "Build configuration") | ||
151 | |||
152 | self.failure_tv = BuildFailureTreeView() | ||
153 | self.failure_model = self.builder.handler.build.model.failure_model() | ||
154 | self.failure_tv.set_model(self.failure_model) | ||
155 | self.scrolled_view_failure = gtk.ScrolledWindow () | ||
156 | self.scrolled_view_failure.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) | ||
157 | self.scrolled_view_failure.add(self.failure_tv) | ||
158 | self.notebook.append_page(self.scrolled_view_failure, "Issues") | ||
159 | |||
160 | self.build_tv = RunningBuildTreeView(readonly=True, hob=True) | ||
161 | self.build_tv.set_model(self.builder.handler.build.model) | ||
162 | self.scrolled_view_build = gtk.ScrolledWindow () | ||
163 | self.scrolled_view_build.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) | ||
164 | self.scrolled_view_build.add(self.build_tv) | ||
165 | self.notebook.append_page(self.scrolled_view_build, "Log") | ||
166 | |||
167 | self.builder.handler.build.model.connect_after("row-changed", self.scroll_to_present_row, self.scrolled_view_build.get_vadjustment(), self.build_tv) | ||
168 | |||
169 | self.button_box = gtk.HBox(False, 6) | ||
170 | self.back_button = HobAltButton('<< Back') | ||
171 | self.back_button.connect("clicked", self.back_button_clicked_cb) | ||
172 | self.button_box.pack_start(self.back_button, expand=False, fill=False) | ||
173 | |||
174 | def update_build_status(self, current, total, task): | ||
175 | recipe_path, recipe_task = task.split(", ") | ||
176 | recipe = os.path.basename(recipe_path).rstrip(".bb") | ||
177 | tsk_msg = "<b>Running task %s of %s:</b> %s\n<b>Recipe:</b> %s" % (current, total, recipe_task, recipe) | ||
178 | self.task_status.set_markup(tsk_msg) | ||
179 | self.stop_button.set_sensitive(True) | ||
180 | |||
181 | def reset_build_status(self): | ||
182 | self.task_status.set_markup("\n") # to ensure layout is correct | ||
183 | self.endpath = (0,) | ||
184 | |||
185 | def show_issues(self): | ||
186 | self.num_of_issues += 1 | ||
187 | self.notebook.show_indicator_icon("Issues", self.num_of_issues) | ||
188 | self.notebook.queue_draw() | ||
189 | |||
190 | def reset_issues(self): | ||
191 | self.num_of_issues = 0 | ||
192 | self.notebook.hide_indicator_icon("Issues") | ||
193 | |||
194 | def _remove_all_widget(self): | ||
195 | children = self.vbox.get_children() or [] | ||
196 | for child in children: | ||
197 | self.vbox.remove(child) | ||
198 | children = self.box_group_area.get_children() or [] | ||
199 | for child in children: | ||
200 | self.box_group_area.remove(child) | ||
201 | children = self.get_children() or [] | ||
202 | for child in children: | ||
203 | self.remove(child) | ||
204 | |||
205 | def add_build_fail_top_bar(self, actions, log_file=None): | ||
206 | primary_action = "Edit %s" % actions | ||
207 | |||
208 | color = HobColors.ERROR | ||
209 | build_fail_top = gtk.EventBox() | ||
210 | #build_fail_top.set_size_request(-1, 200) | ||
211 | build_fail_top.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) | ||
212 | |||
213 | build_fail_tab = gtk.Table(14, 46, True) | ||
214 | build_fail_top.add(build_fail_tab) | ||
215 | |||
216 | icon = gtk.Image() | ||
217 | icon_pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_INDI_ERROR_FILE) | ||
218 | icon.set_from_pixbuf(icon_pix_buffer) | ||
219 | build_fail_tab.attach(icon, 1, 4, 0, 6) | ||
220 | |||
221 | label = gtk.Label() | ||
222 | label.set_alignment(0.0, 0.5) | ||
223 | label.set_markup("<span size='x-large'><b>%s</b></span>" % self.title) | ||
224 | build_fail_tab.attach(label, 4, 26, 0, 6) | ||
225 | |||
226 | label = gtk.Label() | ||
227 | label.set_alignment(0.0, 0.5) | ||
228 | # Ensure variable disk_full is defined | ||
229 | if not hasattr(self.builder, 'disk_full'): | ||
230 | self.builder.disk_full = False | ||
231 | |||
232 | if self.builder.disk_full: | ||
233 | markup = "<span size='medium'>There is no disk space left, so Hob cannot finish building your image. Free up some disk space\n" | ||
234 | markup += "and restart the build. Check the \"Issues\" tab for more details</span>" | ||
235 | label.set_markup(markup) | ||
236 | else: | ||
237 | label.set_markup("<span size='medium'>Check the \"Issues\" information for more details</span>") | ||
238 | build_fail_tab.attach(label, 4, 40, 4, 9) | ||
239 | |||
240 | # create button 'Edit packages' | ||
241 | action_button = HobButton(primary_action) | ||
242 | #action_button.set_size_request(-1, 40) | ||
243 | action_button.set_tooltip_text("Edit the %s parameters" % actions) | ||
244 | action_button.connect('clicked', self.failure_primary_action_button_clicked_cb, primary_action) | ||
245 | |||
246 | if log_file: | ||
247 | open_log_button = HobAltButton("Open log") | ||
248 | open_log_button.set_relief(gtk.RELIEF_HALF) | ||
249 | open_log_button.set_tooltip_text("Open the build's log file") | ||
250 | open_log_button.connect('clicked', self.open_log_button_clicked_cb, log_file) | ||
251 | |||
252 | attach_pos = (24 if log_file else 14) | ||
253 | file_bug_button = HobAltButton('File a bug') | ||
254 | file_bug_button.set_relief(gtk.RELIEF_HALF) | ||
255 | file_bug_button.set_tooltip_text("Open the Yocto Project bug tracking website") | ||
256 | file_bug_button.connect('clicked', self.failure_activate_file_bug_link_cb) | ||
257 | |||
258 | if not self.builder.disk_full: | ||
259 | build_fail_tab.attach(action_button, 4, 13, 9, 12) | ||
260 | if log_file: | ||
261 | build_fail_tab.attach(open_log_button, 14, 23, 9, 12) | ||
262 | build_fail_tab.attach(file_bug_button, attach_pos, attach_pos + 9, 9, 12) | ||
263 | |||
264 | else: | ||
265 | restart_build = HobButton("Restart the build") | ||
266 | restart_build.set_tooltip_text("Restart the build") | ||
267 | restart_build.connect('clicked', self.restart_build_button_clicked_cb) | ||
268 | |||
269 | build_fail_tab.attach(restart_build, 4, 13, 9, 12) | ||
270 | build_fail_tab.attach(action_button, 14, 23, 9, 12) | ||
271 | if log_file: | ||
272 | build_fail_tab.attach(open_log_button, attach_pos, attach_pos + 9, 9, 12) | ||
273 | |||
274 | self.builder.disk_full = False | ||
275 | return build_fail_top | ||
276 | |||
277 | def show_fail_page(self, title): | ||
278 | self._remove_all_widget() | ||
279 | self.title = "Hob cannot build your %s" % title | ||
280 | |||
281 | self.build_fail_bar = self.add_build_fail_top_bar(title, self.builder.current_logfile) | ||
282 | |||
283 | self.pack_start(self.group_align, expand=True, fill=True) | ||
284 | self.box_group_area.pack_start(self.build_fail_bar, expand=False, fill=False) | ||
285 | self.box_group_area.pack_start(self.vbox, expand=True, fill=True) | ||
286 | |||
287 | self.vbox.pack_start(self.notebook, expand=True, fill=True) | ||
288 | self.show_all() | ||
289 | self.notebook.set_page("Issues") | ||
290 | self.back_button.hide() | ||
291 | |||
292 | def add_build_stop_top_bar(self, action, log_file=None): | ||
293 | color = HobColors.LIGHT_GRAY | ||
294 | build_stop_top = gtk.EventBox() | ||
295 | #build_stop_top.set_size_request(-1, 200) | ||
296 | build_stop_top.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) | ||
297 | build_stop_top.set_flags(gtk.CAN_DEFAULT) | ||
298 | build_stop_top.grab_default() | ||
299 | |||
300 | build_stop_tab = gtk.Table(11, 46, True) | ||
301 | build_stop_top.add(build_stop_tab) | ||
302 | |||
303 | icon = gtk.Image() | ||
304 | icon_pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_INFO_HOVER_FILE) | ||
305 | icon.set_from_pixbuf(icon_pix_buffer) | ||
306 | build_stop_tab.attach(icon, 1, 4, 0, 6) | ||
307 | |||
308 | label = gtk.Label() | ||
309 | label.set_alignment(0.0, 0.5) | ||
310 | label.set_markup("<span size='x-large'><b>%s</b></span>" % self.title) | ||
311 | build_stop_tab.attach(label, 4, 26, 0, 6) | ||
312 | |||
313 | action_button = HobButton("Edit %s" % action) | ||
314 | action_button.set_size_request(-1, 40) | ||
315 | if action == "image": | ||
316 | action_button.set_tooltip_text("Edit the image parameters") | ||
317 | elif action == "recipes": | ||
318 | action_button.set_tooltip_text("Edit the included recipes") | ||
319 | elif action == "packages": | ||
320 | action_button.set_tooltip_text("Edit the included packages") | ||
321 | action_button.connect('clicked', self.stop_primary_action_button_clicked_cb, action) | ||
322 | build_stop_tab.attach(action_button, 4, 13, 6, 9) | ||
323 | |||
324 | if log_file: | ||
325 | open_log_button = HobAltButton("Open log") | ||
326 | open_log_button.set_relief(gtk.RELIEF_HALF) | ||
327 | open_log_button.set_tooltip_text("Open the build's log file") | ||
328 | open_log_button.connect('clicked', self.open_log_button_clicked_cb, log_file) | ||
329 | build_stop_tab.attach(open_log_button, 14, 23, 6, 9) | ||
330 | |||
331 | attach_pos = (24 if log_file else 14) | ||
332 | build_button = HobAltButton("Build new image") | ||
333 | #build_button.set_size_request(-1, 40) | ||
334 | build_button.set_tooltip_text("Create a new image from scratch") | ||
335 | build_button.connect('clicked', self.new_image_button_clicked_cb) | ||
336 | build_stop_tab.attach(build_button, attach_pos, attach_pos + 9, 6, 9) | ||
337 | |||
338 | return build_stop_top, action_button | ||
339 | |||
340 | def show_stop_page(self, action): | ||
341 | self._remove_all_widget() | ||
342 | self.title = "Build stopped" | ||
343 | self.build_stop_bar, action_button = self.add_build_stop_top_bar(action, self.builder.current_logfile) | ||
344 | |||
345 | self.pack_start(self.group_align, expand=True, fill=True) | ||
346 | self.box_group_area.pack_start(self.build_stop_bar, expand=False, fill=False) | ||
347 | self.box_group_area.pack_start(self.vbox, expand=True, fill=True) | ||
348 | |||
349 | self.vbox.pack_start(self.notebook, expand=True, fill=True) | ||
350 | self.show_all() | ||
351 | self.back_button.hide() | ||
352 | return action_button | ||
353 | |||
354 | def show_page(self, step): | ||
355 | self._remove_all_widget() | ||
356 | if step == self.builder.PACKAGE_GENERATING or step == self.builder.FAST_IMAGE_GENERATING: | ||
357 | self.title = "Building packages ..." | ||
358 | else: | ||
359 | self.title = "Building image ..." | ||
360 | self.build_details_top = self.add_onto_top_bar(None) | ||
361 | self.pack_start(self.build_details_top, expand=False, fill=False) | ||
362 | self.pack_start(self.group_align, expand=True, fill=True) | ||
363 | |||
364 | self.box_group_area.pack_start(self.vbox, expand=True, fill=True) | ||
365 | |||
366 | self.progress_bar.reset() | ||
367 | self.config_tv.reset() | ||
368 | self.vbox.pack_start(self.progress_box, expand=False, fill=False) | ||
369 | |||
370 | self.vbox.pack_start(self.notebook, expand=True, fill=True) | ||
371 | |||
372 | self.box_group_area.pack_end(self.button_box, expand=False, fill=False) | ||
373 | self.show_all() | ||
374 | self.notebook.set_page("Log") | ||
375 | self.back_button.hide() | ||
376 | |||
377 | self.reset_build_status() | ||
378 | self.reset_issues() | ||
379 | |||
380 | def update_progress_bar(self, title, fraction, status=None): | ||
381 | self.progress_bar.update(fraction) | ||
382 | self.progress_bar.set_title(title) | ||
383 | self.progress_bar.set_rcstyle(status) | ||
384 | |||
385 | def back_button_clicked_cb(self, button): | ||
386 | self.builder.show_configuration() | ||
387 | |||
388 | def new_image_button_clicked_cb(self, button): | ||
389 | self.builder.reset() | ||
390 | |||
391 | def show_back_button(self): | ||
392 | self.back_button.show() | ||
393 | |||
394 | def stop_button_clicked_cb(self, button): | ||
395 | self.builder.stop_build() | ||
396 | |||
397 | def hide_stop_button(self): | ||
398 | self.stop_button.set_sensitive(False) | ||
399 | self.stop_button.hide() | ||
400 | |||
401 | def scroll_to_present_row(self, model, path, iter, v_adj, treeview): | ||
402 | if treeview and v_adj: | ||
403 | if path[0] > self.endpath[0]: # check the event is a new row append or not | ||
404 | self.endpath = path | ||
405 | # check the gtk.adjustment position is at end boundary or not | ||
406 | if (v_adj.upper <= v_adj.page_size) or (v_adj.value == v_adj.upper - v_adj.page_size): | ||
407 | treeview.scroll_to_cell(path) | ||
408 | |||
409 | def show_configurations(self, configurations, params): | ||
410 | self.config_tv.show(configurations, params) | ||
411 | |||
412 | def failure_primary_action_button_clicked_cb(self, button, action): | ||
413 | if "Edit recipes" in action: | ||
414 | self.builder.show_recipes() | ||
415 | elif "Edit packages" in action: | ||
416 | self.builder.show_packages() | ||
417 | elif "Edit image" in action: | ||
418 | self.builder.show_configuration() | ||
419 | |||
420 | def restart_build_button_clicked_cb(self, button): | ||
421 | self.builder.just_bake() | ||
422 | |||
423 | def stop_primary_action_button_clicked_cb(self, button, action): | ||
424 | if "recipes" in action: | ||
425 | self.builder.show_recipes() | ||
426 | elif "packages" in action: | ||
427 | self.builder.show_packages() | ||
428 | elif "image" in action: | ||
429 | self.builder.show_configuration() | ||
430 | |||
431 | def open_log_button_clicked_cb(self, button, log_file): | ||
432 | if log_file: | ||
433 | log_file = "file:///" + log_file | ||
434 | gtk.show_uri(screen=button.get_screen(), uri=log_file, timestamp=0) | ||
435 | |||
436 | def failure_activate_file_bug_link_cb(self, button): | ||
437 | button.child.emit('activate-link', "http://bugzilla.yoctoproject.org") | ||
diff --git a/bitbake/lib/bb/ui/crumbs/builder.py b/bitbake/lib/bb/ui/crumbs/builder.py deleted file mode 100755 index 457cadc77a..0000000000 --- a/bitbake/lib/bb/ui/crumbs/builder.py +++ /dev/null | |||
@@ -1,1534 +0,0 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # | ||
3 | # BitBake Graphical GTK User Interface | ||
4 | # | ||
5 | # Copyright (C) 2011-2012 Intel Corporation | ||
6 | # | ||
7 | # Authored by Joshua Lock <josh@linux.intel.com> | ||
8 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | ||
9 | # Authored by Shane Wang <shane.wang@intel.com> | ||
10 | # | ||
11 | # This program is free software; you can redistribute it and/or modify | ||
12 | # it under the terms of the GNU General Public License version 2 as | ||
13 | # published by the Free Software Foundation. | ||
14 | # | ||
15 | # This program is distributed in the hope that it will be useful, | ||
16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | # GNU General Public License for more details. | ||
19 | # | ||
20 | # You should have received a copy of the GNU General Public License along | ||
21 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
22 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
23 | |||
24 | import glib | ||
25 | import gtk, gobject | ||
26 | import copy | ||
27 | import os | ||
28 | import subprocess | ||
29 | import shlex | ||
30 | import re | ||
31 | import logging | ||
32 | import sys | ||
33 | import signal | ||
34 | import time | ||
35 | from bb.ui.crumbs.imageconfigurationpage import ImageConfigurationPage | ||
36 | from bb.ui.crumbs.recipeselectionpage import RecipeSelectionPage | ||
37 | from bb.ui.crumbs.packageselectionpage import PackageSelectionPage | ||
38 | from bb.ui.crumbs.builddetailspage import BuildDetailsPage | ||
39 | from bb.ui.crumbs.imagedetailspage import ImageDetailsPage | ||
40 | from bb.ui.crumbs.sanitycheckpage import SanityCheckPage | ||
41 | from bb.ui.crumbs.hobwidget import hwc, HobButton, HobAltButton | ||
42 | from bb.ui.crumbs.persistenttooltip import PersistentTooltip | ||
43 | import bb.ui.crumbs.utils | ||
44 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
45 | from bb.ui.crumbs.hig.simplesettingsdialog import SimpleSettingsDialog | ||
46 | from bb.ui.crumbs.hig.advancedsettingsdialog import AdvancedSettingsDialog | ||
47 | from bb.ui.crumbs.hig.deployimagedialog import DeployImageDialog | ||
48 | from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog | ||
49 | from bb.ui.crumbs.hig.imageselectiondialog import ImageSelectionDialog | ||
50 | from bb.ui.crumbs.hig.parsingwarningsdialog import ParsingWarningsDialog | ||
51 | from bb.ui.crumbs.hig.propertydialog import PropertyDialog | ||
52 | |||
53 | hobVer = 20120808 | ||
54 | |||
55 | class Configuration: | ||
56 | '''Represents the data structure of configuration.''' | ||
57 | |||
58 | @classmethod | ||
59 | def parse_proxy_string(cls, proxy): | ||
60 | pattern = "^\s*((http|https|ftp|socks|cvs)://)?((\S+):(\S+)@)?([^\s:]+)(:(\d+))?/?" | ||
61 | match = re.search(pattern, proxy) | ||
62 | if match: | ||
63 | return match.group(2), match.group(4), match.group(5), match.group(6), match.group(8) | ||
64 | else: | ||
65 | return None, None, None, "", "" | ||
66 | |||
67 | @classmethod | ||
68 | def make_host_string(cls, prot, user, passwd, host, default_prot=""): | ||
69 | if host == None or host == "": | ||
70 | return "" | ||
71 | |||
72 | passwd = passwd or "" | ||
73 | |||
74 | if user != None and user != "": | ||
75 | if prot == None or prot == "": | ||
76 | prot = default_prot | ||
77 | return prot + "://" + user + ":" + passwd + "@" + host | ||
78 | else: | ||
79 | if prot == None or prot == "": | ||
80 | return host | ||
81 | else: | ||
82 | return prot + "://" + host | ||
83 | |||
84 | @classmethod | ||
85 | def make_port_string(cls, port): | ||
86 | port = port or "" | ||
87 | return port | ||
88 | |||
89 | @classmethod | ||
90 | def make_proxy_string(cls, prot, user, passwd, host, port, default_prot=""): | ||
91 | if host == None or host == "":# or port == None or port == "": | ||
92 | return "" | ||
93 | |||
94 | return Configuration.make_host_string(prot, user, passwd, host, default_prot) + (":" + Configuration.make_port_string(port) if port else "") | ||
95 | |||
96 | def __init__(self): | ||
97 | self.curr_mach = "" | ||
98 | self.selected_image = None | ||
99 | # settings | ||
100 | self.curr_distro = "" | ||
101 | self.dldir = self.sstatedir = self.sstatemirror = "" | ||
102 | self.pmake = self.bbthread = 0 | ||
103 | self.curr_package_format = "" | ||
104 | self.image_rootfs_size = self.image_extra_size = 0 | ||
105 | self.image_overhead_factor = 1 | ||
106 | self.incompat_license = "" | ||
107 | self.curr_sdk_machine = "" | ||
108 | self.conf_version = self.lconf_version = "" | ||
109 | self.extra_setting = {} | ||
110 | self.toolchain_build = False | ||
111 | self.image_fstypes = "" | ||
112 | self.image_size = None | ||
113 | self.image_packages = [] | ||
114 | # bblayers.conf | ||
115 | self.layers = [] | ||
116 | # image/recipes/packages | ||
117 | self.clear_selection() | ||
118 | |||
119 | self.user_selected_packages = [] | ||
120 | |||
121 | self.default_task = "build" | ||
122 | |||
123 | # proxy settings | ||
124 | self.enable_proxy = None | ||
125 | self.same_proxy = False | ||
126 | self.proxies = { | ||
127 | "http" : [None, None, None, "", ""], # protocol : [prot, user, passwd, host, port] | ||
128 | "https" : [None, None, None, "", ""], | ||
129 | "ftp" : [None, None, None, "", ""], | ||
130 | "socks" : [None, None, None, "", ""], | ||
131 | "cvs" : [None, None, None, "", ""], | ||
132 | } | ||
133 | |||
134 | def clear_selection(self): | ||
135 | self.selected_recipes = [] | ||
136 | self.selected_packages = [] | ||
137 | self.initial_selected_image = None | ||
138 | self.initial_selected_packages = [] | ||
139 | self.initial_user_selected_packages = [] | ||
140 | |||
141 | def split_proxy(self, protocol, proxy): | ||
142 | entry = [] | ||
143 | prot, user, passwd, host, port = Configuration.parse_proxy_string(proxy) | ||
144 | entry.append(prot) | ||
145 | entry.append(user) | ||
146 | entry.append(passwd) | ||
147 | entry.append(host) | ||
148 | entry.append(port) | ||
149 | self.proxies[protocol] = entry | ||
150 | |||
151 | def combine_proxy(self, protocol): | ||
152 | entry = self.proxies[protocol] | ||
153 | return Configuration.make_proxy_string(entry[0], entry[1], entry[2], entry[3], entry[4], protocol) | ||
154 | |||
155 | def combine_host_only(self, protocol): | ||
156 | entry = self.proxies[protocol] | ||
157 | return Configuration.make_host_string(entry[0], entry[1], entry[2], entry[3], protocol) | ||
158 | |||
159 | def combine_port_only(self, protocol): | ||
160 | entry = self.proxies[protocol] | ||
161 | return Configuration.make_port_string(entry[4]) | ||
162 | |||
163 | def update(self, params): | ||
164 | # settings | ||
165 | self.curr_distro = params["distro"] | ||
166 | self.dldir = params["dldir"] | ||
167 | self.sstatedir = params["sstatedir"] | ||
168 | self.sstatemirror = params["sstatemirror"] | ||
169 | self.pmake = int(params["pmake"].split()[1]) | ||
170 | self.bbthread = params["bbthread"] | ||
171 | self.curr_package_format = " ".join(params["pclass"].split("package_")).strip() | ||
172 | self.image_rootfs_size = params["image_rootfs_size"] | ||
173 | self.image_extra_size = params["image_extra_size"] | ||
174 | self.image_overhead_factor = params['image_overhead_factor'] | ||
175 | self.incompat_license = params["incompat_license"] | ||
176 | self.curr_sdk_machine = params["sdk_machine"] | ||
177 | self.conf_version = params["conf_version"] | ||
178 | self.lconf_version = params["lconf_version"] | ||
179 | self.image_fstypes = params["image_fstypes"] | ||
180 | # self.extra_setting/self.toolchain_build | ||
181 | # bblayers.conf | ||
182 | self.layers = params["layer"].split() | ||
183 | self.layers_non_removable = params["layers_non_removable"].split() | ||
184 | self.default_task = params["default_task"] | ||
185 | |||
186 | # proxy settings | ||
187 | self.enable_proxy = params["http_proxy"] != "" or params["https_proxy"] != "" \ | ||
188 | or params["ftp_proxy"] != "" or params["socks_proxy"] != "" \ | ||
189 | or params["cvs_proxy_host"] != "" or params["cvs_proxy_port"] != "" | ||
190 | self.split_proxy("http", params["http_proxy"]) | ||
191 | self.split_proxy("https", params["https_proxy"]) | ||
192 | self.split_proxy("ftp", params["ftp_proxy"]) | ||
193 | self.split_proxy("socks", params["socks_proxy"]) | ||
194 | self.split_proxy("cvs", params["cvs_proxy_host"] + ":" + params["cvs_proxy_port"]) | ||
195 | |||
196 | def save(self, handler, defaults=False): | ||
197 | # bblayers.conf | ||
198 | handler.set_var_in_file("BBLAYERS", self.layers, "bblayers.conf") | ||
199 | # local.conf | ||
200 | if not defaults: | ||
201 | handler.early_assign_var_in_file("MACHINE", self.curr_mach, "local.conf") | ||
202 | handler.set_var_in_file("DISTRO", self.curr_distro, "local.conf") | ||
203 | handler.set_var_in_file("DL_DIR", self.dldir, "local.conf") | ||
204 | handler.set_var_in_file("SSTATE_DIR", self.sstatedir, "local.conf") | ||
205 | sstate_mirror_list = self.sstatemirror.split("\\n ") | ||
206 | sstate_mirror_list_modified = [] | ||
207 | for mirror in sstate_mirror_list: | ||
208 | if mirror != "": | ||
209 | mirror = mirror + "\\n" | ||
210 | sstate_mirror_list_modified.append(mirror) | ||
211 | handler.set_var_in_file("SSTATE_MIRRORS", sstate_mirror_list_modified, "local.conf") | ||
212 | handler.set_var_in_file("PARALLEL_MAKE", "-j %s" % self.pmake, "local.conf") | ||
213 | handler.set_var_in_file("BB_NUMBER_THREADS", self.bbthread, "local.conf") | ||
214 | handler.set_var_in_file("PACKAGE_CLASSES", " ".join(["package_" + i for i in self.curr_package_format.split()]), "local.conf") | ||
215 | handler.set_var_in_file("IMAGE_ROOTFS_SIZE", self.image_rootfs_size, "local.conf") | ||
216 | handler.set_var_in_file("IMAGE_EXTRA_SPACE", self.image_extra_size, "local.conf") | ||
217 | handler.set_var_in_file("INCOMPATIBLE_LICENSE", self.incompat_license, "local.conf") | ||
218 | handler.set_var_in_file("SDKMACHINE", self.curr_sdk_machine, "local.conf") | ||
219 | handler.set_var_in_file("CONF_VERSION", self.conf_version, "local.conf") | ||
220 | handler.set_var_in_file("LCONF_VERSION", self.lconf_version, "bblayers.conf") | ||
221 | handler.set_extra_config(self.extra_setting) | ||
222 | handler.set_var_in_file("TOOLCHAIN_BUILD", self.toolchain_build, "local.conf") | ||
223 | handler.set_var_in_file("IMAGE_FSTYPES", self.image_fstypes, "local.conf") | ||
224 | if not defaults: | ||
225 | # image/recipes/packages | ||
226 | handler.set_var_in_file("__SELECTED_IMAGE__", self.selected_image, "local.conf") | ||
227 | handler.set_var_in_file("DEPENDS", self.selected_recipes, "local.conf") | ||
228 | handler.set_var_in_file("IMAGE_INSTALL", self.user_selected_packages, "local.conf") | ||
229 | # proxy | ||
230 | if self.enable_proxy == True: | ||
231 | handler.set_var_in_file("http_proxy", self.combine_proxy("http"), "local.conf") | ||
232 | handler.set_var_in_file("https_proxy", self.combine_proxy("https"), "local.conf") | ||
233 | handler.set_var_in_file("ftp_proxy", self.combine_proxy("ftp"), "local.conf") | ||
234 | handler.set_var_in_file("all_proxy", self.combine_proxy("socks"), "local.conf") | ||
235 | handler.set_var_in_file("CVS_PROXY_HOST", self.combine_host_only("cvs"), "local.conf") | ||
236 | handler.set_var_in_file("CVS_PROXY_PORT", self.combine_port_only("cvs"), "local.conf") | ||
237 | else: | ||
238 | handler.set_var_in_file("http_proxy", "", "local.conf") | ||
239 | handler.set_var_in_file("https_proxy", "", "local.conf") | ||
240 | handler.set_var_in_file("ftp_proxy", "", "local.conf") | ||
241 | handler.set_var_in_file("all_proxy", "", "local.conf") | ||
242 | handler.set_var_in_file("CVS_PROXY_HOST", "", "local.conf") | ||
243 | handler.set_var_in_file("CVS_PROXY_PORT", "", "local.conf") | ||
244 | |||
245 | def __str__(self): | ||
246 | s = "VERSION: '%s', BBLAYERS: '%s', MACHINE: '%s', DISTRO: '%s', DL_DIR: '%s'," % \ | ||
247 | (hobVer, " ".join(self.layers), self.curr_mach, self.curr_distro, self.dldir ) | ||
248 | s += "SSTATE_DIR: '%s', SSTATE_MIRROR: '%s', PARALLEL_MAKE: '-j %s', BB_NUMBER_THREADS: '%s', PACKAGE_CLASSES: '%s', " % \ | ||
249 | (self.sstatedir, self.sstatemirror, self.pmake, self.bbthread, " ".join(["package_" + i for i in self.curr_package_format.split()])) | ||
250 | s += "IMAGE_ROOTFS_SIZE: '%s', IMAGE_EXTRA_SPACE: '%s', INCOMPATIBLE_LICENSE: '%s', SDKMACHINE: '%s', CONF_VERSION: '%s', " % \ | ||
251 | (self.image_rootfs_size, self.image_extra_size, self.incompat_license, self.curr_sdk_machine, self.conf_version) | ||
252 | s += "LCONF_VERSION: '%s', EXTRA_SETTING: '%s', TOOLCHAIN_BUILD: '%s', IMAGE_FSTYPES: '%s', __SELECTED_IMAGE__: '%s', " % \ | ||
253 | (self.lconf_version, self.extra_setting, self.toolchain_build, self.image_fstypes, self.selected_image) | ||
254 | s += "DEPENDS: '%s', IMAGE_INSTALL: '%s', enable_proxy: '%s', use_same_proxy: '%s', http_proxy: '%s', " % \ | ||
255 | (self.selected_recipes, self.user_selected_packages, self.enable_proxy, self.same_proxy, self.combine_proxy("http")) | ||
256 | s += "https_proxy: '%s', ftp_proxy: '%s', all_proxy: '%s', CVS_PROXY_HOST: '%s', CVS_PROXY_PORT: '%s'" % \ | ||
257 | (self.combine_proxy("https"), self.combine_proxy("ftp"), self.combine_proxy("socks"), | ||
258 | self.combine_host_only("cvs"), self.combine_port_only("cvs")) | ||
259 | return s | ||
260 | |||
261 | class Parameters: | ||
262 | '''Represents other variables like available machines, etc.''' | ||
263 | |||
264 | def __init__(self): | ||
265 | # Variables | ||
266 | self.max_threads = 65535 | ||
267 | self.core_base = "" | ||
268 | self.image_addr = "" | ||
269 | self.image_types = [] | ||
270 | self.runnable_image_types = [] | ||
271 | self.runnable_machine_patterns = [] | ||
272 | self.deployable_image_types = [] | ||
273 | self.tmpdir = "" | ||
274 | |||
275 | self.all_machines = [] | ||
276 | self.all_package_formats = [] | ||
277 | self.all_distros = [] | ||
278 | self.all_sdk_machines = [] | ||
279 | self.all_layers = [] | ||
280 | self.image_names = [] | ||
281 | self.image_white_pattern = "" | ||
282 | self.image_black_pattern = "" | ||
283 | |||
284 | # for build log to show | ||
285 | self.bb_version = "" | ||
286 | self.target_arch = "" | ||
287 | self.target_os = "" | ||
288 | self.distro_version = "" | ||
289 | self.tune_pkgarch = "" | ||
290 | |||
291 | def update(self, params): | ||
292 | self.max_threads = params["max_threads"] | ||
293 | self.core_base = params["core_base"] | ||
294 | self.image_addr = params["image_addr"] | ||
295 | self.image_types = params["image_types"].split() | ||
296 | self.runnable_image_types = params["runnable_image_types"].split() | ||
297 | self.runnable_machine_patterns = params["runnable_machine_patterns"].split() | ||
298 | self.deployable_image_types = params["deployable_image_types"].split() | ||
299 | self.tmpdir = params["tmpdir"] | ||
300 | self.image_white_pattern = params["image_white_pattern"] | ||
301 | self.image_black_pattern = params["image_black_pattern"] | ||
302 | self.kernel_image_type = params["kernel_image_type"] | ||
303 | # for build log to show | ||
304 | self.bb_version = params["bb_version"] | ||
305 | self.target_arch = params["target_arch"] | ||
306 | self.target_os = params["target_os"] | ||
307 | self.distro_version = params["distro_version"] | ||
308 | self.tune_pkgarch = params["tune_pkgarch"] | ||
309 | |||
310 | def hob_conf_filter(fn, data): | ||
311 | if fn.endswith("/local.conf"): | ||
312 | distro = data.getVar("DISTRO_HOB", False) | ||
313 | if distro: | ||
314 | if distro != "defaultsetup": | ||
315 | data.setVar("DISTRO", distro) | ||
316 | else: | ||
317 | data.delVar("DISTRO") | ||
318 | |||
319 | keys = ["MACHINE_HOB", "SDKMACHINE_HOB", "PACKAGE_CLASSES_HOB", \ | ||
320 | "BB_NUMBER_THREADS_HOB", "PARALLEL_MAKE_HOB", "DL_DIR_HOB", \ | ||
321 | "SSTATE_DIR_HOB", "SSTATE_MIRRORS_HOB", "INCOMPATIBLE_LICENSE_HOB"] | ||
322 | for key in keys: | ||
323 | var_hob = data.getVar(key, False) | ||
324 | if var_hob: | ||
325 | data.setVar(key.split("_HOB")[0], var_hob) | ||
326 | return | ||
327 | |||
328 | if fn.endswith("/bblayers.conf"): | ||
329 | layers = data.getVar("BBLAYERS_HOB", False) | ||
330 | if layers: | ||
331 | data.setVar("BBLAYERS", layers) | ||
332 | return | ||
333 | |||
334 | class Builder(gtk.Window): | ||
335 | |||
336 | (INITIAL_CHECKS, | ||
337 | MACHINE_SELECTION, | ||
338 | RCPPKGINFO_POPULATING, | ||
339 | RCPPKGINFO_POPULATED, | ||
340 | BASEIMG_SELECTED, | ||
341 | RECIPE_SELECTION, | ||
342 | PACKAGE_GENERATING, | ||
343 | PACKAGE_GENERATED, | ||
344 | PACKAGE_SELECTION, | ||
345 | FAST_IMAGE_GENERATING, | ||
346 | IMAGE_GENERATING, | ||
347 | IMAGE_GENERATED, | ||
348 | MY_IMAGE_OPENED, | ||
349 | BACK, | ||
350 | END_NOOP) = range(15) | ||
351 | |||
352 | (SANITY_CHECK, | ||
353 | IMAGE_CONFIGURATION, | ||
354 | RECIPE_DETAILS, | ||
355 | BUILD_DETAILS, | ||
356 | PACKAGE_DETAILS, | ||
357 | IMAGE_DETAILS, | ||
358 | END_TAB) = range(7) | ||
359 | |||
360 | __step2page__ = { | ||
361 | INITIAL_CHECKS : SANITY_CHECK, | ||
362 | MACHINE_SELECTION : IMAGE_CONFIGURATION, | ||
363 | RCPPKGINFO_POPULATING : IMAGE_CONFIGURATION, | ||
364 | RCPPKGINFO_POPULATED : IMAGE_CONFIGURATION, | ||
365 | BASEIMG_SELECTED : IMAGE_CONFIGURATION, | ||
366 | RECIPE_SELECTION : RECIPE_DETAILS, | ||
367 | PACKAGE_GENERATING : BUILD_DETAILS, | ||
368 | PACKAGE_GENERATED : PACKAGE_DETAILS, | ||
369 | PACKAGE_SELECTION : PACKAGE_DETAILS, | ||
370 | FAST_IMAGE_GENERATING : BUILD_DETAILS, | ||
371 | IMAGE_GENERATING : BUILD_DETAILS, | ||
372 | IMAGE_GENERATED : IMAGE_DETAILS, | ||
373 | MY_IMAGE_OPENED : IMAGE_DETAILS, | ||
374 | END_NOOP : None, | ||
375 | } | ||
376 | |||
377 | SANITY_CHECK_MIN_DISPLAY_TIME = 5 | ||
378 | |||
379 | def __init__(self, hobHandler, recipe_model, package_model): | ||
380 | super(Builder, self).__init__() | ||
381 | |||
382 | self.hob_image = "hob-image" | ||
383 | |||
384 | # handler | ||
385 | self.handler = hobHandler | ||
386 | |||
387 | # logger | ||
388 | self.logger = logging.getLogger("BitBake") | ||
389 | self.consolelog = None | ||
390 | self.current_logfile = None | ||
391 | |||
392 | # configuration and parameters | ||
393 | self.configuration = Configuration() | ||
394 | self.parameters = Parameters() | ||
395 | |||
396 | # build step | ||
397 | self.current_step = None | ||
398 | self.previous_step = None | ||
399 | |||
400 | self.stopping = False | ||
401 | |||
402 | # recipe model and package model | ||
403 | self.recipe_model = recipe_model | ||
404 | self.package_model = package_model | ||
405 | |||
406 | # Indicate whether user has customized the image | ||
407 | self.customized = False | ||
408 | |||
409 | # Indicate whether the UI is working | ||
410 | self.sensitive = True | ||
411 | |||
412 | # Indicate whether the sanity check ran | ||
413 | self.sanity_checked = False | ||
414 | |||
415 | # save parsing warnings | ||
416 | self.parsing_warnings = [] | ||
417 | |||
418 | # create visual elements | ||
419 | self.create_visual_elements() | ||
420 | |||
421 | # connect the signals to functions | ||
422 | self.connect("delete-event", self.destroy_window_cb) | ||
423 | self.recipe_model.connect ("recipe-selection-changed", self.recipelist_changed_cb) | ||
424 | self.package_model.connect("package-selection-changed", self.packagelist_changed_cb) | ||
425 | self.handler.connect("config-updated", self.handler_config_updated_cb) | ||
426 | self.handler.connect("package-formats-updated", self.handler_package_formats_updated_cb) | ||
427 | self.handler.connect("parsing-started", self.handler_parsing_started_cb) | ||
428 | self.handler.connect("parsing", self.handler_parsing_cb) | ||
429 | self.handler.connect("parsing-completed", self.handler_parsing_completed_cb) | ||
430 | self.handler.build.connect("build-started", self.handler_build_started_cb) | ||
431 | self.handler.build.connect("build-succeeded", self.handler_build_succeeded_cb) | ||
432 | self.handler.build.connect("build-failed", self.handler_build_failed_cb) | ||
433 | self.handler.build.connect("build-aborted", self.handler_build_aborted_cb) | ||
434 | self.handler.build.connect("task-started", self.handler_task_started_cb) | ||
435 | self.handler.build.connect("disk-full", self.handler_disk_full_cb) | ||
436 | self.handler.build.connect("log-error", self.handler_build_failure_cb) | ||
437 | self.handler.build.connect("log-warning", self.handler_build_failure_cb) | ||
438 | self.handler.build.connect("log", self.handler_build_log_cb) | ||
439 | self.handler.build.connect("no-provider", self.handler_no_provider_cb) | ||
440 | self.handler.connect("generating-data", self.handler_generating_data_cb) | ||
441 | self.handler.connect("data-generated", self.handler_data_generated_cb) | ||
442 | self.handler.connect("command-succeeded", self.handler_command_succeeded_cb) | ||
443 | self.handler.connect("command-failed", self.handler_command_failed_cb) | ||
444 | self.handler.connect("parsing-warning", self.handler_parsing_warning_cb) | ||
445 | self.handler.connect("sanity-failed", self.handler_sanity_failed_cb) | ||
446 | self.handler.connect("recipe-populated", self.handler_recipe_populated_cb) | ||
447 | self.handler.connect("package-populated", self.handler_package_populated_cb) | ||
448 | |||
449 | self.handler.append_to_bbfiles("${TOPDIR}/recipes/images/custom/*.bb") | ||
450 | self.handler.append_to_bbfiles("${TOPDIR}/recipes/images/*.bb") | ||
451 | self.initiate_new_build_async() | ||
452 | |||
453 | signal.signal(signal.SIGINT, self.event_handle_SIGINT) | ||
454 | |||
455 | def create_visual_elements(self): | ||
456 | self.set_title("Hob") | ||
457 | self.set_icon_name("applications-development") | ||
458 | self.set_resizable(True) | ||
459 | |||
460 | try: | ||
461 | window_width = self.get_screen().get_width() | ||
462 | window_height = self.get_screen().get_height() | ||
463 | except AttributeError: | ||
464 | print "Please set DISPLAY variable before running Hob." | ||
465 | sys.exit(1) | ||
466 | |||
467 | if window_width >= hwc.MAIN_WIN_WIDTH: | ||
468 | window_width = hwc.MAIN_WIN_WIDTH | ||
469 | window_height = hwc.MAIN_WIN_HEIGHT | ||
470 | self.set_size_request(window_width, window_height) | ||
471 | |||
472 | self.vbox = gtk.VBox(False, 0) | ||
473 | self.vbox.set_border_width(0) | ||
474 | self.add(self.vbox) | ||
475 | |||
476 | # create pages | ||
477 | self.image_configuration_page = ImageConfigurationPage(self) | ||
478 | self.recipe_details_page = RecipeSelectionPage(self) | ||
479 | self.build_details_page = BuildDetailsPage(self) | ||
480 | self.package_details_page = PackageSelectionPage(self) | ||
481 | self.image_details_page = ImageDetailsPage(self) | ||
482 | self.sanity_check_page = SanityCheckPage(self) | ||
483 | self.display_sanity_check = False | ||
484 | self.sanity_check_post_func = False | ||
485 | self.had_network_error = False | ||
486 | |||
487 | self.nb = gtk.Notebook() | ||
488 | self.nb.set_show_tabs(False) | ||
489 | self.nb.insert_page(self.sanity_check_page, None, self.SANITY_CHECK) | ||
490 | self.nb.insert_page(self.image_configuration_page, None, self.IMAGE_CONFIGURATION) | ||
491 | self.nb.insert_page(self.recipe_details_page, None, self.RECIPE_DETAILS) | ||
492 | self.nb.insert_page(self.build_details_page, None, self.BUILD_DETAILS) | ||
493 | self.nb.insert_page(self.package_details_page, None, self.PACKAGE_DETAILS) | ||
494 | self.nb.insert_page(self.image_details_page, None, self.IMAGE_DETAILS) | ||
495 | self.vbox.pack_start(self.nb, expand=True, fill=True) | ||
496 | |||
497 | self.show_all() | ||
498 | self.nb.set_current_page(0) | ||
499 | |||
500 | def sanity_check_timeout(self): | ||
501 | # The minimum time for showing the 'sanity check' page has passe | ||
502 | # If someone set the 'sanity_check_post_step' meanwhile, execute it now | ||
503 | self.display_sanity_check = False | ||
504 | if self.sanity_check_post_func: | ||
505 | temp = self.sanity_check_post_func | ||
506 | self.sanity_check_post_func = None | ||
507 | temp() | ||
508 | return False | ||
509 | |||
510 | def show_sanity_check_page(self): | ||
511 | # This window must stay on screen for at least 5 seconds, according to the design document | ||
512 | self.nb.set_current_page(self.SANITY_CHECK) | ||
513 | self.sanity_check_post_step = None | ||
514 | self.display_sanity_check = True | ||
515 | self.sanity_check_page.start() | ||
516 | gobject.timeout_add(self.SANITY_CHECK_MIN_DISPLAY_TIME * 1000, self.sanity_check_timeout) | ||
517 | |||
518 | def execute_after_sanity_check(self, func): | ||
519 | if not self.display_sanity_check: | ||
520 | func() | ||
521 | else: | ||
522 | self.sanity_check_post_func = func | ||
523 | |||
524 | def generate_configuration(self): | ||
525 | if not self.sanity_checked: | ||
526 | self.show_sanity_check_page() | ||
527 | self.handler.generate_configuration() | ||
528 | |||
529 | def initiate_new_build_async(self): | ||
530 | self.configuration.selected_image = None | ||
531 | self.switch_page(self.MACHINE_SELECTION) | ||
532 | self.handler.init_cooker() | ||
533 | self.handler.set_extra_inherit("image_types") | ||
534 | self.generate_configuration() | ||
535 | |||
536 | def update_config_async(self): | ||
537 | self.set_user_config() | ||
538 | self.generate_configuration() | ||
539 | self.switch_page(self.MACHINE_SELECTION) | ||
540 | |||
541 | def sanity_check(self): | ||
542 | self.handler.trigger_sanity_check() | ||
543 | |||
544 | def populate_recipe_package_info_async(self): | ||
545 | self.switch_page(self.RCPPKGINFO_POPULATING) | ||
546 | # Parse recipes | ||
547 | self.set_user_config() | ||
548 | self.handler.generate_recipes() | ||
549 | |||
550 | def generate_packages_async(self, log = False): | ||
551 | self.switch_page(self.PACKAGE_GENERATING) | ||
552 | if log: | ||
553 | self.current_logfile = self.handler.get_logfile() | ||
554 | self.do_log(self.current_logfile) | ||
555 | # Build packages | ||
556 | _, all_recipes = self.recipe_model.get_selected_recipes() | ||
557 | self.set_user_config() | ||
558 | self.handler.reset_build() | ||
559 | self.handler.generate_packages(all_recipes, self.configuration.default_task) | ||
560 | |||
561 | def restore_initial_selected_packages(self): | ||
562 | self.package_model.set_selected_packages(self.configuration.initial_user_selected_packages, True) | ||
563 | self.package_model.set_selected_packages(self.configuration.initial_selected_packages) | ||
564 | for package in self.configuration.selected_packages: | ||
565 | if package not in self.configuration.initial_selected_packages: | ||
566 | self.package_model.exclude_item(self.package_model.find_path_for_item(package)) | ||
567 | |||
568 | def fast_generate_image_async(self, log = False): | ||
569 | self.switch_page(self.FAST_IMAGE_GENERATING) | ||
570 | if log: | ||
571 | self.current_logfile = self.handler.get_logfile() | ||
572 | self.do_log(self.current_logfile) | ||
573 | # Build packages | ||
574 | _, all_recipes = self.recipe_model.get_selected_recipes() | ||
575 | self.set_user_config() | ||
576 | self.handler.reset_build() | ||
577 | self.handler.generate_packages(all_recipes, self.configuration.default_task) | ||
578 | |||
579 | def generate_image_async(self, cont = False): | ||
580 | self.switch_page(self.IMAGE_GENERATING) | ||
581 | self.handler.reset_build() | ||
582 | if not cont: | ||
583 | self.current_logfile = self.handler.get_logfile() | ||
584 | self.do_log(self.current_logfile) | ||
585 | # Build image | ||
586 | self.set_user_config() | ||
587 | toolchain_packages = [] | ||
588 | base_image = None | ||
589 | if self.configuration.toolchain_build: | ||
590 | toolchain_packages = self.package_model.get_selected_packages_toolchain() | ||
591 | if self.configuration.selected_image == self.recipe_model.__custom_image__: | ||
592 | packages = self.package_model.get_selected_packages() | ||
593 | image = self.hob_image | ||
594 | base_image = self.configuration.initial_selected_image | ||
595 | else: | ||
596 | packages = [] | ||
597 | image = self.configuration.selected_image | ||
598 | self.handler.generate_image(image, | ||
599 | base_image, | ||
600 | packages, | ||
601 | toolchain_packages, | ||
602 | self.configuration.default_task) | ||
603 | |||
604 | def generate_new_image(self, image, description): | ||
605 | base_image = self.configuration.initial_selected_image | ||
606 | if base_image == self.recipe_model.__custom_image__: | ||
607 | base_image = None | ||
608 | packages = self.package_model.get_selected_packages() | ||
609 | self.handler.generate_new_image(image, base_image, packages, description) | ||
610 | |||
611 | def ensure_dir(self, directory): | ||
612 | self.handler.ensure_dir(directory) | ||
613 | |||
614 | def get_parameters_sync(self): | ||
615 | return self.handler.get_parameters() | ||
616 | |||
617 | def request_package_info_async(self): | ||
618 | self.handler.request_package_info() | ||
619 | |||
620 | def cancel_build_sync(self, force=False): | ||
621 | self.handler.cancel_build(force) | ||
622 | |||
623 | def cancel_parse_sync(self): | ||
624 | self.handler.cancel_parse() | ||
625 | |||
626 | def switch_page(self, next_step): | ||
627 | # Main Workflow (Business Logic) | ||
628 | self.nb.set_current_page(self.__step2page__[next_step]) | ||
629 | |||
630 | if next_step == self.MACHINE_SELECTION: # init step | ||
631 | self.image_configuration_page.show_machine() | ||
632 | |||
633 | elif next_step == self.RCPPKGINFO_POPULATING: | ||
634 | # MACHINE CHANGED action or SETTINGS CHANGED | ||
635 | # show the progress bar | ||
636 | self.image_configuration_page.show_info_populating() | ||
637 | |||
638 | elif next_step == self.RCPPKGINFO_POPULATED: | ||
639 | self.image_configuration_page.show_info_populated() | ||
640 | |||
641 | elif next_step == self.BASEIMG_SELECTED: | ||
642 | self.image_configuration_page.show_baseimg_selected() | ||
643 | |||
644 | elif next_step == self.RECIPE_SELECTION: | ||
645 | if self.recipe_model.get_selected_image() == self.recipe_model.__custom_image__: | ||
646 | self.recipe_details_page.set_recipe_curr_tab(self.recipe_details_page.ALL) | ||
647 | else: | ||
648 | self.recipe_details_page.set_recipe_curr_tab(self.recipe_details_page.INCLUDED) | ||
649 | |||
650 | elif next_step == self.PACKAGE_SELECTION: | ||
651 | self.configuration.initial_selected_packages = self.configuration.selected_packages | ||
652 | self.configuration.initial_user_selected_packages = self.configuration.user_selected_packages | ||
653 | self.package_details_page.set_title("Edit packages") | ||
654 | if self.recipe_model.get_selected_image() == self.recipe_model.__custom_image__: | ||
655 | self.package_details_page.set_packages_curr_tab(self.package_details_page.ALL) | ||
656 | else: | ||
657 | self.package_details_page.set_packages_curr_tab(self.package_details_page.INCLUDED) | ||
658 | self.package_details_page.show_page(self.current_logfile) | ||
659 | |||
660 | |||
661 | elif next_step == self.PACKAGE_GENERATING or next_step == self.FAST_IMAGE_GENERATING: | ||
662 | # both PACKAGE_GENERATING and FAST_IMAGE_GENERATING share the same page | ||
663 | self.build_details_page.show_page(next_step) | ||
664 | |||
665 | elif next_step == self.PACKAGE_GENERATED: | ||
666 | self.package_details_page.set_title("Step 2 of 2: Edit packages") | ||
667 | if self.recipe_model.get_selected_image() == self.recipe_model.__custom_image__: | ||
668 | self.package_details_page.set_packages_curr_tab(self.package_details_page.ALL) | ||
669 | else: | ||
670 | self.package_details_page.set_packages_curr_tab(self.package_details_page.INCLUDED) | ||
671 | self.package_details_page.show_page(self.current_logfile) | ||
672 | |||
673 | elif next_step == self.IMAGE_GENERATING: | ||
674 | # after packages are generated, selected_packages need to | ||
675 | # be updated in package_model per selected_image in recipe_model | ||
676 | self.build_details_page.show_page(next_step) | ||
677 | |||
678 | elif next_step == self.IMAGE_GENERATED: | ||
679 | self.image_details_page.show_page(next_step) | ||
680 | |||
681 | elif next_step == self.MY_IMAGE_OPENED: | ||
682 | self.image_details_page.show_page(next_step) | ||
683 | |||
684 | self.previous_step = self.current_step | ||
685 | self.current_step = next_step | ||
686 | |||
687 | def set_user_config_proxies(self): | ||
688 | if self.configuration.enable_proxy == True: | ||
689 | self.handler.set_http_proxy(self.configuration.combine_proxy("http")) | ||
690 | self.handler.set_https_proxy(self.configuration.combine_proxy("https")) | ||
691 | self.handler.set_ftp_proxy(self.configuration.combine_proxy("ftp")) | ||
692 | self.handler.set_socks_proxy(self.configuration.combine_proxy("socks")) | ||
693 | self.handler.set_cvs_proxy(self.configuration.combine_host_only("cvs"), self.configuration.combine_port_only("cvs")) | ||
694 | elif self.configuration.enable_proxy == False: | ||
695 | self.handler.set_http_proxy("") | ||
696 | self.handler.set_https_proxy("") | ||
697 | self.handler.set_ftp_proxy("") | ||
698 | self.handler.set_socks_proxy("") | ||
699 | self.handler.set_cvs_proxy("", "") | ||
700 | |||
701 | def set_user_config_extra(self): | ||
702 | self.handler.set_rootfs_size(self.configuration.image_rootfs_size) | ||
703 | self.handler.set_extra_size(self.configuration.image_extra_size) | ||
704 | self.handler.set_incompatible_license(self.configuration.incompat_license) | ||
705 | self.handler.set_sdk_machine(self.configuration.curr_sdk_machine) | ||
706 | self.handler.set_image_fstypes(self.configuration.image_fstypes) | ||
707 | self.handler.set_extra_config(self.configuration.extra_setting) | ||
708 | self.handler.set_extra_inherit("packageinfo image_types") | ||
709 | self.set_user_config_proxies() | ||
710 | |||
711 | def set_user_config(self): | ||
712 | # set bb layers | ||
713 | self.handler.set_bblayers(self.configuration.layers) | ||
714 | # set local configuration | ||
715 | self.handler.set_machine(self.configuration.curr_mach) | ||
716 | self.handler.set_package_format(self.configuration.curr_package_format) | ||
717 | self.handler.set_distro(self.configuration.curr_distro) | ||
718 | self.handler.set_dl_dir(self.configuration.dldir) | ||
719 | self.handler.set_sstate_dir(self.configuration.sstatedir) | ||
720 | self.handler.set_sstate_mirrors(self.configuration.sstatemirror) | ||
721 | self.handler.set_pmake(self.configuration.pmake) | ||
722 | self.handler.set_bbthreads(self.configuration.bbthread) | ||
723 | self.set_user_config_extra() | ||
724 | |||
725 | def update_recipe_model(self, selected_image, selected_recipes): | ||
726 | self.recipe_model.set_selected_image(selected_image) | ||
727 | self.recipe_model.set_selected_recipes(selected_recipes) | ||
728 | |||
729 | def update_package_model(self, selected_packages, user_selected_packages=None): | ||
730 | if user_selected_packages: | ||
731 | left = self.package_model.set_selected_packages(user_selected_packages, True) | ||
732 | self.configuration.user_selected_packages += left | ||
733 | left = self.package_model.set_selected_packages(selected_packages) | ||
734 | self.configuration.selected_packages += left | ||
735 | |||
736 | def update_configuration_parameters(self, params): | ||
737 | if params: | ||
738 | self.configuration.update(params) | ||
739 | self.parameters.update(params) | ||
740 | |||
741 | def set_base_image(self): | ||
742 | self.configuration.initial_selected_image = self.configuration.selected_image | ||
743 | if self.configuration.selected_image != self.recipe_model.__custom_image__: | ||
744 | self.hob_image = self.configuration.selected_image + "-edited" | ||
745 | |||
746 | def reset(self): | ||
747 | self.configuration.curr_mach = "" | ||
748 | self.configuration.clear_selection() | ||
749 | self.image_configuration_page.switch_machine_combo() | ||
750 | self.switch_page(self.MACHINE_SELECTION) | ||
751 | |||
752 | # Callback Functions | ||
753 | def handler_config_updated_cb(self, handler, which, values): | ||
754 | if which == "distro": | ||
755 | self.parameters.all_distros = values | ||
756 | elif which == "machine": | ||
757 | self.parameters.all_machines = values | ||
758 | self.image_configuration_page.update_machine_combo() | ||
759 | elif which == "machine-sdk": | ||
760 | self.parameters.all_sdk_machines = values | ||
761 | |||
762 | def handler_package_formats_updated_cb(self, handler, formats): | ||
763 | self.parameters.all_package_formats = formats | ||
764 | |||
765 | def switch_to_image_configuration_helper(self): | ||
766 | self.sanity_check_page.stop() | ||
767 | self.switch_page(self.IMAGE_CONFIGURATION) | ||
768 | self.image_configuration_page.switch_machine_combo() | ||
769 | |||
770 | def show_network_error_dialog_helper(self): | ||
771 | self.sanity_check_page.stop() | ||
772 | self.show_network_error_dialog() | ||
773 | |||
774 | def handler_command_succeeded_cb(self, handler, initcmd): | ||
775 | if initcmd == self.handler.GENERATE_CONFIGURATION: | ||
776 | if not self.configuration.curr_mach: | ||
777 | self.configuration.curr_mach = self.handler.runCommand(["getVariable", "HOB_MACHINE"]) or "" | ||
778 | self.update_configuration_parameters(self.get_parameters_sync()) | ||
779 | if not self.sanity_checked: | ||
780 | self.sanity_check() | ||
781 | self.sanity_checked = True | ||
782 | elif initcmd == self.handler.SANITY_CHECK: | ||
783 | if self.had_network_error: | ||
784 | self.had_network_error = False | ||
785 | self.execute_after_sanity_check(self.show_network_error_dialog_helper) | ||
786 | else: | ||
787 | # Switch to the 'image configuration' page now, but we might need | ||
788 | # to wait for the minimum display time of the sanity check page | ||
789 | self.execute_after_sanity_check(self.switch_to_image_configuration_helper) | ||
790 | elif initcmd in [self.handler.GENERATE_RECIPES, | ||
791 | self.handler.GENERATE_PACKAGES, | ||
792 | self.handler.GENERATE_IMAGE]: | ||
793 | self.update_configuration_parameters(self.get_parameters_sync()) | ||
794 | self.request_package_info_async() | ||
795 | elif initcmd == self.handler.POPULATE_PACKAGEINFO: | ||
796 | if self.current_step == self.RCPPKGINFO_POPULATING: | ||
797 | self.switch_page(self.RCPPKGINFO_POPULATED) | ||
798 | self.rcppkglist_populated() | ||
799 | return | ||
800 | |||
801 | self.rcppkglist_populated() | ||
802 | if self.current_step == self.FAST_IMAGE_GENERATING: | ||
803 | self.generate_image_async(True) | ||
804 | |||
805 | def show_error_dialog(self, msg): | ||
806 | lbl = "<b>Hob found an error</b>" | ||
807 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg) | ||
808 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
809 | HobButton.style_button(button) | ||
810 | response = dialog.run() | ||
811 | dialog.destroy() | ||
812 | |||
813 | def show_warning_dialog(self): | ||
814 | dialog = ParsingWarningsDialog(title = "View warnings", | ||
815 | warnings = self.parsing_warnings, | ||
816 | parent = None, | ||
817 | flags = gtk.DIALOG_DESTROY_WITH_PARENT | ||
818 | | gtk.DIALOG_NO_SEPARATOR) | ||
819 | response = dialog.run() | ||
820 | dialog.destroy() | ||
821 | |||
822 | def show_network_error_dialog(self): | ||
823 | lbl = "<b>Hob cannot connect to the network</b>" | ||
824 | msg = msg + "Please check your network connection. If you are using a proxy server, please make sure it is configured correctly." | ||
825 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg) | ||
826 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
827 | HobButton.style_button(button) | ||
828 | button = dialog.add_button("Proxy settings", gtk.RESPONSE_CANCEL) | ||
829 | HobButton.style_button(button) | ||
830 | res = dialog.run() | ||
831 | dialog.destroy() | ||
832 | if res == gtk.RESPONSE_CANCEL: | ||
833 | res, settings_changed = self.show_simple_settings_dialog(SimpleSettingsDialog.PROXIES_PAGE_ID) | ||
834 | if not res: | ||
835 | return | ||
836 | if settings_changed: | ||
837 | self.reparse_post_adv_settings() | ||
838 | |||
839 | def handler_command_failed_cb(self, handler, msg): | ||
840 | if msg: | ||
841 | self.show_error_dialog(msg) | ||
842 | self.reset() | ||
843 | |||
844 | def handler_parsing_warning_cb(self, handler, warn_msg): | ||
845 | self.parsing_warnings.append(warn_msg) | ||
846 | |||
847 | def handler_sanity_failed_cb(self, handler, msg, network_error): | ||
848 | self.reset() | ||
849 | if network_error: | ||
850 | # Mark this in an internal field. The "network error" dialog will be | ||
851 | # shown later, when a SanityCheckPassed event will be handled | ||
852 | # (as sent by sanity.bbclass) | ||
853 | self.had_network_error = True | ||
854 | else: | ||
855 | msg = msg.replace("your local.conf", "Settings") | ||
856 | self.show_error_dialog(msg) | ||
857 | self.reset() | ||
858 | |||
859 | def window_sensitive(self, sensitive): | ||
860 | self.image_configuration_page.machine_combo.set_sensitive(sensitive) | ||
861 | self.image_configuration_page.machine_combo.child.set_sensitive(sensitive) | ||
862 | self.image_configuration_page.image_combo.set_sensitive(sensitive) | ||
863 | self.image_configuration_page.image_combo.child.set_sensitive(sensitive) | ||
864 | self.image_configuration_page.layer_button.set_sensitive(sensitive) | ||
865 | self.image_configuration_page.layer_info_icon.set_sensitive(sensitive) | ||
866 | self.image_configuration_page.toolbar.set_sensitive(sensitive) | ||
867 | self.image_configuration_page.view_adv_configuration_button.set_sensitive(sensitive) | ||
868 | self.image_configuration_page.config_build_button.set_sensitive(sensitive) | ||
869 | |||
870 | self.recipe_details_page.set_sensitive(sensitive) | ||
871 | self.package_details_page.set_sensitive(sensitive) | ||
872 | self.build_details_page.set_sensitive(sensitive) | ||
873 | self.image_details_page.set_sensitive(sensitive) | ||
874 | |||
875 | if sensitive: | ||
876 | self.window.set_cursor(None) | ||
877 | else: | ||
878 | self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) | ||
879 | self.sensitive = sensitive | ||
880 | |||
881 | |||
882 | def handler_generating_data_cb(self, handler): | ||
883 | self.window_sensitive(False) | ||
884 | |||
885 | def handler_data_generated_cb(self, handler): | ||
886 | self.window_sensitive(True) | ||
887 | |||
888 | def rcppkglist_populated(self): | ||
889 | selected_image = self.configuration.selected_image | ||
890 | selected_recipes = self.configuration.selected_recipes[:] | ||
891 | selected_packages = self.configuration.selected_packages[:] | ||
892 | user_selected_packages = self.configuration.user_selected_packages[:] | ||
893 | |||
894 | self.image_configuration_page.update_image_combo(self.recipe_model, selected_image) | ||
895 | self.image_configuration_page.update_image_desc() | ||
896 | self.update_recipe_model(selected_image, selected_recipes) | ||
897 | self.update_package_model(selected_packages, user_selected_packages) | ||
898 | |||
899 | def recipelist_changed_cb(self, recipe_model): | ||
900 | self.recipe_details_page.refresh_selection() | ||
901 | |||
902 | def packagelist_changed_cb(self, package_model): | ||
903 | self.package_details_page.refresh_selection() | ||
904 | |||
905 | def handler_recipe_populated_cb(self, handler): | ||
906 | self.image_configuration_page.update_progress_bar("Populating recipes", 0.99) | ||
907 | |||
908 | def handler_package_populated_cb(self, handler): | ||
909 | self.image_configuration_page.update_progress_bar("Populating packages", 1.0) | ||
910 | |||
911 | def handler_parsing_started_cb(self, handler, message): | ||
912 | if self.current_step != self.RCPPKGINFO_POPULATING: | ||
913 | return | ||
914 | |||
915 | fraction = 0 | ||
916 | if message["eventname"] == "TreeDataPreparationStarted": | ||
917 | fraction = 0.6 + fraction | ||
918 | self.image_configuration_page.stop_button.set_sensitive(False) | ||
919 | self.image_configuration_page.update_progress_bar("Generating dependency tree", fraction) | ||
920 | else: | ||
921 | self.image_configuration_page.stop_button.set_sensitive(True) | ||
922 | self.image_configuration_page.update_progress_bar(message["title"], fraction) | ||
923 | |||
924 | def handler_parsing_cb(self, handler, message): | ||
925 | if self.current_step != self.RCPPKGINFO_POPULATING: | ||
926 | return | ||
927 | |||
928 | fraction = message["current"] * 1.0/message["total"] | ||
929 | if message["eventname"] == "TreeDataPreparationProgress": | ||
930 | fraction = 0.6 + 0.38 * fraction | ||
931 | self.image_configuration_page.update_progress_bar("Generating dependency tree", fraction) | ||
932 | else: | ||
933 | fraction = 0.6 * fraction | ||
934 | self.image_configuration_page.update_progress_bar(message["title"], fraction) | ||
935 | |||
936 | def handler_parsing_completed_cb(self, handler, message): | ||
937 | if self.current_step != self.RCPPKGINFO_POPULATING: | ||
938 | return | ||
939 | |||
940 | if message["eventname"] == "TreeDataPreparationCompleted": | ||
941 | fraction = 0.98 | ||
942 | else: | ||
943 | fraction = 0.6 | ||
944 | self.image_configuration_page.update_progress_bar("Generating dependency tree", fraction) | ||
945 | |||
946 | def handler_build_started_cb(self, running_build): | ||
947 | if self.current_step == self.FAST_IMAGE_GENERATING: | ||
948 | fraction = 0 | ||
949 | elif self.current_step == self.IMAGE_GENERATING: | ||
950 | if self.previous_step == self.FAST_IMAGE_GENERATING: | ||
951 | fraction = 0.9 | ||
952 | else: | ||
953 | fraction = 0 | ||
954 | elif self.current_step == self.PACKAGE_GENERATING: | ||
955 | fraction = 0 | ||
956 | self.build_details_page.update_progress_bar("Build Started: ", fraction) | ||
957 | self.build_details_page.show_configurations(self.configuration, self.parameters) | ||
958 | |||
959 | def build_succeeded(self): | ||
960 | if self.current_step == self.FAST_IMAGE_GENERATING: | ||
961 | fraction = 0.9 | ||
962 | elif self.current_step == self.IMAGE_GENERATING: | ||
963 | fraction = 1.0 | ||
964 | version = "" | ||
965 | self.parameters.image_names = [] | ||
966 | selected_image = self.recipe_model.get_selected_image() | ||
967 | if selected_image == self.recipe_model.__custom_image__: | ||
968 | if self.configuration.initial_selected_image != selected_image: | ||
969 | version = self.recipe_model.get_custom_image_version() | ||
970 | linkname = self.hob_image + version + "-" + self.configuration.curr_mach | ||
971 | else: | ||
972 | linkname = selected_image + '-' + self.configuration.curr_mach | ||
973 | image_extension = self.get_image_extension() | ||
974 | for image_type in self.parameters.image_types: | ||
975 | if image_type in image_extension: | ||
976 | real_types = image_extension[image_type] | ||
977 | else: | ||
978 | real_types = [image_type] | ||
979 | for real_image_type in real_types: | ||
980 | linkpath = self.parameters.image_addr + '/' + linkname + '.' + real_image_type | ||
981 | if os.path.exists(linkpath): | ||
982 | self.parameters.image_names.append(os.readlink(linkpath)) | ||
983 | elif self.current_step == self.PACKAGE_GENERATING: | ||
984 | fraction = 1.0 | ||
985 | self.build_details_page.update_progress_bar("Build Completed: ", fraction) | ||
986 | self.handler.build_succeeded_async() | ||
987 | self.stopping = False | ||
988 | |||
989 | if self.current_step == self.PACKAGE_GENERATING: | ||
990 | self.switch_page(self.PACKAGE_GENERATED) | ||
991 | elif self.current_step == self.IMAGE_GENERATING: | ||
992 | self.switch_page(self.IMAGE_GENERATED) | ||
993 | |||
994 | def build_failed(self): | ||
995 | if self.stopping: | ||
996 | status = "stop" | ||
997 | message = "Build stopped: " | ||
998 | fraction = self.build_details_page.progress_bar.get_fraction() | ||
999 | stop_to_next_edit = "" | ||
1000 | if self.current_step == self.FAST_IMAGE_GENERATING: | ||
1001 | stop_to_next_edit = "image configuration" | ||
1002 | elif self.current_step == self.IMAGE_GENERATING: | ||
1003 | if self.previous_step == self.FAST_IMAGE_GENERATING: | ||
1004 | stop_to_next_edit = "image configuration" | ||
1005 | else: | ||
1006 | stop_to_next_edit = "packages" | ||
1007 | elif self.current_step == self.PACKAGE_GENERATING: | ||
1008 | stop_to_next_edit = "recipes" | ||
1009 | button = self.build_details_page.show_stop_page(stop_to_next_edit.split(' ')[0]) | ||
1010 | self.set_default(button) | ||
1011 | else: | ||
1012 | fail_to_next_edit = "" | ||
1013 | if self.current_step == self.FAST_IMAGE_GENERATING: | ||
1014 | fail_to_next_edit = "image configuration" | ||
1015 | fraction = 0.9 | ||
1016 | elif self.current_step == self.IMAGE_GENERATING: | ||
1017 | if self.previous_step == self.FAST_IMAGE_GENERATING: | ||
1018 | fail_to_next_edit = "image configuration" | ||
1019 | else: | ||
1020 | fail_to_next_edit = "packages" | ||
1021 | fraction = 1.0 | ||
1022 | elif self.current_step == self.PACKAGE_GENERATING: | ||
1023 | fail_to_next_edit = "recipes" | ||
1024 | fraction = 1.0 | ||
1025 | self.build_details_page.show_fail_page(fail_to_next_edit.split(' ')[0]) | ||
1026 | status = "fail" | ||
1027 | message = "Build failed: " | ||
1028 | self.build_details_page.update_progress_bar(message, fraction, status) | ||
1029 | self.build_details_page.show_back_button() | ||
1030 | self.build_details_page.hide_stop_button() | ||
1031 | self.handler.build_failed_async() | ||
1032 | self.stopping = False | ||
1033 | |||
1034 | def handler_build_succeeded_cb(self, running_build): | ||
1035 | if not self.stopping: | ||
1036 | self.build_succeeded() | ||
1037 | else: | ||
1038 | self.build_failed() | ||
1039 | |||
1040 | |||
1041 | def handler_build_failed_cb(self, running_build): | ||
1042 | self.build_failed() | ||
1043 | |||
1044 | def handler_build_aborted_cb(self, running_build): | ||
1045 | self.build_failed() | ||
1046 | |||
1047 | def handler_no_provider_cb(self, running_build, msg): | ||
1048 | dialog = CrumbsMessageDialog(self, glib.markup_escape_text(msg), gtk.MESSAGE_INFO) | ||
1049 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
1050 | HobButton.style_button(button) | ||
1051 | dialog.run() | ||
1052 | dialog.destroy() | ||
1053 | self.build_failed() | ||
1054 | |||
1055 | def handler_task_started_cb(self, running_build, message): | ||
1056 | fraction = message["current"] * 1.0/message["total"] | ||
1057 | title = "Build packages" | ||
1058 | if self.current_step == self.FAST_IMAGE_GENERATING: | ||
1059 | if message["eventname"] == "sceneQueueTaskStarted": | ||
1060 | fraction = 0.27 * fraction | ||
1061 | elif message["eventname"] == "runQueueTaskStarted": | ||
1062 | fraction = 0.27 + 0.63 * fraction | ||
1063 | elif self.current_step == self.IMAGE_GENERATING: | ||
1064 | title = "Build image" | ||
1065 | if self.previous_step == self.FAST_IMAGE_GENERATING: | ||
1066 | if message["eventname"] == "sceneQueueTaskStarted": | ||
1067 | fraction = 0.27 + 0.63 + 0.03 * fraction | ||
1068 | elif message["eventname"] == "runQueueTaskStarted": | ||
1069 | fraction = 0.27 + 0.63 + 0.03 + 0.07 * fraction | ||
1070 | else: | ||
1071 | if message["eventname"] == "sceneQueueTaskStarted": | ||
1072 | fraction = 0.2 * fraction | ||
1073 | elif message["eventname"] == "runQueueTaskStarted": | ||
1074 | fraction = 0.2 + 0.8 * fraction | ||
1075 | elif self.current_step == self.PACKAGE_GENERATING: | ||
1076 | if message["eventname"] == "sceneQueueTaskStarted": | ||
1077 | fraction = 0.2 * fraction | ||
1078 | elif message["eventname"] == "runQueueTaskStarted": | ||
1079 | fraction = 0.2 + 0.8 * fraction | ||
1080 | self.build_details_page.update_progress_bar(title + ": ", fraction) | ||
1081 | self.build_details_page.update_build_status(message["current"], message["total"], message["task"]) | ||
1082 | |||
1083 | def handler_disk_full_cb(self, running_build): | ||
1084 | self.disk_full = True | ||
1085 | |||
1086 | def handler_build_failure_cb(self, running_build): | ||
1087 | self.build_details_page.show_issues() | ||
1088 | |||
1089 | def handler_build_log_cb(self, running_build, func, obj): | ||
1090 | if hasattr(self.logger, func): | ||
1091 | getattr(self.logger, func)(obj) | ||
1092 | |||
1093 | def destroy_window_cb(self, widget, event): | ||
1094 | if not self.sensitive: | ||
1095 | return True | ||
1096 | elif self.handler.building: | ||
1097 | self.stop_build() | ||
1098 | return True | ||
1099 | else: | ||
1100 | gtk.main_quit() | ||
1101 | |||
1102 | def event_handle_SIGINT(self, signal, frame): | ||
1103 | for w in gtk.window_list_toplevels(): | ||
1104 | if w.get_modal(): | ||
1105 | w.response(gtk.RESPONSE_DELETE_EVENT) | ||
1106 | sys.exit(0) | ||
1107 | |||
1108 | def build_packages(self): | ||
1109 | _, all_recipes = self.recipe_model.get_selected_recipes() | ||
1110 | if not all_recipes: | ||
1111 | lbl = "<b>No selections made</b>" | ||
1112 | msg = "You have not made any selections" | ||
1113 | msg = msg + " so there isn't anything to bake at this time." | ||
1114 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg) | ||
1115 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
1116 | HobButton.style_button(button) | ||
1117 | dialog.run() | ||
1118 | dialog.destroy() | ||
1119 | return | ||
1120 | self.generate_packages_async(True) | ||
1121 | |||
1122 | def build_image(self): | ||
1123 | selected_packages = self.package_model.get_selected_packages() | ||
1124 | if not selected_packages: | ||
1125 | lbl = "<b>No selections made</b>" | ||
1126 | msg = "You have not made any selections" | ||
1127 | msg = msg + " so there isn't anything to bake at this time." | ||
1128 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg) | ||
1129 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
1130 | HobButton.style_button(button) | ||
1131 | dialog.run() | ||
1132 | dialog.destroy() | ||
1133 | return | ||
1134 | self.generate_image_async(True) | ||
1135 | |||
1136 | def just_bake(self): | ||
1137 | selected_image = self.recipe_model.get_selected_image() | ||
1138 | selected_packages = self.package_model.get_selected_packages() or [] | ||
1139 | |||
1140 | # If no base image and no selected packages don't build anything | ||
1141 | if not (selected_packages or selected_image != self.recipe_model.__custom_image__): | ||
1142 | lbl = "<b>No selections made</b>" | ||
1143 | msg = "You have not made any selections" | ||
1144 | msg = msg + " so there isn't anything to bake at this time." | ||
1145 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg) | ||
1146 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
1147 | HobButton.style_button(button) | ||
1148 | dialog.run() | ||
1149 | dialog.destroy() | ||
1150 | return | ||
1151 | |||
1152 | self.fast_generate_image_async(True) | ||
1153 | |||
1154 | def show_recipe_property_dialog(self, properties): | ||
1155 | information = {} | ||
1156 | dialog = PropertyDialog(title = properties["name"] +' '+ "properties", | ||
1157 | parent = self, | ||
1158 | information = properties, | ||
1159 | flags = gtk.DIALOG_DESTROY_WITH_PARENT | ||
1160 | | gtk.DIALOG_NO_SEPARATOR) | ||
1161 | |||
1162 | dialog.set_modal(False) | ||
1163 | |||
1164 | button = dialog.add_button("Close", gtk.RESPONSE_NO) | ||
1165 | HobAltButton.style_button(button) | ||
1166 | button.connect("clicked", lambda w: dialog.destroy()) | ||
1167 | |||
1168 | dialog.run() | ||
1169 | |||
1170 | def show_packages_property_dialog(self, properties): | ||
1171 | information = {} | ||
1172 | dialog = PropertyDialog(title = properties["name"] +' '+ "properties", | ||
1173 | parent = self, | ||
1174 | information = properties, | ||
1175 | flags = gtk.DIALOG_DESTROY_WITH_PARENT | ||
1176 | | gtk.DIALOG_NO_SEPARATOR) | ||
1177 | |||
1178 | dialog.set_modal(False) | ||
1179 | |||
1180 | button = dialog.add_button("Close", gtk.RESPONSE_NO) | ||
1181 | HobAltButton.style_button(button) | ||
1182 | button.connect("clicked", lambda w: dialog.destroy()) | ||
1183 | |||
1184 | dialog.run() | ||
1185 | |||
1186 | def show_layer_selection_dialog(self): | ||
1187 | dialog = LayerSelectionDialog(title = "Layers", | ||
1188 | layers = copy.deepcopy(self.configuration.layers), | ||
1189 | layers_non_removable = copy.deepcopy(self.configuration.layers_non_removable), | ||
1190 | all_layers = self.parameters.all_layers, | ||
1191 | parent = self, | ||
1192 | flags = gtk.DIALOG_MODAL | ||
1193 | | gtk.DIALOG_DESTROY_WITH_PARENT | ||
1194 | | gtk.DIALOG_NO_SEPARATOR) | ||
1195 | button = dialog.add_button("Cancel", gtk.RESPONSE_NO) | ||
1196 | HobAltButton.style_button(button) | ||
1197 | button = dialog.add_button("OK", gtk.RESPONSE_YES) | ||
1198 | HobButton.style_button(button) | ||
1199 | response = dialog.run() | ||
1200 | if response == gtk.RESPONSE_YES: | ||
1201 | self.configuration.layers = dialog.layers | ||
1202 | # DO refresh layers | ||
1203 | if dialog.layers_changed: | ||
1204 | self.update_config_async() | ||
1205 | dialog.destroy() | ||
1206 | |||
1207 | def get_image_extension(self): | ||
1208 | image_extension = {} | ||
1209 | for type in self.parameters.image_types: | ||
1210 | ext = self.handler.runCommand(["getVariable", "IMAGE_EXTENSION_%s" % type]) | ||
1211 | if ext: | ||
1212 | image_extension[type] = ext.split(' ') | ||
1213 | |||
1214 | return image_extension | ||
1215 | |||
1216 | def show_load_my_images_dialog(self): | ||
1217 | image_extension = self.get_image_extension() | ||
1218 | dialog = ImageSelectionDialog(self.parameters.image_addr, self.parameters.image_types, | ||
1219 | "Open My Images", self, | ||
1220 | gtk.FILE_CHOOSER_ACTION_SAVE, None, | ||
1221 | image_extension) | ||
1222 | button = dialog.add_button("Cancel", gtk.RESPONSE_NO) | ||
1223 | HobAltButton.style_button(button) | ||
1224 | button = dialog.add_button("Open", gtk.RESPONSE_YES) | ||
1225 | HobButton.style_button(button) | ||
1226 | response = dialog.run() | ||
1227 | if response == gtk.RESPONSE_YES: | ||
1228 | if not dialog.image_names: | ||
1229 | lbl = "<b>No selections made</b>" | ||
1230 | msg = "You have not made any selections" | ||
1231 | crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg) | ||
1232 | button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK) | ||
1233 | HobButton.style_button(button) | ||
1234 | crumbs_dialog.run() | ||
1235 | crumbs_dialog.destroy() | ||
1236 | dialog.destroy() | ||
1237 | return | ||
1238 | |||
1239 | self.parameters.image_addr = dialog.image_folder | ||
1240 | self.parameters.image_names = dialog.image_names[:] | ||
1241 | self.switch_page(self.MY_IMAGE_OPENED) | ||
1242 | |||
1243 | dialog.destroy() | ||
1244 | |||
1245 | def show_adv_settings_dialog(self, tab=None): | ||
1246 | dialog = AdvancedSettingsDialog(title = "Advanced configuration", | ||
1247 | configuration = copy.deepcopy(self.configuration), | ||
1248 | all_image_types = self.parameters.image_types, | ||
1249 | all_package_formats = self.parameters.all_package_formats, | ||
1250 | all_distros = self.parameters.all_distros, | ||
1251 | all_sdk_machines = self.parameters.all_sdk_machines, | ||
1252 | max_threads = self.parameters.max_threads, | ||
1253 | parent = self, | ||
1254 | flags = gtk.DIALOG_MODAL | ||
1255 | | gtk.DIALOG_DESTROY_WITH_PARENT | ||
1256 | | gtk.DIALOG_NO_SEPARATOR) | ||
1257 | button = dialog.add_button("Cancel", gtk.RESPONSE_NO) | ||
1258 | HobAltButton.style_button(button) | ||
1259 | button = dialog.add_button("Save", gtk.RESPONSE_YES) | ||
1260 | HobButton.style_button(button) | ||
1261 | dialog.set_save_button(button) | ||
1262 | response = dialog.run() | ||
1263 | settings_changed = False | ||
1264 | if response == gtk.RESPONSE_YES: | ||
1265 | self.configuration = dialog.configuration | ||
1266 | self.configuration.save(self.handler, True) # remember settings | ||
1267 | settings_changed = dialog.settings_changed | ||
1268 | dialog.destroy() | ||
1269 | return response == gtk.RESPONSE_YES, settings_changed | ||
1270 | |||
1271 | def show_simple_settings_dialog(self, tab=None): | ||
1272 | dialog = SimpleSettingsDialog(title = "Settings", | ||
1273 | configuration = copy.deepcopy(self.configuration), | ||
1274 | all_image_types = self.parameters.image_types, | ||
1275 | all_package_formats = self.parameters.all_package_formats, | ||
1276 | all_distros = self.parameters.all_distros, | ||
1277 | all_sdk_machines = self.parameters.all_sdk_machines, | ||
1278 | max_threads = self.parameters.max_threads, | ||
1279 | parent = self, | ||
1280 | flags = gtk.DIALOG_MODAL | ||
1281 | | gtk.DIALOG_DESTROY_WITH_PARENT | ||
1282 | | gtk.DIALOG_NO_SEPARATOR, | ||
1283 | handler = self.handler) | ||
1284 | button = dialog.add_button("Cancel", gtk.RESPONSE_NO) | ||
1285 | HobAltButton.style_button(button) | ||
1286 | button = dialog.add_button("Save", gtk.RESPONSE_YES) | ||
1287 | HobButton.style_button(button) | ||
1288 | if tab: | ||
1289 | dialog.switch_to_page(tab) | ||
1290 | response = dialog.run() | ||
1291 | settings_changed = False | ||
1292 | if response == gtk.RESPONSE_YES: | ||
1293 | self.configuration = dialog.configuration | ||
1294 | self.configuration.save(self.handler, True) # remember settings | ||
1295 | settings_changed = dialog.settings_changed | ||
1296 | if dialog.proxy_settings_changed: | ||
1297 | self.set_user_config_proxies() | ||
1298 | elif dialog.proxy_test_ran: | ||
1299 | # The user might have modified the proxies in the "Proxy" | ||
1300 | # tab, which in turn made the proxy settings modify in bb. | ||
1301 | # If "Cancel" was pressed, restore the previous proxy | ||
1302 | # settings inside bb. | ||
1303 | self.set_user_config_proxies() | ||
1304 | dialog.destroy() | ||
1305 | return response == gtk.RESPONSE_YES, settings_changed | ||
1306 | |||
1307 | def reparse_post_adv_settings(self): | ||
1308 | if not self.configuration.curr_mach: | ||
1309 | self.update_config_async() | ||
1310 | else: | ||
1311 | self.configuration.clear_selection() | ||
1312 | # DO reparse recipes | ||
1313 | self.populate_recipe_package_info_async() | ||
1314 | |||
1315 | def deploy_image(self, image_name): | ||
1316 | if not image_name: | ||
1317 | lbl = "<b>Please select an image to deploy.</b>" | ||
1318 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO) | ||
1319 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
1320 | HobButton.style_button(button) | ||
1321 | dialog.run() | ||
1322 | dialog.destroy() | ||
1323 | return | ||
1324 | |||
1325 | image_path = os.path.join(self.parameters.image_addr, image_name) | ||
1326 | dialog = DeployImageDialog(title = "Usb Image Maker", | ||
1327 | image_path = image_path, | ||
1328 | parent = self, | ||
1329 | flags = gtk.DIALOG_MODAL | ||
1330 | | gtk.DIALOG_DESTROY_WITH_PARENT | ||
1331 | | gtk.DIALOG_NO_SEPARATOR) | ||
1332 | button = dialog.add_button("Close", gtk.RESPONSE_NO) | ||
1333 | HobAltButton.style_button(button) | ||
1334 | button = dialog.add_button("Make usb image", gtk.RESPONSE_YES) | ||
1335 | HobButton.style_button(button) | ||
1336 | response = dialog.run() | ||
1337 | dialog.destroy() | ||
1338 | |||
1339 | def show_load_kernel_dialog(self): | ||
1340 | dialog = gtk.FileChooserDialog("Load Kernel Files", self, | ||
1341 | gtk.FILE_CHOOSER_ACTION_SAVE) | ||
1342 | button = dialog.add_button("Cancel", gtk.RESPONSE_NO) | ||
1343 | HobAltButton.style_button(button) | ||
1344 | button = dialog.add_button("Open", gtk.RESPONSE_YES) | ||
1345 | HobButton.style_button(button) | ||
1346 | filter = gtk.FileFilter() | ||
1347 | filter.set_name("Kernel Files") | ||
1348 | filter.add_pattern("*.bin") | ||
1349 | dialog.add_filter(filter) | ||
1350 | |||
1351 | dialog.set_current_folder(self.parameters.image_addr) | ||
1352 | |||
1353 | response = dialog.run() | ||
1354 | kernel_path = "" | ||
1355 | if response == gtk.RESPONSE_YES: | ||
1356 | kernel_path = dialog.get_filename() | ||
1357 | |||
1358 | dialog.destroy() | ||
1359 | |||
1360 | return kernel_path | ||
1361 | |||
1362 | def show_load_run_script_dialog(self): | ||
1363 | dialog = gtk.FileChooserDialog("Select Run Script", self, | ||
1364 | gtk.FILE_CHOOSER_ACTION_OPEN) | ||
1365 | button = dialog.add_button("Cancel", gtk.RESPONSE_NO) | ||
1366 | HobAltButton.style_button(button) | ||
1367 | button = dialog.add_button("Select", gtk.RESPONSE_YES) | ||
1368 | HobButton.style_button(button) | ||
1369 | |||
1370 | dialog.set_current_folder(self.parameters.image_addr) | ||
1371 | |||
1372 | response = dialog.run() | ||
1373 | run_script_path = "" | ||
1374 | if response == gtk.RESPONSE_YES: | ||
1375 | run_script_path = dialog.get_filename() | ||
1376 | |||
1377 | dialog.destroy() | ||
1378 | |||
1379 | return run_script_path | ||
1380 | |||
1381 | def runqemu_image(self, image_name, kernel_name): | ||
1382 | if not image_name or not kernel_name: | ||
1383 | lbl = "<b>Please select %s to launch in QEMU.</b>" % ("a kernel" if image_name else "an image") | ||
1384 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO) | ||
1385 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
1386 | HobButton.style_button(button) | ||
1387 | dialog.run() | ||
1388 | dialog.destroy() | ||
1389 | return | ||
1390 | |||
1391 | kernel_path = os.path.join(self.parameters.image_addr, kernel_name) | ||
1392 | image_path = os.path.join(self.parameters.image_addr, image_name) | ||
1393 | |||
1394 | source_env_path = os.path.join(self.parameters.core_base, "oe-init-build-env") | ||
1395 | tmp_path = self.parameters.tmpdir | ||
1396 | cmdline = bb.ui.crumbs.utils.which_terminal() | ||
1397 | if os.path.exists(image_path) and os.path.exists(kernel_path) \ | ||
1398 | and os.path.exists(source_env_path) and os.path.exists(tmp_path) \ | ||
1399 | and cmdline: | ||
1400 | cmdline += "\' bash -c \"export OE_TMPDIR=" + tmp_path + "; " | ||
1401 | cmdline += "source " + source_env_path + " " + os.getcwd() + "; " | ||
1402 | cmdline += "runqemu " + kernel_path + " " + image_path + "\"\'" | ||
1403 | subprocess.Popen(shlex.split(cmdline)) | ||
1404 | else: | ||
1405 | lbl = "<b>Path error</b>" | ||
1406 | msg = "One of your paths is wrong," | ||
1407 | msg = msg + " please make sure the following paths exist:\n" | ||
1408 | msg = msg + "image path:" + image_path + "\n" | ||
1409 | msg = msg + "kernel path:" + kernel_path + "\n" | ||
1410 | msg = msg + "source environment path:" + source_env_path + "\n" | ||
1411 | msg = msg + "tmp path: " + tmp_path + "." | ||
1412 | msg = msg + "You may be missing either xterm or vte for terminal services." | ||
1413 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg) | ||
1414 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
1415 | HobButton.style_button(button) | ||
1416 | dialog.run() | ||
1417 | dialog.destroy() | ||
1418 | |||
1419 | def run_custom_image(self, image_name, custom_sim_path): | ||
1420 | if not image_name or not custom_sim_path: | ||
1421 | if not image_name: | ||
1422 | lbl = "<b>Please select an image to launch in the custom simulator.</b>" | ||
1423 | else: | ||
1424 | lbl = "<b>Please select a custom simulator for launching the selected image.</b>" | ||
1425 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO) | ||
1426 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
1427 | HobButton.style_button(button) | ||
1428 | dialog.run() | ||
1429 | dialog.destroy() | ||
1430 | return | ||
1431 | |||
1432 | image_path = os.path.join(self.parameters.image_addr, image_name) | ||
1433 | |||
1434 | source_env_path = os.path.join(self.parameters.core_base, "oe-init-build-env") | ||
1435 | tmp_path = self.parameters.tmpdir | ||
1436 | cmdline = bb.ui.crumbs.utils.which_terminal() | ||
1437 | if os.path.exists(image_path) and os.path.exists(custom_sim_path) \ | ||
1438 | and os.path.exists(source_env_path) and os.path.exists(tmp_path) \ | ||
1439 | and cmdline: | ||
1440 | cmdline += "\' bash -c \"export OE_TMPDIR=" + tmp_path + "; " | ||
1441 | cmdline += "source " + source_env_path + " " + os.getcwd() + "; " | ||
1442 | cmdline += custom_sim_path + " " + image_path + "\"\'" | ||
1443 | subprocess.Popen(shlex.split(cmdline)) | ||
1444 | else: | ||
1445 | lbl = "<b>Path error</b>" | ||
1446 | msg = "One of your paths is wrong," | ||
1447 | msg = msg + " please make sure the following paths exist:\n" | ||
1448 | msg = msg + "image path:" + image_path + "\n" | ||
1449 | msg = msg + "custom simulator path:" + custom_sim_path + "\n" | ||
1450 | msg = msg + "source environment path:" + source_env_path + "\n" | ||
1451 | msg = msg + "tmp path: " + tmp_path + "." | ||
1452 | msg = msg + "You may be missing either xterm or vte for terminal services." | ||
1453 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg) | ||
1454 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
1455 | HobButton.style_button(button) | ||
1456 | dialog.run() | ||
1457 | dialog.destroy() | ||
1458 | |||
1459 | def show_packages(self): | ||
1460 | self.package_details_page.refresh_tables() | ||
1461 | self.switch_page(self.PACKAGE_SELECTION) | ||
1462 | |||
1463 | def show_recipes(self): | ||
1464 | self.switch_page(self.RECIPE_SELECTION) | ||
1465 | |||
1466 | def show_image_details(self): | ||
1467 | self.switch_page(self.IMAGE_GENERATED) | ||
1468 | |||
1469 | def show_configuration(self): | ||
1470 | self.switch_page(self.BASEIMG_SELECTED) | ||
1471 | |||
1472 | def stop_build(self): | ||
1473 | if self.stopping: | ||
1474 | lbl = "<b>Force Stop build?</b>" | ||
1475 | msg = "You've already selected Stop once," | ||
1476 | msg = msg + " would you like to 'Force Stop' the build?\n\n" | ||
1477 | msg = msg + "This will stop the build as quickly as possible but may" | ||
1478 | msg = msg + " well leave your build directory in an unusable state" | ||
1479 | msg = msg + " that requires manual steps to fix." | ||
1480 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_WARNING, msg) | ||
1481 | button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL) | ||
1482 | HobAltButton.style_button(button) | ||
1483 | button = dialog.add_button("Force Stop", gtk.RESPONSE_YES) | ||
1484 | HobButton.style_button(button) | ||
1485 | else: | ||
1486 | lbl = "<b>Stop build?</b>" | ||
1487 | msg = "Are you sure you want to stop this" | ||
1488 | msg = msg + " build?\n\n'Stop' will stop the build as soon as all in" | ||
1489 | msg = msg + " progress build tasks are finished. However if a" | ||
1490 | msg = msg + " lengthy compilation phase is in progress this may take" | ||
1491 | msg = msg + " some time.\n\n" | ||
1492 | msg = msg + "'Force Stop' will stop the build as quickly as" | ||
1493 | msg = msg + " possible but may well leave your build directory in an" | ||
1494 | msg = msg + " unusable state that requires manual steps to fix." | ||
1495 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_WARNING, msg) | ||
1496 | button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL) | ||
1497 | HobAltButton.style_button(button) | ||
1498 | button = dialog.add_button("Force stop", gtk.RESPONSE_YES) | ||
1499 | HobAltButton.style_button(button) | ||
1500 | button = dialog.add_button("Stop", gtk.RESPONSE_OK) | ||
1501 | HobButton.style_button(button) | ||
1502 | response = dialog.run() | ||
1503 | dialog.destroy() | ||
1504 | if response != gtk.RESPONSE_CANCEL: | ||
1505 | self.stopping = True | ||
1506 | if response == gtk.RESPONSE_OK: | ||
1507 | self.build_details_page.progress_bar.set_stop_title("Stopping the build....") | ||
1508 | self.build_details_page.progress_bar.set_rcstyle("stop") | ||
1509 | self.cancel_build_sync() | ||
1510 | elif response == gtk.RESPONSE_YES: | ||
1511 | self.cancel_build_sync(True) | ||
1512 | |||
1513 | def do_log(self, consolelogfile = None): | ||
1514 | if consolelogfile: | ||
1515 | bb.utils.mkdirhier(os.path.dirname(consolelogfile)) | ||
1516 | if self.consolelog: | ||
1517 | self.logger.removeHandler(self.consolelog) | ||
1518 | self.consolelog = None | ||
1519 | self.consolelog = logging.FileHandler(consolelogfile) | ||
1520 | bb.msg.addDefaultlogFilter(self.consolelog) | ||
1521 | format = bb.msg.BBLogFormatter("%(levelname)s: %(message)s") | ||
1522 | self.consolelog.setFormatter(format) | ||
1523 | |||
1524 | self.logger.addHandler(self.consolelog) | ||
1525 | |||
1526 | def get_topdir(self): | ||
1527 | return self.handler.get_topdir() | ||
1528 | |||
1529 | def wait(self, delay): | ||
1530 | time_start = time.time() | ||
1531 | time_end = time_start + delay | ||
1532 | while time_end > time.time(): | ||
1533 | while gtk.events_pending(): | ||
1534 | gtk.main_iteration() | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/advancedsettingsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/advancedsettingsdialog.py deleted file mode 100644 index e0b3553c2f..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/advancedsettingsdialog.py +++ /dev/null | |||
@@ -1,341 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011-2012 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 hashlib | ||
25 | from bb.ui.crumbs.hobwidget import HobInfoButton, HobButton | ||
26 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
27 | from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper | ||
28 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
29 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
30 | from bb.ui.crumbs.hig.proxydetailsdialog import ProxyDetailsDialog | ||
31 | |||
32 | """ | ||
33 | The following are convenience classes for implementing GNOME HIG compliant | ||
34 | BitBake GUI's | ||
35 | In summary: spacing = 12px, border-width = 6px | ||
36 | """ | ||
37 | |||
38 | class AdvancedSettingsDialog (CrumbsDialog, SettingsUIHelper): | ||
39 | |||
40 | def details_cb(self, button, parent, protocol): | ||
41 | dialog = ProxyDetailsDialog(title = protocol.upper() + " Proxy Details", | ||
42 | user = self.configuration.proxies[protocol][1], | ||
43 | passwd = self.configuration.proxies[protocol][2], | ||
44 | parent = parent, | ||
45 | flags = gtk.DIALOG_MODAL | ||
46 | | gtk.DIALOG_DESTROY_WITH_PARENT | ||
47 | | gtk.DIALOG_NO_SEPARATOR) | ||
48 | dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK) | ||
49 | response = dialog.run() | ||
50 | if response == gtk.RESPONSE_OK: | ||
51 | self.configuration.proxies[protocol][1] = dialog.user | ||
52 | self.configuration.proxies[protocol][2] = dialog.passwd | ||
53 | self.refresh_proxy_components() | ||
54 | dialog.destroy() | ||
55 | |||
56 | def set_save_button(self, button): | ||
57 | self.save_button = button | ||
58 | |||
59 | def rootfs_combo_changed_cb(self, rootfs_combo, all_package_format, check_hbox): | ||
60 | combo_item = self.rootfs_combo.get_active_text() | ||
61 | modified = False | ||
62 | for child in check_hbox.get_children(): | ||
63 | if isinstance(child, gtk.CheckButton): | ||
64 | check_hbox.remove(child) | ||
65 | modified = True | ||
66 | for format in all_package_format: | ||
67 | if format != combo_item: | ||
68 | check_button = gtk.CheckButton(format) | ||
69 | check_hbox.pack_start(check_button, expand=False, fill=False) | ||
70 | modified = True | ||
71 | if modified: | ||
72 | check_hbox.remove(self.pkgfmt_info) | ||
73 | check_hbox.pack_start(self.pkgfmt_info, expand=False, fill=False) | ||
74 | check_hbox.show_all() | ||
75 | |||
76 | def gen_pkgfmt_widget(self, curr_package_format, all_package_format, tooltip_combo="", tooltip_extra=""): | ||
77 | pkgfmt_vbox = gtk.VBox(False, 6) | ||
78 | |||
79 | label = self.gen_label_widget("Root file system package format") | ||
80 | pkgfmt_vbox.pack_start(label, expand=False, fill=False) | ||
81 | |||
82 | rootfs_format = "" | ||
83 | if curr_package_format: | ||
84 | rootfs_format = curr_package_format.split()[0] | ||
85 | |||
86 | rootfs_format_widget, rootfs_combo = self.gen_combo_widget(rootfs_format, all_package_format, tooltip_combo) | ||
87 | pkgfmt_vbox.pack_start(rootfs_format_widget, expand=False, fill=False) | ||
88 | |||
89 | label = self.gen_label_widget("Additional package formats") | ||
90 | pkgfmt_vbox.pack_start(label, expand=False, fill=False) | ||
91 | |||
92 | check_hbox = gtk.HBox(False, 12) | ||
93 | pkgfmt_vbox.pack_start(check_hbox, expand=False, fill=False) | ||
94 | for format in all_package_format: | ||
95 | if format != rootfs_format: | ||
96 | check_button = gtk.CheckButton(format) | ||
97 | is_active = (format in curr_package_format.split()) | ||
98 | check_button.set_active(is_active) | ||
99 | check_hbox.pack_start(check_button, expand=False, fill=False) | ||
100 | |||
101 | self.pkgfmt_info = HobInfoButton(tooltip_extra, self) | ||
102 | check_hbox.pack_start(self.pkgfmt_info, expand=False, fill=False) | ||
103 | |||
104 | rootfs_combo.connect("changed", self.rootfs_combo_changed_cb, all_package_format, check_hbox) | ||
105 | |||
106 | pkgfmt_vbox.show_all() | ||
107 | |||
108 | return pkgfmt_vbox, rootfs_combo, check_hbox | ||
109 | |||
110 | def __init__(self, title, configuration, all_image_types, | ||
111 | all_package_formats, all_distros, all_sdk_machines, | ||
112 | max_threads, parent, flags, buttons=None): | ||
113 | super(AdvancedSettingsDialog, self).__init__(title, parent, flags, buttons) | ||
114 | |||
115 | # class members from other objects | ||
116 | # bitbake settings from Builder.Configuration | ||
117 | self.configuration = configuration | ||
118 | self.image_types = all_image_types | ||
119 | self.all_package_formats = all_package_formats | ||
120 | self.all_distros = all_distros[:] | ||
121 | self.all_sdk_machines = all_sdk_machines | ||
122 | self.max_threads = max_threads | ||
123 | |||
124 | # class members for internal use | ||
125 | self.distro_combo = None | ||
126 | self.dldir_text = None | ||
127 | self.sstatedir_text = None | ||
128 | self.sstatemirror_text = None | ||
129 | self.bb_spinner = None | ||
130 | self.pmake_spinner = None | ||
131 | self.rootfs_size_spinner = None | ||
132 | self.extra_size_spinner = None | ||
133 | self.gplv3_checkbox = None | ||
134 | self.sdk_checkbox = None | ||
135 | self.image_types_checkbuttons = {} | ||
136 | |||
137 | self.md5 = self.config_md5() | ||
138 | self.settings_changed = False | ||
139 | |||
140 | # create visual elements on the dialog | ||
141 | self.save_button = None | ||
142 | self.create_visual_elements() | ||
143 | self.connect("response", self.response_cb) | ||
144 | |||
145 | def _get_sorted_value(self, var): | ||
146 | return " ".join(sorted(str(var).split())) + "\n" | ||
147 | |||
148 | def config_md5(self): | ||
149 | data = "" | ||
150 | data += ("PACKAGE_CLASSES: " + self.configuration.curr_package_format + '\n') | ||
151 | data += ("DISTRO: " + self._get_sorted_value(self.configuration.curr_distro)) | ||
152 | data += ("IMAGE_ROOTFS_SIZE: " + self._get_sorted_value(self.configuration.image_rootfs_size)) | ||
153 | data += ("IMAGE_EXTRA_SIZE: " + self._get_sorted_value(self.configuration.image_extra_size)) | ||
154 | data += ("INCOMPATIBLE_LICENSE: " + self._get_sorted_value(self.configuration.incompat_license)) | ||
155 | data += ("SDK_MACHINE: " + self._get_sorted_value(self.configuration.curr_sdk_machine)) | ||
156 | data += ("TOOLCHAIN_BUILD: " + self._get_sorted_value(self.configuration.toolchain_build)) | ||
157 | data += ("IMAGE_FSTYPES: " + self._get_sorted_value(self.configuration.image_fstypes)) | ||
158 | return hashlib.md5(data).hexdigest() | ||
159 | |||
160 | def create_visual_elements(self): | ||
161 | self.nb = gtk.Notebook() | ||
162 | self.nb.set_show_tabs(True) | ||
163 | self.nb.append_page(self.create_image_types_page(), gtk.Label("Image types")) | ||
164 | self.nb.append_page(self.create_output_page(), gtk.Label("Output")) | ||
165 | self.nb.set_current_page(0) | ||
166 | self.vbox.pack_start(self.nb, expand=True, fill=True) | ||
167 | self.vbox.pack_end(gtk.HSeparator(), expand=True, fill=True) | ||
168 | |||
169 | self.show_all() | ||
170 | |||
171 | def get_num_checked_image_types(self): | ||
172 | total = 0 | ||
173 | for b in self.image_types_checkbuttons.values(): | ||
174 | if b.get_active(): | ||
175 | total = total + 1 | ||
176 | return total | ||
177 | |||
178 | def set_save_button_state(self): | ||
179 | if self.save_button: | ||
180 | self.save_button.set_sensitive(self.get_num_checked_image_types() > 0) | ||
181 | |||
182 | def image_type_checkbutton_clicked_cb(self, button): | ||
183 | self.set_save_button_state() | ||
184 | if self.get_num_checked_image_types() == 0: | ||
185 | # Show an error dialog | ||
186 | lbl = "<b>Select an image type</b>" | ||
187 | msg = "You need to select at least one image type." | ||
188 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_WARNING, msg) | ||
189 | button = dialog.add_button("OK", gtk.RESPONSE_OK) | ||
190 | HobButton.style_button(button) | ||
191 | response = dialog.run() | ||
192 | dialog.destroy() | ||
193 | |||
194 | def create_image_types_page(self): | ||
195 | main_vbox = gtk.VBox(False, 16) | ||
196 | main_vbox.set_border_width(6) | ||
197 | |||
198 | advanced_vbox = gtk.VBox(False, 6) | ||
199 | advanced_vbox.set_border_width(6) | ||
200 | |||
201 | distro_vbox = gtk.VBox(False, 6) | ||
202 | label = self.gen_label_widget("Distro:") | ||
203 | tooltip = "Selects the Yocto Project distribution you want" | ||
204 | try: | ||
205 | i = self.all_distros.index( "defaultsetup" ) | ||
206 | except ValueError: | ||
207 | i = -1 | ||
208 | if i != -1: | ||
209 | self.all_distros[ i ] = "Default" | ||
210 | if self.configuration.curr_distro == "defaultsetup": | ||
211 | self.configuration.curr_distro = "Default" | ||
212 | distro_widget, self.distro_combo = self.gen_combo_widget(self.configuration.curr_distro, self.all_distros,"<b>Distro</b>" + "*" + tooltip) | ||
213 | distro_vbox.pack_start(label, expand=False, fill=False) | ||
214 | distro_vbox.pack_start(distro_widget, expand=False, fill=False) | ||
215 | main_vbox.pack_start(distro_vbox, expand=False, fill=False) | ||
216 | |||
217 | |||
218 | rows = (len(self.image_types)+1)/3 | ||
219 | table = gtk.Table(rows + 1, 10, True) | ||
220 | advanced_vbox.pack_start(table, expand=False, fill=False) | ||
221 | |||
222 | tooltip = "Image file system types you want." | ||
223 | info = HobInfoButton("<b>Image types</b>" + "*" + tooltip, self) | ||
224 | label = self.gen_label_widget("Image types:") | ||
225 | align = gtk.Alignment(0, 0.5, 0, 0) | ||
226 | table.attach(align, 0, 4, 0, 1) | ||
227 | align.add(label) | ||
228 | table.attach(info, 4, 5, 0, 1) | ||
229 | |||
230 | i = 1 | ||
231 | j = 1 | ||
232 | for image_type in sorted(self.image_types): | ||
233 | self.image_types_checkbuttons[image_type] = gtk.CheckButton(image_type) | ||
234 | self.image_types_checkbuttons[image_type].connect("toggled", self.image_type_checkbutton_clicked_cb) | ||
235 | article = "" | ||
236 | if image_type.startswith(("a", "e", "i", "o", "u")): | ||
237 | article = "n" | ||
238 | if image_type == "live": | ||
239 | self.image_types_checkbuttons[image_type].set_tooltip_text("Build iso and hddimg images") | ||
240 | else: | ||
241 | self.image_types_checkbuttons[image_type].set_tooltip_text("Build a%s %s image" % (article, image_type)) | ||
242 | table.attach(self.image_types_checkbuttons[image_type], j - 1, j + 3, i, i + 1) | ||
243 | if image_type in self.configuration.image_fstypes.split(): | ||
244 | self.image_types_checkbuttons[image_type].set_active(True) | ||
245 | i += 1 | ||
246 | if i > rows: | ||
247 | i = 1 | ||
248 | j = j + 4 | ||
249 | |||
250 | main_vbox.pack_start(advanced_vbox, expand=False, fill=False) | ||
251 | self.set_save_button_state() | ||
252 | |||
253 | return main_vbox | ||
254 | |||
255 | def create_output_page(self): | ||
256 | advanced_vbox = gtk.VBox(False, 6) | ||
257 | advanced_vbox.set_border_width(6) | ||
258 | |||
259 | advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Package format</span>'), expand=False, fill=False) | ||
260 | sub_vbox = gtk.VBox(False, 6) | ||
261 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
262 | tooltip_combo = "Selects the package format used to generate rootfs." | ||
263 | tooltip_extra = "Selects extra package formats to build" | ||
264 | pkgfmt_widget, self.rootfs_combo, self.check_hbox = self.gen_pkgfmt_widget(self.configuration.curr_package_format, self.all_package_formats,"<b>Root file system package format</b>" + "*" + tooltip_combo,"<b>Additional package formats</b>" + "*" + tooltip_extra) | ||
265 | sub_vbox.pack_start(pkgfmt_widget, expand=False, fill=False) | ||
266 | |||
267 | advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Image size</span>'), expand=False, fill=False) | ||
268 | sub_vbox = gtk.VBox(False, 6) | ||
269 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
270 | label = self.gen_label_widget("Image basic size (in MB)") | ||
271 | tooltip = "Defines the size for the generated image. The OpenEmbedded build system determines the final size for the generated image using an algorithm that takes into account the initial disk space used for the generated image, the Image basic size value, and the Additional free space value.\n\nFor more information, check the <a href=\"http://www.yoctoproject.org/docs/current/poky-ref-manual/poky-ref-manual.html#var-IMAGE_ROOTFS_SIZE\">Yocto Project Reference Manual</a>." | ||
272 | rootfs_size_widget, self.rootfs_size_spinner = self.gen_spinner_widget(int(self.configuration.image_rootfs_size*1.0/1024), 0, 65536,"<b>Image basic size</b>" + "*" + tooltip) | ||
273 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
274 | sub_vbox.pack_start(rootfs_size_widget, expand=False, fill=False) | ||
275 | |||
276 | sub_vbox = gtk.VBox(False, 6) | ||
277 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
278 | label = self.gen_label_widget("Additional free space (in MB)") | ||
279 | tooltip = "Sets extra free disk space to be added to the generated image. Use this variable when you want to ensure that a specific amount of free disk space is available on a device after an image is installed and running." | ||
280 | extra_size_widget, self.extra_size_spinner = self.gen_spinner_widget(int(self.configuration.image_extra_size*1.0/1024), 0, 65536,"<b>Additional free space</b>" + "*" + tooltip) | ||
281 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
282 | sub_vbox.pack_start(extra_size_widget, expand=False, fill=False) | ||
283 | |||
284 | advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Licensing</span>'), expand=False, fill=False) | ||
285 | self.gplv3_checkbox = gtk.CheckButton("Exclude GPLv3 packages") | ||
286 | self.gplv3_checkbox.set_tooltip_text("Check this box to prevent GPLv3 packages from being included in your image") | ||
287 | if "GPLv3" in self.configuration.incompat_license.split(): | ||
288 | self.gplv3_checkbox.set_active(True) | ||
289 | else: | ||
290 | self.gplv3_checkbox.set_active(False) | ||
291 | advanced_vbox.pack_start(self.gplv3_checkbox, expand=False, fill=False) | ||
292 | |||
293 | advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">SDK</span>'), expand=False, fill=False) | ||
294 | sub_hbox = gtk.HBox(False, 6) | ||
295 | advanced_vbox.pack_start(sub_hbox, expand=False, fill=False) | ||
296 | self.sdk_checkbox = gtk.CheckButton("Populate SDK") | ||
297 | tooltip = "Check this box to generate an SDK tarball that consists of the cross-toolchain and a sysroot that contains development packages for your image." | ||
298 | self.sdk_checkbox.set_tooltip_text(tooltip) | ||
299 | self.sdk_checkbox.set_active(self.configuration.toolchain_build) | ||
300 | sub_hbox.pack_start(self.sdk_checkbox, expand=False, fill=False) | ||
301 | |||
302 | tooltip = "Select the host platform for which you want to run the toolchain contained in the SDK tarball." | ||
303 | sdk_machine_widget, self.sdk_machine_combo = self.gen_combo_widget(self.configuration.curr_sdk_machine, self.all_sdk_machines,"<b>Populate SDK</b>" + "*" + tooltip) | ||
304 | sub_hbox.pack_start(sdk_machine_widget, expand=False, fill=False) | ||
305 | |||
306 | return advanced_vbox | ||
307 | |||
308 | def response_cb(self, dialog, response_id): | ||
309 | package_format = [] | ||
310 | package_format.append(self.rootfs_combo.get_active_text()) | ||
311 | for child in self.check_hbox: | ||
312 | if isinstance(child, gtk.CheckButton) and child.get_active(): | ||
313 | package_format.append(child.get_label()) | ||
314 | self.configuration.curr_package_format = " ".join(package_format) | ||
315 | |||
316 | distro = self.distro_combo.get_active_text() | ||
317 | if distro == "Default": | ||
318 | distro = "defaultsetup" | ||
319 | self.configuration.curr_distro = distro | ||
320 | self.configuration.image_rootfs_size = self.rootfs_size_spinner.get_value_as_int() * 1024 | ||
321 | self.configuration.image_extra_size = self.extra_size_spinner.get_value_as_int() * 1024 | ||
322 | |||
323 | self.configuration.image_fstypes = "" | ||
324 | for image_type in self.image_types: | ||
325 | if self.image_types_checkbuttons[image_type].get_active(): | ||
326 | self.configuration.image_fstypes += (" " + image_type) | ||
327 | self.configuration.image_fstypes.strip() | ||
328 | |||
329 | if self.gplv3_checkbox.get_active(): | ||
330 | if "GPLv3" not in self.configuration.incompat_license.split(): | ||
331 | self.configuration.incompat_license += " GPLv3" | ||
332 | else: | ||
333 | if "GPLv3" in self.configuration.incompat_license.split(): | ||
334 | self.configuration.incompat_license = self.configuration.incompat_license.split().remove("GPLv3") | ||
335 | self.configuration.incompat_license = " ".join(self.configuration.incompat_license or []) | ||
336 | self.configuration.incompat_license = self.configuration.incompat_license.strip() | ||
337 | |||
338 | self.configuration.toolchain_build = self.sdk_checkbox.get_active() | ||
339 | self.configuration.curr_sdk_machine = self.sdk_machine_combo.get_active_text() | ||
340 | md5 = self.config_md5() | ||
341 | self.settings_changed = (self.md5 != md5) | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/parsingwarningsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/parsingwarningsdialog.py deleted file mode 100644 index 33bac39db8..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/parsingwarningsdialog.py +++ /dev/null | |||
@@ -1,163 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011-2012 Intel Corporation | ||
5 | # | ||
6 | # Authored by Cristiana Voicu <cristiana.voicu@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 | |||
21 | import gtk | ||
22 | import gobject | ||
23 | from bb.ui.crumbs.hobwidget import HobAltButton | ||
24 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
25 | |||
26 | """ | ||
27 | The following are convenience classes for implementing GNOME HIG compliant | ||
28 | BitBake GUI's | ||
29 | In summary: spacing = 12px, border-width = 6px | ||
30 | """ | ||
31 | |||
32 | # | ||
33 | # ParsingWarningsDialog | ||
34 | # | ||
35 | class ParsingWarningsDialog (CrumbsDialog): | ||
36 | |||
37 | def __init__(self, title, warnings, parent, flags, buttons=None): | ||
38 | super(ParsingWarningsDialog, self).__init__(title, parent, flags, buttons) | ||
39 | |||
40 | self.warnings = warnings | ||
41 | self.warning_on = 0 | ||
42 | self.warn_nb = len(warnings) | ||
43 | |||
44 | # create visual elements on the dialog | ||
45 | self.create_visual_elements() | ||
46 | |||
47 | def cancel_button_cb(self, button): | ||
48 | self.destroy() | ||
49 | |||
50 | def previous_button_cb(self, button): | ||
51 | self.warning_on = self.warning_on - 1 | ||
52 | self.refresh_components() | ||
53 | |||
54 | def next_button_cb(self, button): | ||
55 | self.warning_on = self.warning_on + 1 | ||
56 | self.refresh_components() | ||
57 | |||
58 | def refresh_components(self): | ||
59 | lbl = self.warnings[self.warning_on] | ||
60 | #when the warning text has more than 400 chars, it uses a scroll bar | ||
61 | if 0<= len(lbl) < 400: | ||
62 | self.warning_label.set_size_request(320, 230) | ||
63 | self.warning_label.set_use_markup(True) | ||
64 | self.warning_label.set_line_wrap(True) | ||
65 | self.warning_label.set_markup(lbl) | ||
66 | self.warning_label.set_property("yalign", 0.00) | ||
67 | else: | ||
68 | self.textWindow.set_shadow_type(gtk.SHADOW_IN) | ||
69 | self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | ||
70 | self.msgView = gtk.TextView() | ||
71 | self.msgView.set_editable(False) | ||
72 | self.msgView.set_wrap_mode(gtk.WRAP_WORD) | ||
73 | self.msgView.set_cursor_visible(False) | ||
74 | self.msgView.set_size_request(320, 230) | ||
75 | self.buf = gtk.TextBuffer() | ||
76 | self.buf.set_text(lbl) | ||
77 | self.msgView.set_buffer(self.buf) | ||
78 | self.textWindow.add(self.msgView) | ||
79 | self.msgView.show() | ||
80 | |||
81 | if self.warning_on==0: | ||
82 | self.previous_button.set_sensitive(False) | ||
83 | else: | ||
84 | self.previous_button.set_sensitive(True) | ||
85 | |||
86 | if self.warning_on==self.warn_nb-1: | ||
87 | self.next_button.set_sensitive(False) | ||
88 | else: | ||
89 | self.next_button.set_sensitive(True) | ||
90 | |||
91 | if self.warn_nb>1: | ||
92 | self.heading = "Warning " + str(self.warning_on + 1) + " of " + str(self.warn_nb) | ||
93 | self.heading_label.set_markup('<span weight="bold">%s</span>' % self.heading) | ||
94 | else: | ||
95 | self.heading = "Warning" | ||
96 | self.heading_label.set_markup('<span weight="bold">%s</span>' % self.heading) | ||
97 | |||
98 | self.show_all() | ||
99 | |||
100 | if 0<= len(lbl) < 400: | ||
101 | self.textWindow.hide() | ||
102 | else: | ||
103 | self.warning_label.hide() | ||
104 | |||
105 | def create_visual_elements(self): | ||
106 | self.set_size_request(350, 350) | ||
107 | self.heading_label = gtk.Label() | ||
108 | self.heading_label.set_alignment(0, 0) | ||
109 | self.warning_label = gtk.Label() | ||
110 | self.warning_label.set_selectable(True) | ||
111 | self.warning_label.set_alignment(0, 0) | ||
112 | self.textWindow = gtk.ScrolledWindow() | ||
113 | |||
114 | table = gtk.Table(1, 10, False) | ||
115 | |||
116 | cancel_button = gtk.Button() | ||
117 | cancel_button.set_label("Close") | ||
118 | cancel_button.connect("clicked", self.cancel_button_cb) | ||
119 | cancel_button.set_size_request(110, 30) | ||
120 | |||
121 | self.previous_button = gtk.Button() | ||
122 | image1 = gtk.image_new_from_stock(gtk.STOCK_GO_BACK, gtk.ICON_SIZE_BUTTON) | ||
123 | image1.show() | ||
124 | box = gtk.HBox(False, 6) | ||
125 | box.show() | ||
126 | self.previous_button.add(box) | ||
127 | lbl = gtk.Label("Previous") | ||
128 | lbl.show() | ||
129 | box.pack_start(image1, expand=False, fill=False, padding=3) | ||
130 | box.pack_start(lbl, expand=True, fill=True, padding=3) | ||
131 | self.previous_button.connect("clicked", self.previous_button_cb) | ||
132 | self.previous_button.set_size_request(110, 30) | ||
133 | |||
134 | self.next_button = gtk.Button() | ||
135 | image2 = gtk.image_new_from_stock(gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON) | ||
136 | image2.show() | ||
137 | box = gtk.HBox(False, 6) | ||
138 | box.show() | ||
139 | self.next_button.add(box) | ||
140 | lbl = gtk.Label("Next") | ||
141 | lbl.show() | ||
142 | box.pack_start(lbl, expand=True, fill=True, padding=3) | ||
143 | box.pack_start(image2, expand=False, fill=False, padding=3) | ||
144 | self.next_button.connect("clicked", self.next_button_cb) | ||
145 | self.next_button.set_size_request(110, 30) | ||
146 | |||
147 | #when there more than one warning, we need "previous" and "next" button | ||
148 | if self.warn_nb>1: | ||
149 | self.vbox.pack_start(self.heading_label, expand=False, fill=False) | ||
150 | self.vbox.pack_start(self.warning_label, expand=False, fill=False) | ||
151 | self.vbox.pack_start(self.textWindow, expand=False, fill=False) | ||
152 | table.attach(cancel_button, 6, 7, 0, 1, xoptions=gtk.SHRINK) | ||
153 | table.attach(self.previous_button, 7, 8, 0, 1, xoptions=gtk.SHRINK) | ||
154 | table.attach(self.next_button, 8, 9, 0, 1, xoptions=gtk.SHRINK) | ||
155 | self.vbox.pack_end(table, expand=False, fill=False) | ||
156 | else: | ||
157 | self.vbox.pack_start(self.heading_label, expand=False, fill=False) | ||
158 | self.vbox.pack_start(self.warning_label, expand=False, fill=False) | ||
159 | self.vbox.pack_start(self.textWindow, expand=False, fill=False) | ||
160 | cancel_button = self.add_button("Close", gtk.RESPONSE_CANCEL) | ||
161 | HobAltButton.style_button(cancel_button) | ||
162 | |||
163 | self.refresh_components() | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py deleted file mode 100644 index 69e7dffb6d..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py +++ /dev/null | |||
@@ -1,90 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011-2012 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 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
25 | |||
26 | """ | ||
27 | The following are convenience classes for implementing GNOME HIG compliant | ||
28 | BitBake GUI's | ||
29 | In summary: spacing = 12px, border-width = 6px | ||
30 | """ | ||
31 | |||
32 | class ProxyDetailsDialog (CrumbsDialog): | ||
33 | |||
34 | def __init__(self, title, user, passwd, parent, flags, buttons=None): | ||
35 | super(ProxyDetailsDialog, self).__init__(title, parent, flags, buttons) | ||
36 | self.connect("response", self.response_cb) | ||
37 | |||
38 | self.auth = not (user == None or passwd == None or user == "") | ||
39 | self.user = user or "" | ||
40 | self.passwd = passwd or "" | ||
41 | |||
42 | # create visual elements on the dialog | ||
43 | self.create_visual_elements() | ||
44 | |||
45 | def create_visual_elements(self): | ||
46 | self.auth_checkbox = gtk.CheckButton("Use authentication") | ||
47 | self.auth_checkbox.set_tooltip_text("Check this box to set the username and the password") | ||
48 | self.auth_checkbox.set_active(self.auth) | ||
49 | self.auth_checkbox.connect("toggled", self.auth_checkbox_toggled_cb) | ||
50 | self.vbox.pack_start(self.auth_checkbox, expand=False, fill=False) | ||
51 | |||
52 | hbox = gtk.HBox(False, 6) | ||
53 | self.user_label = gtk.Label("Username:") | ||
54 | self.user_text = gtk.Entry() | ||
55 | self.user_text.set_text(self.user) | ||
56 | hbox.pack_start(self.user_label, expand=False, fill=False) | ||
57 | hbox.pack_end(self.user_text, expand=False, fill=False) | ||
58 | self.vbox.pack_start(hbox, expand=False, fill=False) | ||
59 | |||
60 | hbox = gtk.HBox(False, 6) | ||
61 | self.passwd_label = gtk.Label("Password:") | ||
62 | self.passwd_text = gtk.Entry() | ||
63 | self.passwd_text.set_text(self.passwd) | ||
64 | hbox.pack_start(self.passwd_label, expand=False, fill=False) | ||
65 | hbox.pack_end(self.passwd_text, expand=False, fill=False) | ||
66 | self.vbox.pack_start(hbox, expand=False, fill=False) | ||
67 | |||
68 | self.refresh_auth_components() | ||
69 | self.show_all() | ||
70 | |||
71 | def refresh_auth_components(self): | ||
72 | self.user_label.set_sensitive(self.auth) | ||
73 | self.user_text.set_editable(self.auth) | ||
74 | self.user_text.set_sensitive(self.auth) | ||
75 | self.passwd_label.set_sensitive(self.auth) | ||
76 | self.passwd_text.set_editable(self.auth) | ||
77 | self.passwd_text.set_sensitive(self.auth) | ||
78 | |||
79 | def auth_checkbox_toggled_cb(self, button): | ||
80 | self.auth = self.auth_checkbox.get_active() | ||
81 | self.refresh_auth_components() | ||
82 | |||
83 | def response_cb(self, dialog, response_id): | ||
84 | if response_id == gtk.RESPONSE_OK: | ||
85 | if self.auth: | ||
86 | self.user = self.user_text.get_text() | ||
87 | self.passwd = self.passwd_text.get_text() | ||
88 | else: | ||
89 | self.user = None | ||
90 | self.passwd = None | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/retrieveimagedialog.py b/bitbake/lib/bb/ui/crumbs/hig/retrieveimagedialog.py deleted file mode 100644 index 9017139850..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/retrieveimagedialog.py +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2013 Intel Corporation | ||
5 | # | ||
6 | # Authored by Cristiana Voicu <cristiana.voicu@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 | |||
21 | import gtk | ||
22 | |||
23 | class RetrieveImageDialog (gtk.FileChooserDialog): | ||
24 | """ | ||
25 | This class is used to create a dialog that permits to retrieve | ||
26 | a custom image saved previously from Hob. | ||
27 | """ | ||
28 | def __init__(self, directory,title, parent, flags, buttons=None): | ||
29 | super(RetrieveImageDialog, self).__init__(title, None, gtk.FILE_CHOOSER_ACTION_OPEN, | ||
30 | (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN, gtk.RESPONSE_OK)) | ||
31 | self.directory = directory | ||
32 | |||
33 | # create visual elements on the dialog | ||
34 | self.create_visual_elements() | ||
35 | |||
36 | def create_visual_elements(self): | ||
37 | self.set_show_hidden(True) | ||
38 | self.set_default_response(gtk.RESPONSE_OK) | ||
39 | self.set_current_folder(self.directory) | ||
40 | |||
41 | vbox = self.get_children()[0].get_children()[0].get_children()[0] | ||
42 | for child in vbox.get_children()[0].get_children()[0].get_children()[0].get_children(): | ||
43 | vbox.get_children()[0].get_children()[0].get_children()[0].remove(child) | ||
44 | |||
45 | label1 = gtk.Label() | ||
46 | label1.set_text("File system" + self.directory) | ||
47 | label1.show() | ||
48 | vbox.get_children()[0].get_children()[0].get_children()[0].pack_start(label1, expand=False, fill=False, padding=0) | ||
49 | vbox.get_children()[0].get_children()[1].get_children()[0].hide() | ||
50 | |||
51 | self.get_children()[0].get_children()[1].get_children()[0].set_label("Select") | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/saveimagedialog.py b/bitbake/lib/bb/ui/crumbs/hig/saveimagedialog.py deleted file mode 100644 index 4195f70e1e..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/saveimagedialog.py +++ /dev/null | |||
@@ -1,159 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2013 Intel Corporation | ||
5 | # | ||
6 | # Authored by Cristiana Voicu <cristiana.voicu@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 | |||
21 | import gtk | ||
22 | import glib | ||
23 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
24 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
25 | from bb.ui.crumbs.hobwidget import HobButton | ||
26 | |||
27 | class SaveImageDialog (CrumbsDialog): | ||
28 | """ | ||
29 | This class is used to create a dialog that permits to save | ||
30 | a custom image in a predefined directory. | ||
31 | """ | ||
32 | def __init__(self, directory, name, description, title, parent, flags, buttons=None): | ||
33 | super(SaveImageDialog, self).__init__(title, parent, flags, buttons) | ||
34 | self.directory = directory | ||
35 | self.builder = parent | ||
36 | self.name_field = name | ||
37 | self.description_field = description | ||
38 | |||
39 | # create visual elements on the dialog | ||
40 | self.create_visual_elements() | ||
41 | |||
42 | def create_visual_elements(self): | ||
43 | self.set_default_response(gtk.RESPONSE_OK) | ||
44 | self.vbox.set_border_width(6) | ||
45 | |||
46 | sub_vbox = gtk.VBox(False, 12) | ||
47 | self.vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
48 | label = gtk.Label() | ||
49 | label.set_alignment(0, 0) | ||
50 | label.set_markup("<b>Name</b>") | ||
51 | sub_label = gtk.Label() | ||
52 | sub_label.set_alignment(0, 0) | ||
53 | content = "Image recipe names should be all lowercase and include only alphanumeric\n" | ||
54 | content += "characters. The only special character you can use is the ASCII hyphen (-)." | ||
55 | sub_label.set_markup(content) | ||
56 | self.name_entry = gtk.Entry() | ||
57 | self.name_entry.set_text(self.name_field) | ||
58 | self.name_entry.set_size_request(350,30) | ||
59 | self.name_entry.connect("changed", self.name_entry_changed) | ||
60 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
61 | sub_vbox.pack_start(sub_label, expand=False, fill=False) | ||
62 | sub_vbox.pack_start(self.name_entry, expand=False, fill=False) | ||
63 | |||
64 | sub_vbox = gtk.VBox(False, 12) | ||
65 | self.vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
66 | label = gtk.Label() | ||
67 | label.set_alignment(0, 0) | ||
68 | label.set_markup("<b>Description</b> (optional)") | ||
69 | sub_label = gtk.Label() | ||
70 | sub_label.set_alignment(0, 0) | ||
71 | sub_label.set_markup("The description should be less than 150 characters long.") | ||
72 | self.description_entry = gtk.TextView() | ||
73 | description_buffer = self.description_entry.get_buffer() | ||
74 | description_buffer.set_text(self.description_field) | ||
75 | description_buffer.connect("insert-text", self.limit_description_length) | ||
76 | self.description_entry.set_wrap_mode(gtk.WRAP_WORD) | ||
77 | self.description_entry.set_size_request(350,50) | ||
78 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
79 | sub_vbox.pack_start(sub_label, expand=False, fill=False) | ||
80 | sub_vbox.pack_start(self.description_entry, expand=False, fill=False) | ||
81 | |||
82 | sub_vbox = gtk.VBox(False, 12) | ||
83 | self.vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
84 | label = gtk.Label() | ||
85 | label.set_alignment(0, 0) | ||
86 | label.set_markup("Your image recipe will be saved to:") | ||
87 | sub_label = gtk.Label() | ||
88 | sub_label.set_alignment(0, 0) | ||
89 | sub_label.set_markup(self.directory) | ||
90 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
91 | sub_vbox.pack_start(sub_label, expand=False, fill=False) | ||
92 | |||
93 | table = gtk.Table(1, 4, True) | ||
94 | |||
95 | cancel_button = gtk.Button() | ||
96 | cancel_button.set_label("Cancel") | ||
97 | cancel_button.connect("clicked", self.cancel_button_cb) | ||
98 | cancel_button.set_size_request(110, 30) | ||
99 | |||
100 | self.save_button = gtk.Button() | ||
101 | self.save_button.set_label("Save") | ||
102 | self.save_button.connect("clicked", self.save_button_cb) | ||
103 | self.save_button.set_size_request(110, 30) | ||
104 | if self.name_entry.get_text() == '': | ||
105 | self.save_button.set_sensitive(False) | ||
106 | |||
107 | table.attach(cancel_button, 2, 3, 0, 1) | ||
108 | table.attach(self.save_button, 3, 4, 0, 1) | ||
109 | self.vbox.pack_end(table, expand=False, fill=False) | ||
110 | |||
111 | self.show_all() | ||
112 | |||
113 | def limit_description_length(self, textbuffer, iter, text, length): | ||
114 | buffer_bounds = textbuffer.get_bounds() | ||
115 | entire_text = textbuffer.get_text(*buffer_bounds) | ||
116 | entire_text += text | ||
117 | if len(entire_text)>150 or text=="\n": | ||
118 | textbuffer.emit_stop_by_name("insert-text") | ||
119 | |||
120 | def name_entry_changed(self, entry): | ||
121 | text = entry.get_text() | ||
122 | if text == '': | ||
123 | self.save_button.set_sensitive(False) | ||
124 | else: | ||
125 | self.save_button.set_sensitive(True) | ||
126 | |||
127 | def cancel_button_cb(self, button): | ||
128 | self.destroy() | ||
129 | |||
130 | def save_button_cb(self, button): | ||
131 | text = self.name_entry.get_text() | ||
132 | new_text = text.replace("-","") | ||
133 | description_buffer = self.description_entry.get_buffer() | ||
134 | description = description_buffer.get_text(description_buffer.get_start_iter(),description_buffer.get_end_iter()) | ||
135 | if new_text.islower() and new_text.isalnum(): | ||
136 | self.builder.image_details_page.image_saved = True | ||
137 | self.builder.customized = False | ||
138 | self.builder.generate_new_image(self.directory+text, description) | ||
139 | self.builder.recipe_model.set_in_list(text, description) | ||
140 | self.builder.recipe_model.set_selected_image(text) | ||
141 | self.builder.image_details_page.show_page(self.builder.IMAGE_GENERATED) | ||
142 | self.builder.image_details_page.name_field_template = text | ||
143 | self.builder.image_details_page.description_field_template = description | ||
144 | self.destroy() | ||
145 | else: | ||
146 | self.show_invalid_input_error_dialog() | ||
147 | |||
148 | def show_invalid_input_error_dialog(self): | ||
149 | lbl = "<b>Invalid characters in image recipe name</b>" | ||
150 | msg = "Image recipe names should be all lowercase and\n" | ||
151 | msg += "include only alphanumeric characters. The only\n" | ||
152 | msg += "special character you can use is the ASCII hyphen (-)." | ||
153 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg) | ||
154 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
155 | HobButton.style_button(button) | ||
156 | |||
157 | res = dialog.run() | ||
158 | self.name_entry.grab_focus() | ||
159 | dialog.destroy() | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/simplesettingsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/simplesettingsdialog.py deleted file mode 100644 index b5eb3d8738..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/simplesettingsdialog.py +++ /dev/null | |||
@@ -1,891 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011-2012 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 | import hashlib | ||
26 | from bb.ui.crumbs.hobwidget import hic, HobInfoButton, HobButton, HobAltButton | ||
27 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
28 | from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper | ||
29 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
30 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
31 | from bb.ui.crumbs.hig.proxydetailsdialog import ProxyDetailsDialog | ||
32 | |||
33 | """ | ||
34 | The following are convenience classes for implementing GNOME HIG compliant | ||
35 | BitBake GUI's | ||
36 | In summary: spacing = 12px, border-width = 6px | ||
37 | """ | ||
38 | |||
39 | class SimpleSettingsDialog (CrumbsDialog, SettingsUIHelper): | ||
40 | |||
41 | (BUILD_ENV_PAGE_ID, | ||
42 | SHARED_STATE_PAGE_ID, | ||
43 | PROXIES_PAGE_ID, | ||
44 | OTHERS_PAGE_ID) = range(4) | ||
45 | |||
46 | (TEST_NETWORK_NONE, | ||
47 | TEST_NETWORK_INITIAL, | ||
48 | TEST_NETWORK_RUNNING, | ||
49 | TEST_NETWORK_PASSED, | ||
50 | TEST_NETWORK_FAILED, | ||
51 | TEST_NETWORK_CANCELED) = range(6) | ||
52 | |||
53 | TARGETS = [ | ||
54 | ("MY_TREE_MODEL_ROW", gtk.TARGET_SAME_WIDGET, 0), | ||
55 | ("text/plain", 0, 1), | ||
56 | ("TEXT", 0, 2), | ||
57 | ("STRING", 0, 3), | ||
58 | ] | ||
59 | |||
60 | def __init__(self, title, configuration, all_image_types, | ||
61 | all_package_formats, all_distros, all_sdk_machines, | ||
62 | max_threads, parent, flags, handler, buttons=None): | ||
63 | super(SimpleSettingsDialog, self).__init__(title, parent, flags, buttons) | ||
64 | |||
65 | # class members from other objects | ||
66 | # bitbake settings from Builder.Configuration | ||
67 | self.configuration = configuration | ||
68 | self.image_types = all_image_types | ||
69 | self.all_package_formats = all_package_formats | ||
70 | self.all_distros = all_distros | ||
71 | self.all_sdk_machines = all_sdk_machines | ||
72 | self.max_threads = max_threads | ||
73 | |||
74 | # class members for internal use | ||
75 | self.dldir_text = None | ||
76 | self.sstatedir_text = None | ||
77 | self.sstatemirrors_list = [] | ||
78 | self.sstatemirrors_changed = 0 | ||
79 | self.bb_spinner = None | ||
80 | self.pmake_spinner = None | ||
81 | self.rootfs_size_spinner = None | ||
82 | self.extra_size_spinner = None | ||
83 | self.gplv3_checkbox = None | ||
84 | self.toolchain_checkbox = None | ||
85 | self.setting_store = None | ||
86 | self.image_types_checkbuttons = {} | ||
87 | |||
88 | self.md5 = self.config_md5() | ||
89 | self.proxy_md5 = self.config_proxy_md5() | ||
90 | self.settings_changed = False | ||
91 | self.proxy_settings_changed = False | ||
92 | self.handler = handler | ||
93 | self.proxy_test_ran = False | ||
94 | self.selected_mirror_row = 0 | ||
95 | self.new_mirror = False | ||
96 | |||
97 | # create visual elements on the dialog | ||
98 | self.create_visual_elements() | ||
99 | self.connect("response", self.response_cb) | ||
100 | |||
101 | def _get_sorted_value(self, var): | ||
102 | return " ".join(sorted(str(var).split())) + "\n" | ||
103 | |||
104 | def config_proxy_md5(self): | ||
105 | data = ("ENABLE_PROXY: " + self._get_sorted_value(self.configuration.enable_proxy)) | ||
106 | if self.configuration.enable_proxy: | ||
107 | for protocol in self.configuration.proxies.keys(): | ||
108 | data += (protocol + ": " + self._get_sorted_value(self.configuration.combine_proxy(protocol))) | ||
109 | return hashlib.md5(data).hexdigest() | ||
110 | |||
111 | def config_md5(self): | ||
112 | data = "" | ||
113 | for key in self.configuration.extra_setting.keys(): | ||
114 | data += (key + ": " + self._get_sorted_value(self.configuration.extra_setting[key])) | ||
115 | return hashlib.md5(data).hexdigest() | ||
116 | |||
117 | def gen_proxy_entry_widget(self, protocol, parent, need_button=True, line=0): | ||
118 | label = gtk.Label(protocol.upper() + " proxy") | ||
119 | self.proxy_table.attach(label, 0, 1, line, line+1, xpadding=24) | ||
120 | |||
121 | proxy_entry = gtk.Entry() | ||
122 | proxy_entry.set_size_request(300, -1) | ||
123 | self.proxy_table.attach(proxy_entry, 1, 2, line, line+1, ypadding=4) | ||
124 | |||
125 | self.proxy_table.attach(gtk.Label(":"), 2, 3, line, line+1, xpadding=12, ypadding=4) | ||
126 | |||
127 | port_entry = gtk.Entry() | ||
128 | port_entry.set_size_request(60, -1) | ||
129 | self.proxy_table.attach(port_entry, 3, 4, line, line+1, ypadding=4) | ||
130 | |||
131 | details_button = HobAltButton("Details") | ||
132 | details_button.connect("clicked", self.details_cb, parent, protocol) | ||
133 | self.proxy_table.attach(details_button, 4, 5, line, line+1, xpadding=4, yoptions=gtk.EXPAND) | ||
134 | |||
135 | return proxy_entry, port_entry, details_button | ||
136 | |||
137 | def refresh_proxy_components(self): | ||
138 | self.same_checkbox.set_sensitive(self.configuration.enable_proxy) | ||
139 | |||
140 | self.http_proxy.set_text(self.configuration.combine_host_only("http")) | ||
141 | self.http_proxy.set_editable(self.configuration.enable_proxy) | ||
142 | self.http_proxy.set_sensitive(self.configuration.enable_proxy) | ||
143 | self.http_proxy_port.set_text(self.configuration.combine_port_only("http")) | ||
144 | self.http_proxy_port.set_editable(self.configuration.enable_proxy) | ||
145 | self.http_proxy_port.set_sensitive(self.configuration.enable_proxy) | ||
146 | self.http_proxy_details.set_sensitive(self.configuration.enable_proxy) | ||
147 | |||
148 | self.https_proxy.set_text(self.configuration.combine_host_only("https")) | ||
149 | self.https_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
150 | self.https_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
151 | self.https_proxy_port.set_text(self.configuration.combine_port_only("https")) | ||
152 | self.https_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
153 | self.https_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
154 | self.https_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
155 | |||
156 | self.ftp_proxy.set_text(self.configuration.combine_host_only("ftp")) | ||
157 | self.ftp_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
158 | self.ftp_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
159 | self.ftp_proxy_port.set_text(self.configuration.combine_port_only("ftp")) | ||
160 | self.ftp_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
161 | self.ftp_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
162 | self.ftp_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
163 | |||
164 | self.socks_proxy.set_text(self.configuration.combine_host_only("socks")) | ||
165 | self.socks_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
166 | self.socks_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
167 | self.socks_proxy_port.set_text(self.configuration.combine_port_only("socks")) | ||
168 | self.socks_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
169 | self.socks_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
170 | self.socks_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
171 | |||
172 | self.cvs_proxy.set_text(self.configuration.combine_host_only("cvs")) | ||
173 | self.cvs_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
174 | self.cvs_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
175 | self.cvs_proxy_port.set_text(self.configuration.combine_port_only("cvs")) | ||
176 | self.cvs_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
177 | self.cvs_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
178 | self.cvs_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy)) | ||
179 | |||
180 | if self.configuration.same_proxy: | ||
181 | if self.http_proxy.get_text(): | ||
182 | [w.set_text(self.http_proxy.get_text()) for w in self.same_proxy_addresses] | ||
183 | if self.http_proxy_port.get_text(): | ||
184 | [w.set_text(self.http_proxy_port.get_text()) for w in self.same_proxy_ports] | ||
185 | |||
186 | def proxy_checkbox_toggled_cb(self, button): | ||
187 | self.configuration.enable_proxy = self.proxy_checkbox.get_active() | ||
188 | if not self.configuration.enable_proxy: | ||
189 | self.configuration.same_proxy = False | ||
190 | self.same_checkbox.set_active(self.configuration.same_proxy) | ||
191 | self.save_proxy_data() | ||
192 | self.refresh_proxy_components() | ||
193 | |||
194 | def same_checkbox_toggled_cb(self, button): | ||
195 | self.configuration.same_proxy = self.same_checkbox.get_active() | ||
196 | self.save_proxy_data() | ||
197 | self.refresh_proxy_components() | ||
198 | |||
199 | def save_proxy_data(self): | ||
200 | self.configuration.split_proxy("http", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text()) | ||
201 | if self.configuration.same_proxy: | ||
202 | self.configuration.split_proxy("https", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text()) | ||
203 | self.configuration.split_proxy("ftp", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text()) | ||
204 | self.configuration.split_proxy("socks", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text()) | ||
205 | self.configuration.split_proxy("cvs", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text()) | ||
206 | else: | ||
207 | self.configuration.split_proxy("https", self.https_proxy.get_text() + ":" + self.https_proxy_port.get_text()) | ||
208 | self.configuration.split_proxy("ftp", self.ftp_proxy.get_text() + ":" + self.ftp_proxy_port.get_text()) | ||
209 | self.configuration.split_proxy("socks", self.socks_proxy.get_text() + ":" + self.socks_proxy_port.get_text()) | ||
210 | self.configuration.split_proxy("cvs", self.cvs_proxy.get_text() + ":" + self.cvs_proxy_port.get_text()) | ||
211 | |||
212 | def response_cb(self, dialog, response_id): | ||
213 | if response_id == gtk.RESPONSE_YES: | ||
214 | if self.proxy_checkbox.get_active(): | ||
215 | # Check that all proxy entries have a corresponding port | ||
216 | for proxy, port in zip(self.all_proxy_addresses, self.all_proxy_ports): | ||
217 | if proxy.get_text() and not port.get_text(): | ||
218 | lbl = "<b>Enter all port numbers</b>" | ||
219 | msg = "Proxy servers require a port number. Please make sure you have entered a port number for each proxy server." | ||
220 | dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_WARNING, msg) | ||
221 | button = dialog.add_button("Close", gtk.RESPONSE_OK) | ||
222 | HobButton.style_button(button) | ||
223 | response = dialog.run() | ||
224 | dialog.destroy() | ||
225 | self.emit_stop_by_name("response") | ||
226 | return | ||
227 | |||
228 | self.configuration.dldir = self.dldir_text.get_text() | ||
229 | self.configuration.sstatedir = self.sstatedir_text.get_text() | ||
230 | self.configuration.sstatemirror = "" | ||
231 | for mirror in self.sstatemirrors_list: | ||
232 | if mirror[1] != "" and mirror[2].startswith("file://"): | ||
233 | smirror = mirror[2] + " " + mirror[1] + " \\n " | ||
234 | self.configuration.sstatemirror += smirror | ||
235 | self.configuration.bbthread = self.bb_spinner.get_value_as_int() | ||
236 | self.configuration.pmake = self.pmake_spinner.get_value_as_int() | ||
237 | self.save_proxy_data() | ||
238 | self.configuration.extra_setting = {} | ||
239 | it = self.setting_store.get_iter_first() | ||
240 | while it: | ||
241 | key = self.setting_store.get_value(it, 0) | ||
242 | value = self.setting_store.get_value(it, 1) | ||
243 | self.configuration.extra_setting[key] = value | ||
244 | it = self.setting_store.iter_next(it) | ||
245 | |||
246 | md5 = self.config_md5() | ||
247 | self.settings_changed = (self.md5 != md5) | ||
248 | self.proxy_settings_changed = (self.proxy_md5 != self.config_proxy_md5()) | ||
249 | |||
250 | def create_build_environment_page(self): | ||
251 | advanced_vbox = gtk.VBox(False, 6) | ||
252 | advanced_vbox.set_border_width(6) | ||
253 | |||
254 | advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Parallel threads</span>'), expand=False, fill=False) | ||
255 | sub_vbox = gtk.VBox(False, 6) | ||
256 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
257 | label = self.gen_label_widget("BitBake parallel threads") | ||
258 | tooltip = "Sets the number of threads that BitBake tasks can simultaneously run. See the <a href=\"" | ||
259 | tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/" | ||
260 | tooltip += "poky-ref-manual.html#var-BB_NUMBER_THREADS\">Poky reference manual</a> for information" | ||
261 | bbthread_widget, self.bb_spinner = self.gen_spinner_widget(self.configuration.bbthread, 1, self.max_threads,"<b>BitBake prallalel threads</b>" + "*" + tooltip) | ||
262 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
263 | sub_vbox.pack_start(bbthread_widget, expand=False, fill=False) | ||
264 | |||
265 | sub_vbox = gtk.VBox(False, 6) | ||
266 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
267 | label = self.gen_label_widget("Make parallel threads") | ||
268 | tooltip = "Sets the maximum number of threads the host can use during the build. See the <a href=\"" | ||
269 | tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/" | ||
270 | tooltip += "poky-ref-manual.html#var-PARALLEL_MAKE\">Poky reference manual</a> for information" | ||
271 | pmake_widget, self.pmake_spinner = self.gen_spinner_widget(self.configuration.pmake, 1, self.max_threads,"<b>Make parallel threads</b>" + "*" + tooltip) | ||
272 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
273 | sub_vbox.pack_start(pmake_widget, expand=False, fill=False) | ||
274 | |||
275 | advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Downloaded source code</span>'), expand=False, fill=False) | ||
276 | sub_vbox = gtk.VBox(False, 6) | ||
277 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
278 | label = self.gen_label_widget("Downloads directory") | ||
279 | tooltip = "Select a folder that caches the upstream project source code" | ||
280 | dldir_widget, self.dldir_text = self.gen_entry_widget(self.configuration.dldir, self,"<b>Downloaded source code</b>" + "*" + tooltip) | ||
281 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
282 | sub_vbox.pack_start(dldir_widget, expand=False, fill=False) | ||
283 | |||
284 | return advanced_vbox | ||
285 | |||
286 | def create_shared_state_page(self): | ||
287 | advanced_vbox = gtk.VBox(False) | ||
288 | advanced_vbox.set_border_width(12) | ||
289 | |||
290 | sub_vbox = gtk.VBox(False) | ||
291 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False, padding=24) | ||
292 | content = "<span>Shared state directory</span>" | ||
293 | tooltip = "Select a folder that caches your prebuilt results" | ||
294 | label = self.gen_label_info_widget(content,"<b>Shared state directory</b>" + "*" + tooltip) | ||
295 | sstatedir_widget, self.sstatedir_text = self.gen_entry_widget(self.configuration.sstatedir, self) | ||
296 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
297 | sub_vbox.pack_start(sstatedir_widget, expand=False, fill=False, padding=6) | ||
298 | |||
299 | content = "<span weight=\"bold\">Shared state mirrors</span>" | ||
300 | tooltip = "URLs pointing to pre-built mirrors that will speed your build. " | ||
301 | tooltip += "Select the \'Standard\' configuration if the structure of your " | ||
302 | tooltip += "mirror replicates the structure of your local shared state directory. " | ||
303 | tooltip += "For more information on shared state mirrors, check the <a href=\"" | ||
304 | tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/" | ||
305 | tooltip += "poky-ref-manual.html#shared-state\">Yocto Project Reference Manual</a>." | ||
306 | table = self.gen_label_info_widget(content,"<b>Shared state mirrors</b>" + "*" + tooltip) | ||
307 | advanced_vbox.pack_start(table, expand=False, fill=False, padding=6) | ||
308 | |||
309 | sub_vbox = gtk.VBox(False) | ||
310 | advanced_vbox.pack_start(sub_vbox, gtk.TRUE, gtk.TRUE, 0) | ||
311 | |||
312 | if self.sstatemirrors_changed == 0: | ||
313 | self.sstatemirrors_changed = 1 | ||
314 | sstatemirrors = self.configuration.sstatemirror | ||
315 | if sstatemirrors == "": | ||
316 | sm_list = ["Standard", "", "file://(.*)"] | ||
317 | self.sstatemirrors_list.append(sm_list) | ||
318 | else: | ||
319 | sstatemirrors = [x for x in sstatemirrors.split('\\n')] | ||
320 | for sstatemirror in sstatemirrors: | ||
321 | sstatemirror_fields = [x for x in sstatemirror.split(' ') if x.strip()] | ||
322 | if len(sstatemirror_fields) == 2: | ||
323 | if sstatemirror_fields[0] == "file://(.*)" or sstatemirror_fields[0] == "file://.*": | ||
324 | sm_list = ["Standard", sstatemirror_fields[1], sstatemirror_fields[0]] | ||
325 | else: | ||
326 | sm_list = ["Custom", sstatemirror_fields[1], sstatemirror_fields[0]] | ||
327 | self.sstatemirrors_list.append(sm_list) | ||
328 | |||
329 | sstatemirrors_widget, sstatemirrors_store = self.gen_shared_sstate_widget(self.sstatemirrors_list, self) | ||
330 | sub_vbox.pack_start(sstatemirrors_widget, expand=True, fill=True) | ||
331 | |||
332 | table = gtk.Table(1, 10, False) | ||
333 | table.set_col_spacings(6) | ||
334 | add_mirror_button = HobAltButton("Add mirror") | ||
335 | add_mirror_button.connect("clicked", self.add_mirror) | ||
336 | add_mirror_button.set_size_request(120,30) | ||
337 | table.attach(add_mirror_button, 1, 2, 0, 1, xoptions=gtk.SHRINK) | ||
338 | |||
339 | self.delete_button = HobAltButton("Delete mirror") | ||
340 | self.delete_button.connect("clicked", self.delete_cb) | ||
341 | self.delete_button.set_size_request(120, 30) | ||
342 | table.attach(self.delete_button, 3, 4, 0, 1, xoptions=gtk.SHRINK) | ||
343 | |||
344 | advanced_vbox.pack_start(table, expand=False, fill=False, padding=6) | ||
345 | |||
346 | return advanced_vbox | ||
347 | |||
348 | def gen_shared_sstate_widget(self, sstatemirrors_list, window): | ||
349 | hbox = gtk.HBox(False) | ||
350 | |||
351 | sstatemirrors_store = gtk.ListStore(str, str, str) | ||
352 | for sstatemirror in sstatemirrors_list: | ||
353 | sstatemirrors_store.append(sstatemirror) | ||
354 | |||
355 | self.sstatemirrors_tv = gtk.TreeView() | ||
356 | self.sstatemirrors_tv.set_rules_hint(True) | ||
357 | self.sstatemirrors_tv.set_headers_visible(True) | ||
358 | tree_selection = self.sstatemirrors_tv.get_selection() | ||
359 | tree_selection.set_mode(gtk.SELECTION_SINGLE) | ||
360 | |||
361 | # Allow enable drag and drop of rows including row move | ||
362 | self.sstatemirrors_tv.enable_model_drag_source( gtk.gdk.BUTTON1_MASK, | ||
363 | self.TARGETS, | ||
364 | gtk.gdk.ACTION_DEFAULT| | ||
365 | gtk.gdk.ACTION_MOVE) | ||
366 | self.sstatemirrors_tv.enable_model_drag_dest(self.TARGETS, | ||
367 | gtk.gdk.ACTION_DEFAULT) | ||
368 | self.sstatemirrors_tv.connect("drag_data_get", self.drag_data_get_cb) | ||
369 | self.sstatemirrors_tv.connect("drag_data_received", self.drag_data_received_cb) | ||
370 | |||
371 | |||
372 | self.scroll = gtk.ScrolledWindow() | ||
373 | self.scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) | ||
374 | self.scroll.set_shadow_type(gtk.SHADOW_IN) | ||
375 | self.scroll.connect('size-allocate', self.scroll_changed) | ||
376 | self.scroll.add(self.sstatemirrors_tv) | ||
377 | |||
378 | #list store for cell renderer | ||
379 | m = gtk.ListStore(gobject.TYPE_STRING) | ||
380 | m.append(["Standard"]) | ||
381 | m.append(["Custom"]) | ||
382 | |||
383 | cell0 = gtk.CellRendererCombo() | ||
384 | cell0.set_property("model",m) | ||
385 | cell0.set_property("text-column", 0) | ||
386 | cell0.set_property("editable", True) | ||
387 | cell0.set_property("has-entry", False) | ||
388 | col0 = gtk.TreeViewColumn("Configuration") | ||
389 | col0.pack_start(cell0, False) | ||
390 | col0.add_attribute(cell0, "text", 0) | ||
391 | col0.set_cell_data_func(cell0, self.configuration_field) | ||
392 | self.sstatemirrors_tv.append_column(col0) | ||
393 | |||
394 | cell0.connect("edited", self.combo_changed, sstatemirrors_store) | ||
395 | |||
396 | self.cell1 = gtk.CellRendererText() | ||
397 | self.cell1.set_padding(5,2) | ||
398 | col1 = gtk.TreeViewColumn('Regex', self.cell1) | ||
399 | col1.set_cell_data_func(self.cell1, self.regex_field) | ||
400 | self.sstatemirrors_tv.append_column(col1) | ||
401 | |||
402 | self.cell1.connect("edited", self.regex_changed, sstatemirrors_store) | ||
403 | |||
404 | cell2 = gtk.CellRendererText() | ||
405 | cell2.set_padding(5,2) | ||
406 | cell2.set_property("editable", True) | ||
407 | col2 = gtk.TreeViewColumn('URL', cell2) | ||
408 | col2.set_cell_data_func(cell2, self.url_field) | ||
409 | self.sstatemirrors_tv.append_column(col2) | ||
410 | |||
411 | cell2.connect("edited", self.url_changed, sstatemirrors_store) | ||
412 | |||
413 | self.sstatemirrors_tv.set_model(sstatemirrors_store) | ||
414 | self.sstatemirrors_tv.set_cursor(self.selected_mirror_row) | ||
415 | hbox.pack_start(self.scroll, expand=True, fill=True) | ||
416 | hbox.show_all() | ||
417 | |||
418 | return hbox, sstatemirrors_store | ||
419 | |||
420 | def drag_data_get_cb(self, treeview, context, selection, target_id, etime): | ||
421 | treeselection = treeview.get_selection() | ||
422 | model, iter = treeselection.get_selected() | ||
423 | data = model.get_string_from_iter(iter) | ||
424 | selection.set(selection.target, 8, data) | ||
425 | |||
426 | def drag_data_received_cb(self, treeview, context, x, y, selection, info, etime): | ||
427 | model = treeview.get_model() | ||
428 | data = [] | ||
429 | tree_iter = model.get_iter_from_string(selection.data) | ||
430 | data.append(model.get_value(tree_iter, 0)) | ||
431 | data.append(model.get_value(tree_iter, 1)) | ||
432 | data.append(model.get_value(tree_iter, 2)) | ||
433 | |||
434 | drop_info = treeview.get_dest_row_at_pos(x, y) | ||
435 | if drop_info: | ||
436 | path, position = drop_info | ||
437 | iter = model.get_iter(path) | ||
438 | if (position == gtk.TREE_VIEW_DROP_BEFORE or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): | ||
439 | model.insert_before(iter, data) | ||
440 | else: | ||
441 | model.insert_after(iter, data) | ||
442 | else: | ||
443 | model.append(data) | ||
444 | if context.action == gtk.gdk.ACTION_MOVE: | ||
445 | context.finish(True, True, etime) | ||
446 | return | ||
447 | |||
448 | def delete_cb(self, button): | ||
449 | selection = self.sstatemirrors_tv.get_selection() | ||
450 | tree_model, tree_iter = selection.get_selected() | ||
451 | index = int(tree_model.get_string_from_iter(tree_iter)) | ||
452 | if index == 0: | ||
453 | self.selected_mirror_row = index | ||
454 | else: | ||
455 | self.selected_mirror_row = index - 1 | ||
456 | self.sstatemirrors_list.pop(index) | ||
457 | self.refresh_shared_state_page() | ||
458 | if not self.sstatemirrors_list: | ||
459 | self.delete_button.set_sensitive(False) | ||
460 | |||
461 | def add_mirror(self, button): | ||
462 | self.new_mirror = True | ||
463 | tooltip = "Select the pre-built mirror that will speed your build" | ||
464 | index = len(self.sstatemirrors_list) | ||
465 | self.selected_mirror_row = index | ||
466 | sm_list = ["Standard", "", "file://(.*)"] | ||
467 | self.sstatemirrors_list.append(sm_list) | ||
468 | self.refresh_shared_state_page() | ||
469 | |||
470 | def scroll_changed(self, widget, event, data=None): | ||
471 | if self.new_mirror == True: | ||
472 | adj = widget.get_vadjustment() | ||
473 | adj.set_value(adj.upper - adj.page_size) | ||
474 | self.new_mirror = False | ||
475 | |||
476 | def combo_changed(self, widget, path, text, model): | ||
477 | model[path][0] = text | ||
478 | selection = self.sstatemirrors_tv.get_selection() | ||
479 | tree_model, tree_iter = selection.get_selected() | ||
480 | index = int(tree_model.get_string_from_iter(tree_iter)) | ||
481 | self.sstatemirrors_list[index][0] = text | ||
482 | |||
483 | def regex_changed(self, cell, path, new_text, user_data): | ||
484 | user_data[path][2] = new_text | ||
485 | selection = self.sstatemirrors_tv.get_selection() | ||
486 | tree_model, tree_iter = selection.get_selected() | ||
487 | index = int(tree_model.get_string_from_iter(tree_iter)) | ||
488 | self.sstatemirrors_list[index][2] = new_text | ||
489 | return | ||
490 | |||
491 | def url_changed(self, cell, path, new_text, user_data): | ||
492 | if new_text!="Enter the mirror URL" and new_text!="Match regex and replace it with this URL": | ||
493 | user_data[path][1] = new_text | ||
494 | selection = self.sstatemirrors_tv.get_selection() | ||
495 | tree_model, tree_iter = selection.get_selected() | ||
496 | index = int(tree_model.get_string_from_iter(tree_iter)) | ||
497 | self.sstatemirrors_list[index][1] = new_text | ||
498 | return | ||
499 | |||
500 | def configuration_field(self, column, cell, model, iter): | ||
501 | cell.set_property('text', model.get_value(iter, 0)) | ||
502 | if model.get_value(iter, 0) == "Standard": | ||
503 | self.cell1.set_property("sensitive", False) | ||
504 | self.cell1.set_property("editable", False) | ||
505 | else: | ||
506 | self.cell1.set_property("sensitive", True) | ||
507 | self.cell1.set_property("editable", True) | ||
508 | return | ||
509 | |||
510 | def regex_field(self, column, cell, model, iter): | ||
511 | cell.set_property('text', model.get_value(iter, 2)) | ||
512 | return | ||
513 | |||
514 | def url_field(self, column, cell, model, iter): | ||
515 | text = model.get_value(iter, 1) | ||
516 | if text == "": | ||
517 | if model.get_value(iter, 0) == "Standard": | ||
518 | text = "Enter the mirror URL" | ||
519 | else: | ||
520 | text = "Match regex and replace it with this URL" | ||
521 | cell.set_property('text', text) | ||
522 | return | ||
523 | |||
524 | def refresh_shared_state_page(self): | ||
525 | page_num = self.nb.get_current_page() | ||
526 | self.nb.remove_page(page_num); | ||
527 | self.nb.insert_page(self.create_shared_state_page(), gtk.Label("Shared state"),page_num) | ||
528 | self.show_all() | ||
529 | self.nb.set_current_page(page_num) | ||
530 | |||
531 | def test_proxy_ended(self, passed): | ||
532 | self.proxy_test_running = False | ||
533 | self.set_test_proxy_state(self.TEST_NETWORK_PASSED if passed else self.TEST_NETWORK_FAILED) | ||
534 | self.set_sensitive(True) | ||
535 | self.refresh_proxy_components() | ||
536 | |||
537 | def timer_func(self): | ||
538 | self.test_proxy_progress.pulse() | ||
539 | return self.proxy_test_running | ||
540 | |||
541 | def test_network_button_cb(self, b): | ||
542 | self.set_test_proxy_state(self.TEST_NETWORK_RUNNING) | ||
543 | self.set_sensitive(False) | ||
544 | self.save_proxy_data() | ||
545 | if self.configuration.enable_proxy == True: | ||
546 | self.handler.set_http_proxy(self.configuration.combine_proxy("http")) | ||
547 | self.handler.set_https_proxy(self.configuration.combine_proxy("https")) | ||
548 | self.handler.set_ftp_proxy(self.configuration.combine_proxy("ftp")) | ||
549 | self.handler.set_socks_proxy(self.configuration.combine_proxy("socks")) | ||
550 | self.handler.set_cvs_proxy(self.configuration.combine_host_only("cvs"), self.configuration.combine_port_only("cvs")) | ||
551 | elif self.configuration.enable_proxy == False: | ||
552 | self.handler.set_http_proxy("") | ||
553 | self.handler.set_https_proxy("") | ||
554 | self.handler.set_ftp_proxy("") | ||
555 | self.handler.set_socks_proxy("") | ||
556 | self.handler.set_cvs_proxy("", "") | ||
557 | self.proxy_test_ran = True | ||
558 | self.proxy_test_running = True | ||
559 | gobject.timeout_add(100, self.timer_func) | ||
560 | self.handler.trigger_network_test() | ||
561 | |||
562 | def test_proxy_focus_event(self, w, direction): | ||
563 | if self.test_proxy_state in [self.TEST_NETWORK_PASSED, self.TEST_NETWORK_FAILED]: | ||
564 | self.set_test_proxy_state(self.TEST_NETWORK_INITIAL) | ||
565 | return False | ||
566 | |||
567 | def http_proxy_changed(self, e): | ||
568 | if not self.configuration.same_proxy: | ||
569 | return | ||
570 | if e == self.http_proxy: | ||
571 | [w.set_text(self.http_proxy.get_text()) for w in self.same_proxy_addresses] | ||
572 | else: | ||
573 | [w.set_text(self.http_proxy_port.get_text()) for w in self.same_proxy_ports] | ||
574 | |||
575 | def proxy_address_focus_out_event(self, w, direction): | ||
576 | text = w.get_text() | ||
577 | if not text: | ||
578 | return False | ||
579 | if text.find("//") == -1: | ||
580 | w.set_text("http://" + text) | ||
581 | return False | ||
582 | |||
583 | def set_test_proxy_state(self, state): | ||
584 | if self.test_proxy_state == state: | ||
585 | return | ||
586 | [self.proxy_table.remove(w) for w in self.test_gui_elements] | ||
587 | if state == self.TEST_NETWORK_INITIAL: | ||
588 | self.proxy_table.attach(self.test_network_button, 1, 2, 5, 6) | ||
589 | self.test_network_button.show() | ||
590 | elif state == self.TEST_NETWORK_RUNNING: | ||
591 | self.test_proxy_progress.set_rcstyle("running") | ||
592 | self.test_proxy_progress.set_text("Testing network configuration") | ||
593 | self.proxy_table.attach(self.test_proxy_progress, 0, 5, 5, 6, xpadding=4) | ||
594 | self.test_proxy_progress.show() | ||
595 | else: # passed or failed | ||
596 | self.dummy_progress.update(1.0) | ||
597 | if state == self.TEST_NETWORK_PASSED: | ||
598 | self.dummy_progress.set_text("Your network is properly configured") | ||
599 | self.dummy_progress.set_rcstyle("running") | ||
600 | else: | ||
601 | self.dummy_progress.set_text("Network test failed") | ||
602 | self.dummy_progress.set_rcstyle("fail") | ||
603 | self.proxy_table.attach(self.dummy_progress, 0, 4, 5, 6) | ||
604 | self.proxy_table.attach(self.retest_network_button, 4, 5, 5, 6, xpadding=4) | ||
605 | self.dummy_progress.show() | ||
606 | self.retest_network_button.show() | ||
607 | self.test_proxy_state = state | ||
608 | |||
609 | def create_network_page(self): | ||
610 | advanced_vbox = gtk.VBox(False, 6) | ||
611 | advanced_vbox.set_border_width(6) | ||
612 | self.same_proxy_addresses = [] | ||
613 | self.same_proxy_ports = [] | ||
614 | self.all_proxy_ports = [] | ||
615 | self.all_proxy_addresses = [] | ||
616 | |||
617 | sub_vbox = gtk.VBox(False, 6) | ||
618 | advanced_vbox.pack_start(sub_vbox, expand=False, fill=False) | ||
619 | label = self.gen_label_widget("<span weight=\"bold\">Set the proxies used when fetching source code</span>") | ||
620 | tooltip = "Set the proxies used when fetching source code. A blank field uses a direct internet connection." | ||
621 | info = HobInfoButton("<span weight=\"bold\">Set the proxies used when fetching source code</span>" + "*" + tooltip, self) | ||
622 | hbox = gtk.HBox(False, 12) | ||
623 | hbox.pack_start(label, expand=True, fill=True) | ||
624 | hbox.pack_start(info, expand=False, fill=False) | ||
625 | sub_vbox.pack_start(hbox, expand=False, fill=False) | ||
626 | |||
627 | proxy_test_focus = [] | ||
628 | self.direct_checkbox = gtk.RadioButton(None, "Direct network connection") | ||
629 | proxy_test_focus.append(self.direct_checkbox) | ||
630 | self.direct_checkbox.set_tooltip_text("Check this box to use a direct internet connection with no proxy") | ||
631 | self.direct_checkbox.set_active(not self.configuration.enable_proxy) | ||
632 | sub_vbox.pack_start(self.direct_checkbox, expand=False, fill=False) | ||
633 | |||
634 | self.proxy_checkbox = gtk.RadioButton(self.direct_checkbox, "Manual proxy configuration") | ||
635 | proxy_test_focus.append(self.proxy_checkbox) | ||
636 | self.proxy_checkbox.set_tooltip_text("Check this box to manually set up a specific proxy") | ||
637 | self.proxy_checkbox.set_active(self.configuration.enable_proxy) | ||
638 | sub_vbox.pack_start(self.proxy_checkbox, expand=False, fill=False) | ||
639 | |||
640 | self.same_checkbox = gtk.CheckButton("Use the HTTP proxy for all protocols") | ||
641 | proxy_test_focus.append(self.same_checkbox) | ||
642 | self.same_checkbox.set_tooltip_text("Check this box to use the HTTP proxy for all five proxies") | ||
643 | self.same_checkbox.set_active(self.configuration.same_proxy) | ||
644 | hbox = gtk.HBox(False, 12) | ||
645 | hbox.pack_start(self.same_checkbox, expand=False, fill=False, padding=24) | ||
646 | sub_vbox.pack_start(hbox, expand=False, fill=False) | ||
647 | |||
648 | self.proxy_table = gtk.Table(6, 5, False) | ||
649 | self.http_proxy, self.http_proxy_port, self.http_proxy_details = self.gen_proxy_entry_widget( | ||
650 | "http", self, True, 0) | ||
651 | proxy_test_focus +=[self.http_proxy, self.http_proxy_port] | ||
652 | self.http_proxy.connect("changed", self.http_proxy_changed) | ||
653 | self.http_proxy_port.connect("changed", self.http_proxy_changed) | ||
654 | |||
655 | self.https_proxy, self.https_proxy_port, self.https_proxy_details = self.gen_proxy_entry_widget( | ||
656 | "https", self, True, 1) | ||
657 | proxy_test_focus += [self.https_proxy, self.https_proxy_port] | ||
658 | self.same_proxy_addresses.append(self.https_proxy) | ||
659 | self.same_proxy_ports.append(self.https_proxy_port) | ||
660 | |||
661 | self.ftp_proxy, self.ftp_proxy_port, self.ftp_proxy_details = self.gen_proxy_entry_widget( | ||
662 | "ftp", self, True, 2) | ||
663 | proxy_test_focus += [self.ftp_proxy, self.ftp_proxy_port] | ||
664 | self.same_proxy_addresses.append(self.ftp_proxy) | ||
665 | self.same_proxy_ports.append(self.ftp_proxy_port) | ||
666 | |||
667 | self.socks_proxy, self.socks_proxy_port, self.socks_proxy_details = self.gen_proxy_entry_widget( | ||
668 | "socks", self, True, 3) | ||
669 | proxy_test_focus += [self.socks_proxy, self.socks_proxy_port] | ||
670 | self.same_proxy_addresses.append(self.socks_proxy) | ||
671 | self.same_proxy_ports.append(self.socks_proxy_port) | ||
672 | |||
673 | self.cvs_proxy, self.cvs_proxy_port, self.cvs_proxy_details = self.gen_proxy_entry_widget( | ||
674 | "cvs", self, True, 4) | ||
675 | proxy_test_focus += [self.cvs_proxy, self.cvs_proxy_port] | ||
676 | self.same_proxy_addresses.append(self.cvs_proxy) | ||
677 | self.same_proxy_ports.append(self.cvs_proxy_port) | ||
678 | self.all_proxy_ports = self.same_proxy_ports + [self.http_proxy_port] | ||
679 | self.all_proxy_addresses = self.same_proxy_addresses + [self.http_proxy] | ||
680 | sub_vbox.pack_start(self.proxy_table, expand=False, fill=False) | ||
681 | self.proxy_table.show_all() | ||
682 | |||
683 | # Create the graphical elements for the network test feature, but don't display them yet | ||
684 | self.test_network_button = HobAltButton("Test network configuration") | ||
685 | self.test_network_button.connect("clicked", self.test_network_button_cb) | ||
686 | self.test_proxy_progress = HobProgressBar() | ||
687 | self.dummy_progress = HobProgressBar() | ||
688 | self.retest_network_button = HobAltButton("Retest") | ||
689 | self.retest_network_button.connect("clicked", self.test_network_button_cb) | ||
690 | self.test_gui_elements = [self.test_network_button, self.test_proxy_progress, self.dummy_progress, self.retest_network_button] | ||
691 | # Initialize the network tester | ||
692 | self.test_proxy_state = self.TEST_NETWORK_NONE | ||
693 | self.set_test_proxy_state(self.TEST_NETWORK_INITIAL) | ||
694 | self.proxy_test_passed_id = self.handler.connect("network-passed", lambda h:self.test_proxy_ended(True)) | ||
695 | self.proxy_test_failed_id = self.handler.connect("network-failed", lambda h:self.test_proxy_ended(False)) | ||
696 | [w.connect("focus-in-event", self.test_proxy_focus_event) for w in proxy_test_focus] | ||
697 | [w.connect("focus-out-event", self.proxy_address_focus_out_event) for w in self.all_proxy_addresses] | ||
698 | |||
699 | self.direct_checkbox.connect("toggled", self.proxy_checkbox_toggled_cb) | ||
700 | self.proxy_checkbox.connect("toggled", self.proxy_checkbox_toggled_cb) | ||
701 | self.same_checkbox.connect("toggled", self.same_checkbox_toggled_cb) | ||
702 | |||
703 | self.refresh_proxy_components() | ||
704 | return advanced_vbox | ||
705 | |||
706 | def switch_to_page(self, page_id): | ||
707 | self.nb.set_current_page(page_id) | ||
708 | |||
709 | def details_cb(self, button, parent, protocol): | ||
710 | self.save_proxy_data() | ||
711 | dialog = ProxyDetailsDialog(title = protocol.upper() + " Proxy Details", | ||
712 | user = self.configuration.proxies[protocol][1], | ||
713 | passwd = self.configuration.proxies[protocol][2], | ||
714 | parent = parent, | ||
715 | flags = gtk.DIALOG_MODAL | ||
716 | | gtk.DIALOG_DESTROY_WITH_PARENT | ||
717 | | gtk.DIALOG_NO_SEPARATOR) | ||
718 | dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK) | ||
719 | response = dialog.run() | ||
720 | if response == gtk.RESPONSE_OK: | ||
721 | self.configuration.proxies[protocol][1] = dialog.user | ||
722 | self.configuration.proxies[protocol][2] = dialog.passwd | ||
723 | self.refresh_proxy_components() | ||
724 | dialog.destroy() | ||
725 | |||
726 | def rootfs_combo_changed_cb(self, rootfs_combo, all_package_format, check_hbox): | ||
727 | combo_item = self.rootfs_combo.get_active_text() | ||
728 | for child in check_hbox.get_children(): | ||
729 | if isinstance(child, gtk.CheckButton): | ||
730 | check_hbox.remove(child) | ||
731 | for format in all_package_format: | ||
732 | if format != combo_item: | ||
733 | check_button = gtk.CheckButton(format) | ||
734 | check_hbox.pack_start(check_button, expand=False, fill=False) | ||
735 | check_hbox.show_all() | ||
736 | |||
737 | def gen_pkgfmt_widget(self, curr_package_format, all_package_format, tooltip_combo="", tooltip_extra=""): | ||
738 | pkgfmt_hbox = gtk.HBox(False, 24) | ||
739 | |||
740 | rootfs_vbox = gtk.VBox(False, 6) | ||
741 | pkgfmt_hbox.pack_start(rootfs_vbox, expand=False, fill=False) | ||
742 | |||
743 | label = self.gen_label_widget("Root file system package format") | ||
744 | rootfs_vbox.pack_start(label, expand=False, fill=False) | ||
745 | |||
746 | rootfs_format = "" | ||
747 | if curr_package_format: | ||
748 | rootfs_format = curr_package_format.split()[0] | ||
749 | |||
750 | rootfs_format_widget, rootfs_combo = self.gen_combo_widget(rootfs_format, all_package_format, tooltip_combo) | ||
751 | rootfs_vbox.pack_start(rootfs_format_widget, expand=False, fill=False) | ||
752 | |||
753 | extra_vbox = gtk.VBox(False, 6) | ||
754 | pkgfmt_hbox.pack_start(extra_vbox, expand=False, fill=False) | ||
755 | |||
756 | label = self.gen_label_widget("Additional package formats") | ||
757 | extra_vbox.pack_start(label, expand=False, fill=False) | ||
758 | |||
759 | check_hbox = gtk.HBox(False, 12) | ||
760 | extra_vbox.pack_start(check_hbox, expand=False, fill=False) | ||
761 | for format in all_package_format: | ||
762 | if format != rootfs_format: | ||
763 | check_button = gtk.CheckButton(format) | ||
764 | is_active = (format in curr_package_format.split()) | ||
765 | check_button.set_active(is_active) | ||
766 | check_hbox.pack_start(check_button, expand=False, fill=False) | ||
767 | |||
768 | info = HobInfoButton(tooltip_extra, self) | ||
769 | check_hbox.pack_end(info, expand=False, fill=False) | ||
770 | |||
771 | rootfs_combo.connect("changed", self.rootfs_combo_changed_cb, all_package_format, check_hbox) | ||
772 | |||
773 | pkgfmt_hbox.show_all() | ||
774 | |||
775 | return pkgfmt_hbox, rootfs_combo, check_hbox | ||
776 | |||
777 | def editable_settings_cell_edited(self, cell, path_string, new_text, model): | ||
778 | it = model.get_iter_from_string(path_string) | ||
779 | column = cell.get_data("column") | ||
780 | model.set(it, column, new_text) | ||
781 | |||
782 | def editable_settings_add_item_clicked(self, button, model): | ||
783 | new_item = ["##KEY##", "##VALUE##"] | ||
784 | |||
785 | iter = model.append() | ||
786 | model.set (iter, | ||
787 | 0, new_item[0], | ||
788 | 1, new_item[1], | ||
789 | ) | ||
790 | |||
791 | def editable_settings_remove_item_clicked(self, button, treeview): | ||
792 | selection = treeview.get_selection() | ||
793 | model, iter = selection.get_selected() | ||
794 | |||
795 | if iter: | ||
796 | path = model.get_path(iter)[0] | ||
797 | model.remove(iter) | ||
798 | |||
799 | def gen_editable_settings(self, setting, tooltip=""): | ||
800 | setting_hbox = gtk.HBox(False, 12) | ||
801 | |||
802 | vbox = gtk.VBox(False, 12) | ||
803 | setting_hbox.pack_start(vbox, expand=True, fill=True) | ||
804 | |||
805 | setting_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) | ||
806 | for key in setting.keys(): | ||
807 | setting_store.set(setting_store.append(), 0, key, 1, setting[key]) | ||
808 | |||
809 | setting_tree = gtk.TreeView(setting_store) | ||
810 | setting_tree.set_headers_visible(True) | ||
811 | setting_tree.set_size_request(300, 100) | ||
812 | |||
813 | col = gtk.TreeViewColumn('Key') | ||
814 | col.set_min_width(100) | ||
815 | col.set_max_width(150) | ||
816 | col.set_resizable(True) | ||
817 | col1 = gtk.TreeViewColumn('Value') | ||
818 | col1.set_min_width(100) | ||
819 | col1.set_max_width(150) | ||
820 | col1.set_resizable(True) | ||
821 | setting_tree.append_column(col) | ||
822 | setting_tree.append_column(col1) | ||
823 | cell = gtk.CellRendererText() | ||
824 | cell.set_property('width-chars', 10) | ||
825 | cell.set_property('editable', True) | ||
826 | cell.set_data("column", 0) | ||
827 | cell.connect("edited", self.editable_settings_cell_edited, setting_store) | ||
828 | cell1 = gtk.CellRendererText() | ||
829 | cell1.set_property('width-chars', 10) | ||
830 | cell1.set_property('editable', True) | ||
831 | cell1.set_data("column", 1) | ||
832 | cell1.connect("edited", self.editable_settings_cell_edited, setting_store) | ||
833 | col.pack_start(cell, True) | ||
834 | col1.pack_end(cell1, True) | ||
835 | col.set_attributes(cell, text=0) | ||
836 | col1.set_attributes(cell1, text=1) | ||
837 | |||
838 | scroll = gtk.ScrolledWindow() | ||
839 | scroll.set_shadow_type(gtk.SHADOW_IN) | ||
840 | scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | ||
841 | scroll.add(setting_tree) | ||
842 | vbox.pack_start(scroll, expand=True, fill=True) | ||
843 | |||
844 | # some buttons | ||
845 | hbox = gtk.HBox(True, 6) | ||
846 | vbox.pack_start(hbox, False, False) | ||
847 | |||
848 | button = gtk.Button(stock=gtk.STOCK_ADD) | ||
849 | button.connect("clicked", self.editable_settings_add_item_clicked, setting_store) | ||
850 | hbox.pack_start(button) | ||
851 | |||
852 | button = gtk.Button(stock=gtk.STOCK_REMOVE) | ||
853 | button.connect("clicked", self.editable_settings_remove_item_clicked, setting_tree) | ||
854 | hbox.pack_start(button) | ||
855 | |||
856 | info = HobInfoButton(tooltip, self) | ||
857 | setting_hbox.pack_start(info, expand=False, fill=False) | ||
858 | |||
859 | return setting_hbox, setting_store | ||
860 | |||
861 | def create_others_page(self): | ||
862 | advanced_vbox = gtk.VBox(False, 6) | ||
863 | advanced_vbox.set_border_width(6) | ||
864 | |||
865 | sub_vbox = gtk.VBox(False, 6) | ||
866 | advanced_vbox.pack_start(sub_vbox, expand=True, fill=True) | ||
867 | label = self.gen_label_widget("<span weight=\"bold\">Add your own variables:</span>") | ||
868 | tooltip = "These are key/value pairs for your extra settings. Click \'Add\' and then directly edit the key and the value" | ||
869 | setting_widget, self.setting_store = self.gen_editable_settings(self.configuration.extra_setting,"<b>Add your own variables</b>" + "*" + tooltip) | ||
870 | sub_vbox.pack_start(label, expand=False, fill=False) | ||
871 | sub_vbox.pack_start(setting_widget, expand=True, fill=True) | ||
872 | |||
873 | return advanced_vbox | ||
874 | |||
875 | def create_visual_elements(self): | ||
876 | self.nb = gtk.Notebook() | ||
877 | self.nb.set_show_tabs(True) | ||
878 | self.nb.append_page(self.create_build_environment_page(), gtk.Label("Build environment")) | ||
879 | self.nb.append_page(self.create_shared_state_page(), gtk.Label("Shared state")) | ||
880 | self.nb.append_page(self.create_network_page(), gtk.Label("Network")) | ||
881 | self.nb.append_page(self.create_others_page(), gtk.Label("Others")) | ||
882 | self.nb.set_current_page(0) | ||
883 | self.vbox.pack_start(self.nb, expand=True, fill=True) | ||
884 | self.vbox.pack_end(gtk.HSeparator(), expand=True, fill=True) | ||
885 | |||
886 | self.show_all() | ||
887 | |||
888 | def destroy(self): | ||
889 | self.handler.disconnect(self.proxy_test_passed_id) | ||
890 | self.handler.disconnect(self.proxy_test_failed_id) | ||
891 | super(SimpleSettingsDialog, self).destroy() | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hobeventhandler.py b/bitbake/lib/bb/ui/crumbs/hobeventhandler.py deleted file mode 100644 index b71fb33d30..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hobeventhandler.py +++ /dev/null | |||
@@ -1,645 +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 | # | ||
9 | # This program is free software; you can redistribute it and/or modify | ||
10 | # it under the terms of the GNU General Public License version 2 as | ||
11 | # published by the Free Software Foundation. | ||
12 | # | ||
13 | # This program is distributed in the hope that it will be useful, | ||
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | # GNU General Public License for more details. | ||
17 | # | ||
18 | # You should have received a copy of the GNU General Public License along | ||
19 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | |||
22 | import gobject | ||
23 | import logging | ||
24 | import ast | ||
25 | from bb.ui.crumbs.runningbuild import RunningBuild | ||
26 | |||
27 | class HobHandler(gobject.GObject): | ||
28 | |||
29 | """ | ||
30 | This object does BitBake event handling for the hob gui. | ||
31 | """ | ||
32 | __gsignals__ = { | ||
33 | "package-formats-updated" : (gobject.SIGNAL_RUN_LAST, | ||
34 | gobject.TYPE_NONE, | ||
35 | (gobject.TYPE_PYOBJECT,)), | ||
36 | "config-updated" : (gobject.SIGNAL_RUN_LAST, | ||
37 | gobject.TYPE_NONE, | ||
38 | (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT,)), | ||
39 | "command-succeeded" : (gobject.SIGNAL_RUN_LAST, | ||
40 | gobject.TYPE_NONE, | ||
41 | (gobject.TYPE_INT,)), | ||
42 | "command-failed" : (gobject.SIGNAL_RUN_LAST, | ||
43 | gobject.TYPE_NONE, | ||
44 | (gobject.TYPE_STRING,)), | ||
45 | "parsing-warning" : (gobject.SIGNAL_RUN_LAST, | ||
46 | gobject.TYPE_NONE, | ||
47 | (gobject.TYPE_STRING,)), | ||
48 | "sanity-failed" : (gobject.SIGNAL_RUN_LAST, | ||
49 | gobject.TYPE_NONE, | ||
50 | (gobject.TYPE_STRING, gobject.TYPE_INT)), | ||
51 | "generating-data" : (gobject.SIGNAL_RUN_LAST, | ||
52 | gobject.TYPE_NONE, | ||
53 | ()), | ||
54 | "data-generated" : (gobject.SIGNAL_RUN_LAST, | ||
55 | gobject.TYPE_NONE, | ||
56 | ()), | ||
57 | "parsing-started" : (gobject.SIGNAL_RUN_LAST, | ||
58 | gobject.TYPE_NONE, | ||
59 | (gobject.TYPE_PYOBJECT,)), | ||
60 | "parsing" : (gobject.SIGNAL_RUN_LAST, | ||
61 | gobject.TYPE_NONE, | ||
62 | (gobject.TYPE_PYOBJECT,)), | ||
63 | "parsing-completed" : (gobject.SIGNAL_RUN_LAST, | ||
64 | gobject.TYPE_NONE, | ||
65 | (gobject.TYPE_PYOBJECT,)), | ||
66 | "recipe-populated" : (gobject.SIGNAL_RUN_LAST, | ||
67 | gobject.TYPE_NONE, | ||
68 | ()), | ||
69 | "package-populated" : (gobject.SIGNAL_RUN_LAST, | ||
70 | gobject.TYPE_NONE, | ||
71 | ()), | ||
72 | "network-passed" : (gobject.SIGNAL_RUN_LAST, | ||
73 | gobject.TYPE_NONE, | ||
74 | ()), | ||
75 | "network-failed" : (gobject.SIGNAL_RUN_LAST, | ||
76 | gobject.TYPE_NONE, | ||
77 | ()), | ||
78 | } | ||
79 | |||
80 | (GENERATE_CONFIGURATION, GENERATE_RECIPES, GENERATE_PACKAGES, GENERATE_IMAGE, POPULATE_PACKAGEINFO, SANITY_CHECK, NETWORK_TEST) = range(7) | ||
81 | (SUB_PATH_LAYERS, SUB_FILES_DISTRO, SUB_FILES_MACH, SUB_FILES_SDKMACH, SUB_MATCH_CLASS, SUB_PARSE_CONFIG, SUB_SANITY_CHECK, | ||
82 | SUB_GNERATE_TGTS, SUB_GENERATE_PKGINFO, SUB_BUILD_RECIPES, SUB_BUILD_IMAGE, SUB_NETWORK_TEST) = range(12) | ||
83 | |||
84 | def __init__(self, server, recipe_model, package_model): | ||
85 | super(HobHandler, self).__init__() | ||
86 | |||
87 | self.build = RunningBuild(sequential=True) | ||
88 | |||
89 | self.recipe_model = recipe_model | ||
90 | self.package_model = package_model | ||
91 | |||
92 | self.commands_async = [] | ||
93 | self.generating = False | ||
94 | self.current_phase = None | ||
95 | self.building = False | ||
96 | self.recipe_queue = [] | ||
97 | self.package_queue = [] | ||
98 | |||
99 | self.server = server | ||
100 | self.error_msg = "" | ||
101 | self.initcmd = None | ||
102 | self.parsing = False | ||
103 | |||
104 | def set_busy(self): | ||
105 | if not self.generating: | ||
106 | self.emit("generating-data") | ||
107 | self.generating = True | ||
108 | |||
109 | def clear_busy(self): | ||
110 | if self.generating: | ||
111 | self.emit("data-generated") | ||
112 | self.generating = False | ||
113 | |||
114 | def runCommand(self, commandline): | ||
115 | try: | ||
116 | result, error = self.server.runCommand(commandline) | ||
117 | if error: | ||
118 | raise Exception("Error running command '%s': %s" % (commandline, error)) | ||
119 | return result | ||
120 | except Exception as e: | ||
121 | self.commands_async = [] | ||
122 | self.clear_busy() | ||
123 | self.emit("command-failed", "Hob Exception - %s" % (str(e))) | ||
124 | return None | ||
125 | |||
126 | def run_next_command(self, initcmd=None): | ||
127 | if initcmd != None: | ||
128 | self.initcmd = initcmd | ||
129 | |||
130 | if self.commands_async: | ||
131 | self.set_busy() | ||
132 | next_command = self.commands_async.pop(0) | ||
133 | else: | ||
134 | self.clear_busy() | ||
135 | if self.initcmd != None: | ||
136 | self.emit("command-succeeded", self.initcmd) | ||
137 | return | ||
138 | |||
139 | if next_command == self.SUB_PATH_LAYERS: | ||
140 | self.runCommand(["findConfigFilePath", "bblayers.conf"]) | ||
141 | elif next_command == self.SUB_FILES_DISTRO: | ||
142 | self.runCommand(["findConfigFiles", "DISTRO"]) | ||
143 | elif next_command == self.SUB_FILES_MACH: | ||
144 | self.runCommand(["findConfigFiles", "MACHINE"]) | ||
145 | elif next_command == self.SUB_FILES_SDKMACH: | ||
146 | self.runCommand(["findConfigFiles", "MACHINE-SDK"]) | ||
147 | elif next_command == self.SUB_MATCH_CLASS: | ||
148 | self.runCommand(["findFilesMatchingInDir", "rootfs_", "classes"]) | ||
149 | elif next_command == self.SUB_PARSE_CONFIG: | ||
150 | self.runCommand(["resetCooker"]) | ||
151 | elif next_command == self.SUB_GNERATE_TGTS: | ||
152 | self.runCommand(["generateTargetsTree", "classes/image.bbclass", []]) | ||
153 | elif next_command == self.SUB_GENERATE_PKGINFO: | ||
154 | self.runCommand(["triggerEvent", "bb.event.RequestPackageInfo()"]) | ||
155 | elif next_command == self.SUB_SANITY_CHECK: | ||
156 | self.runCommand(["triggerEvent", "bb.event.SanityCheck()"]) | ||
157 | elif next_command == self.SUB_NETWORK_TEST: | ||
158 | self.runCommand(["triggerEvent", "bb.event.NetworkTest()"]) | ||
159 | elif next_command == self.SUB_BUILD_RECIPES: | ||
160 | self.clear_busy() | ||
161 | self.building = True | ||
162 | self.runCommand(["buildTargets", self.recipe_queue, self.default_task]) | ||
163 | self.recipe_queue = [] | ||
164 | elif next_command == self.SUB_BUILD_IMAGE: | ||
165 | self.clear_busy() | ||
166 | self.building = True | ||
167 | target = self.image | ||
168 | |||
169 | if self.base_image: | ||
170 | # Request the build of a custom image | ||
171 | self.generate_hob_base_image(target) | ||
172 | self.set_var_in_file("LINGUAS_INSTALL", "", "local.conf") | ||
173 | hobImage = self.runCommand(["matchFile", target + ".bb"]) | ||
174 | if self.base_image != self.recipe_model.__custom_image__: | ||
175 | baseImage = self.runCommand(["matchFile", self.base_image + ".bb"]) | ||
176 | version = self.runCommand(["generateNewImage", hobImage, baseImage, self.package_queue, True, ""]) | ||
177 | target += version | ||
178 | self.recipe_model.set_custom_image_version(version) | ||
179 | |||
180 | targets = [target] | ||
181 | if self.toolchain_packages: | ||
182 | self.set_var_in_file("TOOLCHAIN_TARGET_TASK", " ".join(self.toolchain_packages), "local.conf") | ||
183 | targets.append(target + ":do_populate_sdk") | ||
184 | |||
185 | self.runCommand(["buildTargets", targets, self.default_task]) | ||
186 | |||
187 | def display_error(self): | ||
188 | self.clear_busy() | ||
189 | self.emit("command-failed", self.error_msg) | ||
190 | self.error_msg = "" | ||
191 | if self.building: | ||
192 | self.building = False | ||
193 | |||
194 | def handle_event(self, event): | ||
195 | if not event: | ||
196 | return | ||
197 | if self.building: | ||
198 | self.current_phase = "building" | ||
199 | self.build.handle_event(event) | ||
200 | |||
201 | if isinstance(event, bb.event.PackageInfo): | ||
202 | self.package_model.populate(event._pkginfolist) | ||
203 | self.emit("package-populated") | ||
204 | self.run_next_command() | ||
205 | |||
206 | elif isinstance(event, bb.event.SanityCheckPassed): | ||
207 | reparse = self.runCommand(["getVariable", "BB_INVALIDCONF"]) or None | ||
208 | if reparse is True: | ||
209 | self.set_var_in_file("BB_INVALIDCONF", False, "local.conf") | ||
210 | self.runCommand(["setPrePostConfFiles", "conf/.hob.conf", ""]) | ||
211 | self.commands_async.prepend(self.SUB_PARSE_CONFIG) | ||
212 | self.run_next_command() | ||
213 | |||
214 | elif isinstance(event, bb.event.SanityCheckFailed): | ||
215 | self.emit("sanity-failed", event._msg, event._network_error) | ||
216 | |||
217 | elif isinstance(event, logging.LogRecord): | ||
218 | if not self.building: | ||
219 | if event.levelno >= logging.ERROR: | ||
220 | formatter = bb.msg.BBLogFormatter() | ||
221 | msg = formatter.format(event) | ||
222 | self.error_msg += msg + '\n' | ||
223 | elif event.levelno >= logging.WARNING and self.parsing == True: | ||
224 | formatter = bb.msg.BBLogFormatter() | ||
225 | msg = formatter.format(event) | ||
226 | warn_msg = msg + '\n' | ||
227 | self.emit("parsing-warning", warn_msg) | ||
228 | |||
229 | elif isinstance(event, bb.event.TargetsTreeGenerated): | ||
230 | self.current_phase = "data generation" | ||
231 | if event._model: | ||
232 | self.recipe_model.populate(event._model) | ||
233 | self.emit("recipe-populated") | ||
234 | elif isinstance(event, bb.event.ConfigFilesFound): | ||
235 | self.current_phase = "configuration lookup" | ||
236 | var = event._variable | ||
237 | values = event._values | ||
238 | values.sort() | ||
239 | self.emit("config-updated", var, values) | ||
240 | elif isinstance(event, bb.event.ConfigFilePathFound): | ||
241 | self.current_phase = "configuration lookup" | ||
242 | elif isinstance(event, bb.event.FilesMatchingFound): | ||
243 | self.current_phase = "configuration lookup" | ||
244 | # FIXME: hard coding, should at least be a variable shared between | ||
245 | # here and the caller | ||
246 | if event._pattern == "rootfs_": | ||
247 | formats = [] | ||
248 | for match in event._matches: | ||
249 | classname, sep, cls = match.rpartition(".") | ||
250 | fs, sep, format = classname.rpartition("_") | ||
251 | formats.append(format) | ||
252 | formats.sort() | ||
253 | self.emit("package-formats-updated", formats) | ||
254 | elif isinstance(event, bb.command.CommandCompleted): | ||
255 | self.current_phase = None | ||
256 | self.run_next_command() | ||
257 | elif isinstance(event, bb.command.CommandFailed): | ||
258 | if event.error not in ("Forced shutdown", "Stopped build"): | ||
259 | self.error_msg += event.error | ||
260 | self.commands_async = [] | ||
261 | self.display_error() | ||
262 | elif isinstance(event, (bb.event.ParseStarted, | ||
263 | bb.event.CacheLoadStarted, | ||
264 | bb.event.TreeDataPreparationStarted, | ||
265 | )): | ||
266 | message = {} | ||
267 | message["eventname"] = bb.event.getName(event) | ||
268 | message["current"] = 0 | ||
269 | message["total"] = None | ||
270 | message["title"] = "Parsing recipes" | ||
271 | self.emit("parsing-started", message) | ||
272 | if isinstance(event, bb.event.ParseStarted): | ||
273 | self.parsing = True | ||
274 | elif isinstance(event, (bb.event.ParseProgress, | ||
275 | bb.event.CacheLoadProgress, | ||
276 | bb.event.TreeDataPreparationProgress)): | ||
277 | message = {} | ||
278 | message["eventname"] = bb.event.getName(event) | ||
279 | message["current"] = event.current | ||
280 | message["total"] = event.total | ||
281 | message["title"] = "Parsing recipes" | ||
282 | self.emit("parsing", message) | ||
283 | elif isinstance(event, (bb.event.ParseCompleted, | ||
284 | bb.event.CacheLoadCompleted, | ||
285 | bb.event.TreeDataPreparationCompleted)): | ||
286 | message = {} | ||
287 | message["eventname"] = bb.event.getName(event) | ||
288 | message["current"] = event.total | ||
289 | message["total"] = event.total | ||
290 | message["title"] = "Parsing recipes" | ||
291 | self.emit("parsing-completed", message) | ||
292 | if isinstance(event, bb.event.ParseCompleted): | ||
293 | self.parsing = False | ||
294 | elif isinstance(event, bb.event.NetworkTestFailed): | ||
295 | self.emit("network-failed") | ||
296 | self.run_next_command() | ||
297 | elif isinstance(event, bb.event.NetworkTestPassed): | ||
298 | self.emit("network-passed") | ||
299 | self.run_next_command() | ||
300 | |||
301 | if self.error_msg and not self.commands_async: | ||
302 | self.display_error() | ||
303 | |||
304 | return | ||
305 | |||
306 | def init_cooker(self): | ||
307 | self.runCommand(["createConfigFile", ".hob.conf"]) | ||
308 | |||
309 | def set_extra_inherit(self, bbclass): | ||
310 | self.append_var_in_file("INHERIT", bbclass, ".hob.conf") | ||
311 | |||
312 | def set_bblayers(self, bblayers): | ||
313 | self.set_var_in_file("BBLAYERS", " ".join(bblayers), "bblayers.conf") | ||
314 | |||
315 | def set_machine(self, machine): | ||
316 | if machine: | ||
317 | self.early_assign_var_in_file("MACHINE", machine, "local.conf") | ||
318 | |||
319 | def set_sdk_machine(self, sdk_machine): | ||
320 | self.set_var_in_file("SDKMACHINE", sdk_machine, "local.conf") | ||
321 | |||
322 | def set_image_fstypes(self, image_fstypes): | ||
323 | self.set_var_in_file("IMAGE_FSTYPES", image_fstypes, "local.conf") | ||
324 | |||
325 | def set_distro(self, distro): | ||
326 | self.set_var_in_file("DISTRO", distro, "local.conf") | ||
327 | |||
328 | def set_package_format(self, format): | ||
329 | package_classes = "" | ||
330 | for pkgfmt in format.split(): | ||
331 | package_classes += ("package_%s" % pkgfmt + " ") | ||
332 | self.set_var_in_file("PACKAGE_CLASSES", package_classes, "local.conf") | ||
333 | |||
334 | def set_bbthreads(self, threads): | ||
335 | self.set_var_in_file("BB_NUMBER_THREADS", threads, "local.conf") | ||
336 | |||
337 | def set_pmake(self, threads): | ||
338 | pmake = "-j %s" % threads | ||
339 | self.set_var_in_file("PARALLEL_MAKE", pmake, "local.conf") | ||
340 | |||
341 | def set_dl_dir(self, directory): | ||
342 | self.set_var_in_file("DL_DIR", directory, "local.conf") | ||
343 | |||
344 | def set_sstate_dir(self, directory): | ||
345 | self.set_var_in_file("SSTATE_DIR", directory, "local.conf") | ||
346 | |||
347 | def set_sstate_mirrors(self, url): | ||
348 | self.set_var_in_file("SSTATE_MIRRORS", url, "local.conf") | ||
349 | |||
350 | def set_extra_size(self, image_extra_size): | ||
351 | self.set_var_in_file("IMAGE_ROOTFS_EXTRA_SPACE", str(image_extra_size), "local.conf") | ||
352 | |||
353 | def set_rootfs_size(self, image_rootfs_size): | ||
354 | self.set_var_in_file("IMAGE_ROOTFS_SIZE", str(image_rootfs_size), "local.conf") | ||
355 | |||
356 | def set_incompatible_license(self, incompat_license): | ||
357 | self.set_var_in_file("INCOMPATIBLE_LICENSE", incompat_license, "local.conf") | ||
358 | |||
359 | def set_extra_setting(self, extra_setting): | ||
360 | self.set_var_in_file("EXTRA_SETTING", extra_setting, "local.conf") | ||
361 | |||
362 | def set_extra_config(self, extra_setting): | ||
363 | old_extra_setting = self.runCommand(["getVariable", "EXTRA_SETTING"]) or {} | ||
364 | old_extra_setting = str(old_extra_setting) | ||
365 | |||
366 | old_extra_setting = ast.literal_eval(old_extra_setting) | ||
367 | if not type(old_extra_setting) == dict: | ||
368 | old_extra_setting = {} | ||
369 | |||
370 | # settings not changed | ||
371 | if old_extra_setting == extra_setting: | ||
372 | return | ||
373 | |||
374 | # remove the old EXTRA SETTING variable | ||
375 | self.remove_var_from_file("EXTRA_SETTING") | ||
376 | |||
377 | # remove old settings from conf | ||
378 | for key in old_extra_setting.keys(): | ||
379 | if key not in extra_setting: | ||
380 | self.remove_var_from_file(key) | ||
381 | |||
382 | # add new settings | ||
383 | for key, value in extra_setting.iteritems(): | ||
384 | self.set_var_in_file(key, value, "local.conf") | ||
385 | |||
386 | if extra_setting: | ||
387 | self.set_var_in_file("EXTRA_SETTING", extra_setting, "local.conf") | ||
388 | |||
389 | def set_http_proxy(self, http_proxy): | ||
390 | self.set_var_in_file("http_proxy", http_proxy, "local.conf") | ||
391 | |||
392 | def set_https_proxy(self, https_proxy): | ||
393 | self.set_var_in_file("https_proxy", https_proxy, "local.conf") | ||
394 | |||
395 | def set_ftp_proxy(self, ftp_proxy): | ||
396 | self.set_var_in_file("ftp_proxy", ftp_proxy, "local.conf") | ||
397 | |||
398 | def set_socks_proxy(self, socks_proxy): | ||
399 | self.set_var_in_file("all_proxy", socks_proxy, "local.conf") | ||
400 | |||
401 | def set_cvs_proxy(self, host, port): | ||
402 | self.set_var_in_file("CVS_PROXY_HOST", host, "local.conf") | ||
403 | self.set_var_in_file("CVS_PROXY_PORT", port, "local.conf") | ||
404 | |||
405 | def request_package_info(self): | ||
406 | self.commands_async.append(self.SUB_GENERATE_PKGINFO) | ||
407 | self.run_next_command(self.POPULATE_PACKAGEINFO) | ||
408 | |||
409 | def trigger_sanity_check(self): | ||
410 | self.commands_async.append(self.SUB_SANITY_CHECK) | ||
411 | self.run_next_command(self.SANITY_CHECK) | ||
412 | |||
413 | def trigger_network_test(self): | ||
414 | self.commands_async.append(self.SUB_NETWORK_TEST) | ||
415 | self.run_next_command(self.NETWORK_TEST) | ||
416 | |||
417 | def generate_configuration(self): | ||
418 | self.runCommand(["setPrePostConfFiles", "conf/.hob.conf", ""]) | ||
419 | self.commands_async.append(self.SUB_PARSE_CONFIG) | ||
420 | self.commands_async.append(self.SUB_PATH_LAYERS) | ||
421 | self.commands_async.append(self.SUB_FILES_DISTRO) | ||
422 | self.commands_async.append(self.SUB_FILES_MACH) | ||
423 | self.commands_async.append(self.SUB_FILES_SDKMACH) | ||
424 | self.commands_async.append(self.SUB_MATCH_CLASS) | ||
425 | self.run_next_command(self.GENERATE_CONFIGURATION) | ||
426 | |||
427 | def generate_recipes(self): | ||
428 | self.runCommand(["setPrePostConfFiles", "conf/.hob.conf", ""]) | ||
429 | self.commands_async.append(self.SUB_PARSE_CONFIG) | ||
430 | self.commands_async.append(self.SUB_GNERATE_TGTS) | ||
431 | self.run_next_command(self.GENERATE_RECIPES) | ||
432 | |||
433 | def generate_packages(self, tgts, default_task="build"): | ||
434 | targets = [] | ||
435 | targets.extend(tgts) | ||
436 | self.recipe_queue = targets | ||
437 | self.default_task = default_task | ||
438 | self.runCommand(["setPrePostConfFiles", "conf/.hob.conf", ""]) | ||
439 | self.commands_async.append(self.SUB_PARSE_CONFIG) | ||
440 | self.commands_async.append(self.SUB_BUILD_RECIPES) | ||
441 | self.run_next_command(self.GENERATE_PACKAGES) | ||
442 | |||
443 | def generate_image(self, image, base_image, image_packages=None, toolchain_packages=None, default_task="build"): | ||
444 | self.image = image | ||
445 | self.base_image = base_image | ||
446 | if image_packages: | ||
447 | self.package_queue = image_packages | ||
448 | else: | ||
449 | self.package_queue = [] | ||
450 | if toolchain_packages: | ||
451 | self.toolchain_packages = toolchain_packages | ||
452 | else: | ||
453 | self.toolchain_packages = [] | ||
454 | self.default_task = default_task | ||
455 | self.runCommand(["setPrePostConfFiles", "conf/.hob.conf", ""]) | ||
456 | self.commands_async.append(self.SUB_PARSE_CONFIG) | ||
457 | self.commands_async.append(self.SUB_BUILD_IMAGE) | ||
458 | self.run_next_command(self.GENERATE_IMAGE) | ||
459 | |||
460 | def generate_new_image(self, image, base_image, package_queue, description): | ||
461 | if base_image: | ||
462 | base_image = self.runCommand(["matchFile", self.base_image + ".bb"]) | ||
463 | self.runCommand(["generateNewImage", image, base_image, package_queue, False, description]) | ||
464 | |||
465 | def generate_hob_base_image(self, hob_image): | ||
466 | image_dir = self.get_topdir() + "/recipes/images/" | ||
467 | recipe_name = hob_image + ".bb" | ||
468 | self.ensure_dir(image_dir) | ||
469 | self.generate_new_image(image_dir + recipe_name, None, [], "") | ||
470 | |||
471 | def ensure_dir(self, directory): | ||
472 | self.runCommand(["ensureDir", directory]) | ||
473 | |||
474 | def build_succeeded_async(self): | ||
475 | self.building = False | ||
476 | |||
477 | def build_failed_async(self): | ||
478 | self.initcmd = None | ||
479 | self.commands_async = [] | ||
480 | self.building = False | ||
481 | |||
482 | def cancel_parse(self): | ||
483 | self.runCommand(["stateForceShutdown"]) | ||
484 | |||
485 | def cancel_build(self, force=False): | ||
486 | if force: | ||
487 | # Force the cooker to stop as quickly as possible | ||
488 | self.runCommand(["stateForceShutdown"]) | ||
489 | else: | ||
490 | # Wait for tasks to complete before shutting down, this helps | ||
491 | # leave the workdir in a usable state | ||
492 | self.runCommand(["stateShutdown"]) | ||
493 | |||
494 | def reset_build(self): | ||
495 | self.build.reset() | ||
496 | |||
497 | def get_logfile(self): | ||
498 | return self.server.runCommand(["getVariable", "BB_CONSOLELOG"])[0] | ||
499 | |||
500 | def get_topdir(self): | ||
501 | return self.runCommand(["getVariable", "TOPDIR"]) or "" | ||
502 | |||
503 | def _remove_redundant(self, string): | ||
504 | ret = [] | ||
505 | for i in string.split(): | ||
506 | if i not in ret: | ||
507 | ret.append(i) | ||
508 | return " ".join(ret) | ||
509 | |||
510 | def set_var_in_file(self, var, val, default_file=None): | ||
511 | self.runCommand(["enableDataTracking"]) | ||
512 | self.server.runCommand(["setVarFile", var, val, default_file, "set"]) | ||
513 | self.runCommand(["disableDataTracking"]) | ||
514 | |||
515 | def early_assign_var_in_file(self, var, val, default_file=None): | ||
516 | self.runCommand(["enableDataTracking"]) | ||
517 | self.server.runCommand(["setVarFile", var, val, default_file, "earlyAssign"]) | ||
518 | self.runCommand(["disableDataTracking"]) | ||
519 | |||
520 | def remove_var_from_file(self, var): | ||
521 | self.server.runCommand(["removeVarFile", var]) | ||
522 | |||
523 | def append_var_in_file(self, var, val, default_file=None): | ||
524 | self.server.runCommand(["setVarFile", var, val, default_file, "append"]) | ||
525 | |||
526 | def append_to_bbfiles(self, val): | ||
527 | bbfiles = self.runCommand(["getVariable", "BBFILES", "False"]) or "" | ||
528 | bbfiles = bbfiles.split() | ||
529 | if val not in bbfiles: | ||
530 | self.append_var_in_file("BBFILES", val, "bblayers.conf") | ||
531 | |||
532 | def get_parameters(self): | ||
533 | # retrieve the parameters from bitbake | ||
534 | params = {} | ||
535 | params["core_base"] = self.runCommand(["getVariable", "COREBASE"]) or "" | ||
536 | params["layer"] = self.runCommand(["getVariable", "BBLAYERS"]) or "" | ||
537 | params["layers_non_removable"] = self.runCommand(["getVariable", "BBLAYERS_NON_REMOVABLE"]) or "" | ||
538 | params["dldir"] = self.runCommand(["getVariable", "DL_DIR"]) or "" | ||
539 | params["machine"] = self.runCommand(["getVariable", "MACHINE"]) or "" | ||
540 | params["distro"] = self.runCommand(["getVariable", "DISTRO"]) or "defaultsetup" | ||
541 | params["pclass"] = self.runCommand(["getVariable", "PACKAGE_CLASSES"]) or "" | ||
542 | params["sstatedir"] = self.runCommand(["getVariable", "SSTATE_DIR"]) or "" | ||
543 | params["sstatemirror"] = self.runCommand(["getVariable", "SSTATE_MIRRORS"]) or "" | ||
544 | |||
545 | num_threads = self.runCommand(["getCpuCount"]) | ||
546 | if not num_threads: | ||
547 | num_threads = 1 | ||
548 | max_threads = 65536 | ||
549 | else: | ||
550 | try: | ||
551 | num_threads = int(num_threads) | ||
552 | max_threads = 16 * num_threads | ||
553 | except: | ||
554 | num_threads = 1 | ||
555 | max_threads = 65536 | ||
556 | params["max_threads"] = max_threads | ||
557 | |||
558 | bbthread = self.runCommand(["getVariable", "BB_NUMBER_THREADS"]) | ||
559 | if not bbthread: | ||
560 | bbthread = num_threads | ||
561 | else: | ||
562 | try: | ||
563 | bbthread = int(bbthread) | ||
564 | except: | ||
565 | bbthread = num_threads | ||
566 | params["bbthread"] = bbthread | ||
567 | |||
568 | pmake = self.runCommand(["getVariable", "PARALLEL_MAKE"]) | ||
569 | if not pmake: | ||
570 | pmake = num_threads | ||
571 | elif isinstance(pmake, int): | ||
572 | pass | ||
573 | else: | ||
574 | try: | ||
575 | pmake = int(pmake.lstrip("-j ")) | ||
576 | except: | ||
577 | pmake = num_threads | ||
578 | params["pmake"] = "-j %s" % pmake | ||
579 | |||
580 | params["image_addr"] = self.runCommand(["getVariable", "DEPLOY_DIR_IMAGE"]) or "" | ||
581 | |||
582 | image_extra_size = self.runCommand(["getVariable", "IMAGE_ROOTFS_EXTRA_SPACE"]) | ||
583 | if not image_extra_size: | ||
584 | image_extra_size = 0 | ||
585 | else: | ||
586 | try: | ||
587 | image_extra_size = int(image_extra_size) | ||
588 | except: | ||
589 | image_extra_size = 0 | ||
590 | params["image_extra_size"] = image_extra_size | ||
591 | |||
592 | image_rootfs_size = self.runCommand(["getVariable", "IMAGE_ROOTFS_SIZE"]) | ||
593 | if not image_rootfs_size: | ||
594 | image_rootfs_size = 0 | ||
595 | else: | ||
596 | try: | ||
597 | image_rootfs_size = int(image_rootfs_size) | ||
598 | except: | ||
599 | image_rootfs_size = 0 | ||
600 | params["image_rootfs_size"] = image_rootfs_size | ||
601 | |||
602 | image_overhead_factor = self.runCommand(["getVariable", "IMAGE_OVERHEAD_FACTOR"]) | ||
603 | if not image_overhead_factor: | ||
604 | image_overhead_factor = 1 | ||
605 | else: | ||
606 | try: | ||
607 | image_overhead_factor = float(image_overhead_factor) | ||
608 | except: | ||
609 | image_overhead_factor = 1 | ||
610 | params['image_overhead_factor'] = image_overhead_factor | ||
611 | |||
612 | params["incompat_license"] = self._remove_redundant(self.runCommand(["getVariable", "INCOMPATIBLE_LICENSE"]) or "") | ||
613 | params["sdk_machine"] = self.runCommand(["getVariable", "SDKMACHINE"]) or self.runCommand(["getVariable", "SDK_ARCH"]) or "" | ||
614 | |||
615 | params["image_fstypes"] = self._remove_redundant(self.runCommand(["getVariable", "IMAGE_FSTYPES"]) or "") | ||
616 | |||
617 | params["image_types"] = self._remove_redundant(self.runCommand(["getVariable", "IMAGE_TYPES"]) or "") | ||
618 | |||
619 | params["conf_version"] = self.runCommand(["getVariable", "CONF_VERSION"]) or "" | ||
620 | params["lconf_version"] = self.runCommand(["getVariable", "LCONF_VERSION"]) or "" | ||
621 | |||
622 | params["runnable_image_types"] = self._remove_redundant(self.runCommand(["getVariable", "RUNNABLE_IMAGE_TYPES"]) or "") | ||
623 | params["runnable_machine_patterns"] = self._remove_redundant(self.runCommand(["getVariable", "RUNNABLE_MACHINE_PATTERNS"]) or "") | ||
624 | params["deployable_image_types"] = self._remove_redundant(self.runCommand(["getVariable", "DEPLOYABLE_IMAGE_TYPES"]) or "") | ||
625 | params["kernel_image_type"] = self.runCommand(["getVariable", "KERNEL_IMAGETYPE"]) or "" | ||
626 | params["tmpdir"] = self.runCommand(["getVariable", "TMPDIR"]) or "" | ||
627 | params["distro_version"] = self.runCommand(["getVariable", "DISTRO_VERSION"]) or "" | ||
628 | params["target_os"] = self.runCommand(["getVariable", "TARGET_OS"]) or "" | ||
629 | params["target_arch"] = self.runCommand(["getVariable", "TARGET_ARCH"]) or "" | ||
630 | params["tune_pkgarch"] = self.runCommand(["getVariable", "TUNE_PKGARCH"]) or "" | ||
631 | params["bb_version"] = self.runCommand(["getVariable", "BB_MIN_VERSION"]) or "" | ||
632 | |||
633 | params["default_task"] = self.runCommand(["getVariable", "BB_DEFAULT_TASK"]) or "build" | ||
634 | |||
635 | params["socks_proxy"] = self.runCommand(["getVariable", "all_proxy"]) or "" | ||
636 | params["http_proxy"] = self.runCommand(["getVariable", "http_proxy"]) or "" | ||
637 | params["ftp_proxy"] = self.runCommand(["getVariable", "ftp_proxy"]) or "" | ||
638 | params["https_proxy"] = self.runCommand(["getVariable", "https_proxy"]) or "" | ||
639 | |||
640 | params["cvs_proxy_host"] = self.runCommand(["getVariable", "CVS_PROXY_HOST"]) or "" | ||
641 | params["cvs_proxy_port"] = self.runCommand(["getVariable", "CVS_PROXY_PORT"]) or "" | ||
642 | |||
643 | params["image_white_pattern"] = self.runCommand(["getVariable", "BBUI_IMAGE_WHITE_PATTERN"]) or "" | ||
644 | params["image_black_pattern"] = self.runCommand(["getVariable", "BBUI_IMAGE_BLACK_PATTERN"]) or "" | ||
645 | return params | ||
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__ | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hobpages.py b/bitbake/lib/bb/ui/crumbs/hobpages.py deleted file mode 100755 index 0fd3598c3a..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hobpages.py +++ /dev/null | |||
@@ -1,128 +0,0 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # | ||
3 | # BitBake Graphical GTK User Interface | ||
4 | # | ||
5 | # Copyright (C) 2012 Intel Corporation | ||
6 | # | ||
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 | from bb.ui.crumbs.hobcolor import HobColors | ||
25 | from bb.ui.crumbs.hobwidget import hwc | ||
26 | |||
27 | # | ||
28 | # HobPage: the super class for all Hob-related pages | ||
29 | # | ||
30 | class HobPage (gtk.VBox): | ||
31 | |||
32 | def __init__(self, builder, title = None): | ||
33 | super(HobPage, self).__init__(False, 0) | ||
34 | self.builder = builder | ||
35 | self.builder_width, self.builder_height = self.builder.size_request() | ||
36 | |||
37 | if not title: | ||
38 | self.title = "Hob -- Image Creator" | ||
39 | else: | ||
40 | self.title = title | ||
41 | self.title_label = gtk.Label() | ||
42 | |||
43 | self.box_group_area = gtk.VBox(False, 12) | ||
44 | self.box_group_area.set_size_request(self.builder_width - 73 - 73, self.builder_height - 88 - 15 - 15) | ||
45 | self.group_align = gtk.Alignment(xalign = 0, yalign=0.5, xscale=1, yscale=1) | ||
46 | self.group_align.set_padding(15, 15, 73, 73) | ||
47 | self.group_align.add(self.box_group_area) | ||
48 | self.box_group_area.set_homogeneous(False) | ||
49 | |||
50 | def set_title(self, title): | ||
51 | self.title = title | ||
52 | self.title_label.set_markup("<span size='x-large'>%s</span>" % self.title) | ||
53 | |||
54 | def add_onto_top_bar(self, widget = None, padding = 0): | ||
55 | # the top button occupies 1/7 of the page height | ||
56 | # setup an event box | ||
57 | eventbox = gtk.EventBox() | ||
58 | style = eventbox.get_style().copy() | ||
59 | style.bg[gtk.STATE_NORMAL] = eventbox.get_colormap().alloc_color(HobColors.LIGHT_GRAY, False, False) | ||
60 | eventbox.set_style(style) | ||
61 | eventbox.set_size_request(-1, 88) | ||
62 | |||
63 | hbox = gtk.HBox() | ||
64 | |||
65 | self.title_label = gtk.Label() | ||
66 | self.title_label.set_markup("<span size='x-large'>%s</span>" % self.title) | ||
67 | hbox.pack_start(self.title_label, expand=False, fill=False, padding=20) | ||
68 | |||
69 | if widget: | ||
70 | # add the widget in the event box | ||
71 | hbox.pack_end(widget, expand=False, fill=False, padding=padding) | ||
72 | eventbox.add(hbox) | ||
73 | |||
74 | return eventbox | ||
75 | |||
76 | def span_tag(self, size="medium", weight="normal", forground="#1c1c1c"): | ||
77 | span_tag = "weight='%s' foreground='%s' size='%s'" % (weight, forground, size) | ||
78 | return span_tag | ||
79 | |||
80 | def append_toolbar_button(self, toolbar, buttonname, icon_disp, icon_hovor, tip, cb): | ||
81 | # Create a button and append it on the toolbar according to button name | ||
82 | icon = gtk.Image() | ||
83 | icon_display = icon_disp | ||
84 | icon_hover = icon_hovor | ||
85 | pix_buffer = gtk.gdk.pixbuf_new_from_file(icon_display) | ||
86 | icon.set_from_pixbuf(pix_buffer) | ||
87 | tip_text = tip | ||
88 | button = toolbar.append_item(buttonname, tip, None, icon, cb) | ||
89 | return button | ||
90 | |||
91 | @staticmethod | ||
92 | def _size_to_string(size): | ||
93 | try: | ||
94 | if not size: | ||
95 | size_str = "0 B" | ||
96 | else: | ||
97 | if len(str(int(size))) > 6: | ||
98 | size_str = '%.1f' % (size*1.0/(1024*1024)) + ' MB' | ||
99 | elif len(str(int(size))) > 3: | ||
100 | size_str = '%.1f' % (size*1.0/1024) + ' KB' | ||
101 | else: | ||
102 | size_str = str(size) + ' B' | ||
103 | except: | ||
104 | size_str = "0 B" | ||
105 | return size_str | ||
106 | |||
107 | @staticmethod | ||
108 | def _string_to_size(str_size): | ||
109 | try: | ||
110 | if not str_size: | ||
111 | size = 0 | ||
112 | else: | ||
113 | unit = str_size.split() | ||
114 | if len(unit) > 1: | ||
115 | if unit[1] == 'MB': | ||
116 | size = float(unit[0])*1024*1024 | ||
117 | elif unit[1] == 'KB': | ||
118 | size = float(unit[0])*1024 | ||
119 | elif unit[1] == 'B': | ||
120 | size = float(unit[0]) | ||
121 | else: | ||
122 | size = 0 | ||
123 | else: | ||
124 | size = float(unit[0]) | ||
125 | except: | ||
126 | size = 0 | ||
127 | return size | ||
128 | |||
diff --git a/bitbake/lib/bb/ui/crumbs/imageconfigurationpage.py b/bitbake/lib/bb/ui/crumbs/imageconfigurationpage.py deleted file mode 100644 index 2766bea8c7..0000000000 --- a/bitbake/lib/bb/ui/crumbs/imageconfigurationpage.py +++ /dev/null | |||
@@ -1,561 +0,0 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # | ||
3 | # BitBake Graphical GTK User Interface | ||
4 | # | ||
5 | # Copyright (C) 2012 Intel Corporation | ||
6 | # | ||
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 glib | ||
25 | import re | ||
26 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
27 | from bb.ui.crumbs.hobcolor import HobColors | ||
28 | from bb.ui.crumbs.hobwidget import hic, HobImageButton, HobInfoButton, HobAltButton, HobButton | ||
29 | from bb.ui.crumbs.hoblistmodel import RecipeListModel | ||
30 | from bb.ui.crumbs.hobpages import HobPage | ||
31 | from bb.ui.crumbs.hig.retrieveimagedialog import RetrieveImageDialog | ||
32 | |||
33 | # | ||
34 | # ImageConfigurationPage | ||
35 | # | ||
36 | class ImageConfigurationPage (HobPage): | ||
37 | |||
38 | __dummy_machine__ = "--select a machine--" | ||
39 | __dummy_image__ = "--select an image recipe--" | ||
40 | __custom_image__ = "Select from my image recipes" | ||
41 | |||
42 | def __init__(self, builder): | ||
43 | super(ImageConfigurationPage, self).__init__(builder, "Image configuration") | ||
44 | |||
45 | self.image_combo_id = None | ||
46 | # we use machine_combo_changed_by_manual to identify the machine is changed by code | ||
47 | # or by manual. If by manual, all user's recipe selection and package selection are | ||
48 | # cleared. | ||
49 | self.machine_combo_changed_by_manual = True | ||
50 | self.stopping = False | ||
51 | self.warning_shift = 0 | ||
52 | self.custom_image_selected = None | ||
53 | self.create_visual_elements() | ||
54 | |||
55 | def create_visual_elements(self): | ||
56 | # create visual elements | ||
57 | self.toolbar = gtk.Toolbar() | ||
58 | self.toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL) | ||
59 | self.toolbar.set_style(gtk.TOOLBAR_BOTH) | ||
60 | |||
61 | my_images_button = self.append_toolbar_button(self.toolbar, | ||
62 | "Images", | ||
63 | hic.ICON_IMAGES_DISPLAY_FILE, | ||
64 | hic.ICON_IMAGES_HOVER_FILE, | ||
65 | "Open previously built images", | ||
66 | self.my_images_button_clicked_cb) | ||
67 | settings_button = self.append_toolbar_button(self.toolbar, | ||
68 | "Settings", | ||
69 | hic.ICON_SETTINGS_DISPLAY_FILE, | ||
70 | hic.ICON_SETTINGS_HOVER_FILE, | ||
71 | "View additional build settings", | ||
72 | self.settings_button_clicked_cb) | ||
73 | |||
74 | self.config_top_button = self.add_onto_top_bar(self.toolbar) | ||
75 | |||
76 | self.gtable = gtk.Table(40, 40, True) | ||
77 | self.create_config_machine() | ||
78 | self.create_config_baseimg() | ||
79 | self.config_build_button = self.create_config_build_button() | ||
80 | |||
81 | def _remove_all_widget(self): | ||
82 | children = self.gtable.get_children() or [] | ||
83 | for child in children: | ||
84 | self.gtable.remove(child) | ||
85 | children = self.box_group_area.get_children() or [] | ||
86 | for child in children: | ||
87 | self.box_group_area.remove(child) | ||
88 | children = self.get_children() or [] | ||
89 | for child in children: | ||
90 | self.remove(child) | ||
91 | |||
92 | def _pack_components(self, pack_config_build_button = False): | ||
93 | self._remove_all_widget() | ||
94 | self.pack_start(self.config_top_button, expand=False, fill=False) | ||
95 | self.pack_start(self.group_align, expand=True, fill=True) | ||
96 | |||
97 | self.box_group_area.pack_start(self.gtable, expand=True, fill=True) | ||
98 | if pack_config_build_button: | ||
99 | self.box_group_area.pack_end(self.config_build_button, expand=False, fill=False) | ||
100 | else: | ||
101 | box = gtk.HBox(False, 6) | ||
102 | box.show() | ||
103 | subbox = gtk.HBox(False, 0) | ||
104 | subbox.set_size_request(205, 49) | ||
105 | subbox.show() | ||
106 | box.add(subbox) | ||
107 | self.box_group_area.pack_end(box, False, False) | ||
108 | |||
109 | def show_machine(self): | ||
110 | self.progress_bar.reset() | ||
111 | self._pack_components(pack_config_build_button = False) | ||
112 | self.set_config_machine_layout(show_progress_bar = False) | ||
113 | self.show_all() | ||
114 | |||
115 | def update_progress_bar(self, title, fraction, status=None): | ||
116 | if self.stopping == False: | ||
117 | self.progress_bar.update(fraction) | ||
118 | self.progress_bar.set_text(title) | ||
119 | self.progress_bar.set_rcstyle(status) | ||
120 | |||
121 | def show_info_populating(self): | ||
122 | self._pack_components(pack_config_build_button = False) | ||
123 | self.set_config_machine_layout(show_progress_bar = True) | ||
124 | self.show_all() | ||
125 | |||
126 | def show_info_populated(self): | ||
127 | self.progress_bar.reset() | ||
128 | self._pack_components(pack_config_build_button = False) | ||
129 | self.set_config_machine_layout(show_progress_bar = False) | ||
130 | self.set_config_baseimg_layout() | ||
131 | self.show_all() | ||
132 | |||
133 | def show_baseimg_selected(self): | ||
134 | self.progress_bar.reset() | ||
135 | self._pack_components(pack_config_build_button = True) | ||
136 | self.set_config_machine_layout(show_progress_bar = False) | ||
137 | self.set_config_baseimg_layout() | ||
138 | self.show_all() | ||
139 | if self.builder.recipe_model.get_selected_image() == self.builder.recipe_model.__custom_image__: | ||
140 | self.just_bake_button.hide() | ||
141 | |||
142 | def add_warnings_bar(self): | ||
143 | #create the warnings bar shown when recipes parsing generates warnings | ||
144 | color = HobColors.KHAKI | ||
145 | warnings_bar = gtk.EventBox() | ||
146 | warnings_bar.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) | ||
147 | warnings_bar.set_flags(gtk.CAN_DEFAULT) | ||
148 | warnings_bar.grab_default() | ||
149 | |||
150 | build_stop_tab = gtk.Table(10, 20, True) | ||
151 | warnings_bar.add(build_stop_tab) | ||
152 | |||
153 | icon = gtk.Image() | ||
154 | icon_pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_INDI_ALERT_FILE) | ||
155 | icon.set_from_pixbuf(icon_pix_buffer) | ||
156 | build_stop_tab.attach(icon, 0, 2, 0, 10) | ||
157 | |||
158 | label = gtk.Label() | ||
159 | label.set_alignment(0.0, 0.5) | ||
160 | warnings_nb = len(self.builder.parsing_warnings) | ||
161 | if warnings_nb == 1: | ||
162 | label.set_markup("<span size='x-large'><b>1 recipe parsing warning</b></span>") | ||
163 | else: | ||
164 | label.set_markup("<span size='x-large'><b>%s recipe parsing warnings</b></span>" % warnings_nb) | ||
165 | build_stop_tab.attach(label, 2, 12, 0, 10) | ||
166 | |||
167 | view_warnings_button = HobButton("View warnings") | ||
168 | view_warnings_button.connect('clicked', self.view_warnings_button_clicked_cb) | ||
169 | build_stop_tab.attach(view_warnings_button, 15, 19, 1, 9) | ||
170 | |||
171 | return warnings_bar | ||
172 | |||
173 | def disable_warnings_bar(self): | ||
174 | if self.builder.parsing_warnings: | ||
175 | if hasattr(self, 'warnings_bar'): | ||
176 | self.warnings_bar.hide_all() | ||
177 | self.builder.parsing_warnings = [] | ||
178 | |||
179 | def create_config_machine(self): | ||
180 | self.machine_title = gtk.Label() | ||
181 | self.machine_title.set_alignment(0.0, 0.5) | ||
182 | mark = "<span %s>Select a machine</span>" % self.span_tag('x-large', 'bold') | ||
183 | self.machine_title.set_markup(mark) | ||
184 | |||
185 | self.machine_title_desc = gtk.Label() | ||
186 | self.machine_title_desc.set_alignment(0.0, 0.5) | ||
187 | mark = ("<span %s>Your selection is the profile of the target machine for which you" | ||
188 | " are building the image.\n</span>") % (self.span_tag('medium')) | ||
189 | self.machine_title_desc.set_markup(mark) | ||
190 | |||
191 | self.machine_combo = gtk.combo_box_new_text() | ||
192 | self.machine_combo.connect("changed", self.machine_combo_changed_cb) | ||
193 | |||
194 | icon_file = hic.ICON_LAYERS_DISPLAY_FILE | ||
195 | hover_file = hic.ICON_LAYERS_HOVER_FILE | ||
196 | self.layer_button = HobImageButton("Layers", "Add support for machines, software, etc.", | ||
197 | icon_file, hover_file) | ||
198 | self.layer_button.connect("clicked", self.layer_button_clicked_cb) | ||
199 | |||
200 | markup = "Layers are a powerful mechanism to extend the Yocto Project " | ||
201 | markup += "with your own functionality.\n" | ||
202 | markup += "For more on layers, check the <a href=\"" | ||
203 | markup += "http://www.yoctoproject.org/docs/current/dev-manual/" | ||
204 | markup += "dev-manual.html#understanding-and-using-layers\">reference manual</a>." | ||
205 | self.layer_info_icon = HobInfoButton("<b>Layers</b>" + "*" + markup, self.get_parent()) | ||
206 | self.progress_bar = HobProgressBar() | ||
207 | self.stop_button = HobAltButton("Stop") | ||
208 | self.stop_button.connect("clicked", self.stop_button_clicked_cb) | ||
209 | self.machine_separator = gtk.HSeparator() | ||
210 | |||
211 | def set_config_machine_layout(self, show_progress_bar = False): | ||
212 | self.gtable.attach(self.machine_title, 0, 40, 0, 4) | ||
213 | self.gtable.attach(self.machine_title_desc, 0, 40, 4, 6) | ||
214 | self.gtable.attach(self.machine_combo, 0, 12, 7, 10) | ||
215 | self.gtable.attach(self.layer_button, 14, 36, 7, 12) | ||
216 | self.gtable.attach(self.layer_info_icon, 36, 40, 7, 11) | ||
217 | if show_progress_bar: | ||
218 | #self.gtable.attach(self.progress_box, 0, 40, 15, 18) | ||
219 | self.gtable.attach(self.progress_bar, 0, 37, 15, 18) | ||
220 | self.gtable.attach(self.stop_button, 37, 40, 15, 18, 0, 0) | ||
221 | if self.builder.parsing_warnings: | ||
222 | self.warnings_bar = self.add_warnings_bar() | ||
223 | self.gtable.attach(self.warnings_bar, 0, 40, 14, 18) | ||
224 | self.warning_shift = 4 | ||
225 | else: | ||
226 | self.warning_shift = 0 | ||
227 | self.gtable.attach(self.machine_separator, 0, 40, 13, 14) | ||
228 | |||
229 | def create_config_baseimg(self): | ||
230 | self.image_title = gtk.Label() | ||
231 | self.image_title.set_alignment(0, 1.0) | ||
232 | mark = "<span %s>Select an image recipe</span>" % self.span_tag('x-large', 'bold') | ||
233 | self.image_title.set_markup(mark) | ||
234 | |||
235 | self.image_title_desc = gtk.Label() | ||
236 | self.image_title_desc.set_alignment(0, 0.5) | ||
237 | |||
238 | mark = ("<span %s>Image recipes are a starting point for the type of image you want. " | ||
239 | "You can build them as \n" | ||
240 | "they are or edit them to suit your needs.\n</span>") % self.span_tag('medium') | ||
241 | self.image_title_desc.set_markup(mark) | ||
242 | |||
243 | self.image_combo = gtk.combo_box_new_text() | ||
244 | self.image_combo.set_row_separator_func(self.combo_separator_func, None) | ||
245 | self.image_combo_id = self.image_combo.connect("changed", self.image_combo_changed_cb) | ||
246 | |||
247 | self.image_desc = gtk.Label() | ||
248 | self.image_desc.set_alignment(0.0, 0.5) | ||
249 | self.image_desc.set_size_request(256, -1) | ||
250 | self.image_desc.set_justify(gtk.JUSTIFY_LEFT) | ||
251 | self.image_desc.set_line_wrap(True) | ||
252 | |||
253 | # button to view recipes | ||
254 | icon_file = hic.ICON_RCIPE_DISPLAY_FILE | ||
255 | hover_file = hic.ICON_RCIPE_HOVER_FILE | ||
256 | self.view_adv_configuration_button = HobImageButton("Advanced configuration", | ||
257 | "Select image types, package formats, etc", | ||
258 | icon_file, hover_file) | ||
259 | self.view_adv_configuration_button.connect("clicked", self.view_adv_configuration_button_clicked_cb) | ||
260 | |||
261 | self.image_separator = gtk.HSeparator() | ||
262 | |||
263 | def combo_separator_func(self, model, iter, user_data): | ||
264 | name = model.get_value(iter, 0) | ||
265 | if name == "--Separator--": | ||
266 | return True | ||
267 | |||
268 | def set_config_baseimg_layout(self): | ||
269 | self.gtable.attach(self.image_title, 0, 40, 15+self.warning_shift, 17+self.warning_shift) | ||
270 | self.gtable.attach(self.image_title_desc, 0, 40, 18+self.warning_shift, 22+self.warning_shift) | ||
271 | self.gtable.attach(self.image_combo, 0, 12, 23+self.warning_shift, 26+self.warning_shift) | ||
272 | self.gtable.attach(self.image_desc, 0, 12, 27+self.warning_shift, 33+self.warning_shift) | ||
273 | self.gtable.attach(self.view_adv_configuration_button, 14, 36, 23+self.warning_shift, 28+self.warning_shift) | ||
274 | self.gtable.attach(self.image_separator, 0, 40, 35+self.warning_shift, 36+self.warning_shift) | ||
275 | |||
276 | def create_config_build_button(self): | ||
277 | # Create the "Build packages" and "Build image" buttons at the bottom | ||
278 | button_box = gtk.HBox(False, 6) | ||
279 | |||
280 | # create button "Build image" | ||
281 | self.just_bake_button = HobButton("Build image") | ||
282 | self.just_bake_button.set_tooltip_text("Build the image recipe as it is") | ||
283 | self.just_bake_button.connect("clicked", self.just_bake_button_clicked_cb) | ||
284 | button_box.pack_end(self.just_bake_button, expand=False, fill=False) | ||
285 | |||
286 | # create button "Edit image recipe" | ||
287 | self.edit_image_button = HobAltButton("Edit image recipe") | ||
288 | self.edit_image_button.set_tooltip_text("Customize the recipes and packages to be included in your image") | ||
289 | self.edit_image_button.connect("clicked", self.edit_image_button_clicked_cb) | ||
290 | button_box.pack_end(self.edit_image_button, expand=False, fill=False) | ||
291 | |||
292 | return button_box | ||
293 | |||
294 | def stop_button_clicked_cb(self, button): | ||
295 | self.stopping = True | ||
296 | self.progress_bar.set_text("Stopping recipe parsing") | ||
297 | self.progress_bar.set_rcstyle("stop") | ||
298 | self.builder.cancel_parse_sync() | ||
299 | |||
300 | def view_warnings_button_clicked_cb(self, button): | ||
301 | self.builder.show_warning_dialog() | ||
302 | |||
303 | def machine_combo_changed_idle_cb(self): | ||
304 | self.builder.window.set_cursor(None) | ||
305 | |||
306 | def machine_combo_changed_cb(self, machine_combo): | ||
307 | self.stopping = False | ||
308 | self.builder.parsing_warnings = [] | ||
309 | combo_item = machine_combo.get_active_text() | ||
310 | if not combo_item or combo_item == self.__dummy_machine__: | ||
311 | return | ||
312 | |||
313 | self.builder.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) | ||
314 | self.builder.wait(0.1) #wait for combo and cursor to update | ||
315 | |||
316 | # remove __dummy_machine__ item from the store list after first user selection | ||
317 | # because it is no longer valid | ||
318 | combo_store = machine_combo.get_model() | ||
319 | if len(combo_store) and (combo_store[0][0] == self.__dummy_machine__): | ||
320 | machine_combo.remove_text(0) | ||
321 | |||
322 | self.builder.configuration.curr_mach = combo_item | ||
323 | if self.machine_combo_changed_by_manual: | ||
324 | self.builder.configuration.clear_selection() | ||
325 | # reset machine_combo_changed_by_manual | ||
326 | self.machine_combo_changed_by_manual = True | ||
327 | |||
328 | self.builder.configuration.selected_image = None | ||
329 | |||
330 | # Do reparse recipes | ||
331 | self.builder.populate_recipe_package_info_async() | ||
332 | |||
333 | glib.idle_add(self.machine_combo_changed_idle_cb) | ||
334 | |||
335 | def update_machine_combo(self): | ||
336 | self.disable_warnings_bar() | ||
337 | all_machines = [self.__dummy_machine__] + self.builder.parameters.all_machines | ||
338 | |||
339 | model = self.machine_combo.get_model() | ||
340 | model.clear() | ||
341 | for machine in all_machines: | ||
342 | self.machine_combo.append_text(machine) | ||
343 | self.machine_combo.set_active(0) | ||
344 | |||
345 | def switch_machine_combo(self): | ||
346 | self.disable_warnings_bar() | ||
347 | self.machine_combo_changed_by_manual = False | ||
348 | model = self.machine_combo.get_model() | ||
349 | active = 0 | ||
350 | while active < len(model): | ||
351 | if model[active][0] == self.builder.configuration.curr_mach: | ||
352 | self.machine_combo.set_active(active) | ||
353 | return | ||
354 | active += 1 | ||
355 | |||
356 | if model[0][0] != self.__dummy_machine__: | ||
357 | self.machine_combo.insert_text(0, self.__dummy_machine__) | ||
358 | |||
359 | self.machine_combo.set_active(0) | ||
360 | |||
361 | def update_image_desc(self): | ||
362 | desc = "" | ||
363 | selected_image = self.image_combo.get_active_text() | ||
364 | if selected_image and selected_image in self.builder.recipe_model.pn_path.keys(): | ||
365 | image_path = self.builder.recipe_model.pn_path[selected_image] | ||
366 | image_iter = self.builder.recipe_model.get_iter(image_path) | ||
367 | desc = self.builder.recipe_model.get_value(image_iter, self.builder.recipe_model.COL_DESC) | ||
368 | |||
369 | mark = ("<span %s>%s</span>\n") % (self.span_tag('small'), desc) | ||
370 | self.image_desc.set_markup(mark) | ||
371 | |||
372 | def image_combo_changed_idle_cb(self, selected_image, selected_recipes, selected_packages): | ||
373 | self.builder.update_recipe_model(selected_image, selected_recipes) | ||
374 | self.builder.update_package_model(selected_packages) | ||
375 | self.builder.window_sensitive(True) | ||
376 | |||
377 | def image_combo_changed_cb(self, combo): | ||
378 | self.builder.window_sensitive(False) | ||
379 | selected_image = self.image_combo.get_active_text() | ||
380 | if selected_image == self.__custom_image__: | ||
381 | topdir = self.builder.get_topdir() | ||
382 | images_dir = topdir + "/recipes/images/custom/" | ||
383 | self.builder.ensure_dir(images_dir) | ||
384 | |||
385 | dialog = RetrieveImageDialog(images_dir, "Select from my image recipes", | ||
386 | self.builder, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) | ||
387 | response = dialog.run() | ||
388 | if response == gtk.RESPONSE_OK: | ||
389 | image_name = dialog.get_filename() | ||
390 | head, tail = os.path.split(image_name) | ||
391 | selected_image = os.path.splitext(tail)[0] | ||
392 | self.custom_image_selected = selected_image | ||
393 | self.update_image_combo(self.builder.recipe_model, selected_image) | ||
394 | else: | ||
395 | selected_image = self.__dummy_image__ | ||
396 | self.update_image_combo(self.builder.recipe_model, None) | ||
397 | dialog.destroy() | ||
398 | else: | ||
399 | if self.custom_image_selected: | ||
400 | self.custom_image_selected = None | ||
401 | self.update_image_combo(self.builder.recipe_model, selected_image) | ||
402 | |||
403 | if not selected_image or (selected_image == self.__dummy_image__): | ||
404 | self.builder.window_sensitive(True) | ||
405 | self.just_bake_button.hide() | ||
406 | self.edit_image_button.hide() | ||
407 | return | ||
408 | |||
409 | # remove __dummy_image__ item from the store list after first user selection | ||
410 | # because it is no longer valid | ||
411 | combo_store = combo.get_model() | ||
412 | if len(combo_store) and (combo_store[0][0] == self.__dummy_image__): | ||
413 | combo.remove_text(0) | ||
414 | |||
415 | self.builder.customized = False | ||
416 | |||
417 | selected_recipes = [] | ||
418 | |||
419 | image_path = self.builder.recipe_model.pn_path[selected_image] | ||
420 | image_iter = self.builder.recipe_model.get_iter(image_path) | ||
421 | selected_packages = self.builder.recipe_model.get_value(image_iter, self.builder.recipe_model.COL_INSTALL).split() | ||
422 | self.update_image_desc() | ||
423 | |||
424 | self.builder.recipe_model.reset() | ||
425 | self.builder.package_model.reset() | ||
426 | |||
427 | self.show_baseimg_selected() | ||
428 | |||
429 | if selected_image == self.builder.recipe_model.__custom_image__: | ||
430 | self.just_bake_button.hide() | ||
431 | |||
432 | glib.idle_add(self.image_combo_changed_idle_cb, selected_image, selected_recipes, selected_packages) | ||
433 | |||
434 | def _image_combo_connect_signal(self): | ||
435 | if not self.image_combo_id: | ||
436 | self.image_combo_id = self.image_combo.connect("changed", self.image_combo_changed_cb) | ||
437 | |||
438 | def _image_combo_disconnect_signal(self): | ||
439 | if self.image_combo_id: | ||
440 | self.image_combo.disconnect(self.image_combo_id) | ||
441 | self.image_combo_id = None | ||
442 | |||
443 | def update_image_combo(self, recipe_model, selected_image): | ||
444 | # Update the image combo according to the images in the recipe_model | ||
445 | # populate image combo | ||
446 | filter = {RecipeListModel.COL_TYPE : ['image']} | ||
447 | image_model = recipe_model.tree_model(filter) | ||
448 | image_model.set_sort_column_id(recipe_model.COL_NAME, gtk.SORT_ASCENDING) | ||
449 | active = 0 | ||
450 | cnt = 0 | ||
451 | |||
452 | white_pattern = [] | ||
453 | if self.builder.parameters.image_white_pattern: | ||
454 | for i in self.builder.parameters.image_white_pattern.split(): | ||
455 | white_pattern.append(re.compile(i)) | ||
456 | |||
457 | black_pattern = [] | ||
458 | if self.builder.parameters.image_black_pattern: | ||
459 | for i in self.builder.parameters.image_black_pattern.split(): | ||
460 | black_pattern.append(re.compile(i)) | ||
461 | black_pattern.append(re.compile("hob-image")) | ||
462 | black_pattern.append(re.compile("edited(-[0-9]*)*.bb$")) | ||
463 | |||
464 | it = image_model.get_iter_first() | ||
465 | self._image_combo_disconnect_signal() | ||
466 | model = self.image_combo.get_model() | ||
467 | model.clear() | ||
468 | # Set a indicator text to combo store when first open | ||
469 | if not selected_image: | ||
470 | self.image_combo.append_text(self.__dummy_image__) | ||
471 | cnt = cnt + 1 | ||
472 | |||
473 | self.image_combo.append_text(self.__custom_image__) | ||
474 | self.image_combo.append_text("--Separator--") | ||
475 | cnt = cnt + 2 | ||
476 | |||
477 | topdir = self.builder.get_topdir() | ||
478 | # append and set active | ||
479 | while it: | ||
480 | path = image_model.get_path(it) | ||
481 | it = image_model.iter_next(it) | ||
482 | image_name = image_model[path][recipe_model.COL_NAME] | ||
483 | if image_name == self.builder.recipe_model.__custom_image__: | ||
484 | continue | ||
485 | |||
486 | if black_pattern: | ||
487 | allow = True | ||
488 | for pattern in black_pattern: | ||
489 | if pattern.search(image_name): | ||
490 | allow = False | ||
491 | break | ||
492 | elif white_pattern: | ||
493 | allow = False | ||
494 | for pattern in white_pattern: | ||
495 | if pattern.search(image_name): | ||
496 | allow = True | ||
497 | break | ||
498 | else: | ||
499 | allow = True | ||
500 | |||
501 | file_name = image_model[path][recipe_model.COL_FILE] | ||
502 | if file_name and topdir in file_name: | ||
503 | allow = False | ||
504 | |||
505 | if allow: | ||
506 | self.image_combo.append_text(image_name) | ||
507 | if image_name == selected_image: | ||
508 | active = cnt | ||
509 | cnt = cnt + 1 | ||
510 | self.image_combo.append_text(self.builder.recipe_model.__custom_image__) | ||
511 | |||
512 | if selected_image == self.builder.recipe_model.__custom_image__: | ||
513 | active = cnt | ||
514 | |||
515 | if self.custom_image_selected: | ||
516 | self.image_combo.append_text("--Separator--") | ||
517 | self.image_combo.append_text(self.custom_image_selected) | ||
518 | cnt = cnt + 2 | ||
519 | if self.custom_image_selected == selected_image: | ||
520 | active = cnt | ||
521 | |||
522 | self.image_combo.set_active(active) | ||
523 | |||
524 | if active != 0: | ||
525 | self.show_baseimg_selected() | ||
526 | |||
527 | self._image_combo_connect_signal() | ||
528 | |||
529 | def layer_button_clicked_cb(self, button): | ||
530 | # Create a layer selection dialog | ||
531 | self.builder.show_layer_selection_dialog() | ||
532 | |||
533 | def view_adv_configuration_button_clicked_cb(self, button): | ||
534 | # Create an advanced settings dialog | ||
535 | response, settings_changed = self.builder.show_adv_settings_dialog() | ||
536 | if not response: | ||
537 | return | ||
538 | if settings_changed: | ||
539 | self.builder.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) | ||
540 | self.builder.wait(0.1) #wait for adv_settings_dialog to terminate | ||
541 | self.builder.reparse_post_adv_settings() | ||
542 | self.builder.window.set_cursor(None) | ||
543 | |||
544 | def just_bake_button_clicked_cb(self, button): | ||
545 | self.builder.parsing_warnings = [] | ||
546 | self.builder.just_bake() | ||
547 | |||
548 | def edit_image_button_clicked_cb(self, button): | ||
549 | self.builder.set_base_image() | ||
550 | self.builder.show_recipes() | ||
551 | |||
552 | def my_images_button_clicked_cb(self, button): | ||
553 | self.builder.show_load_my_images_dialog() | ||
554 | |||
555 | def settings_button_clicked_cb(self, button): | ||
556 | # Create an advanced settings dialog | ||
557 | response, settings_changed = self.builder.show_simple_settings_dialog() | ||
558 | if not response: | ||
559 | return | ||
560 | if settings_changed: | ||
561 | self.builder.reparse_post_adv_settings() | ||
diff --git a/bitbake/lib/bb/ui/crumbs/imagedetailspage.py b/bitbake/lib/bb/ui/crumbs/imagedetailspage.py deleted file mode 100755 index 32d4854166..0000000000 --- a/bitbake/lib/bb/ui/crumbs/imagedetailspage.py +++ /dev/null | |||
@@ -1,705 +0,0 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # | ||
3 | # BitBake Graphical GTK User Interface | ||
4 | # | ||
5 | # Copyright (C) 2012 Intel Corporation | ||
6 | # | ||
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 gobject | ||
24 | import gtk | ||
25 | from bb.ui.crumbs.hobcolor import HobColors | ||
26 | from bb.ui.crumbs.hobwidget import hic, HobViewTable, HobAltButton, HobButton | ||
27 | from bb.ui.crumbs.hobpages import HobPage | ||
28 | import subprocess | ||
29 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
30 | from bb.ui.crumbs.hig.saveimagedialog import SaveImageDialog | ||
31 | |||
32 | # | ||
33 | # ImageDetailsPage | ||
34 | # | ||
35 | class ImageDetailsPage (HobPage): | ||
36 | |||
37 | class DetailBox (gtk.EventBox): | ||
38 | def __init__(self, widget = None, varlist = None, vallist = None, icon = None, button = None, button2=None, color = HobColors.LIGHT_GRAY): | ||
39 | gtk.EventBox.__init__(self) | ||
40 | |||
41 | # set color | ||
42 | style = self.get_style().copy() | ||
43 | style.bg[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(color, False, False) | ||
44 | self.set_style(style) | ||
45 | |||
46 | self.row = gtk.Table(1, 2, False) | ||
47 | self.row.set_border_width(10) | ||
48 | self.add(self.row) | ||
49 | |||
50 | total_rows = 0 | ||
51 | if widget: | ||
52 | total_rows = 10 | ||
53 | if varlist and vallist: | ||
54 | # pack the icon and the text on the left | ||
55 | total_rows += len(varlist) | ||
56 | self.table = gtk.Table(total_rows, 20, True) | ||
57 | self.table.set_row_spacings(6) | ||
58 | self.table.set_size_request(100, -1) | ||
59 | self.row.attach(self.table, 0, 1, 0, 1, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL) | ||
60 | |||
61 | colid = 0 | ||
62 | rowid = 0 | ||
63 | self.line_widgets = {} | ||
64 | if icon: | ||
65 | self.table.attach(icon, colid, colid + 2, 0, 1) | ||
66 | colid = colid + 2 | ||
67 | if widget: | ||
68 | self.table.attach(widget, colid, 20, 0, 10) | ||
69 | rowid = 10 | ||
70 | if varlist and vallist: | ||
71 | for row in range(rowid, total_rows): | ||
72 | index = row - rowid | ||
73 | self.line_widgets[varlist[index]] = self.text2label(varlist[index], vallist[index]) | ||
74 | self.table.attach(self.line_widgets[varlist[index]], colid, 20, row, row + 1) | ||
75 | # pack the button on the right | ||
76 | if button: | ||
77 | self.bbox = gtk.VBox() | ||
78 | self.bbox.pack_start(button, expand=True, fill=False) | ||
79 | if button2: | ||
80 | self.bbox.pack_start(button2, expand=True, fill=False) | ||
81 | self.bbox.set_size_request(150,-1) | ||
82 | self.row.attach(self.bbox, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.EXPAND) | ||
83 | |||
84 | def update_line_widgets(self, variable, value): | ||
85 | if len(self.line_widgets) == 0: | ||
86 | return | ||
87 | if not isinstance(self.line_widgets[variable], gtk.Label): | ||
88 | return | ||
89 | self.line_widgets[variable].set_markup(self.format_line(variable, value)) | ||
90 | |||
91 | def wrap_line(self, inputs): | ||
92 | # wrap the long text of inputs | ||
93 | wrap_width_chars = 75 | ||
94 | outputs = "" | ||
95 | tmps = inputs | ||
96 | less_chars = len(inputs) | ||
97 | while (less_chars - wrap_width_chars) > 0: | ||
98 | less_chars -= wrap_width_chars | ||
99 | outputs += tmps[:wrap_width_chars] + "\n " | ||
100 | tmps = inputs[less_chars:] | ||
101 | outputs += tmps | ||
102 | return outputs | ||
103 | |||
104 | def format_line(self, variable, value): | ||
105 | wraped_value = self.wrap_line(value) | ||
106 | markup = "<span weight=\'bold\'>%s</span>" % variable | ||
107 | markup += "<span weight=\'normal\' foreground=\'#1c1c1c\' font_desc=\'14px\'>%s</span>" % wraped_value | ||
108 | return markup | ||
109 | |||
110 | def text2label(self, variable, value): | ||
111 | # append the name:value to the left box | ||
112 | # such as "Name: hob-core-minimal-variant-2011-12-15-beagleboard" | ||
113 | label = gtk.Label() | ||
114 | label.set_alignment(0.0, 0.5) | ||
115 | label.set_markup(self.format_line(variable, value)) | ||
116 | return label | ||
117 | |||
118 | class BuildDetailBox (gtk.EventBox): | ||
119 | def __init__(self, varlist = None, vallist = None, icon = None, color = HobColors.LIGHT_GRAY): | ||
120 | gtk.EventBox.__init__(self) | ||
121 | |||
122 | # set color | ||
123 | style = self.get_style().copy() | ||
124 | style.bg[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(color, False, False) | ||
125 | self.set_style(style) | ||
126 | |||
127 | self.hbox = gtk.HBox() | ||
128 | self.hbox.set_border_width(10) | ||
129 | self.add(self.hbox) | ||
130 | |||
131 | total_rows = 0 | ||
132 | if varlist and vallist: | ||
133 | # pack the icon and the text on the left | ||
134 | total_rows += len(varlist) | ||
135 | self.table = gtk.Table(total_rows, 20, True) | ||
136 | self.table.set_row_spacings(6) | ||
137 | self.table.set_size_request(100, -1) | ||
138 | self.hbox.pack_start(self.table, expand=True, fill=True, padding=15) | ||
139 | |||
140 | colid = 0 | ||
141 | rowid = 0 | ||
142 | self.line_widgets = {} | ||
143 | if icon: | ||
144 | self.table.attach(icon, colid, colid + 2, 0, 1) | ||
145 | colid = colid + 2 | ||
146 | if varlist and vallist: | ||
147 | for row in range(rowid, total_rows): | ||
148 | index = row - rowid | ||
149 | self.line_widgets[varlist[index]] = self.text2label(varlist[index], vallist[index]) | ||
150 | self.table.attach(self.line_widgets[varlist[index]], colid, 20, row, row + 1) | ||
151 | |||
152 | def update_line_widgets(self, variable, value): | ||
153 | if len(self.line_widgets) == 0: | ||
154 | return | ||
155 | if not isinstance(self.line_widgets[variable], gtk.Label): | ||
156 | return | ||
157 | self.line_widgets[variable].set_markup(self.format_line(variable, value)) | ||
158 | |||
159 | def wrap_line(self, inputs): | ||
160 | # wrap the long text of inputs | ||
161 | wrap_width_chars = 75 | ||
162 | outputs = "" | ||
163 | tmps = inputs | ||
164 | less_chars = len(inputs) | ||
165 | while (less_chars - wrap_width_chars) > 0: | ||
166 | less_chars -= wrap_width_chars | ||
167 | outputs += tmps[:wrap_width_chars] + "\n " | ||
168 | tmps = inputs[less_chars:] | ||
169 | outputs += tmps | ||
170 | return outputs | ||
171 | |||
172 | def format_line(self, variable, value): | ||
173 | wraped_value = self.wrap_line(value) | ||
174 | markup = "<span weight=\'bold\'>%s</span>" % variable | ||
175 | markup += "<span weight=\'normal\' foreground=\'#1c1c1c\' font_desc=\'14px\'>%s</span>" % wraped_value | ||
176 | return markup | ||
177 | |||
178 | def text2label(self, variable, value): | ||
179 | # append the name:value to the left box | ||
180 | # such as "Name: hob-core-minimal-variant-2011-12-15-beagleboard" | ||
181 | label = gtk.Label() | ||
182 | label.set_alignment(0.0, 0.5) | ||
183 | label.set_markup(self.format_line(variable, value)) | ||
184 | return label | ||
185 | |||
186 | def __init__(self, builder): | ||
187 | super(ImageDetailsPage, self).__init__(builder, "Image details") | ||
188 | |||
189 | self.image_store = [] | ||
190 | self.button_ids = {} | ||
191 | self.details_bottom_buttons = gtk.HBox(False, 6) | ||
192 | self.image_saved = False | ||
193 | self.create_visual_elements() | ||
194 | self.name_field_template = "" | ||
195 | self.description_field_template = "" | ||
196 | |||
197 | def create_visual_elements(self): | ||
198 | # create visual elements | ||
199 | # create the toolbar | ||
200 | self.toolbar = gtk.Toolbar() | ||
201 | self.toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL) | ||
202 | self.toolbar.set_style(gtk.TOOLBAR_BOTH) | ||
203 | |||
204 | my_images_button = self.append_toolbar_button(self.toolbar, | ||
205 | "Images", | ||
206 | hic.ICON_IMAGES_DISPLAY_FILE, | ||
207 | hic.ICON_IMAGES_HOVER_FILE, | ||
208 | "Open previously built images", | ||
209 | self.my_images_button_clicked_cb) | ||
210 | settings_button = self.append_toolbar_button(self.toolbar, | ||
211 | "Settings", | ||
212 | hic.ICON_SETTINGS_DISPLAY_FILE, | ||
213 | hic.ICON_SETTINGS_HOVER_FILE, | ||
214 | "View additional build settings", | ||
215 | self.settings_button_clicked_cb) | ||
216 | |||
217 | self.details_top_buttons = self.add_onto_top_bar(self.toolbar) | ||
218 | |||
219 | def _remove_all_widget(self): | ||
220 | children = self.get_children() or [] | ||
221 | for child in children: | ||
222 | self.remove(child) | ||
223 | children = self.box_group_area.get_children() or [] | ||
224 | for child in children: | ||
225 | self.box_group_area.remove(child) | ||
226 | children = self.details_bottom_buttons.get_children() or [] | ||
227 | for child in children: | ||
228 | self.details_bottom_buttons.remove(child) | ||
229 | |||
230 | def show_page(self, step): | ||
231 | self.build_succeeded = (step == self.builder.IMAGE_GENERATED) | ||
232 | image_addr = self.builder.parameters.image_addr | ||
233 | image_names = self.builder.parameters.image_names | ||
234 | if self.build_succeeded: | ||
235 | machine = self.builder.configuration.curr_mach | ||
236 | base_image = self.builder.recipe_model.get_selected_image() | ||
237 | layers = self.builder.configuration.layers | ||
238 | pkg_num = "%s" % len(self.builder.package_model.get_selected_packages()) | ||
239 | log_file = self.builder.current_logfile | ||
240 | else: | ||
241 | pkg_num = "N/A" | ||
242 | log_file = None | ||
243 | |||
244 | # remove | ||
245 | for button_id, button in self.button_ids.items(): | ||
246 | button.disconnect(button_id) | ||
247 | self._remove_all_widget() | ||
248 | |||
249 | # repack | ||
250 | self.pack_start(self.details_top_buttons, expand=False, fill=False) | ||
251 | self.pack_start(self.group_align, expand=True, fill=True) | ||
252 | |||
253 | self.build_result = None | ||
254 | if self.image_saved or (self.build_succeeded and self.builder.current_step == self.builder.IMAGE_GENERATING): | ||
255 | # building is the previous step | ||
256 | icon = gtk.Image() | ||
257 | pixmap_path = hic.ICON_INDI_CONFIRM_FILE | ||
258 | color = HobColors.RUNNING | ||
259 | pix_buffer = gtk.gdk.pixbuf_new_from_file(pixmap_path) | ||
260 | icon.set_from_pixbuf(pix_buffer) | ||
261 | varlist = [""] | ||
262 | if self.image_saved: | ||
263 | vallist = ["Your image recipe has been saved"] | ||
264 | else: | ||
265 | vallist = ["Your image is ready"] | ||
266 | self.build_result = self.BuildDetailBox(varlist=varlist, vallist=vallist, icon=icon, color=color) | ||
267 | self.box_group_area.pack_start(self.build_result, expand=False, fill=False) | ||
268 | |||
269 | self.buttonlist = ["Build new image", "Save image recipe", "Run image", "Deploy image"] | ||
270 | |||
271 | # Name | ||
272 | self.image_store = [] | ||
273 | self.toggled_image = "" | ||
274 | default_image_size = 0 | ||
275 | self.num_toggled = 0 | ||
276 | i = 0 | ||
277 | for image_name in image_names: | ||
278 | image_size = HobPage._size_to_string(os.stat(os.path.join(image_addr, image_name)).st_size) | ||
279 | |||
280 | image_attr = ("run" if (self.test_type_runnable(image_name) and self.test_mach_runnable(image_name)) else \ | ||
281 | ("deploy" if self.test_deployable(image_name) else "")) | ||
282 | is_toggled = (image_attr != "") | ||
283 | |||
284 | if not self.toggled_image: | ||
285 | if i == (len(image_names) - 1): | ||
286 | is_toggled = True | ||
287 | if is_toggled: | ||
288 | default_image_size = image_size | ||
289 | self.toggled_image = image_name | ||
290 | |||
291 | split_stuff = image_name.split('.') | ||
292 | if "rootfs" in split_stuff: | ||
293 | image_type = image_name[(len(split_stuff[0]) + len(".rootfs") + 1):] | ||
294 | else: | ||
295 | image_type = image_name[(len(split_stuff[0]) + 1):] | ||
296 | |||
297 | self.image_store.append({'name': image_name, | ||
298 | 'type': image_type, | ||
299 | 'size': image_size, | ||
300 | 'is_toggled': is_toggled, | ||
301 | 'action_attr': image_attr,}) | ||
302 | |||
303 | i = i + 1 | ||
304 | self.num_toggled += is_toggled | ||
305 | |||
306 | self.is_runnable = self.create_bottom_buttons(self.buttonlist, self.toggled_image) | ||
307 | |||
308 | # Generated image files info | ||
309 | varlist = ["Name: ", "Files created: ", "Directory: "] | ||
310 | vallist = [] | ||
311 | |||
312 | vallist.append(image_name.split('.')[0]) | ||
313 | vallist.append(', '.join(fileitem['type'] for fileitem in self.image_store)) | ||
314 | vallist.append(image_addr) | ||
315 | |||
316 | view_files_button = HobAltButton("View files") | ||
317 | view_files_button.connect("clicked", self.view_files_clicked_cb, image_addr) | ||
318 | view_files_button.set_tooltip_text("Open the directory containing the image files") | ||
319 | open_log_button = None | ||
320 | if log_file: | ||
321 | open_log_button = HobAltButton("Open log") | ||
322 | open_log_button.connect("clicked", self.open_log_clicked_cb, log_file) | ||
323 | open_log_button.set_tooltip_text("Open the build's log file") | ||
324 | self.image_detail = self.DetailBox(varlist=varlist, vallist=vallist, button=view_files_button, button2=open_log_button) | ||
325 | self.box_group_area.pack_start(self.image_detail, expand=False, fill=True) | ||
326 | |||
327 | # The default script path to run the image (runqemu) | ||
328 | self.run_script_path = os.path.join(self.builder.parameters.core_base, "scripts/runqemu") | ||
329 | self.run_script_detail = None | ||
330 | varlist = ["Run script: "] | ||
331 | vallist = [] | ||
332 | vallist.append(self.run_script_path) | ||
333 | |||
334 | change_run_script_button = HobAltButton("Change") | ||
335 | change_run_script_button.connect("clicked", self.change_run_script_cb) | ||
336 | change_run_script_button.set_tooltip_text("Change run script") | ||
337 | self.run_script_detail = self.DetailBox(varlist=varlist, vallist=vallist, button=change_run_script_button) | ||
338 | self.box_group_area.pack_start(self.run_script_detail, expand=False, fill=True) | ||
339 | |||
340 | # The default kernel box for the qemu images | ||
341 | self.sel_kernel = "" | ||
342 | self.kernel_detail = None | ||
343 | if self.test_mach_runnable(image_name): | ||
344 | self.sel_kernel = self.get_kernel_file_name() | ||
345 | |||
346 | # varlist = ["Kernel: "] | ||
347 | # vallist = [] | ||
348 | # vallist.append(self.sel_kernel) | ||
349 | |||
350 | # change_kernel_button = HobAltButton("Change") | ||
351 | # change_kernel_button.connect("clicked", self.change_kernel_cb) | ||
352 | # change_kernel_button.set_tooltip_text("Change qemu kernel file") | ||
353 | # self.kernel_detail = self.DetailBox(varlist=varlist, vallist=vallist, button=change_kernel_button) | ||
354 | # self.box_group_area.pack_start(self.kernel_detail, expand=True, fill=True) | ||
355 | |||
356 | # Machine, Image recipe and Layers | ||
357 | layer_num_limit = 15 | ||
358 | varlist = ["Machine: ", "Image recipe: ", "Layers: "] | ||
359 | vallist = [] | ||
360 | self.setting_detail = None | ||
361 | if self.build_succeeded: | ||
362 | vallist.append(machine) | ||
363 | if self.builder.recipe_model.is_custom_image(): | ||
364 | if self.builder.configuration.initial_selected_image == self.builder.recipe_model.__custom_image__: | ||
365 | base_image ="New image recipe" | ||
366 | else: | ||
367 | base_image = self.builder.configuration.initial_selected_image + " (edited)" | ||
368 | vallist.append(base_image) | ||
369 | i = 0 | ||
370 | for layer in layers: | ||
371 | if i > layer_num_limit: | ||
372 | break | ||
373 | varlist.append(" - ") | ||
374 | i += 1 | ||
375 | vallist.append("") | ||
376 | i = 0 | ||
377 | for layer in layers: | ||
378 | if i > layer_num_limit: | ||
379 | break | ||
380 | elif i == layer_num_limit: | ||
381 | vallist.append("and more...") | ||
382 | else: | ||
383 | vallist.append(layer) | ||
384 | i += 1 | ||
385 | |||
386 | edit_config_button = HobAltButton("Edit configuration") | ||
387 | edit_config_button.set_tooltip_text("Edit machine and image recipe") | ||
388 | edit_config_button.connect("clicked", self.edit_config_button_clicked_cb) | ||
389 | self.setting_detail = self.DetailBox(varlist=varlist, vallist=vallist, button=edit_config_button) | ||
390 | self.box_group_area.pack_start(self.setting_detail, expand=True, fill=True) | ||
391 | |||
392 | # Packages included, and Total image size | ||
393 | varlist = ["Packages included: ", "Total image size: "] | ||
394 | vallist = [] | ||
395 | vallist.append(pkg_num) | ||
396 | vallist.append(default_image_size) | ||
397 | self.builder.configuration.image_size = default_image_size | ||
398 | self.builder.configuration.image_packages = self.builder.configuration.selected_packages | ||
399 | if self.build_succeeded: | ||
400 | edit_packages_button = HobAltButton("Edit packages") | ||
401 | edit_packages_button.set_tooltip_text("Edit the packages included in your image") | ||
402 | edit_packages_button.connect("clicked", self.edit_packages_button_clicked_cb) | ||
403 | else: # get to this page from "My images" | ||
404 | edit_packages_button = None | ||
405 | self.package_detail = self.DetailBox(varlist=varlist, vallist=vallist, button=edit_packages_button) | ||
406 | self.box_group_area.pack_start(self.package_detail, expand=True, fill=True) | ||
407 | |||
408 | # pack the buttons at the bottom, at this time they are already created. | ||
409 | if self.build_succeeded: | ||
410 | self.box_group_area.pack_end(self.details_bottom_buttons, expand=False, fill=False) | ||
411 | else: # for "My images" page | ||
412 | self.details_separator = gtk.HSeparator() | ||
413 | self.box_group_area.pack_start(self.details_separator, expand=False, fill=False) | ||
414 | self.box_group_area.pack_start(self.details_bottom_buttons, expand=False, fill=False) | ||
415 | |||
416 | self.show_all() | ||
417 | if self.kernel_detail and (not self.is_runnable): | ||
418 | self.kernel_detail.hide() | ||
419 | if self.run_script_detail and self.is_runnable: | ||
420 | self.run_script_detail.hide() | ||
421 | self.image_saved = False | ||
422 | |||
423 | def view_files_clicked_cb(self, button, image_addr): | ||
424 | subprocess.call("xdg-open /%s" % image_addr, shell=True) | ||
425 | |||
426 | def open_log_clicked_cb(self, button, log_file): | ||
427 | if log_file: | ||
428 | log_file = "file:///" + log_file | ||
429 | gtk.show_uri(screen=button.get_screen(), uri=log_file, timestamp=0) | ||
430 | |||
431 | def refresh_package_detail_box(self, image_size): | ||
432 | self.package_detail.update_line_widgets("Total image size: ", image_size) | ||
433 | |||
434 | def test_type_runnable(self, image_name): | ||
435 | type_runnable = False | ||
436 | for t in self.builder.parameters.runnable_image_types: | ||
437 | if image_name.endswith(t): | ||
438 | type_runnable = True | ||
439 | break | ||
440 | return type_runnable | ||
441 | |||
442 | def test_mach_runnable(self, image_name): | ||
443 | mach_runnable = False | ||
444 | for t in self.builder.parameters.runnable_machine_patterns: | ||
445 | if t in image_name: | ||
446 | mach_runnable = True | ||
447 | break | ||
448 | return mach_runnable | ||
449 | |||
450 | def test_deployable(self, image_name): | ||
451 | if self.builder.configuration.curr_mach.startswith("qemu"): | ||
452 | return False | ||
453 | deployable = False | ||
454 | for t in self.builder.parameters.deployable_image_types: | ||
455 | if image_name.endswith(t): | ||
456 | deployable = True | ||
457 | break | ||
458 | return deployable | ||
459 | |||
460 | def get_kernel_file_name(self, kernel_addr=""): | ||
461 | kernel_name = "" | ||
462 | |||
463 | if not kernel_addr: | ||
464 | kernel_addr = self.builder.parameters.image_addr | ||
465 | |||
466 | files = [f for f in os.listdir(kernel_addr) if f[0] <> '.'] | ||
467 | for check_file in files: | ||
468 | if check_file.endswith(".bin"): | ||
469 | name_splits = check_file.split(".")[0] | ||
470 | if self.builder.parameters.kernel_image_type in name_splits.split("-"): | ||
471 | kernel_name = check_file | ||
472 | break | ||
473 | |||
474 | return kernel_name | ||
475 | |||
476 | def show_builded_images_dialog(self, widget, primary_action=""): | ||
477 | title = primary_action if primary_action else "Your builded images" | ||
478 | dialog = CrumbsDialog(title, self.builder, | ||
479 | gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) | ||
480 | dialog.set_border_width(12) | ||
481 | |||
482 | label = gtk.Label() | ||
483 | label.set_use_markup(True) | ||
484 | label.set_alignment(0.0, 0.5) | ||
485 | label.set_padding(12,0) | ||
486 | if primary_action == "Run image": | ||
487 | label.set_markup("<span font_desc='12'>Select the image file you want to run:</span>") | ||
488 | elif primary_action == "Deploy image": | ||
489 | label.set_markup("<span font_desc='12'>Select the image file you want to deploy:</span>") | ||
490 | else: | ||
491 | label.set_markup("<span font_desc='12'>Select the image file you want to %s</span>" % primary_action) | ||
492 | dialog.vbox.pack_start(label, expand=False, fill=False) | ||
493 | |||
494 | # filter created images as action attribution (deploy or run) | ||
495 | action_attr = "" | ||
496 | action_images = [] | ||
497 | for fileitem in self.image_store: | ||
498 | action_attr = fileitem['action_attr'] | ||
499 | if (action_attr == 'run' and primary_action == "Run image") \ | ||
500 | or (action_attr == 'deploy' and primary_action == "Deploy image"): | ||
501 | action_images.append(fileitem) | ||
502 | if (len(action_images) == 0 and primary_action == "Run image"): | ||
503 | # if there are no qemu runnable images, let the user choose any of the existing images for custom run | ||
504 | action_images = self.image_store | ||
505 | # pack the corresponding 'runnable' or 'deploy' radio_buttons, if there has no more than one file. | ||
506 | # assume that there does not both have 'deploy' and 'runnable' files in the same building result | ||
507 | # in possible as design. | ||
508 | curr_row = 0 | ||
509 | rows = (len(action_images)) if len(action_images) < 10 else 10 | ||
510 | table = gtk.Table(rows, 10, True) | ||
511 | table.set_row_spacings(6) | ||
512 | table.set_col_spacing(0, 12) | ||
513 | table.set_col_spacing(5, 12) | ||
514 | |||
515 | sel_parent_btn = None | ||
516 | for fileitem in action_images: | ||
517 | sel_btn = gtk.RadioButton(sel_parent_btn, fileitem['type']) | ||
518 | sel_parent_btn = sel_btn if not sel_parent_btn else sel_parent_btn | ||
519 | if curr_row == 0: | ||
520 | sel_btn.set_active(True) | ||
521 | self.toggled_image = fileitem['name'] | ||
522 | sel_btn.connect('toggled', self.table_selected_cb, fileitem) | ||
523 | if curr_row < 10: | ||
524 | table.attach(sel_btn, 0, 4, curr_row, curr_row + 1, xpadding=24) | ||
525 | else: | ||
526 | table.attach(sel_btn, 5, 9, curr_row - 10, curr_row - 9, xpadding=24) | ||
527 | curr_row += 1 | ||
528 | |||
529 | dialog.vbox.pack_start(table, expand=False, fill=False, padding=6) | ||
530 | |||
531 | button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL) | ||
532 | HobAltButton.style_button(button) | ||
533 | |||
534 | if primary_action: | ||
535 | button = dialog.add_button(primary_action, gtk.RESPONSE_YES) | ||
536 | HobButton.style_button(button) | ||
537 | |||
538 | dialog.show_all() | ||
539 | |||
540 | response = dialog.run() | ||
541 | dialog.destroy() | ||
542 | |||
543 | if response != gtk.RESPONSE_YES: | ||
544 | return | ||
545 | # perform the primary action on the image selected by the user | ||
546 | for fileitem in self.image_store: | ||
547 | if fileitem['name'] == self.toggled_image: | ||
548 | if (fileitem['action_attr'] == 'run' and primary_action == "Run image"): | ||
549 | self.builder.runqemu_image(fileitem['name'], self.sel_kernel) | ||
550 | elif (fileitem['action_attr'] == 'deploy' and primary_action == "Deploy image"): | ||
551 | self.builder.deploy_image(fileitem['name']) | ||
552 | elif (primary_action == "Run image"): | ||
553 | self.builder.run_custom_image(fileitem['name'], self.run_script_path) | ||
554 | |||
555 | def table_selected_cb(self, tbutton, image): | ||
556 | image['is_toggled'] = tbutton.get_active() | ||
557 | if image['is_toggled']: | ||
558 | self.toggled_image = image['name'] | ||
559 | |||
560 | def change_kernel_cb(self, widget): | ||
561 | kernel_path = self.builder.show_load_kernel_dialog() | ||
562 | if kernel_path and self.kernel_detail: | ||
563 | import os.path | ||
564 | self.sel_kernel = os.path.basename(kernel_path) | ||
565 | self.kernel_detail.update_line_widgets("Kernel: ", self.sel_kernel); | ||
566 | |||
567 | def change_run_script_cb(self, widget): | ||
568 | self.run_script_path = self.builder.show_load_run_script_dialog() | ||
569 | if self.run_script_path and self.run_script_detail: | ||
570 | import os.path | ||
571 | self.sel_run_script = os.path.basename(self.run_script_path) | ||
572 | self.run_script_detail.update_line_widgets("Run script: ", self.run_script_path) | ||
573 | |||
574 | def create_bottom_buttons(self, buttonlist, image_name): | ||
575 | # Create the buttons at the bottom | ||
576 | created = False | ||
577 | packed = False | ||
578 | self.button_ids = {} | ||
579 | is_runnable = False | ||
580 | |||
581 | # create button "Deploy image" | ||
582 | name = "Deploy image" | ||
583 | if name in buttonlist and self.test_deployable(image_name): | ||
584 | deploy_button = HobButton('Deploy image') | ||
585 | #deploy_button.set_size_request(205, 49) | ||
586 | deploy_button.set_tooltip_text("Burn a live image to a USB drive or flash memory") | ||
587 | deploy_button.set_flags(gtk.CAN_DEFAULT) | ||
588 | button_id = deploy_button.connect("clicked", self.deploy_button_clicked_cb) | ||
589 | self.button_ids[button_id] = deploy_button | ||
590 | self.details_bottom_buttons.pack_end(deploy_button, expand=False, fill=False) | ||
591 | created = True | ||
592 | packed = True | ||
593 | |||
594 | name = "Run image" | ||
595 | if name in buttonlist: | ||
596 | name = "Run qemu image" | ||
597 | is_runnable = True | ||
598 | if not (self.test_type_runnable(image_name) and self.test_mach_runnable(image_name)): | ||
599 | name = "Run custom image" | ||
600 | is_runnable = False | ||
601 | if created == True: | ||
602 | # separator | ||
603 | #label = gtk.Label(" or ") | ||
604 | #self.details_bottom_buttons.pack_end(label, expand=False, fill=False) | ||
605 | |||
606 | # create button "Run image" | ||
607 | run_button = HobAltButton(name) | ||
608 | else: | ||
609 | # create button "Run image" as the primary button | ||
610 | run_button = HobButton(name) | ||
611 | #run_button.set_size_request(205, 49) | ||
612 | run_button.set_flags(gtk.CAN_DEFAULT) | ||
613 | packed = True | ||
614 | if is_runnable: | ||
615 | run_button.set_tooltip_text("Start up an image with qemu emulator") | ||
616 | else: | ||
617 | run_button.set_tooltip_text("Start up an image with custom simulator") | ||
618 | button_id = run_button.connect("clicked", self.run_button_clicked_cb) | ||
619 | self.button_ids[button_id] = run_button | ||
620 | self.details_bottom_buttons.pack_end(run_button, expand=False, fill=False) | ||
621 | created = True | ||
622 | |||
623 | name = "Save image recipe" | ||
624 | if name in buttonlist and self.builder.recipe_model.is_custom_image(): | ||
625 | save_button = HobAltButton("Save image recipe") | ||
626 | save_button.set_tooltip_text("Keep your changes saving them as an image recipe") | ||
627 | save_button.set_sensitive(not self.image_saved) | ||
628 | button_id = save_button.connect("clicked", self.save_button_clicked_cb) | ||
629 | self.button_ids[button_id] = save_button | ||
630 | self.details_bottom_buttons.pack_end(save_button, expand=False, fill=False) | ||
631 | |||
632 | name = "Build new image" | ||
633 | if name in buttonlist: | ||
634 | # create button "Build new image" | ||
635 | if packed: | ||
636 | build_new_button = HobAltButton("Build new image") | ||
637 | else: | ||
638 | build_new_button = HobButton("Build new image") | ||
639 | build_new_button.set_flags(gtk.CAN_DEFAULT) | ||
640 | #build_new_button.set_size_request(205, 49) | ||
641 | self.details_bottom_buttons.pack_end(build_new_button, expand=False, fill=False) | ||
642 | build_new_button.set_tooltip_text("Create a new image from scratch") | ||
643 | button_id = build_new_button.connect("clicked", self.build_new_button_clicked_cb) | ||
644 | self.button_ids[button_id] = build_new_button | ||
645 | |||
646 | return is_runnable | ||
647 | |||
648 | def deploy_button_clicked_cb(self, button): | ||
649 | if self.toggled_image: | ||
650 | if self.num_toggled > 1: | ||
651 | self.set_sensitive(False) | ||
652 | self.show_builded_images_dialog(None, "Deploy image") | ||
653 | self.set_sensitive(True) | ||
654 | else: | ||
655 | self.builder.deploy_image(self.toggled_image) | ||
656 | |||
657 | def run_button_clicked_cb(self, button): | ||
658 | if self.toggled_image: | ||
659 | if self.num_toggled > 1: | ||
660 | self.set_sensitive(False) | ||
661 | self.show_builded_images_dialog(None, "Run image") | ||
662 | self.set_sensitive(True) | ||
663 | else: | ||
664 | if self.is_runnable: | ||
665 | self.builder.runqemu_image(self.toggled_image, self.sel_kernel) | ||
666 | else: | ||
667 | self.builder.run_custom_image(self.toggled_image, self.run_script_path) | ||
668 | |||
669 | def save_button_clicked_cb(self, button): | ||
670 | topdir = self.builder.get_topdir() | ||
671 | images_dir = topdir + "/recipes/images/custom/" | ||
672 | self.builder.ensure_dir(images_dir) | ||
673 | |||
674 | self.name_field_template = self.builder.image_configuration_page.custom_image_selected | ||
675 | if self.name_field_template: | ||
676 | image_path = self.builder.recipe_model.pn_path[self.name_field_template] | ||
677 | image_iter = self.builder.recipe_model.get_iter(image_path) | ||
678 | self.description_field_template = self.builder.recipe_model.get_value(image_iter, self.builder.recipe_model.COL_DESC) | ||
679 | else: | ||
680 | self.name_field_template = "" | ||
681 | |||
682 | dialog = SaveImageDialog(images_dir, self.name_field_template, self.description_field_template, | ||
683 | "Save image recipe", self.builder, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) | ||
684 | response = dialog.run() | ||
685 | dialog.destroy() | ||
686 | |||
687 | def build_new_button_clicked_cb(self, button): | ||
688 | self.builder.initiate_new_build_async() | ||
689 | |||
690 | def edit_config_button_clicked_cb(self, button): | ||
691 | self.builder.show_configuration() | ||
692 | |||
693 | def edit_packages_button_clicked_cb(self, button): | ||
694 | self.builder.show_packages() | ||
695 | |||
696 | def my_images_button_clicked_cb(self, button): | ||
697 | self.builder.show_load_my_images_dialog() | ||
698 | |||
699 | def settings_button_clicked_cb(self, button): | ||
700 | # Create an advanced settings dialog | ||
701 | response, settings_changed = self.builder.show_simple_settings_dialog() | ||
702 | if not response: | ||
703 | return | ||
704 | if settings_changed: | ||
705 | self.builder.reparse_post_adv_settings() | ||
diff --git a/bitbake/lib/bb/ui/crumbs/packageselectionpage.py b/bitbake/lib/bb/ui/crumbs/packageselectionpage.py deleted file mode 100755 index 7c62b36e6b..0000000000 --- a/bitbake/lib/bb/ui/crumbs/packageselectionpage.py +++ /dev/null | |||
@@ -1,355 +0,0 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # | ||
3 | # BitBake Graphical GTK User Interface | ||
4 | # | ||
5 | # Copyright (C) 2012 Intel Corporation | ||
6 | # | ||
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 glib | ||
25 | from bb.ui.crumbs.hobcolor import HobColors | ||
26 | from bb.ui.crumbs.hobwidget import HobViewTable, HobNotebook, HobAltButton, HobButton | ||
27 | from bb.ui.crumbs.hoblistmodel import PackageListModel | ||
28 | from bb.ui.crumbs.hobpages import HobPage | ||
29 | |||
30 | # | ||
31 | # PackageSelectionPage | ||
32 | # | ||
33 | class PackageSelectionPage (HobPage): | ||
34 | |||
35 | pages = [ | ||
36 | { | ||
37 | 'name' : 'Included packages', | ||
38 | 'tooltip' : 'The packages currently included for your image', | ||
39 | 'filter' : { PackageListModel.COL_INC : [True] }, | ||
40 | 'search' : 'Search packages by name', | ||
41 | 'searchtip' : 'Enter a package name to find it', | ||
42 | 'columns' : [{ | ||
43 | 'col_name' : 'Package name', | ||
44 | 'col_id' : PackageListModel.COL_NAME, | ||
45 | 'col_style': 'text', | ||
46 | 'col_min' : 100, | ||
47 | 'col_max' : 300, | ||
48 | 'expand' : 'True' | ||
49 | }, { | ||
50 | 'col_name' : 'Size', | ||
51 | 'col_id' : PackageListModel.COL_SIZE, | ||
52 | 'col_style': 'text', | ||
53 | 'col_min' : 100, | ||
54 | 'col_max' : 300, | ||
55 | 'expand' : 'True' | ||
56 | }, { | ||
57 | 'col_name' : 'Recipe', | ||
58 | 'col_id' : PackageListModel.COL_RCP, | ||
59 | 'col_style': 'text', | ||
60 | 'col_min' : 100, | ||
61 | 'col_max' : 250, | ||
62 | 'expand' : 'True' | ||
63 | }, { | ||
64 | 'col_name' : 'Brought in by (+others)', | ||
65 | 'col_id' : PackageListModel.COL_BINB, | ||
66 | 'col_style': 'binb', | ||
67 | 'col_min' : 100, | ||
68 | 'col_max' : 350, | ||
69 | 'expand' : 'True' | ||
70 | }, { | ||
71 | 'col_name' : 'Included', | ||
72 | 'col_id' : PackageListModel.COL_INC, | ||
73 | 'col_style': 'check toggle', | ||
74 | 'col_min' : 100, | ||
75 | 'col_max' : 100 | ||
76 | }] | ||
77 | }, { | ||
78 | 'name' : 'All packages', | ||
79 | 'tooltip' : 'All packages that have been built', | ||
80 | 'filter' : {}, | ||
81 | 'search' : 'Search packages by name', | ||
82 | 'searchtip' : 'Enter a package name to find it', | ||
83 | 'columns' : [{ | ||
84 | 'col_name' : 'Package name', | ||
85 | 'col_id' : PackageListModel.COL_NAME, | ||
86 | 'col_style': 'text', | ||
87 | 'col_min' : 100, | ||
88 | 'col_max' : 400, | ||
89 | 'expand' : 'True' | ||
90 | }, { | ||
91 | 'col_name' : 'Size', | ||
92 | 'col_id' : PackageListModel.COL_SIZE, | ||
93 | 'col_style': 'text', | ||
94 | 'col_min' : 100, | ||
95 | 'col_max' : 500, | ||
96 | 'expand' : 'True' | ||
97 | }, { | ||
98 | 'col_name' : 'Recipe', | ||
99 | 'col_id' : PackageListModel.COL_RCP, | ||
100 | 'col_style': 'text', | ||
101 | 'col_min' : 100, | ||
102 | 'col_max' : 250, | ||
103 | 'expand' : 'True' | ||
104 | }, { | ||
105 | 'col_name' : 'Included', | ||
106 | 'col_id' : PackageListModel.COL_INC, | ||
107 | 'col_style': 'check toggle', | ||
108 | 'col_min' : 100, | ||
109 | 'col_max' : 100 | ||
110 | }] | ||
111 | } | ||
112 | ] | ||
113 | |||
114 | (INCLUDED, | ||
115 | ALL) = range(2) | ||
116 | |||
117 | def __init__(self, builder): | ||
118 | super(PackageSelectionPage, self).__init__(builder, "Edit packages") | ||
119 | |||
120 | # set invisible members | ||
121 | self.recipe_model = self.builder.recipe_model | ||
122 | self.package_model = self.builder.package_model | ||
123 | |||
124 | # create visual elements | ||
125 | self.create_visual_elements() | ||
126 | |||
127 | def included_clicked_cb(self, button): | ||
128 | self.ins.set_current_page(self.INCLUDED) | ||
129 | |||
130 | def create_visual_elements(self): | ||
131 | self.label = gtk.Label("Packages included: 0\nSelected packages size: 0 MB") | ||
132 | self.eventbox = self.add_onto_top_bar(self.label, 73) | ||
133 | self.pack_start(self.eventbox, expand=False, fill=False) | ||
134 | self.pack_start(self.group_align, expand=True, fill=True) | ||
135 | |||
136 | # set visible members | ||
137 | self.ins = HobNotebook() | ||
138 | self.tables = [] # we need to modify table when the dialog is shown | ||
139 | |||
140 | search_names = [] | ||
141 | search_tips = [] | ||
142 | # append the tab | ||
143 | for page in self.pages: | ||
144 | columns = page['columns'] | ||
145 | name = page['name'] | ||
146 | tab = HobViewTable(columns, name) | ||
147 | search_names.append(page['search']) | ||
148 | search_tips.append(page['searchtip']) | ||
149 | filter = page['filter'] | ||
150 | sort_model = self.package_model.tree_model(filter, initial=True) | ||
151 | tab.set_model(sort_model) | ||
152 | tab.connect("toggled", self.table_toggled_cb, name) | ||
153 | tab.connect("button-release-event", self.button_click_cb) | ||
154 | tab.connect("cell-fadeinout-stopped", self.after_fadeout_checkin_include, filter) | ||
155 | self.ins.append_page(tab, page['name'], page['tooltip']) | ||
156 | self.tables.append(tab) | ||
157 | |||
158 | self.ins.set_entry(search_names, search_tips) | ||
159 | self.ins.search.connect("changed", self.search_entry_changed) | ||
160 | |||
161 | # add all into the dialog | ||
162 | self.box_group_area.pack_start(self.ins, expand=True, fill=True) | ||
163 | |||
164 | self.button_box = gtk.HBox(False, 6) | ||
165 | self.box_group_area.pack_start(self.button_box, expand=False, fill=False) | ||
166 | |||
167 | self.build_image_button = HobButton('Build image') | ||
168 | #self.build_image_button.set_size_request(205, 49) | ||
169 | self.build_image_button.set_tooltip_text("Build target image") | ||
170 | self.build_image_button.set_flags(gtk.CAN_DEFAULT) | ||
171 | self.build_image_button.grab_default() | ||
172 | self.build_image_button.connect("clicked", self.build_image_clicked_cb) | ||
173 | self.button_box.pack_end(self.build_image_button, expand=False, fill=False) | ||
174 | |||
175 | self.back_button = HobAltButton('Cancel') | ||
176 | self.back_button.connect("clicked", self.back_button_clicked_cb) | ||
177 | self.button_box.pack_end(self.back_button, expand=False, fill=False) | ||
178 | |||
179 | def search_entry_changed(self, entry): | ||
180 | text = entry.get_text() | ||
181 | if self.ins.search_focus: | ||
182 | self.ins.search_focus = False | ||
183 | elif self.ins.page_changed: | ||
184 | self.ins.page_change = False | ||
185 | self.filter_search(entry) | ||
186 | elif text not in self.ins.search_names: | ||
187 | self.filter_search(entry) | ||
188 | |||
189 | def filter_search(self, entry): | ||
190 | text = entry.get_text() | ||
191 | current_tab = self.ins.get_current_page() | ||
192 | filter = self.pages[current_tab]['filter'] | ||
193 | filter[PackageListModel.COL_NAME] = text | ||
194 | self.tables[current_tab].set_model(self.package_model.tree_model(filter, search_data=text)) | ||
195 | if self.package_model.filtered_nb == 0: | ||
196 | if not self.ins.get_nth_page(current_tab).top_bar: | ||
197 | self.ins.get_nth_page(current_tab).add_no_result_bar(entry) | ||
198 | self.ins.get_nth_page(current_tab).top_bar.set_no_show_all(True) | ||
199 | self.ins.get_nth_page(current_tab).top_bar.show() | ||
200 | self.ins.get_nth_page(current_tab).scroll.hide() | ||
201 | else: | ||
202 | if self.ins.get_nth_page(current_tab).top_bar: | ||
203 | self.ins.get_nth_page(current_tab).top_bar.hide() | ||
204 | self.ins.get_nth_page(current_tab).scroll.show() | ||
205 | if entry.get_text() == '': | ||
206 | entry.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False) | ||
207 | else: | ||
208 | entry.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, True) | ||
209 | |||
210 | def button_click_cb(self, widget, event): | ||
211 | path, col = widget.table_tree.get_cursor() | ||
212 | tree_model = widget.table_tree.get_model() | ||
213 | if path and col.get_title() != 'Included': # else activation is likely a removal | ||
214 | properties = {'binb': '' , 'name': '', 'size':'', 'recipe':'', 'files_list':''} | ||
215 | properties['binb'] = tree_model.get_value(tree_model.get_iter(path), PackageListModel.COL_BINB) | ||
216 | properties['name'] = tree_model.get_value(tree_model.get_iter(path), PackageListModel.COL_NAME) | ||
217 | properties['size'] = tree_model.get_value(tree_model.get_iter(path), PackageListModel.COL_SIZE) | ||
218 | properties['recipe'] = tree_model.get_value(tree_model.get_iter(path), PackageListModel.COL_RCP) | ||
219 | properties['files_list'] = tree_model.get_value(tree_model.get_iter(path), PackageListModel.COL_FLIST) | ||
220 | |||
221 | self.builder.show_recipe_property_dialog(properties) | ||
222 | |||
223 | def open_log_clicked_cb(self, button, log_file): | ||
224 | if log_file: | ||
225 | log_file = "file:///" + log_file | ||
226 | gtk.show_uri(screen=button.get_screen(), uri=log_file, timestamp=0) | ||
227 | |||
228 | def show_page(self, log_file): | ||
229 | children = self.button_box.get_children() or [] | ||
230 | for child in children: | ||
231 | self.button_box.remove(child) | ||
232 | # re-packed the buttons as request, add the 'open log' button if build success | ||
233 | self.button_box.pack_end(self.build_image_button, expand=False, fill=False) | ||
234 | if log_file: | ||
235 | open_log_button = HobAltButton("Open log") | ||
236 | open_log_button.connect("clicked", self.open_log_clicked_cb, log_file) | ||
237 | open_log_button.set_tooltip_text("Open the build's log file") | ||
238 | self.button_box.pack_end(open_log_button, expand=False, fill=False) | ||
239 | self.button_box.pack_end(self.back_button, expand=False, fill=False) | ||
240 | self.show_all() | ||
241 | |||
242 | def build_image_clicked_cb(self, button): | ||
243 | self.builder.parsing_warnings = [] | ||
244 | self.builder.build_image() | ||
245 | |||
246 | def refresh_tables(self): | ||
247 | self.ins.reset_entry(self.ins.search, 0) | ||
248 | for tab in self.tables: | ||
249 | index = self.tables.index(tab) | ||
250 | filter = self.pages[index]['filter'] | ||
251 | tab.set_model(self.package_model.tree_model(filter, initial=True)) | ||
252 | |||
253 | def back_button_clicked_cb(self, button): | ||
254 | if self.builder.previous_step == self.builder.IMAGE_GENERATED: | ||
255 | self.builder.restore_initial_selected_packages() | ||
256 | self.refresh_selection() | ||
257 | self.builder.show_image_details() | ||
258 | else: | ||
259 | self.builder.show_configuration() | ||
260 | self.refresh_tables() | ||
261 | |||
262 | def refresh_selection(self): | ||
263 | self.builder.configuration.selected_packages = self.package_model.get_selected_packages() | ||
264 | self.builder.configuration.user_selected_packages = self.package_model.get_user_selected_packages() | ||
265 | selected_packages_num = len(self.builder.configuration.selected_packages) | ||
266 | selected_packages_size = self.package_model.get_packages_size() | ||
267 | selected_packages_size_str = HobPage._size_to_string(selected_packages_size) | ||
268 | |||
269 | if self.builder.configuration.image_packages == self.builder.configuration.selected_packages: | ||
270 | image_total_size_str = self.builder.configuration.image_size | ||
271 | else: | ||
272 | image_overhead_factor = self.builder.configuration.image_overhead_factor | ||
273 | image_rootfs_size = self.builder.configuration.image_rootfs_size / 1024 # image_rootfs_size is KB | ||
274 | image_extra_size = self.builder.configuration.image_extra_size / 1024 # image_extra_size is KB | ||
275 | base_size = image_overhead_factor * selected_packages_size | ||
276 | image_total_size = max(base_size, image_rootfs_size) + image_extra_size | ||
277 | if "zypper" in self.builder.configuration.selected_packages: | ||
278 | image_total_size += (51200 * 1024) | ||
279 | image_total_size_str = HobPage._size_to_string(image_total_size) | ||
280 | |||
281 | self.label.set_label("Packages included: %s\nSelected packages size: %s\nEstimated image size: %s" % | ||
282 | (selected_packages_num, selected_packages_size_str, image_total_size_str)) | ||
283 | self.ins.show_indicator_icon("Included packages", selected_packages_num) | ||
284 | |||
285 | def toggle_item_idle_cb(self, path, view_tree, cell, pagename): | ||
286 | if not self.package_model.path_included(path): | ||
287 | self.package_model.include_item(item_path=path, binb="User Selected") | ||
288 | else: | ||
289 | self.pre_fadeout_checkout_include(view_tree) | ||
290 | self.package_model.exclude_item(item_path=path) | ||
291 | self.render_fadeout(view_tree, cell) | ||
292 | |||
293 | self.refresh_selection() | ||
294 | if not self.builder.customized: | ||
295 | self.builder.customized = True | ||
296 | self.builder.set_base_image() | ||
297 | self.builder.configuration.selected_image = self.recipe_model.__custom_image__ | ||
298 | self.builder.rcppkglist_populated() | ||
299 | |||
300 | self.builder.window_sensitive(True) | ||
301 | view_model = view_tree.get_model() | ||
302 | vpath = self.package_model.convert_path_to_vpath(view_model, path) | ||
303 | view_tree.set_cursor(vpath) | ||
304 | |||
305 | def table_toggled_cb(self, table, cell, view_path, toggled_columnid, view_tree, pagename): | ||
306 | # Click to include a package | ||
307 | self.builder.window_sensitive(False) | ||
308 | view_model = view_tree.get_model() | ||
309 | path = self.package_model.convert_vpath_to_path(view_model, view_path) | ||
310 | glib.idle_add(self.toggle_item_idle_cb, path, view_tree, cell, pagename) | ||
311 | |||
312 | def pre_fadeout_checkout_include(self, tree): | ||
313 | #after the fadeout the table will be sorted as before | ||
314 | self.sort_column_id = self.package_model.sort_column_id | ||
315 | self.sort_order = self.package_model.sort_order | ||
316 | |||
317 | self.package_model.resync_fadeout_column(self.package_model.get_iter_first()) | ||
318 | # Check out a model which base on the column COL_FADE_INC, | ||
319 | # it's save the prev state of column COL_INC before do exclude_item | ||
320 | filter = { PackageListModel.COL_FADE_INC : [True]} | ||
321 | new_model = self.package_model.tree_model(filter, excluded_items_ahead=True) | ||
322 | tree.set_model(new_model) | ||
323 | tree.expand_all() | ||
324 | |||
325 | def get_excluded_rows(self, to_render_cells, model, it): | ||
326 | while it: | ||
327 | path = model.get_path(it) | ||
328 | prev_cell_is_active = model.get_value(it, PackageListModel.COL_FADE_INC) | ||
329 | curr_cell_is_active = model.get_value(it, PackageListModel.COL_INC) | ||
330 | if (prev_cell_is_active == True) and (curr_cell_is_active == False): | ||
331 | to_render_cells.append(path) | ||
332 | if model.iter_has_child(it): | ||
333 | self.get_excluded_rows(to_render_cells, model, model.iter_children(it)) | ||
334 | it = model.iter_next(it) | ||
335 | |||
336 | return to_render_cells | ||
337 | |||
338 | def render_fadeout(self, tree, cell): | ||
339 | if (not cell) or (not tree): | ||
340 | return | ||
341 | to_render_cells = [] | ||
342 | view_model = tree.get_model() | ||
343 | self.get_excluded_rows(to_render_cells, view_model, view_model.get_iter_first()) | ||
344 | |||
345 | cell.fadeout(tree, 1000, to_render_cells) | ||
346 | |||
347 | def after_fadeout_checkin_include(self, table, ctrl, cell, tree, filter): | ||
348 | self.package_model.sort_column_id = self.sort_column_id | ||
349 | self.package_model.sort_order = self.sort_order | ||
350 | tree.set_model(self.package_model.tree_model(filter)) | ||
351 | tree.expand_all() | ||
352 | |||
353 | def set_packages_curr_tab(self, curr_page): | ||
354 | self.ins.set_current_page(curr_page) | ||
355 | |||
diff --git a/bitbake/lib/bb/ui/crumbs/recipeselectionpage.py b/bitbake/lib/bb/ui/crumbs/recipeselectionpage.py deleted file mode 100755 index 58db43f706..0000000000 --- a/bitbake/lib/bb/ui/crumbs/recipeselectionpage.py +++ /dev/null | |||
@@ -1,335 +0,0 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # | ||
3 | # BitBake Graphical GTK User Interface | ||
4 | # | ||
5 | # Copyright (C) 2012 Intel Corporation | ||
6 | # | ||
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 glib | ||
25 | from bb.ui.crumbs.hobcolor import HobColors | ||
26 | from bb.ui.crumbs.hobwidget import HobViewTable, HobNotebook, HobAltButton, HobButton | ||
27 | from bb.ui.crumbs.hoblistmodel import RecipeListModel | ||
28 | from bb.ui.crumbs.hobpages import HobPage | ||
29 | |||
30 | # | ||
31 | # RecipeSelectionPage | ||
32 | # | ||
33 | class RecipeSelectionPage (HobPage): | ||
34 | pages = [ | ||
35 | { | ||
36 | 'name' : 'Included recipes', | ||
37 | 'tooltip' : 'The recipes currently included for your image', | ||
38 | 'filter' : { RecipeListModel.COL_INC : [True], | ||
39 | RecipeListModel.COL_TYPE : ['recipe', 'packagegroup'] }, | ||
40 | 'search' : 'Search recipes by name', | ||
41 | 'searchtip' : 'Enter a recipe name to find it', | ||
42 | 'columns' : [{ | ||
43 | 'col_name' : 'Recipe name', | ||
44 | 'col_id' : RecipeListModel.COL_NAME, | ||
45 | 'col_style': 'text', | ||
46 | 'col_min' : 100, | ||
47 | 'col_max' : 400, | ||
48 | 'expand' : 'True' | ||
49 | }, { | ||
50 | 'col_name' : 'Group', | ||
51 | 'col_id' : RecipeListModel.COL_GROUP, | ||
52 | 'col_style': 'text', | ||
53 | 'col_min' : 100, | ||
54 | 'col_max' : 300, | ||
55 | 'expand' : 'True' | ||
56 | }, { | ||
57 | 'col_name' : 'Brought in by (+others)', | ||
58 | 'col_id' : RecipeListModel.COL_BINB, | ||
59 | 'col_style': 'binb', | ||
60 | 'col_min' : 100, | ||
61 | 'col_max' : 500, | ||
62 | 'expand' : 'True' | ||
63 | }, { | ||
64 | 'col_name' : 'Included', | ||
65 | 'col_id' : RecipeListModel.COL_INC, | ||
66 | 'col_style': 'check toggle', | ||
67 | 'col_min' : 100, | ||
68 | 'col_max' : 100 | ||
69 | }] | ||
70 | }, { | ||
71 | 'name' : 'All recipes', | ||
72 | 'tooltip' : 'All recipes in your configured layers', | ||
73 | 'filter' : { RecipeListModel.COL_TYPE : ['recipe'] }, | ||
74 | 'search' : 'Search recipes by name', | ||
75 | 'searchtip' : 'Enter a recipe name to find it', | ||
76 | 'columns' : [{ | ||
77 | 'col_name' : 'Recipe name', | ||
78 | 'col_id' : RecipeListModel.COL_NAME, | ||
79 | 'col_style': 'text', | ||
80 | 'col_min' : 100, | ||
81 | 'col_max' : 400, | ||
82 | 'expand' : 'True' | ||
83 | }, { | ||
84 | 'col_name' : 'Group', | ||
85 | 'col_id' : RecipeListModel.COL_GROUP, | ||
86 | 'col_style': 'text', | ||
87 | 'col_min' : 100, | ||
88 | 'col_max' : 400, | ||
89 | 'expand' : 'True' | ||
90 | }, { | ||
91 | 'col_name' : 'License', | ||
92 | 'col_id' : RecipeListModel.COL_LIC, | ||
93 | 'col_style': 'text', | ||
94 | 'col_min' : 100, | ||
95 | 'col_max' : 400, | ||
96 | 'expand' : 'True' | ||
97 | }, { | ||
98 | 'col_name' : 'Included', | ||
99 | 'col_id' : RecipeListModel.COL_INC, | ||
100 | 'col_style': 'check toggle', | ||
101 | 'col_min' : 100, | ||
102 | 'col_max' : 100 | ||
103 | }] | ||
104 | }, { | ||
105 | 'name' : 'Package Groups', | ||
106 | 'tooltip' : 'All package groups in your configured layers', | ||
107 | 'filter' : { RecipeListModel.COL_TYPE : ['packagegroup'] }, | ||
108 | 'search' : 'Search package groups by name', | ||
109 | 'searchtip' : 'Enter a package group name to find it', | ||
110 | 'columns' : [{ | ||
111 | 'col_name' : 'Package group name', | ||
112 | 'col_id' : RecipeListModel.COL_NAME, | ||
113 | 'col_style': 'text', | ||
114 | 'col_min' : 100, | ||
115 | 'col_max' : 400, | ||
116 | 'expand' : 'True' | ||
117 | }, { | ||
118 | 'col_name' : 'Included', | ||
119 | 'col_id' : RecipeListModel.COL_INC, | ||
120 | 'col_style': 'check toggle', | ||
121 | 'col_min' : 100, | ||
122 | 'col_max' : 100 | ||
123 | }] | ||
124 | } | ||
125 | ] | ||
126 | |||
127 | (INCLUDED, | ||
128 | ALL, | ||
129 | TASKS) = range(3) | ||
130 | |||
131 | def __init__(self, builder = None): | ||
132 | super(RecipeSelectionPage, self).__init__(builder, "Step 1 of 2: Edit recipes") | ||
133 | |||
134 | # set invisible members | ||
135 | self.recipe_model = self.builder.recipe_model | ||
136 | |||
137 | # create visual elements | ||
138 | self.create_visual_elements() | ||
139 | |||
140 | def included_clicked_cb(self, button): | ||
141 | self.ins.set_current_page(self.INCLUDED) | ||
142 | |||
143 | def create_visual_elements(self): | ||
144 | self.eventbox = self.add_onto_top_bar(None, 73) | ||
145 | self.pack_start(self.eventbox, expand=False, fill=False) | ||
146 | self.pack_start(self.group_align, expand=True, fill=True) | ||
147 | |||
148 | # set visible members | ||
149 | self.ins = HobNotebook() | ||
150 | self.tables = [] # we need modify table when the dialog is shown | ||
151 | |||
152 | search_names = [] | ||
153 | search_tips = [] | ||
154 | # append the tabs in order | ||
155 | for page in self.pages: | ||
156 | columns = page['columns'] | ||
157 | name = page['name'] | ||
158 | tab = HobViewTable(columns, name) | ||
159 | search_names.append(page['search']) | ||
160 | search_tips.append(page['searchtip']) | ||
161 | filter = page['filter'] | ||
162 | sort_model = self.recipe_model.tree_model(filter, initial=True) | ||
163 | tab.set_model(sort_model) | ||
164 | tab.connect("toggled", self.table_toggled_cb, name) | ||
165 | tab.connect("button-release-event", self.button_click_cb) | ||
166 | tab.connect("cell-fadeinout-stopped", self.after_fadeout_checkin_include, filter) | ||
167 | self.ins.append_page(tab, page['name'], page['tooltip']) | ||
168 | self.tables.append(tab) | ||
169 | |||
170 | self.ins.set_entry(search_names, search_tips) | ||
171 | self.ins.search.connect("changed", self.search_entry_changed) | ||
172 | |||
173 | # add all into the window | ||
174 | self.box_group_area.pack_start(self.ins, expand=True, fill=True) | ||
175 | |||
176 | button_box = gtk.HBox(False, 6) | ||
177 | self.box_group_area.pack_end(button_box, expand=False, fill=False) | ||
178 | |||
179 | self.build_packages_button = HobButton('Build packages') | ||
180 | #self.build_packages_button.set_size_request(205, 49) | ||
181 | self.build_packages_button.set_tooltip_text("Build selected recipes into packages") | ||
182 | self.build_packages_button.set_flags(gtk.CAN_DEFAULT) | ||
183 | self.build_packages_button.grab_default() | ||
184 | self.build_packages_button.connect("clicked", self.build_packages_clicked_cb) | ||
185 | button_box.pack_end(self.build_packages_button, expand=False, fill=False) | ||
186 | |||
187 | self.back_button = HobAltButton('Cancel') | ||
188 | self.back_button.connect("clicked", self.back_button_clicked_cb) | ||
189 | button_box.pack_end(self.back_button, expand=False, fill=False) | ||
190 | |||
191 | def search_entry_changed(self, entry): | ||
192 | text = entry.get_text() | ||
193 | if self.ins.search_focus: | ||
194 | self.ins.search_focus = False | ||
195 | elif self.ins.page_changed: | ||
196 | self.ins.page_change = False | ||
197 | self.filter_search(entry) | ||
198 | elif text not in self.ins.search_names: | ||
199 | self.filter_search(entry) | ||
200 | |||
201 | def filter_search(self, entry): | ||
202 | text = entry.get_text() | ||
203 | current_tab = self.ins.get_current_page() | ||
204 | filter = self.pages[current_tab]['filter'] | ||
205 | filter[RecipeListModel.COL_NAME] = text | ||
206 | self.tables[current_tab].set_model(self.recipe_model.tree_model(filter, search_data=text)) | ||
207 | if self.recipe_model.filtered_nb == 0: | ||
208 | if not self.ins.get_nth_page(current_tab).top_bar: | ||
209 | self.ins.get_nth_page(current_tab).add_no_result_bar(entry) | ||
210 | self.ins.get_nth_page(current_tab).top_bar.set_no_show_all(True) | ||
211 | self.ins.get_nth_page(current_tab).top_bar.show() | ||
212 | self.ins.get_nth_page(current_tab).scroll.hide() | ||
213 | else: | ||
214 | if self.ins.get_nth_page(current_tab).top_bar: | ||
215 | self.ins.get_nth_page(current_tab).top_bar.hide() | ||
216 | self.ins.get_nth_page(current_tab).scroll.show() | ||
217 | if entry.get_text() == '': | ||
218 | entry.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False) | ||
219 | else: | ||
220 | entry.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, True) | ||
221 | |||
222 | def button_click_cb(self, widget, event): | ||
223 | path, col = widget.table_tree.get_cursor() | ||
224 | tree_model = widget.table_tree.get_model() | ||
225 | if path and col.get_title() != 'Included': # else activation is likely a removal | ||
226 | properties = {'summary': '', 'name': '', 'version': '', 'revision': '', 'binb': '', 'group': '', 'license': '', 'homepage': '', 'bugtracker': '', 'description': ''} | ||
227 | properties['summary'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_SUMMARY) | ||
228 | properties['name'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_NAME) | ||
229 | properties['version'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_VERSION) | ||
230 | properties['revision'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_REVISION) | ||
231 | properties['binb'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_BINB) | ||
232 | properties['group'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_GROUP) | ||
233 | properties['license'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_LIC) | ||
234 | properties['homepage'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_HOMEPAGE) | ||
235 | properties['bugtracker'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_BUGTRACKER) | ||
236 | properties['description'] = tree_model.get_value(tree_model.get_iter(path), RecipeListModel.COL_DESC) | ||
237 | self.builder.show_recipe_property_dialog(properties) | ||
238 | |||
239 | def build_packages_clicked_cb(self, button): | ||
240 | self.refresh_tables() | ||
241 | self.builder.build_packages() | ||
242 | |||
243 | def refresh_tables(self): | ||
244 | self.ins.reset_entry(self.ins.search, 0) | ||
245 | for tab in self.tables: | ||
246 | index = self.tables.index(tab) | ||
247 | filter = self.pages[index]['filter'] | ||
248 | tab.set_model(self.recipe_model.tree_model(filter, search_data="", initial=True)) | ||
249 | |||
250 | def back_button_clicked_cb(self, button): | ||
251 | self.builder.recipe_model.set_selected_image(self.builder.configuration.initial_selected_image) | ||
252 | self.builder.image_configuration_page.update_image_combo(self.builder.recipe_model, self.builder.configuration.initial_selected_image) | ||
253 | self.builder.image_configuration_page.update_image_desc() | ||
254 | self.builder.show_configuration() | ||
255 | self.refresh_tables() | ||
256 | |||
257 | def refresh_selection(self): | ||
258 | self.builder.configuration.selected_image = self.recipe_model.get_selected_image() | ||
259 | _, self.builder.configuration.selected_recipes = self.recipe_model.get_selected_recipes() | ||
260 | self.ins.show_indicator_icon("Included recipes", len(self.builder.configuration.selected_recipes)) | ||
261 | |||
262 | def toggle_item_idle_cb(self, path, view_tree, cell, pagename): | ||
263 | if not self.recipe_model.path_included(path): | ||
264 | self.recipe_model.include_item(item_path=path, binb="User Selected", image_contents=False) | ||
265 | else: | ||
266 | self.pre_fadeout_checkout_include(view_tree, pagename) | ||
267 | self.recipe_model.exclude_item(item_path=path) | ||
268 | self.render_fadeout(view_tree, cell) | ||
269 | |||
270 | self.refresh_selection() | ||
271 | if not self.builder.customized: | ||
272 | self.builder.customized = True | ||
273 | self.builder.configuration.selected_image = self.recipe_model.__custom_image__ | ||
274 | self.builder.rcppkglist_populated() | ||
275 | |||
276 | self.builder.window_sensitive(True) | ||
277 | |||
278 | view_model = view_tree.get_model() | ||
279 | vpath = self.recipe_model.convert_path_to_vpath(view_model, path) | ||
280 | view_tree.set_cursor(vpath) | ||
281 | |||
282 | def table_toggled_cb(self, table, cell, view_path, toggled_columnid, view_tree, pagename): | ||
283 | # Click to include a recipe | ||
284 | self.builder.window_sensitive(False) | ||
285 | view_model = view_tree.get_model() | ||
286 | path = self.recipe_model.convert_vpath_to_path(view_model, view_path) | ||
287 | glib.idle_add(self.toggle_item_idle_cb, path, view_tree, cell, pagename) | ||
288 | |||
289 | def pre_fadeout_checkout_include(self, tree, pagename): | ||
290 | #after the fadeout the table will be sorted as before | ||
291 | self.sort_column_id = self.recipe_model.sort_column_id | ||
292 | self.sort_order = self.recipe_model.sort_order | ||
293 | |||
294 | #resync the included items to a backup fade include column | ||
295 | it = self.recipe_model.get_iter_first() | ||
296 | while it: | ||
297 | active = self.recipe_model.get_value(it, self.recipe_model.COL_INC) | ||
298 | self.recipe_model.set(it, self.recipe_model.COL_FADE_INC, active) | ||
299 | it = self.recipe_model.iter_next(it) | ||
300 | # Check out a model which base on the column COL_FADE_INC, | ||
301 | # it's save the prev state of column COL_INC before do exclude_item | ||
302 | filter = { RecipeListModel.COL_FADE_INC:[True] } | ||
303 | if pagename == "Included recipes": | ||
304 | filter[RecipeListModel.COL_TYPE] = ['recipe', 'packagegroup'] | ||
305 | elif pagename == "All recipes": | ||
306 | filter[RecipeListModel.COL_TYPE] = ['recipe'] | ||
307 | else: | ||
308 | filter[RecipeListModel.COL_TYPE] = ['packagegroup'] | ||
309 | |||
310 | new_model = self.recipe_model.tree_model(filter, excluded_items_ahead=True) | ||
311 | tree.set_model(new_model) | ||
312 | |||
313 | def render_fadeout(self, tree, cell): | ||
314 | if (not cell) or (not tree): | ||
315 | return | ||
316 | to_render_cells = [] | ||
317 | model = tree.get_model() | ||
318 | it = model.get_iter_first() | ||
319 | while it: | ||
320 | path = model.get_path(it) | ||
321 | prev_cell_is_active = model.get_value(it, RecipeListModel.COL_FADE_INC) | ||
322 | curr_cell_is_active = model.get_value(it, RecipeListModel.COL_INC) | ||
323 | if (prev_cell_is_active == True) and (curr_cell_is_active == False): | ||
324 | to_render_cells.append(path) | ||
325 | it = model.iter_next(it) | ||
326 | |||
327 | cell.fadeout(tree, 1000, to_render_cells) | ||
328 | |||
329 | def after_fadeout_checkin_include(self, table, ctrl, cell, tree, filter): | ||
330 | self.recipe_model.sort_column_id = self.sort_column_id | ||
331 | self.recipe_model.sort_order = self.sort_order | ||
332 | tree.set_model(self.recipe_model.tree_model(filter)) | ||
333 | |||
334 | def set_recipe_curr_tab(self, curr_page): | ||
335 | self.ins.set_current_page(curr_page) | ||
diff --git a/bitbake/lib/bb/ui/crumbs/sanitycheckpage.py b/bitbake/lib/bb/ui/crumbs/sanitycheckpage.py deleted file mode 100644 index 76ce2ecc23..0000000000 --- a/bitbake/lib/bb/ui/crumbs/sanitycheckpage.py +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # | ||
3 | # BitBake Graphical GTK User Interface | ||
4 | # | ||
5 | # Copyright (C) 2012 Intel Corporation | ||
6 | # | ||
7 | # Authored by Bogdan Marinescu <bogdan.a.marinescu@intel.com> | ||
8 | # | ||
9 | # This program is free software; you can redistribute it and/or modify | ||
10 | # it under the terms of the GNU General Public License version 2 as | ||
11 | # published by the Free Software Foundation. | ||
12 | # | ||
13 | # This program is distributed in the hope that it will be useful, | ||
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | # GNU General Public License for more details. | ||
17 | # | ||
18 | # You should have received a copy of the GNU General Public License along | ||
19 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | |||
22 | import gtk, gobject | ||
23 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
24 | from bb.ui.crumbs.hobwidget import hic | ||
25 | from bb.ui.crumbs.hobpages import HobPage | ||
26 | |||
27 | # | ||
28 | # SanityCheckPage | ||
29 | # | ||
30 | class SanityCheckPage (HobPage): | ||
31 | |||
32 | def __init__(self, builder): | ||
33 | super(SanityCheckPage, self).__init__(builder) | ||
34 | self.running = False | ||
35 | self.create_visual_elements() | ||
36 | self.show_all() | ||
37 | |||
38 | def make_label(self, text, bold=True): | ||
39 | label = gtk.Label() | ||
40 | label.set_alignment(0.0, 0.5) | ||
41 | mark = "<span %s>%s</span>" % (self.span_tag('x-large', 'bold') if bold else self.span_tag('medium'), text) | ||
42 | label.set_markup(mark) | ||
43 | return label | ||
44 | |||
45 | def start(self): | ||
46 | if not self.running: | ||
47 | self.running = True | ||
48 | gobject.timeout_add(100, self.timer_func) | ||
49 | |||
50 | def stop(self): | ||
51 | self.running = False | ||
52 | |||
53 | def is_running(self): | ||
54 | return self.running | ||
55 | |||
56 | def timer_func(self): | ||
57 | self.progress_bar.pulse() | ||
58 | return self.running | ||
59 | |||
60 | def create_visual_elements(self): | ||
61 | # Table'd layout. 'rows' and 'cols' give the table size | ||
62 | rows, cols = 30, 50 | ||
63 | self.table = gtk.Table(rows, cols, True) | ||
64 | self.pack_start(self.table, expand=False, fill=False) | ||
65 | sx, sy = 2, 2 | ||
66 | # 'info' icon | ||
67 | image = gtk.Image() | ||
68 | image.set_from_file(hic.ICON_INFO_DISPLAY_FILE) | ||
69 | self.table.attach(image, sx, sx + 2, sy, sy + 3 ) | ||
70 | image.show() | ||
71 | # 'Checking' message | ||
72 | label = self.make_label('Hob is checking for correct build system setup') | ||
73 | self.table.attach(label, sx + 2, cols, sy, sy + 3, xpadding=5 ) | ||
74 | label.show() | ||
75 | # 'Shouldn't take long' message. | ||
76 | label = self.make_label("The check shouldn't take long.", False) | ||
77 | self.table.attach(label, sx + 2, cols, sy + 3, sy + 4, xpadding=5) | ||
78 | label.show() | ||
79 | # Progress bar | ||
80 | self.progress_bar = HobProgressBar() | ||
81 | self.table.attach(self.progress_bar, sx + 2, cols - 3, sy + 5, sy + 7, xpadding=5) | ||
82 | self.progress_bar.show() | ||
83 | # All done | ||
84 | self.table.show() | ||
85 | |||
diff --git a/bitbake/lib/bb/ui/hob.py b/bitbake/lib/bb/ui/hob.py deleted file mode 100755 index da5b411891..0000000000 --- a/bitbake/lib/bb/ui/hob.py +++ /dev/null | |||
@@ -1,109 +0,0 @@ | |||
1 | #!/usr/bin/env python | ||
2 | # | ||
3 | # BitBake Graphical GTK User Interface | ||
4 | # | ||
5 | # Copyright (C) 2011 Intel Corporation | ||
6 | # | ||
7 | # Authored by Joshua Lock <josh@linux.intel.com> | ||
8 | # Authored by Dongxiao Xu <dongxiao.xu@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 sys | ||
24 | import os | ||
25 | requirements = "FATAL: Hob requires Gtk+ 2.20.0 or higher, PyGtk 2.21.0 or higher" | ||
26 | try: | ||
27 | import gobject | ||
28 | import gtk | ||
29 | import pygtk | ||
30 | pygtk.require('2.0') # to be certain we don't have gtk+ 1.x !?! | ||
31 | gtkver = gtk.gtk_version | ||
32 | pygtkver = gtk.pygtk_version | ||
33 | if gtkver < (2, 20, 0) or pygtkver < (2, 21, 0): | ||
34 | sys.exit("%s,\nYou have Gtk+ %s and PyGtk %s." % (requirements, | ||
35 | ".".join(map(str, gtkver)), | ||
36 | ".".join(map(str, pygtkver)))) | ||
37 | except ImportError as exc: | ||
38 | sys.exit("%s (%s)." % (requirements, str(exc))) | ||
39 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) | ||
40 | try: | ||
41 | import bb | ||
42 | except RuntimeError as exc: | ||
43 | sys.exit(str(exc)) | ||
44 | from bb.ui import uihelper | ||
45 | from bb.ui.crumbs.hoblistmodel import RecipeListModel, PackageListModel | ||
46 | from bb.ui.crumbs.hobeventhandler import HobHandler | ||
47 | from bb.ui.crumbs.builder import Builder | ||
48 | |||
49 | featureSet = [bb.cooker.CookerFeatures.HOB_EXTRA_CACHES, bb.cooker.CookerFeatures.BASEDATASTORE_TRACKING] | ||
50 | |||
51 | def event_handle_idle_func(eventHandler, hobHandler): | ||
52 | # Consume as many messages as we can in the time available to us | ||
53 | if not eventHandler: | ||
54 | return False | ||
55 | event = eventHandler.getEvent() | ||
56 | while event: | ||
57 | hobHandler.handle_event(event) | ||
58 | event = eventHandler.getEvent() | ||
59 | return True | ||
60 | |||
61 | _evt_list = [ "bb.runqueue.runQueueExitWait", "bb.event.LogExecTTY", "logging.LogRecord", | ||
62 | "bb.build.TaskFailed", "bb.build.TaskBase", "bb.event.ParseStarted", | ||
63 | "bb.event.ParseProgress", "bb.event.ParseCompleted", "bb.event.CacheLoadStarted", | ||
64 | "bb.event.CacheLoadProgress", "bb.event.CacheLoadCompleted", "bb.command.CommandFailed", | ||
65 | "bb.command.CommandExit", "bb.command.CommandCompleted", "bb.cooker.CookerExit", | ||
66 | "bb.event.MultipleProviders", "bb.event.NoProvider", "bb.runqueue.sceneQueueTaskStarted", | ||
67 | "bb.runqueue.runQueueTaskStarted", "bb.runqueue.runQueueTaskFailed", "bb.runqueue.sceneQueueTaskFailed", | ||
68 | "bb.event.BuildBase", "bb.build.TaskStarted", "bb.build.TaskSucceeded", "bb.build.TaskFailedSilent", | ||
69 | "bb.event.SanityCheckPassed", "bb.event.SanityCheckFailed", "bb.event.PackageInfo", | ||
70 | "bb.event.TargetsTreeGenerated", "bb.event.ConfigFilesFound", "bb.event.ConfigFilePathFound", | ||
71 | "bb.event.FilesMatchingFound", "bb.event.NetworkTestFailed", "bb.event.NetworkTestPassed", | ||
72 | "bb.event.BuildStarted", "bb.event.BuildCompleted", "bb.event.DiskFull"] | ||
73 | |||
74 | def main (server, eventHandler, params): | ||
75 | params.updateFromServer(server) | ||
76 | gobject.threads_init() | ||
77 | |||
78 | # That indicates whether the Hob and the bitbake server are | ||
79 | # running on different machines | ||
80 | # recipe model and package model | ||
81 | recipe_model = RecipeListModel() | ||
82 | package_model = PackageListModel() | ||
83 | |||
84 | llevel, debug_domains = bb.msg.constructLogOptions() | ||
85 | server.runCommand(["setEventMask", server.getEventHandle(), llevel, debug_domains, _evt_list]) | ||
86 | hobHandler = HobHandler(server, recipe_model, package_model) | ||
87 | builder = Builder(hobHandler, recipe_model, package_model) | ||
88 | |||
89 | # This timeout function regularly probes the event queue to find out if we | ||
90 | # have any messages waiting for us. | ||
91 | gobject.timeout_add(10, event_handle_idle_func, eventHandler, hobHandler) | ||
92 | |||
93 | try: | ||
94 | gtk.main() | ||
95 | except EnvironmentError as ioerror: | ||
96 | # ignore interrupted io | ||
97 | if ioerror.args[0] == 4: | ||
98 | pass | ||
99 | finally: | ||
100 | hobHandler.cancel_build(force = True) | ||
101 | |||
102 | if __name__ == "__main__": | ||
103 | try: | ||
104 | ret = main() | ||
105 | except Exception: | ||
106 | ret = 1 | ||
107 | import traceback | ||
108 | traceback.print_exc(15) | ||
109 | sys.exit(ret) | ||