summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorBogdan Marinescu <bogdan.a.marinescu@intel.com>2013-01-10 13:08:02 +0200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2013-01-16 12:51:33 +0000
commit7bfb98568a1d7ba8dbd95332d65cd19faec6c725 (patch)
tree6a6d18d67a80e8ca862435d09c3ae63215659c7a /bitbake
parenta746719a46e9277a118fd7d4a6342bb667034132 (diff)
downloadpoky-7bfb98568a1d7ba8dbd95332d65cd19faec6c725.tar.gz
bitbake: hig.py: refactor into individual components
Since hig.py was becoming too large (which impacted maintenance and operations like git merges) it was split into individual files for the classes that were implemented in hig.py. hig is now a Python package (lib/bb/ui/crumbs/hig/). The patch was tested by building core-image-basic/qemux86 in Hob and accessing the various UI elements implemented in hig. Note that the patch does not change the functionality of Hob in any way, it's just a code refactoring that should make life a bit easier for Hob developers. [YOCTO #3200] (Bitbake rev: a7a2b730f915cafe7aa30539622dd1ca64ae41f5) Signed-off-by: Bogdan Marinescu <bogdan.a.marinescu@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rwxr-xr-xbitbake/bin/image-writer4
-rwxr-xr-xbitbake/lib/bb/ui/crumbs/builddetailspage.py2
-rwxr-xr-xbitbake/lib/bb/ui/crumbs/builder.py11
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig.py1978
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/__init__.py0
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/advancedsettingsdialog.py336
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py44
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/crumbsmessagedialog.py95
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py215
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py172
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py296
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/openinglogdialog.py68
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py90
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/settingsuihelper.py216
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/simplesettingsdialog.py722
-rwxr-xr-xbitbake/lib/bb/ui/crumbs/imagedetailspage.py4
-rwxr-xr-xbitbake/lib/bb/ui/crumbs/packageselectionpage.py2
17 files changed, 2268 insertions, 1987 deletions
diff --git a/bitbake/bin/image-writer b/bitbake/bin/image-writer
index 0b9e4505ae..86c38b5769 100755
--- a/bitbake/bin/image-writer
+++ b/bitbake/bin/image-writer
@@ -28,8 +28,10 @@ import gtk
28import optparse 28import optparse
29import pygtk 29import pygtk
30 30
31from bb.ui.crumbs.hig import DeployImageDialog, ImageSelectionDialog, CrumbsMessageDialog
32from bb.ui.crumbs.hobwidget import HobAltButton, HobButton 31from bb.ui.crumbs.hobwidget import HobAltButton, HobButton
32from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
33from bb.ui.crumbs.hig.deployimagedialog import DeployImageDialog
34from bb.ui.crumbs.hig.imageselectiondialog import ImageSelectionDialog
33 35
34# I put all the fs bitbake supported here. Need more test. 36# I put all the fs bitbake supported here. Need more test.
35DEPLOYABLE_IMAGE_TYPES = ["jffs2", "cramfs", "ext2", "ext3", "btrfs", "squashfs", "ubi", "vmdk"] 37DEPLOYABLE_IMAGE_TYPES = ["jffs2", "cramfs", "ext2", "ext3", "btrfs", "squashfs", "ubi", "vmdk"]
diff --git a/bitbake/lib/bb/ui/crumbs/builddetailspage.py b/bitbake/lib/bb/ui/crumbs/builddetailspage.py
index 2ecd95d7f6..64e758d7f4 100755
--- a/bitbake/lib/bb/ui/crumbs/builddetailspage.py
+++ b/bitbake/lib/bb/ui/crumbs/builddetailspage.py
@@ -31,7 +31,7 @@ from bb.ui.crumbs.runningbuild import BuildFailureTreeView
31from bb.ui.crumbs.hobpages import HobPage 31from bb.ui.crumbs.hobpages import HobPage
32from bb.ui.crumbs.hobcolor import HobColors 32from bb.ui.crumbs.hobcolor import HobColors
33from bb.ui.crumbs.hobthreads import OpeningLogThread 33from bb.ui.crumbs.hobthreads import OpeningLogThread
34from bb.ui.crumbs.hig import OpeningLogDialog 34from bb.ui.crumbs.hig.openinglogdialog import OpeningLogDialog
35 35
36class BuildConfigurationTreeView(gtk.TreeView): 36class BuildConfigurationTreeView(gtk.TreeView):
37 def __init__ (self): 37 def __init__ (self):
diff --git a/bitbake/lib/bb/ui/crumbs/builder.py b/bitbake/lib/bb/ui/crumbs/builder.py
index 023ac93ae2..b783dad57f 100755
--- a/bitbake/lib/bb/ui/crumbs/builder.py
+++ b/bitbake/lib/bb/ui/crumbs/builder.py
@@ -38,11 +38,14 @@ from bb.ui.crumbs.builddetailspage import BuildDetailsPage
38from bb.ui.crumbs.imagedetailspage import ImageDetailsPage 38from bb.ui.crumbs.imagedetailspage import ImageDetailsPage
39from bb.ui.crumbs.sanitycheckpage import SanityCheckPage 39from bb.ui.crumbs.sanitycheckpage import SanityCheckPage
40from bb.ui.crumbs.hobwidget import hwc, HobButton, HobAltButton 40from bb.ui.crumbs.hobwidget import hwc, HobButton, HobAltButton
41from bb.ui.crumbs.hig import CrumbsMessageDialog, ImageSelectionDialog, \
42 AdvancedSettingDialog, SimpleSettingsDialog, \
43 LayerSelectionDialog, DeployImageDialog
44from bb.ui.crumbs.persistenttooltip import PersistentTooltip 41from bb.ui.crumbs.persistenttooltip import PersistentTooltip
45import bb.ui.crumbs.utils 42import bb.ui.crumbs.utils
43from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
44from bb.ui.crumbs.hig.simplesettingsdialog import SimpleSettingsDialog
45from bb.ui.crumbs.hig.advancedsettingsdialog import AdvancedSettingsDialog
46from bb.ui.crumbs.hig.deployimagedialog import DeployImageDialog
47from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog
48from bb.ui.crumbs.hig.imageselectiondialog import ImageSelectionDialog
46 49
47hobVer = 20120808 50hobVer = 20120808
48 51
@@ -1295,7 +1298,7 @@ class Builder(gtk.Window):
1295 dialog.destroy() 1298 dialog.destroy()
1296 1299
1297 def show_adv_settings_dialog(self, tab=None): 1300 def show_adv_settings_dialog(self, tab=None):
1298 dialog = AdvancedSettingDialog(title = "Advanced configuration", 1301 dialog = AdvancedSettingsDialog(title = "Advanced configuration",
1299 configuration = copy.deepcopy(self.configuration), 1302 configuration = copy.deepcopy(self.configuration),
1300 all_image_types = self.parameters.image_types, 1303 all_image_types = self.parameters.image_types,
1301 all_package_formats = self.parameters.all_package_formats, 1304 all_package_formats = self.parameters.all_package_formats,
diff --git a/bitbake/lib/bb/ui/crumbs/hig.py b/bitbake/lib/bb/ui/crumbs/hig.py
deleted file mode 100644
index e56cf2a759..0000000000
--- a/bitbake/lib/bb/ui/crumbs/hig.py
+++ /dev/null
@@ -1,1978 +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
23import glob
24import glib
25import gtk
26import gobject
27import hashlib
28import os
29import re
30import shlex
31import subprocess
32import tempfile
33from bb.ui.crumbs.hobcolor import HobColors
34from bb.ui.crumbs.hobwidget import hic, HobViewTable, HobInfoButton, HobButton, HobAltButton, HobIconChecker
35from bb.ui.crumbs.progressbar import HobProgressBar
36import bb.ui.crumbs.utils
37import bb.process
38
39"""
40The following are convenience classes for implementing GNOME HIG compliant
41BitBake GUI's
42In summary: spacing = 12px, border-width = 6px
43"""
44
45
46class SettingsUIHelper():
47
48 def gen_label_widget(self, content):
49 label = gtk.Label()
50 label.set_alignment(0, 0)
51 label.set_markup(content)
52 label.show()
53 return label
54
55 def gen_label_info_widget(self, content, tooltip):
56 table = gtk.Table(1, 10, False)
57 label = self.gen_label_widget(content)
58 info = HobInfoButton(tooltip, self)
59 table.attach(label, 0, 1, 0, 1, xoptions=gtk.FILL)
60 table.attach(info, 1, 2, 0, 1, xoptions=gtk.FILL, xpadding=10)
61 return table
62
63 def gen_spinner_widget(self, content, lower, upper, tooltip=""):
64 hbox = gtk.HBox(False, 12)
65 adjust = gtk.Adjustment(value=content, lower=lower, upper=upper, step_incr=1)
66 spinner = gtk.SpinButton(adjustment=adjust, climb_rate=1, digits=0)
67
68 spinner.set_value(content)
69 hbox.pack_start(spinner, expand=False, fill=False)
70
71 info = HobInfoButton(tooltip, self)
72 hbox.pack_start(info, expand=False, fill=False)
73
74 hbox.show_all()
75 return hbox, spinner
76
77 def gen_combo_widget(self, curr_item, all_item, tooltip=""):
78 hbox = gtk.HBox(False, 12)
79 combo = gtk.combo_box_new_text()
80 hbox.pack_start(combo, expand=False, fill=False)
81
82 index = 0
83 for item in all_item or []:
84 combo.append_text(item)
85 if item == curr_item:
86 combo.set_active(index)
87 index += 1
88
89 info = HobInfoButton(tooltip, self)
90 hbox.pack_start(info, expand=False, fill=False)
91
92 hbox.show_all()
93 return hbox, combo
94
95 def entry_widget_select_path_cb(self, action, parent, entry):
96 dialog = gtk.FileChooserDialog("", parent,
97 gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
98 text = entry.get_text()
99 dialog.set_current_folder(text if len(text) > 0 else os.getcwd())
100 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
101 HobAltButton.style_button(button)
102 button = dialog.add_button("Open", gtk.RESPONSE_YES)
103 HobButton.style_button(button)
104 response = dialog.run()
105 if response == gtk.RESPONSE_YES:
106 path = dialog.get_filename()
107 entry.set_text(path)
108
109 dialog.destroy()
110
111 def gen_entry_widget(self, content, parent, tooltip="", need_button=True):
112 hbox = gtk.HBox(False, 12)
113 entry = gtk.Entry()
114 entry.set_text(content)
115 entry.set_size_request(350,30)
116
117 if need_button:
118 table = gtk.Table(1, 10, False)
119 hbox.pack_start(table, expand=True, fill=True)
120 table.attach(entry, 0, 9, 0, 1, xoptions=gtk.SHRINK)
121 image = gtk.Image()
122 image.set_from_stock(gtk.STOCK_OPEN,gtk.ICON_SIZE_BUTTON)
123 open_button = gtk.Button()
124 open_button.set_image(image)
125 open_button.connect("clicked", self.entry_widget_select_path_cb, parent, entry)
126 table.attach(open_button, 9, 10, 0, 1, xoptions=gtk.SHRINK)
127 else:
128 hbox.pack_start(entry, expand=True, fill=True)
129
130 if tooltip != "":
131 info = HobInfoButton(tooltip, self)
132 hbox.pack_start(info, expand=False, fill=False)
133
134 hbox.show_all()
135 return hbox, entry
136
137 def gen_mirror_entry_widget(self, content, index, match_content=""):
138 hbox = gtk.HBox(False)
139 entry = gtk.Entry()
140 content = content[:-2]
141 entry.set_text(content)
142 entry.set_size_request(350,30)
143
144 entry_match = gtk.Entry()
145 entry_match.set_text(match_content)
146 entry_match.set_size_request(100,30)
147
148 table = gtk.Table(2, 5, False)
149 table.set_row_spacings(12)
150 table.set_col_spacings(6)
151 hbox.pack_start(table, expand=True, fill=True)
152
153 label_configuration = gtk.Label("Configuration")
154 label_configuration.set_alignment(0.0,0.5)
155 label_mirror_url = gtk.Label("Mirror URL")
156 label_mirror_url.set_alignment(0.0,0.5)
157 label_match = gtk.Label("Match")
158 label_match.set_alignment(0.0,0.5)
159 label_replace_with = gtk.Label("Replace with")
160 label_replace_with.set_alignment(0.0,0.5)
161
162 combo = gtk.combo_box_new_text()
163 combo.append_text("Standard")
164 combo.append_text("Custom")
165 if match_content == "":
166 combo.set_active(0)
167 else:
168 combo.set_active(1)
169 combo.connect("changed", self.on_combo_changed, index)
170 combo.set_size_request(100,30)
171
172 delete_button = HobAltButton("Delete")
173 delete_button.connect("clicked", self.delete_cb, index, entry)
174 if content == "" and index == 0 and len(self.sstatemirrors_list) == 1:
175 delete_button.set_sensitive(False)
176 delete_button.set_size_request(100, 30)
177
178 entry_match.connect("changed", self.insert_entry_match_cb, index)
179 entry.connect("changed", self.insert_entry_cb, index, delete_button)
180
181 if match_content == "":
182 table.attach(label_configuration, 1, 2, 0, 1, xoptions=gtk.SHRINK|gtk.FILL)
183 table.attach(label_mirror_url, 2, 3, 0, 1, xoptions=gtk.SHRINK|gtk.FILL)
184 table.attach(combo, 1, 2, 1, 2, xoptions=gtk.SHRINK)
185 table.attach(entry, 2, 3, 1, 2, xoptions=gtk.SHRINK)
186 table.attach(delete_button, 3, 4, 1, 2, xoptions=gtk.SHRINK)
187 else:
188 table.attach(label_configuration, 1, 2, 0, 1, xoptions=gtk.SHRINK|gtk.FILL)
189 table.attach(label_match, 2, 3, 0, 1, xoptions=gtk.SHRINK|gtk.FILL)
190 table.attach(label_replace_with, 3, 4, 0, 1, xoptions=gtk.SHRINK|gtk.FILL)
191 table.attach(combo, 1, 2, 1, 2, xoptions=gtk.SHRINK)
192 table.attach(entry_match, 2, 3, 1, 2, xoptions=gtk.SHRINK)
193 table.attach(entry, 3, 4, 1, 2, xoptions=gtk.SHRINK)
194 table.attach(delete_button, 4, 5, 1, 2, xoptions=gtk.SHRINK)
195
196 hbox.show_all()
197 return hbox
198
199 def insert_entry_match_cb(self, entry_match, index):
200 self.sstatemirrors_list[index][2] = entry_match.get_text()
201
202 def insert_entry_cb(self, entry, index, button):
203 self.sstatemirrors_list[index][1] = entry.get_text()
204 if entry.get_text() == "" and index == 0:
205 button.set_sensitive(False)
206 else:
207 button.set_sensitive(True)
208
209 def on_combo_changed(self, combo, index):
210 if combo.get_active_text() == "Standard":
211 self.sstatemirrors_list[index][0] = 0
212 self.sstatemirrors_list[index][2] = "file://(.*)"
213 else:
214 self.sstatemirrors_list[index][0] = 1
215 self.refresh_shared_state_page()
216
217 def delete_cb(self, button, index, entry):
218 if index == 0 and len(self.sstatemirrors_list)==1:
219 entry.set_text("")
220 else:
221 self.sstatemirrors_list.pop(index)
222 self.refresh_shared_state_page()
223
224 def add_mirror(self, button):
225 tooltip = "Select the pre-built mirror that will speed your build"
226 index = len(self.sstatemirrors_list)
227 sm_list = [0, "", "file://(.*)"]
228 self.sstatemirrors_list.append(sm_list)
229 self.refresh_shared_state_page()
230
231#
232# CrumbsDialog
233#
234class CrumbsDialog(gtk.Dialog):
235 """
236 A GNOME HIG compliant dialog widget.
237 Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons
238 """
239 def __init__(self, title="", parent=None, flags=0, buttons=None):
240 super(CrumbsDialog, self).__init__(title, parent, flags, buttons)
241
242 self.set_property("has-separator", False) # note: deprecated in 2.22
243
244 self.set_border_width(6)
245 self.vbox.set_property("spacing", 12)
246 self.action_area.set_property("spacing", 12)
247 self.action_area.set_property("border-width", 6)
248
249class CrumbsMessageDialog(CrumbsDialog):
250 """
251 A GNOME HIG compliant dialog widget.
252 Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons
253 """
254 def __init__(self, parent=None, label="", icon=gtk.STOCK_INFO, msg=""):
255 super(CrumbsMessageDialog, self).__init__("", parent, gtk.DIALOG_MODAL)
256
257 self.set_border_width(6)
258 self.vbox.set_property("spacing", 12)
259 self.action_area.set_property("spacing", 12)
260 self.action_area.set_property("border-width", 6)
261
262 first_column = gtk.HBox(spacing=12)
263 first_column.set_property("border-width", 6)
264 first_column.show()
265 self.vbox.add(first_column)
266
267 self.icon = gtk.Image()
268 # We have our own Info icon which should be used in preference of the stock icon
269 self.icon_chk = HobIconChecker()
270 self.icon.set_from_stock(self.icon_chk.check_stock_icon(icon), gtk.ICON_SIZE_DIALOG)
271 self.icon.set_property("yalign", 0.00)
272 self.icon.show()
273 first_column.pack_start(self.icon, expand=False, fill=True, padding=0)
274
275 if 0 <= len(msg) < 200:
276 lbl = label + "%s" % glib.markup_escape_text(msg)
277 self.label_short = gtk.Label()
278 self.label_short.set_use_markup(True)
279 self.label_short.set_line_wrap(True)
280 self.label_short.set_markup(lbl)
281 self.label_short.set_property("yalign", 0.00)
282 self.label_short.show()
283 first_column.add(self.label_short)
284 else:
285 second_row = gtk.VBox(spacing=12)
286 second_row.set_property("border-width", 6)
287 self.label_long = gtk.Label()
288 self.label_long.set_use_markup(True)
289 self.label_long.set_line_wrap(True)
290 self.label_long.set_markup(label)
291 self.label_long.set_alignment(0.0, 0.0)
292 second_row.pack_start(self.label_long, expand=False, fill=False, padding=0)
293 self.label_long.show()
294 self.textWindow = gtk.ScrolledWindow()
295 self.textWindow.set_shadow_type(gtk.SHADOW_IN)
296 self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
297 self.msgView = gtk.TextView()
298 self.msgView.set_editable(False)
299 self.msgView.set_wrap_mode(gtk.WRAP_WORD)
300 self.msgView.set_cursor_visible(False)
301 self.msgView.set_size_request(300, 300)
302 self.buf = gtk.TextBuffer()
303 self.buf.set_text(msg)
304 self.msgView.set_buffer(self.buf)
305 self.textWindow.add(self.msgView)
306 self.msgView.show()
307 second_row.add(self.textWindow)
308 self.textWindow.show()
309 first_column.add(second_row)
310 second_row.show()
311
312#
313# SimpleSettings Dialog
314#
315class SimpleSettingsDialog (CrumbsDialog, SettingsUIHelper):
316
317 (BUILD_ENV_PAGE_ID,
318 SHARED_STATE_PAGE_ID,
319 PROXIES_PAGE_ID,
320 OTHERS_PAGE_ID) = range(4)
321
322 (TEST_NETWORK_NONE,
323 TEST_NETWORK_INITIAL,
324 TEST_NETWORK_RUNNING,
325 TEST_NETWORK_PASSED,
326 TEST_NETWORK_FAILED,
327 TEST_NETWORK_CANCELED) = range(6)
328
329 def __init__(self, title, configuration, all_image_types,
330 all_package_formats, all_distros, all_sdk_machines,
331 max_threads, parent, flags, handler, buttons=None):
332 super(SimpleSettingsDialog, self).__init__(title, parent, flags, buttons)
333
334 # class members from other objects
335 # bitbake settings from Builder.Configuration
336 self.configuration = configuration
337 self.image_types = all_image_types
338 self.all_package_formats = all_package_formats
339 self.all_distros = all_distros
340 self.all_sdk_machines = all_sdk_machines
341 self.max_threads = max_threads
342
343 # class members for internal use
344 self.dldir_text = None
345 self.sstatedir_text = None
346 self.sstatemirrors_list = []
347 self.sstatemirrors_changed = 0
348 self.bb_spinner = None
349 self.pmake_spinner = None
350 self.rootfs_size_spinner = None
351 self.extra_size_spinner = None
352 self.gplv3_checkbox = None
353 self.toolchain_checkbox = None
354 self.setting_store = None
355 self.image_types_checkbuttons = {}
356
357 self.md5 = self.config_md5()
358 self.proxy_md5 = self.config_proxy_md5()
359 self.settings_changed = False
360 self.proxy_settings_changed = False
361 self.handler = handler
362 self.proxy_test_ran = False
363
364 # create visual elements on the dialog
365 self.create_visual_elements()
366 self.connect("response", self.response_cb)
367
368 def _get_sorted_value(self, var):
369 return " ".join(sorted(str(var).split())) + "\n"
370
371 def config_proxy_md5(self):
372 data = ("ENABLE_PROXY: " + self._get_sorted_value(self.configuration.enable_proxy))
373 if self.configuration.enable_proxy:
374 for protocol in self.configuration.proxies.keys():
375 data += (protocol + ": " + self._get_sorted_value(self.configuration.combine_proxy(protocol)))
376 return hashlib.md5(data).hexdigest()
377
378 def config_md5(self):
379 data = ""
380 for key in self.configuration.extra_setting.keys():
381 data += (key + ": " + self._get_sorted_value(self.configuration.extra_setting[key]))
382 return hashlib.md5(data).hexdigest()
383
384 def gen_proxy_entry_widget(self, protocol, parent, need_button=True, line=0):
385 label = gtk.Label(protocol.upper() + " proxy")
386 self.proxy_table.attach(label, 0, 1, line, line+1, xpadding=24)
387
388 proxy_entry = gtk.Entry()
389 proxy_entry.set_size_request(300, -1)
390 self.proxy_table.attach(proxy_entry, 1, 2, line, line+1, ypadding=4)
391
392 self.proxy_table.attach(gtk.Label(":"), 2, 3, line, line+1, xpadding=12, ypadding=4)
393
394 port_entry = gtk.Entry()
395 port_entry.set_size_request(60, -1)
396 self.proxy_table.attach(port_entry, 3, 4, line, line+1, ypadding=4)
397
398 details_button = HobAltButton("Details")
399 details_button.connect("clicked", self.details_cb, parent, protocol)
400 self.proxy_table.attach(details_button, 4, 5, line, line+1, xpadding=4, yoptions=gtk.EXPAND)
401
402 return proxy_entry, port_entry, details_button
403
404 def refresh_proxy_components(self):
405 self.same_checkbox.set_sensitive(self.configuration.enable_proxy)
406
407 self.http_proxy.set_text(self.configuration.combine_host_only("http"))
408 self.http_proxy.set_editable(self.configuration.enable_proxy)
409 self.http_proxy.set_sensitive(self.configuration.enable_proxy)
410 self.http_proxy_port.set_text(self.configuration.combine_port_only("http"))
411 self.http_proxy_port.set_editable(self.configuration.enable_proxy)
412 self.http_proxy_port.set_sensitive(self.configuration.enable_proxy)
413 self.http_proxy_details.set_sensitive(self.configuration.enable_proxy)
414
415 self.https_proxy.set_text(self.configuration.combine_host_only("https"))
416 self.https_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
417 self.https_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
418 self.https_proxy_port.set_text(self.configuration.combine_port_only("https"))
419 self.https_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
420 self.https_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
421 self.https_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
422
423 self.ftp_proxy.set_text(self.configuration.combine_host_only("ftp"))
424 self.ftp_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
425 self.ftp_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
426 self.ftp_proxy_port.set_text(self.configuration.combine_port_only("ftp"))
427 self.ftp_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
428 self.ftp_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
429 self.ftp_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
430
431 self.git_proxy.set_text(self.configuration.combine_host_only("git"))
432 self.git_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
433 self.git_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
434 self.git_proxy_port.set_text(self.configuration.combine_port_only("git"))
435 self.git_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
436 self.git_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
437 self.git_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
438
439 self.cvs_proxy.set_text(self.configuration.combine_host_only("cvs"))
440 self.cvs_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
441 self.cvs_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
442 self.cvs_proxy_port.set_text(self.configuration.combine_port_only("cvs"))
443 self.cvs_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
444 self.cvs_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
445 self.cvs_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
446
447 if self.configuration.same_proxy:
448 if self.http_proxy.get_text():
449 [w.set_text(self.http_proxy.get_text()) for w in self.same_proxy_addresses]
450 if self.http_proxy_port.get_text():
451 [w.set_text(self.http_proxy_port.get_text()) for w in self.same_proxy_ports]
452
453 def proxy_checkbox_toggled_cb(self, button):
454 self.configuration.enable_proxy = self.proxy_checkbox.get_active()
455 if not self.configuration.enable_proxy:
456 self.configuration.same_proxy = False
457 self.same_checkbox.set_active(self.configuration.same_proxy)
458 self.save_proxy_data()
459 self.refresh_proxy_components()
460
461 def same_checkbox_toggled_cb(self, button):
462 self.configuration.same_proxy = self.same_checkbox.get_active()
463 self.save_proxy_data()
464 self.refresh_proxy_components()
465
466 def save_proxy_data(self):
467 self.configuration.split_proxy("http", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
468 if self.configuration.same_proxy:
469 self.configuration.split_proxy("https", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
470 self.configuration.split_proxy("ftp", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
471 self.configuration.split_proxy("git", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
472 self.configuration.split_proxy("cvs", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
473 else:
474 self.configuration.split_proxy("https", self.https_proxy.get_text() + ":" + self.https_proxy_port.get_text())
475 self.configuration.split_proxy("ftp", self.ftp_proxy.get_text() + ":" + self.ftp_proxy_port.get_text())
476 self.configuration.split_proxy("git", self.git_proxy.get_text() + ":" + self.git_proxy_port.get_text())
477 self.configuration.split_proxy("cvs", self.cvs_proxy.get_text() + ":" + self.cvs_proxy_port.get_text())
478
479 def response_cb(self, dialog, response_id):
480 if response_id == gtk.RESPONSE_YES:
481 # Check that all proxy entries have a corresponding port
482 for proxy, port in zip(self.all_proxy_addresses, self.all_proxy_ports):
483 if proxy.get_text() and not port.get_text():
484 lbl = "<b>Enter all port numbers</b>\n\n"
485 msg = "Proxy servers require a port number. Please make sure you have entered a port number for each proxy server."
486 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING, msg)
487 button = dialog.add_button("Close", gtk.RESPONSE_OK)
488 HobButton.style_button(button)
489 response = dialog.run()
490 dialog.destroy()
491 self.emit_stop_by_name("response")
492 return
493
494 self.configuration.dldir = self.dldir_text.get_text()
495 self.configuration.sstatedir = self.sstatedir_text.get_text()
496 self.configuration.sstatemirror = ""
497 for mirror in self.sstatemirrors_list:
498 if mirror[1] != "":
499 if mirror[1].endswith("\\1"):
500 smirror = mirror[2] + " " + mirror[1] + " \\n "
501 else:
502 smirror = mirror[2] + " " + mirror[1] + "\\1 \\n "
503 self.configuration.sstatemirror += smirror
504 self.configuration.bbthread = self.bb_spinner.get_value_as_int()
505 self.configuration.pmake = self.pmake_spinner.get_value_as_int()
506 self.save_proxy_data()
507 self.configuration.extra_setting = {}
508 it = self.setting_store.get_iter_first()
509 while it:
510 key = self.setting_store.get_value(it, 0)
511 value = self.setting_store.get_value(it, 1)
512 self.configuration.extra_setting[key] = value
513 it = self.setting_store.iter_next(it)
514
515 md5 = self.config_md5()
516 self.settings_changed = (self.md5 != md5)
517 self.proxy_settings_changed = (self.proxy_md5 != self.config_proxy_md5())
518
519 def create_build_environment_page(self):
520 advanced_vbox = gtk.VBox(False, 6)
521 advanced_vbox.set_border_width(6)
522
523 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Parallel threads</span>'), expand=False, fill=False)
524 sub_vbox = gtk.VBox(False, 6)
525 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
526 label = self.gen_label_widget("BitBake parallel threads")
527 tooltip = "Sets the number of threads that BitBake tasks can simultaneously run. See the <a href=\""
528 tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
529 tooltip += "poky-ref-manual.html#var-BB_NUMBER_THREADS\">Poky reference manual</a> for information"
530 bbthread_widget, self.bb_spinner = self.gen_spinner_widget(self.configuration.bbthread, 1, self.max_threads, tooltip)
531 sub_vbox.pack_start(label, expand=False, fill=False)
532 sub_vbox.pack_start(bbthread_widget, expand=False, fill=False)
533
534 sub_vbox = gtk.VBox(False, 6)
535 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
536 label = self.gen_label_widget("Make parallel threads")
537 tooltip = "Sets the maximum number of threads the host can use during the build. See the <a href=\""
538 tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
539 tooltip += "poky-ref-manual.html#var-PARALLEL_MAKE\">Poky reference manual</a> for information"
540 pmake_widget, self.pmake_spinner = self.gen_spinner_widget(self.configuration.pmake, 1, self.max_threads, tooltip)
541 sub_vbox.pack_start(label, expand=False, fill=False)
542 sub_vbox.pack_start(pmake_widget, expand=False, fill=False)
543
544 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Downloaded source code</span>'), expand=False, fill=False)
545 sub_vbox = gtk.VBox(False, 6)
546 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
547 label = self.gen_label_widget("Downloads directory")
548 tooltip = "Select a folder that caches the upstream project source code"
549 dldir_widget, self.dldir_text = self.gen_entry_widget(self.configuration.dldir, self, tooltip)
550 sub_vbox.pack_start(label, expand=False, fill=False)
551 sub_vbox.pack_start(dldir_widget, expand=False, fill=False)
552
553 return advanced_vbox
554
555 def create_shared_state_page(self):
556 advanced_vbox = gtk.VBox(False)
557 advanced_vbox.set_border_width(12)
558
559 sub_vbox = gtk.VBox(False)
560 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False, padding=24)
561 content = "<span>Shared state directory</span>"
562 tooltip = "Select a folder that caches your prebuilt results"
563 label = self.gen_label_info_widget(content, tooltip)
564 sstatedir_widget, self.sstatedir_text = self.gen_entry_widget(self.configuration.sstatedir, self)
565 sub_vbox.pack_start(label, expand=False, fill=False)
566 sub_vbox.pack_start(sstatedir_widget, expand=False, fill=False, padding=12)
567
568 content = "<span weight=\"bold\">Shared state mirrors</span>"
569 tooltip = "URLs pointing to pre-built mirrors that will speed your build. "
570 tooltip += "Select the \'Standard\' configuration if the structure of your "
571 tooltip += "mirror replicates the structure of your local shared state directory. "
572 tooltip += "For more information on shared state mirrors, check the <a href=\""
573 tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
574 tooltip += "poky-ref-manual.html#shared-state\">Yocto Project Reference Manual</a>."
575 table = self.gen_label_info_widget(content, tooltip)
576 advanced_vbox.pack_start(table, expand=False, fill=False)
577
578 sub_vbox = gtk.VBox(False)
579 scroll = gtk.ScrolledWindow()
580 scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
581 scroll.add_with_viewport(sub_vbox)
582 scroll.connect('size-allocate', self.scroll_changed)
583 advanced_vbox.pack_start(scroll, gtk.TRUE, gtk.TRUE, 0)
584 searched_string = "file://"
585
586 if self.sstatemirrors_changed == 0:
587 self.sstatemirrors_changed = 1
588 sstatemirrors = self.configuration.sstatemirror
589 if sstatemirrors == "":
590 sm_list = [ 0, "", "file://(.*)"]
591 self.sstatemirrors_list.append(sm_list)
592 else:
593 while sstatemirrors.find(searched_string) != -1:
594 if sstatemirrors.find(searched_string,1) != -1:
595 sstatemirror = sstatemirrors[:sstatemirrors.find(searched_string,1)]
596 sstatemirrors = sstatemirrors[sstatemirrors.find(searched_string,1):]
597 else:
598 sstatemirror = sstatemirrors
599 sstatemirrors = sstatemirrors[1:]
600
601 sstatemirror_fields = [x for x in sstatemirror.split(' ') if x.strip()]
602 if sstatemirror_fields[0] == "file://(.*)":
603 sm_list = [ 0, sstatemirror_fields[1], "file://(.*)"]
604 else:
605 sm_list = [ 1, sstatemirror_fields[1], sstatemirror_fields[0]]
606 self.sstatemirrors_list.append(sm_list)
607
608 index = 0
609 for mirror in self.sstatemirrors_list:
610 if mirror[0] == 0:
611 sstatemirror_widget = self.gen_mirror_entry_widget(mirror[1], index)
612 else:
613 sstatemirror_widget = self.gen_mirror_entry_widget(mirror[1], index, mirror[2])
614 sub_vbox.pack_start(sstatemirror_widget, expand=False, fill=False, padding=9)
615 index += 1
616
617 table = gtk.Table(1, 1, False)
618 table.set_col_spacings(6)
619 add_mirror_button = HobAltButton("Add another mirror")
620 add_mirror_button.connect("clicked", self.add_mirror)
621 add_mirror_button.set_size_request(150,30)
622 table.attach(add_mirror_button, 1, 2, 0, 1, xoptions=gtk.SHRINK)
623 advanced_vbox.pack_start(table, expand=False, fill=False, padding=9)
624
625 return advanced_vbox
626
627 def refresh_shared_state_page(self):
628 page_num = self.nb.get_current_page()
629 self.nb.remove_page(page_num);
630 self.nb.insert_page(self.create_shared_state_page(), gtk.Label("Shared state"),page_num)
631 self.show_all()
632 self.nb.set_current_page(page_num)
633
634 def test_proxy_ended(self, passed):
635 self.proxy_test_running = False
636 self.set_test_proxy_state(self.TEST_NETWORK_PASSED if passed else self.TEST_NETWORK_FAILED)
637 self.set_sensitive(True)
638 self.refresh_proxy_components()
639
640 def timer_func(self):
641 self.test_proxy_progress.pulse()
642 return self.proxy_test_running
643
644 def test_network_button_cb(self, b):
645 self.set_test_proxy_state(self.TEST_NETWORK_RUNNING)
646 self.set_sensitive(False)
647 self.save_proxy_data()
648 if self.configuration.enable_proxy == True:
649 self.handler.set_http_proxy(self.configuration.combine_proxy("http"))
650 self.handler.set_https_proxy(self.configuration.combine_proxy("https"))
651 self.handler.set_ftp_proxy(self.configuration.combine_proxy("ftp"))
652 self.handler.set_git_proxy(self.configuration.combine_host_only("git"), self.configuration.combine_port_only("git"))
653 self.handler.set_cvs_proxy(self.configuration.combine_host_only("cvs"), self.configuration.combine_port_only("cvs"))
654 elif self.configuration.enable_proxy == False:
655 self.handler.set_http_proxy("")
656 self.handler.set_https_proxy("")
657 self.handler.set_ftp_proxy("")
658 self.handler.set_git_proxy("", "")
659 self.handler.set_cvs_proxy("", "")
660 self.proxy_test_ran = True
661 self.proxy_test_running = True
662 gobject.timeout_add(100, self.timer_func)
663 self.handler.trigger_network_test()
664
665 def test_proxy_focus_event(self, w, direction):
666 if self.test_proxy_state in [self.TEST_NETWORK_PASSED, self.TEST_NETWORK_FAILED]:
667 self.set_test_proxy_state(self.TEST_NETWORK_INITIAL)
668 return False
669
670 def http_proxy_changed(self, e):
671 if not self.configuration.same_proxy:
672 return
673 if e == self.http_proxy:
674 [w.set_text(self.http_proxy.get_text()) for w in self.same_proxy_addresses]
675 else:
676 [w.set_text(self.http_proxy_port.get_text()) for w in self.same_proxy_ports]
677
678 def proxy_address_focus_out_event(self, w, direction):
679 text = w.get_text()
680 if not text:
681 return False
682 if text.find("//") == -1:
683 w.set_text("http://" + text)
684 return False
685
686 def set_test_proxy_state(self, state):
687 if self.test_proxy_state == state:
688 return
689 [self.proxy_table.remove(w) for w in self.test_gui_elements]
690 if state == self.TEST_NETWORK_INITIAL:
691 self.proxy_table.attach(self.test_network_button, 1, 2, 5, 6)
692 self.test_network_button.show()
693 elif state == self.TEST_NETWORK_RUNNING:
694 self.test_proxy_progress.set_rcstyle("running")
695 self.test_proxy_progress.set_text("Testing network configuration")
696 self.proxy_table.attach(self.test_proxy_progress, 0, 5, 5, 6, xpadding=4)
697 self.test_proxy_progress.show()
698 else: # passed or failed
699 self.dummy_progress.update(1.0)
700 if state == self.TEST_NETWORK_PASSED:
701 self.dummy_progress.set_text("Your network is properly configured")
702 self.dummy_progress.set_rcstyle("running")
703 else:
704 self.dummy_progress.set_text("Network test failed")
705 self.dummy_progress.set_rcstyle("fail")
706 self.proxy_table.attach(self.dummy_progress, 0, 4, 5, 6)
707 self.proxy_table.attach(self.retest_network_button, 4, 5, 5, 6, xpadding=4)
708 self.dummy_progress.show()
709 self.retest_network_button.show()
710 self.test_proxy_state = state
711
712 def create_network_page(self):
713 advanced_vbox = gtk.VBox(False, 6)
714 advanced_vbox.set_border_width(6)
715 self.same_proxy_addresses = []
716 self.same_proxy_ports = []
717 self.all_proxy_ports = []
718 self.all_proxy_addresses = []
719
720 sub_vbox = gtk.VBox(False, 6)
721 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
722 label = self.gen_label_widget("<span weight=\"bold\">Set the proxies used when fetching source code</span>")
723 tooltip = "Set the proxies used when fetching source code. A blank field uses a direct internet connection."
724 info = HobInfoButton(tooltip, self)
725 hbox = gtk.HBox(False, 12)
726 hbox.pack_start(label, expand=True, fill=True)
727 hbox.pack_start(info, expand=False, fill=False)
728 sub_vbox.pack_start(hbox, expand=False, fill=False)
729
730 proxy_test_focus = []
731 self.direct_checkbox = gtk.RadioButton(None, "Direct network connection")
732 proxy_test_focus.append(self.direct_checkbox)
733 self.direct_checkbox.set_tooltip_text("Check this box to use a direct internet connection with no proxy")
734 self.direct_checkbox.set_active(not self.configuration.enable_proxy)
735 sub_vbox.pack_start(self.direct_checkbox, expand=False, fill=False)
736
737 self.proxy_checkbox = gtk.RadioButton(self.direct_checkbox, "Manual proxy configuration")
738 proxy_test_focus.append(self.proxy_checkbox)
739 self.proxy_checkbox.set_tooltip_text("Check this box to manually set up a specific proxy")
740 self.proxy_checkbox.set_active(self.configuration.enable_proxy)
741 sub_vbox.pack_start(self.proxy_checkbox, expand=False, fill=False)
742
743 self.same_checkbox = gtk.CheckButton("Use the HTTP proxy for all protocols")
744 proxy_test_focus.append(self.same_checkbox)
745 self.same_checkbox.set_tooltip_text("Check this box to use the HTTP proxy for all five proxies")
746 self.same_checkbox.set_active(self.configuration.same_proxy)
747 hbox = gtk.HBox(False, 12)
748 hbox.pack_start(self.same_checkbox, expand=False, fill=False, padding=24)
749 sub_vbox.pack_start(hbox, expand=False, fill=False)
750
751 self.proxy_table = gtk.Table(6, 5, False)
752 self.http_proxy, self.http_proxy_port, self.http_proxy_details = self.gen_proxy_entry_widget(
753 "http", self, True, 0)
754 proxy_test_focus +=[self.http_proxy, self.http_proxy_port]
755 self.http_proxy.connect("changed", self.http_proxy_changed)
756 self.http_proxy_port.connect("changed", self.http_proxy_changed)
757
758 self.https_proxy, self.https_proxy_port, self.https_proxy_details = self.gen_proxy_entry_widget(
759 "https", self, True, 1)
760 proxy_test_focus += [self.https_proxy, self.https_proxy_port]
761 self.same_proxy_addresses.append(self.https_proxy)
762 self.same_proxy_ports.append(self.https_proxy_port)
763
764 self.ftp_proxy, self.ftp_proxy_port, self.ftp_proxy_details = self.gen_proxy_entry_widget(
765 "ftp", self, True, 2)
766 proxy_test_focus += [self.ftp_proxy, self.ftp_proxy_port]
767 self.same_proxy_addresses.append(self.ftp_proxy)
768 self.same_proxy_ports.append(self.ftp_proxy_port)
769
770 self.git_proxy, self.git_proxy_port, self.git_proxy_details = self.gen_proxy_entry_widget(
771 "git", self, True, 3)
772 proxy_test_focus += [self.git_proxy, self.git_proxy_port]
773 self.same_proxy_addresses.append(self.git_proxy)
774 self.same_proxy_ports.append(self.git_proxy_port)
775
776 self.cvs_proxy, self.cvs_proxy_port, self.cvs_proxy_details = self.gen_proxy_entry_widget(
777 "cvs", self, True, 4)
778 proxy_test_focus += [self.cvs_proxy, self.cvs_proxy_port]
779 self.same_proxy_addresses.append(self.cvs_proxy)
780 self.same_proxy_ports.append(self.cvs_proxy_port)
781 self.all_proxy_ports = self.same_proxy_ports + [self.http_proxy_port]
782 self.all_proxy_addresses = self.same_proxy_addresses + [self.http_proxy]
783 sub_vbox.pack_start(self.proxy_table, expand=False, fill=False)
784 self.proxy_table.show_all()
785
786 # Create the graphical elements for the network test feature, but don't display them yet
787 self.test_network_button = HobAltButton("Test network configuration")
788 self.test_network_button.connect("clicked", self.test_network_button_cb)
789 self.test_proxy_progress = HobProgressBar()
790 self.dummy_progress = HobProgressBar()
791 self.retest_network_button = HobAltButton("Retest")
792 self.retest_network_button.connect("clicked", self.test_network_button_cb)
793 self.test_gui_elements = [self.test_network_button, self.test_proxy_progress, self.dummy_progress, self.retest_network_button]
794 # Initialize the network tester
795 self.test_proxy_state = self.TEST_NETWORK_NONE
796 self.set_test_proxy_state(self.TEST_NETWORK_INITIAL)
797 self.proxy_test_passed_id = self.handler.connect("network-passed", lambda h:self.test_proxy_ended(True))
798 self.proxy_test_failed_id = self.handler.connect("network-failed", lambda h:self.test_proxy_ended(False))
799 [w.connect("focus-in-event", self.test_proxy_focus_event) for w in proxy_test_focus]
800 [w.connect("focus-out-event", self.proxy_address_focus_out_event) for w in self.all_proxy_addresses]
801
802 self.direct_checkbox.connect("toggled", self.proxy_checkbox_toggled_cb)
803 self.proxy_checkbox.connect("toggled", self.proxy_checkbox_toggled_cb)
804 self.same_checkbox.connect("toggled", self.same_checkbox_toggled_cb)
805
806 self.refresh_proxy_components()
807 return advanced_vbox
808
809 def switch_to_page(self, page_id):
810 self.nb.set_current_page(page_id)
811
812 def details_cb(self, button, parent, protocol):
813 self.save_proxy_data()
814 dialog = ProxyDetailsDialog(title = protocol.upper() + " Proxy Details",
815 user = self.configuration.proxies[protocol][1],
816 passwd = self.configuration.proxies[protocol][2],
817 parent = parent,
818 flags = gtk.DIALOG_MODAL
819 | gtk.DIALOG_DESTROY_WITH_PARENT
820 | gtk.DIALOG_NO_SEPARATOR)
821 dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
822 response = dialog.run()
823 if response == gtk.RESPONSE_OK:
824 self.configuration.proxies[protocol][1] = dialog.user
825 self.configuration.proxies[protocol][2] = dialog.passwd
826 self.refresh_proxy_components()
827 dialog.destroy()
828
829 def rootfs_combo_changed_cb(self, rootfs_combo, all_package_format, check_hbox):
830 combo_item = self.rootfs_combo.get_active_text()
831 for child in check_hbox.get_children():
832 if isinstance(child, gtk.CheckButton):
833 check_hbox.remove(child)
834 for format in all_package_format:
835 if format != combo_item:
836 check_button = gtk.CheckButton(format)
837 check_hbox.pack_start(check_button, expand=False, fill=False)
838 check_hbox.show_all()
839
840 def gen_pkgfmt_widget(self, curr_package_format, all_package_format, tooltip_combo="", tooltip_extra=""):
841 pkgfmt_hbox = gtk.HBox(False, 24)
842
843 rootfs_vbox = gtk.VBox(False, 6)
844 pkgfmt_hbox.pack_start(rootfs_vbox, expand=False, fill=False)
845
846 label = self.gen_label_widget("Root file system package format")
847 rootfs_vbox.pack_start(label, expand=False, fill=False)
848
849 rootfs_format = ""
850 if curr_package_format:
851 rootfs_format = curr_package_format.split()[0]
852
853 rootfs_format_widget, rootfs_combo = self.gen_combo_widget(rootfs_format, all_package_format, tooltip_combo)
854 rootfs_vbox.pack_start(rootfs_format_widget, expand=False, fill=False)
855
856 extra_vbox = gtk.VBox(False, 6)
857 pkgfmt_hbox.pack_start(extra_vbox, expand=False, fill=False)
858
859 label = self.gen_label_widget("Additional package formats")
860 extra_vbox.pack_start(label, expand=False, fill=False)
861
862 check_hbox = gtk.HBox(False, 12)
863 extra_vbox.pack_start(check_hbox, expand=False, fill=False)
864 for format in all_package_format:
865 if format != rootfs_format:
866 check_button = gtk.CheckButton(format)
867 is_active = (format in curr_package_format.split())
868 check_button.set_active(is_active)
869 check_hbox.pack_start(check_button, expand=False, fill=False)
870
871 info = HobInfoButton(tooltip_extra, self)
872 check_hbox.pack_end(info, expand=False, fill=False)
873
874 rootfs_combo.connect("changed", self.rootfs_combo_changed_cb, all_package_format, check_hbox)
875
876 pkgfmt_hbox.show_all()
877
878 return pkgfmt_hbox, rootfs_combo, check_hbox
879
880 def editable_settings_cell_edited(self, cell, path_string, new_text, model):
881 it = model.get_iter_from_string(path_string)
882 column = cell.get_data("column")
883 model.set(it, column, new_text)
884
885 def editable_settings_add_item_clicked(self, button, model):
886 new_item = ["##KEY##", "##VALUE##"]
887
888 iter = model.append()
889 model.set (iter,
890 0, new_item[0],
891 1, new_item[1],
892 )
893
894 def editable_settings_remove_item_clicked(self, button, treeview):
895 selection = treeview.get_selection()
896 model, iter = selection.get_selected()
897
898 if iter:
899 path = model.get_path(iter)[0]
900 model.remove(iter)
901
902 def gen_editable_settings(self, setting, tooltip=""):
903 setting_hbox = gtk.HBox(False, 12)
904
905 vbox = gtk.VBox(False, 12)
906 setting_hbox.pack_start(vbox, expand=True, fill=True)
907
908 setting_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
909 for key in setting.keys():
910 setting_store.set(setting_store.append(), 0, key, 1, setting[key])
911
912 setting_tree = gtk.TreeView(setting_store)
913 setting_tree.set_headers_visible(True)
914 setting_tree.set_size_request(300, 100)
915
916 col = gtk.TreeViewColumn('Key')
917 col.set_min_width(100)
918 col.set_max_width(150)
919 col.set_resizable(True)
920 col1 = gtk.TreeViewColumn('Value')
921 col1.set_min_width(100)
922 col1.set_max_width(150)
923 col1.set_resizable(True)
924 setting_tree.append_column(col)
925 setting_tree.append_column(col1)
926 cell = gtk.CellRendererText()
927 cell.set_property('width-chars', 10)
928 cell.set_property('editable', True)
929 cell.set_data("column", 0)
930 cell.connect("edited", self.editable_settings_cell_edited, setting_store)
931 cell1 = gtk.CellRendererText()
932 cell1.set_property('width-chars', 10)
933 cell1.set_property('editable', True)
934 cell1.set_data("column", 1)
935 cell1.connect("edited", self.editable_settings_cell_edited, setting_store)
936 col.pack_start(cell, True)
937 col1.pack_end(cell1, True)
938 col.set_attributes(cell, text=0)
939 col1.set_attributes(cell1, text=1)
940
941 scroll = gtk.ScrolledWindow()
942 scroll.set_shadow_type(gtk.SHADOW_IN)
943 scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
944 scroll.add(setting_tree)
945 vbox.pack_start(scroll, expand=True, fill=True)
946
947 # some buttons
948 hbox = gtk.HBox(True, 6)
949 vbox.pack_start(hbox, False, False)
950
951 button = gtk.Button(stock=gtk.STOCK_ADD)
952 button.connect("clicked", self.editable_settings_add_item_clicked, setting_store)
953 hbox.pack_start(button)
954
955 button = gtk.Button(stock=gtk.STOCK_REMOVE)
956 button.connect("clicked", self.editable_settings_remove_item_clicked, setting_tree)
957 hbox.pack_start(button)
958
959 info = HobInfoButton(tooltip, self)
960 setting_hbox.pack_start(info, expand=False, fill=False)
961
962 return setting_hbox, setting_store
963
964 def create_others_page(self):
965 advanced_vbox = gtk.VBox(False, 6)
966 advanced_vbox.set_border_width(6)
967
968 sub_vbox = gtk.VBox(False, 6)
969 advanced_vbox.pack_start(sub_vbox, expand=True, fill=True)
970 label = self.gen_label_widget("<span weight=\"bold\">Add your own variables:</span>")
971 tooltip = "These are key/value pairs for your extra settings. Click \'Add\' and then directly edit the key and the value"
972 setting_widget, self.setting_store = self.gen_editable_settings(self.configuration.extra_setting, tooltip)
973 sub_vbox.pack_start(label, expand=False, fill=False)
974 sub_vbox.pack_start(setting_widget, expand=True, fill=True)
975
976 return advanced_vbox
977
978 def create_visual_elements(self):
979 self.nb = gtk.Notebook()
980 self.nb.set_show_tabs(True)
981 self.nb.append_page(self.create_build_environment_page(), gtk.Label("Build environment"))
982 self.nb.append_page(self.create_shared_state_page(), gtk.Label("Shared state"))
983 self.nb.append_page(self.create_network_page(), gtk.Label("Network"))
984 self.nb.append_page(self.create_others_page(), gtk.Label("Others"))
985 self.nb.set_current_page(0)
986 self.vbox.pack_start(self.nb, expand=True, fill=True)
987 self.vbox.pack_end(gtk.HSeparator(), expand=True, fill=True)
988
989 self.show_all()
990
991 def destroy(self):
992 self.handler.disconnect(self.proxy_test_passed_id)
993 self.handler.disconnect(self.proxy_test_failed_id)
994 super(SimpleSettingsDialog, self).destroy()
995
996 def scroll_changed(self, widget, event, data=None):
997 adj = widget.get_vadjustment()
998 adj.set_value(adj.upper - adj.page_size)
999
1000#
1001# AdvancedSettings Dialog
1002#
1003class AdvancedSettingDialog (CrumbsDialog, SettingsUIHelper):
1004
1005 def details_cb(self, button, parent, protocol):
1006 dialog = ProxyDetailsDialog(title = protocol.upper() + " Proxy Details",
1007 user = self.configuration.proxies[protocol][1],
1008 passwd = self.configuration.proxies[protocol][2],
1009 parent = parent,
1010 flags = gtk.DIALOG_MODAL
1011 | gtk.DIALOG_DESTROY_WITH_PARENT
1012 | gtk.DIALOG_NO_SEPARATOR)
1013 dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
1014 response = dialog.run()
1015 if response == gtk.RESPONSE_OK:
1016 self.configuration.proxies[protocol][1] = dialog.user
1017 self.configuration.proxies[protocol][2] = dialog.passwd
1018 self.refresh_proxy_components()
1019 dialog.destroy()
1020
1021 def set_save_button(self, button):
1022 self.save_button = button
1023
1024 def rootfs_combo_changed_cb(self, rootfs_combo, all_package_format, check_hbox):
1025 combo_item = self.rootfs_combo.get_active_text()
1026 modified = False
1027 for child in check_hbox.get_children():
1028 if isinstance(child, gtk.CheckButton):
1029 check_hbox.remove(child)
1030 modified = True
1031 for format in all_package_format:
1032 if format != combo_item:
1033 check_button = gtk.CheckButton(format)
1034 check_hbox.pack_start(check_button, expand=False, fill=False)
1035 modified = True
1036 if modified:
1037 check_hbox.remove(self.pkgfmt_info)
1038 check_hbox.pack_start(self.pkgfmt_info, expand=False, fill=False)
1039 check_hbox.show_all()
1040
1041 def gen_pkgfmt_widget(self, curr_package_format, all_package_format, tooltip_combo="", tooltip_extra=""):
1042 pkgfmt_vbox = gtk.VBox(False, 6)
1043
1044 label = self.gen_label_widget("Root file system package format")
1045 pkgfmt_vbox.pack_start(label, expand=False, fill=False)
1046
1047 rootfs_format = ""
1048 if curr_package_format:
1049 rootfs_format = curr_package_format.split()[0]
1050
1051 rootfs_format_widget, rootfs_combo = self.gen_combo_widget(rootfs_format, all_package_format, tooltip_combo)
1052 pkgfmt_vbox.pack_start(rootfs_format_widget, expand=False, fill=False)
1053
1054 label = self.gen_label_widget("Additional package formats")
1055 pkgfmt_vbox.pack_start(label, expand=False, fill=False)
1056
1057 check_hbox = gtk.HBox(False, 12)
1058 pkgfmt_vbox.pack_start(check_hbox, expand=False, fill=False)
1059 for format in all_package_format:
1060 if format != rootfs_format:
1061 check_button = gtk.CheckButton(format)
1062 is_active = (format in curr_package_format.split())
1063 check_button.set_active(is_active)
1064 check_hbox.pack_start(check_button, expand=False, fill=False)
1065
1066 self.pkgfmt_info = HobInfoButton(tooltip_extra, self)
1067 check_hbox.pack_start(self.pkgfmt_info, expand=False, fill=False)
1068
1069 rootfs_combo.connect("changed", self.rootfs_combo_changed_cb, all_package_format, check_hbox)
1070
1071 pkgfmt_vbox.show_all()
1072
1073 return pkgfmt_vbox, rootfs_combo, check_hbox
1074
1075 def __init__(self, title, configuration, all_image_types,
1076 all_package_formats, all_distros, all_sdk_machines,
1077 max_threads, parent, flags, buttons=None):
1078 super(AdvancedSettingDialog, self).__init__(title, parent, flags, buttons)
1079
1080 # class members from other objects
1081 # bitbake settings from Builder.Configuration
1082 self.configuration = configuration
1083 self.image_types = all_image_types
1084 self.all_package_formats = all_package_formats
1085 self.all_distros = all_distros[:]
1086 self.all_sdk_machines = all_sdk_machines
1087 self.max_threads = max_threads
1088
1089 # class members for internal use
1090 self.distro_combo = None
1091 self.dldir_text = None
1092 self.sstatedir_text = None
1093 self.sstatemirror_text = None
1094 self.bb_spinner = None
1095 self.pmake_spinner = None
1096 self.rootfs_size_spinner = None
1097 self.extra_size_spinner = None
1098 self.gplv3_checkbox = None
1099 self.toolchain_checkbox = None
1100 self.image_types_checkbuttons = {}
1101
1102 self.md5 = self.config_md5()
1103 self.settings_changed = False
1104
1105 # create visual elements on the dialog
1106 self.save_button = None
1107 self.create_visual_elements()
1108 self.connect("response", self.response_cb)
1109
1110 def _get_sorted_value(self, var):
1111 return " ".join(sorted(str(var).split())) + "\n"
1112
1113 def config_md5(self):
1114 data = ""
1115 data += ("PACKAGE_CLASSES: " + self.configuration.curr_package_format + '\n')
1116 data += ("DISTRO: " + self._get_sorted_value(self.configuration.curr_distro))
1117 data += ("IMAGE_ROOTFS_SIZE: " + self._get_sorted_value(self.configuration.image_rootfs_size))
1118 data += ("IMAGE_EXTRA_SIZE: " + self._get_sorted_value(self.configuration.image_extra_size))
1119 data += ("INCOMPATIBLE_LICENSE: " + self._get_sorted_value(self.configuration.incompat_license))
1120 data += ("SDK_MACHINE: " + self._get_sorted_value(self.configuration.curr_sdk_machine))
1121 data += ("TOOLCHAIN_BUILD: " + self._get_sorted_value(self.configuration.toolchain_build))
1122 data += ("IMAGE_FSTYPES: " + self._get_sorted_value(self.configuration.image_fstypes))
1123 return hashlib.md5(data).hexdigest()
1124
1125 def create_visual_elements(self):
1126 self.nb = gtk.Notebook()
1127 self.nb.set_show_tabs(True)
1128 self.nb.append_page(self.create_image_types_page(), gtk.Label("Image types"))
1129 self.nb.append_page(self.create_output_page(), gtk.Label("Output"))
1130 self.nb.set_current_page(0)
1131 self.vbox.pack_start(self.nb, expand=True, fill=True)
1132 self.vbox.pack_end(gtk.HSeparator(), expand=True, fill=True)
1133
1134 self.show_all()
1135
1136 def get_num_checked_image_types(self):
1137 total = 0
1138 for b in self.image_types_checkbuttons.values():
1139 if b.get_active():
1140 total = total + 1
1141 return total
1142
1143 def set_save_button_state(self):
1144 if self.save_button:
1145 self.save_button.set_sensitive(self.get_num_checked_image_types() > 0)
1146
1147 def image_type_checkbutton_clicked_cb(self, button):
1148 self.set_save_button_state()
1149 if self.get_num_checked_image_types() == 0:
1150 # Show an error dialog
1151 lbl = "<b>Select an image type</b>\n\nYou need to select at least one image type."
1152 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
1153 button = dialog.add_button("OK", gtk.RESPONSE_OK)
1154 HobButton.style_button(button)
1155 response = dialog.run()
1156 dialog.destroy()
1157
1158 def create_image_types_page(self):
1159 main_vbox = gtk.VBox(False, 16)
1160 main_vbox.set_border_width(6)
1161
1162 advanced_vbox = gtk.VBox(False, 6)
1163 advanced_vbox.set_border_width(6)
1164
1165 distro_vbox = gtk.VBox(False, 6)
1166 label = self.gen_label_widget("Distro:")
1167 tooltip = "Selects the Yocto Project distribution you want"
1168 try:
1169 i = self.all_distros.index( "defaultsetup" )
1170 except ValueError:
1171 i = -1
1172 if i != -1:
1173 self.all_distros[ i ] = "Default"
1174 if self.configuration.curr_distro == "defaultsetup":
1175 self.configuration.curr_distro = "Default"
1176 distro_widget, self.distro_combo = self.gen_combo_widget(self.configuration.curr_distro, self.all_distros, tooltip)
1177 distro_vbox.pack_start(label, expand=False, fill=False)
1178 distro_vbox.pack_start(distro_widget, expand=False, fill=False)
1179 main_vbox.pack_start(distro_vbox, expand=False, fill=False)
1180
1181
1182 rows = (len(self.image_types)+1)/3
1183 table = gtk.Table(rows + 1, 10, True)
1184 advanced_vbox.pack_start(table, expand=False, fill=False)
1185
1186 tooltip = "Image file system types you want."
1187 info = HobInfoButton(tooltip, self)
1188 label = self.gen_label_widget("Image types:")
1189 align = gtk.Alignment(0, 0.5, 0, 0)
1190 table.attach(align, 0, 4, 0, 1)
1191 align.add(label)
1192 table.attach(info, 4, 5, 0, 1)
1193
1194 i = 1
1195 j = 1
1196 for image_type in sorted(self.image_types):
1197 self.image_types_checkbuttons[image_type] = gtk.CheckButton(image_type)
1198 self.image_types_checkbuttons[image_type].connect("toggled", self.image_type_checkbutton_clicked_cb)
1199 article = ""
1200 if image_type.startswith(("a", "e", "i", "o", "u")):
1201 article = "n"
1202 self.image_types_checkbuttons[image_type].set_tooltip_text("Build a%s %s image" % (article, image_type))
1203 table.attach(self.image_types_checkbuttons[image_type], j - 1, j + 3, i, i + 1)
1204 if image_type in self.configuration.image_fstypes.split():
1205 self.image_types_checkbuttons[image_type].set_active(True)
1206 i += 1
1207 if i > rows:
1208 i = 1
1209 j = j + 4
1210
1211 main_vbox.pack_start(advanced_vbox, expand=False, fill=False)
1212 self.set_save_button_state()
1213
1214 return main_vbox
1215
1216 def create_output_page(self):
1217 advanced_vbox = gtk.VBox(False, 6)
1218 advanced_vbox.set_border_width(6)
1219
1220 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Package format</span>'), expand=False, fill=False)
1221 sub_vbox = gtk.VBox(False, 6)
1222 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
1223 tooltip_combo = "Selects the package format used to generate rootfs."
1224 tooltip_extra = "Selects extra package formats to build"
1225 pkgfmt_widget, self.rootfs_combo, self.check_hbox = self.gen_pkgfmt_widget(self.configuration.curr_package_format, self.all_package_formats, tooltip_combo, tooltip_extra)
1226 sub_vbox.pack_start(pkgfmt_widget, expand=False, fill=False)
1227
1228 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Image size</span>'), expand=False, fill=False)
1229 sub_vbox = gtk.VBox(False, 6)
1230 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
1231 label = self.gen_label_widget("Image basic size (in MB)")
1232 tooltip = "Sets the basic size of your target image.\nThis is the basic size of your target image unless your selected package size exceeds this value or you select \'Image Extra Size\'."
1233 rootfs_size_widget, self.rootfs_size_spinner = self.gen_spinner_widget(int(self.configuration.image_rootfs_size*1.0/1024), 0, 65536, tooltip)
1234 sub_vbox.pack_start(label, expand=False, fill=False)
1235 sub_vbox.pack_start(rootfs_size_widget, expand=False, fill=False)
1236
1237 sub_vbox = gtk.VBox(False, 6)
1238 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
1239 label = self.gen_label_widget("Additional free space (in MB)")
1240 tooltip = "Sets the extra free space of your target image.\nBy default, the system reserves 30% of your image size as free space. If your image contains zypper, it brings in 50MB more space. The maximum free space is 64GB."
1241 extra_size_widget, self.extra_size_spinner = self.gen_spinner_widget(int(self.configuration.image_extra_size*1.0/1024), 0, 65536, tooltip)
1242 sub_vbox.pack_start(label, expand=False, fill=False)
1243 sub_vbox.pack_start(extra_size_widget, expand=False, fill=False)
1244
1245 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Licensing</span>'), expand=False, fill=False)
1246 self.gplv3_checkbox = gtk.CheckButton("Exclude GPLv3 packages")
1247 self.gplv3_checkbox.set_tooltip_text("Check this box to prevent GPLv3 packages from being included in your image")
1248 if "GPLv3" in self.configuration.incompat_license.split():
1249 self.gplv3_checkbox.set_active(True)
1250 else:
1251 self.gplv3_checkbox.set_active(False)
1252 advanced_vbox.pack_start(self.gplv3_checkbox, expand=False, fill=False)
1253
1254 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Toolchain</span>'), expand=False, fill=False)
1255 sub_hbox = gtk.HBox(False, 6)
1256 advanced_vbox.pack_start(sub_hbox, expand=False, fill=False)
1257 self.toolchain_checkbox = gtk.CheckButton("Build toolchain")
1258 self.toolchain_checkbox.set_tooltip_text("Check this box to build the related toolchain with your image")
1259 self.toolchain_checkbox.set_active(self.configuration.toolchain_build)
1260 sub_hbox.pack_start(self.toolchain_checkbox, expand=False, fill=False)
1261
1262 tooltip = "Selects the host platform for which you want to run the toolchain"
1263 sdk_machine_widget, self.sdk_machine_combo = self.gen_combo_widget(self.configuration.curr_sdk_machine, self.all_sdk_machines, tooltip)
1264 sub_hbox.pack_start(sdk_machine_widget, expand=False, fill=False)
1265
1266 return advanced_vbox
1267
1268 def response_cb(self, dialog, response_id):
1269 package_format = []
1270 package_format.append(self.rootfs_combo.get_active_text())
1271 for child in self.check_hbox:
1272 if isinstance(child, gtk.CheckButton) and child.get_active():
1273 package_format.append(child.get_label())
1274 self.configuration.curr_package_format = " ".join(package_format)
1275
1276 distro = self.distro_combo.get_active_text()
1277 if distro == "Default":
1278 distro = "defaultsetup"
1279 self.configuration.curr_distro = distro
1280 self.configuration.image_rootfs_size = self.rootfs_size_spinner.get_value_as_int() * 1024
1281 self.configuration.image_extra_size = self.extra_size_spinner.get_value_as_int() * 1024
1282
1283 self.configuration.image_fstypes = ""
1284 for image_type in self.image_types:
1285 if self.image_types_checkbuttons[image_type].get_active():
1286 self.configuration.image_fstypes += (" " + image_type)
1287 self.configuration.image_fstypes.strip()
1288
1289 if self.gplv3_checkbox.get_active():
1290 if "GPLv3" not in self.configuration.incompat_license.split():
1291 self.configuration.incompat_license += " GPLv3"
1292 else:
1293 if "GPLv3" in self.configuration.incompat_license.split():
1294 self.configuration.incompat_license = self.configuration.incompat_license.split().remove("GPLv3")
1295 self.configuration.incompat_license = " ".join(self.configuration.incompat_license or [])
1296 self.configuration.incompat_license = self.configuration.incompat_license.strip()
1297
1298 self.configuration.toolchain_build = self.toolchain_checkbox.get_active()
1299 self.configuration.curr_sdk_machine = self.sdk_machine_combo.get_active_text()
1300 md5 = self.config_md5()
1301 self.settings_changed = (self.md5 != md5)
1302
1303#
1304# DeployImageDialog
1305#
1306class DeployImageDialog (CrumbsDialog):
1307
1308 __dummy_usb__ = "--select a usb drive--"
1309
1310 def __init__(self, title, image_path, parent, flags, buttons=None, standalone=False):
1311 super(DeployImageDialog, self).__init__(title, parent, flags, buttons)
1312
1313 self.image_path = image_path
1314 self.standalone = standalone
1315
1316 self.create_visual_elements()
1317 self.connect("response", self.response_cb)
1318
1319 def create_visual_elements(self):
1320 self.set_size_request(600, 400)
1321 label = gtk.Label()
1322 label.set_alignment(0.0, 0.5)
1323 markup = "<span font_desc='12'>The image to be written into usb drive:</span>"
1324 label.set_markup(markup)
1325 self.vbox.pack_start(label, expand=False, fill=False, padding=2)
1326
1327 table = gtk.Table(2, 10, False)
1328 table.set_col_spacings(5)
1329 table.set_row_spacings(5)
1330 self.vbox.pack_start(table, expand=True, fill=True)
1331
1332 scroll = gtk.ScrolledWindow()
1333 scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
1334 scroll.set_shadow_type(gtk.SHADOW_IN)
1335 tv = gtk.TextView()
1336 tv.set_editable(False)
1337 tv.set_wrap_mode(gtk.WRAP_WORD)
1338 tv.set_cursor_visible(False)
1339 self.buf = gtk.TextBuffer()
1340 self.buf.set_text(self.image_path)
1341 tv.set_buffer(self.buf)
1342 scroll.add(tv)
1343 table.attach(scroll, 0, 10, 0, 1)
1344
1345 # There are 2 ways to use DeployImageDialog
1346 # One way is that called by HOB when the 'Deploy Image' button is clicked
1347 # The other way is that called by a standalone script.
1348 # Following block of codes handles the latter way. It adds a 'Select Image' button and
1349 # emit a signal when the button is clicked.
1350 if self.standalone:
1351 gobject.signal_new("select_image_clicked", self, gobject.SIGNAL_RUN_FIRST,
1352 gobject.TYPE_NONE, ())
1353 icon = gtk.Image()
1354 pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_IMAGES_DISPLAY_FILE)
1355 icon.set_from_pixbuf(pix_buffer)
1356 button = gtk.Button("Select Image")
1357 button.set_image(icon)
1358 #button.set_size_request(140, 50)
1359 table.attach(button, 9, 10, 1, 2, gtk.FILL, 0, 0, 0)
1360 button.connect("clicked", self.select_image_button_clicked_cb)
1361
1362 separator = gtk.HSeparator()
1363 self.vbox.pack_start(separator, expand=False, fill=False, padding=10)
1364
1365 self.usb_desc = gtk.Label()
1366 self.usb_desc.set_alignment(0.0, 0.5)
1367 markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>"
1368 self.usb_desc.set_markup(markup)
1369
1370 self.usb_combo = gtk.combo_box_new_text()
1371 self.usb_combo.connect("changed", self.usb_combo_changed_cb)
1372 model = self.usb_combo.get_model()
1373 model.clear()
1374 self.usb_combo.append_text(self.__dummy_usb__)
1375 for usb in self.find_all_usb_devices():
1376 self.usb_combo.append_text("/dev/" + usb)
1377 self.usb_combo.set_active(0)
1378 self.vbox.pack_start(self.usb_combo, expand=False, fill=False)
1379 self.vbox.pack_start(self.usb_desc, expand=False, fill=False, padding=2)
1380
1381 self.progress_bar = HobProgressBar()
1382 self.vbox.pack_start(self.progress_bar, expand=False, fill=False)
1383 separator = gtk.HSeparator()
1384 self.vbox.pack_start(separator, expand=False, fill=True, padding=10)
1385
1386 self.vbox.show_all()
1387 self.progress_bar.hide()
1388
1389 def set_image_text_buffer(self, image_path):
1390 self.buf.set_text(image_path)
1391
1392 def set_image_path(self, image_path):
1393 self.image_path = image_path
1394
1395 def popen_read(self, cmd):
1396 tmpout, errors = bb.process.run("%s" % cmd)
1397 return tmpout.strip()
1398
1399 def find_all_usb_devices(self):
1400 usb_devs = [ os.readlink(u)
1401 for u in glob.glob('/dev/disk/by-id/usb*')
1402 if not re.search(r'part\d+', u) ]
1403 return [ '%s' % u[u.rfind('/')+1:] for u in usb_devs ]
1404
1405 def get_usb_info(self, dev):
1406 return "%s %s" % \
1407 (self.popen_read('cat /sys/class/block/%s/device/vendor' % dev),
1408 self.popen_read('cat /sys/class/block/%s/device/model' % dev))
1409
1410 def select_image_button_clicked_cb(self, button):
1411 self.emit('select_image_clicked')
1412
1413 def usb_combo_changed_cb(self, usb_combo):
1414 combo_item = self.usb_combo.get_active_text()
1415 if not combo_item or combo_item == self.__dummy_usb__:
1416 markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>"
1417 self.usb_desc.set_markup(markup)
1418 else:
1419 markup = "<span font_desc='12'>" + self.get_usb_info(combo_item.lstrip("/dev/")) + "</span>"
1420 self.usb_desc.set_markup(markup)
1421
1422 def response_cb(self, dialog, response_id):
1423 if response_id == gtk.RESPONSE_YES:
1424 lbl = ''
1425 combo_item = self.usb_combo.get_active_text()
1426 if combo_item and combo_item != self.__dummy_usb__ and self.image_path:
1427 cmdline = bb.ui.crumbs.utils.which_terminal()
1428 if cmdline:
1429 tmpfile = tempfile.NamedTemporaryFile()
1430 cmdline += "\"sudo dd if=" + self.image_path + \
1431 " of=" + combo_item + "; echo $? > " + tmpfile.name + "\""
1432 subprocess.call(shlex.split(cmdline))
1433
1434 if int(tmpfile.readline().strip()) == 0:
1435 lbl = "<b>Deploy image successfully.</b>"
1436 else:
1437 lbl = "<b>Failed to deploy image.</b>\nPlease check image <b>%s</b> exists and USB device <b>%s</b> is writable." % (self.image_path, combo_item)
1438 tmpfile.close()
1439 else:
1440 if not self.image_path:
1441 lbl = "<b>No selection made.</b>\nYou have not selected an image to deploy."
1442 else:
1443 lbl = "<b>No selection made.</b>\nYou have not selected a USB device."
1444 if len(lbl):
1445 crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
1446 button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK)
1447 HobButton.style_button(button)
1448 crumbs_dialog.run()
1449 crumbs_dialog.destroy()
1450
1451 def update_progress_bar(self, title, fraction, status=None):
1452 self.progress_bar.update(fraction)
1453 self.progress_bar.set_title(title)
1454 self.progress_bar.set_rcstyle(status)
1455
1456 def write_file(self, ifile, ofile):
1457 self.progress_bar.reset()
1458 self.progress_bar.show()
1459
1460 f_from = os.open(ifile, os.O_RDONLY)
1461 f_to = os.open(ofile, os.O_WRONLY)
1462
1463 total_size = os.stat(ifile).st_size
1464 written_size = 0
1465
1466 while True:
1467 buf = os.read(f_from, 1024*1024)
1468 if not buf:
1469 break
1470 os.write(f_to, buf)
1471 written_size += 1024*1024
1472 self.update_progress_bar("Writing to usb:", written_size * 1.0/total_size)
1473
1474 self.update_progress_bar("Writing completed:", 1.0)
1475 os.close(f_from)
1476 os.close(f_to)
1477 self.progress_bar.hide()
1478
1479class CellRendererPixbufActivatable(gtk.CellRendererPixbuf):
1480 """
1481 A custom CellRenderer implementation which is activatable
1482 so that we can handle user clicks
1483 """
1484 __gsignals__ = { 'clicked' : (gobject.SIGNAL_RUN_LAST,
1485 gobject.TYPE_NONE,
1486 (gobject.TYPE_STRING,)), }
1487
1488 def __init__(self):
1489 gtk.CellRendererPixbuf.__init__(self)
1490 self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE)
1491 self.set_property('follow-state', True)
1492
1493 """
1494 Respond to a user click on a cell
1495 """
1496 def do_activate(self, even, widget, path, background_area, cell_area, flags):
1497 self.emit('clicked', path)
1498
1499#
1500# LayerSelectionDialog
1501#
1502class LayerSelectionDialog (CrumbsDialog):
1503
1504 TARGETS = [
1505 ("MY_TREE_MODEL_ROW", gtk.TARGET_SAME_WIDGET, 0),
1506 ("text/plain", 0, 1),
1507 ("TEXT", 0, 2),
1508 ("STRING", 0, 3),
1509 ]
1510
1511 def gen_label_widget(self, content):
1512 label = gtk.Label()
1513 label.set_alignment(0, 0)
1514 label.set_markup(content)
1515 label.show()
1516 return label
1517
1518 def layer_widget_toggled_cb(self, cell, path, layer_store):
1519 name = layer_store[path][0]
1520 toggle = not layer_store[path][1]
1521 layer_store[path][1] = toggle
1522
1523 def layer_widget_add_clicked_cb(self, action, layer_store, parent):
1524 dialog = gtk.FileChooserDialog("Add new layer", parent,
1525 gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
1526 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1527 HobAltButton.style_button(button)
1528 button = dialog.add_button("Open", gtk.RESPONSE_YES)
1529 HobButton.style_button(button)
1530 label = gtk.Label("Select the layer you wish to add")
1531 label.show()
1532 dialog.set_extra_widget(label)
1533 response = dialog.run()
1534 path = dialog.get_filename()
1535 dialog.destroy()
1536
1537 lbl = "<b>Error</b>\nUnable to load layer <i>%s</i> because " % path
1538 if response == gtk.RESPONSE_YES:
1539 import os
1540 import os.path
1541 layers = []
1542 it = layer_store.get_iter_first()
1543 while it:
1544 layers.append(layer_store.get_value(it, 0))
1545 it = layer_store.iter_next(it)
1546
1547 if not path:
1548 lbl += "it is an invalid path."
1549 elif not os.path.exists(path+"/conf/layer.conf"):
1550 lbl += "there is no layer.conf inside the directory."
1551 elif path in layers:
1552 lbl += "it is already in loaded layers."
1553 else:
1554 layer_store.append([path])
1555 return
1556 dialog = CrumbsMessageDialog(parent, lbl)
1557 dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
1558 response = dialog.run()
1559 dialog.destroy()
1560
1561 def layer_widget_del_clicked_cb(self, action, tree_selection, layer_store):
1562 model, iter = tree_selection.get_selected()
1563 if iter:
1564 layer_store.remove(iter)
1565
1566
1567 def gen_layer_widget(self, layers, layers_avail, window, tooltip=""):
1568 hbox = gtk.HBox(False, 6)
1569
1570 layer_tv = gtk.TreeView()
1571 layer_tv.set_rules_hint(True)
1572 layer_tv.set_headers_visible(False)
1573 tree_selection = layer_tv.get_selection()
1574 tree_selection.set_mode(gtk.SELECTION_SINGLE)
1575
1576 # Allow enable drag and drop of rows including row move
1577 layer_tv.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
1578 self.TARGETS,
1579 gtk.gdk.ACTION_DEFAULT|
1580 gtk.gdk.ACTION_MOVE)
1581 layer_tv.enable_model_drag_dest(self.TARGETS,
1582 gtk.gdk.ACTION_DEFAULT)
1583 layer_tv.connect("drag_data_get", self.drag_data_get_cb)
1584 layer_tv.connect("drag_data_received", self.drag_data_received_cb)
1585
1586 col0= gtk.TreeViewColumn('Path')
1587 cell0 = gtk.CellRendererText()
1588 cell0.set_padding(5,2)
1589 col0.pack_start(cell0, True)
1590 col0.set_cell_data_func(cell0, self.draw_layer_path_cb)
1591 layer_tv.append_column(col0)
1592
1593 scroll = gtk.ScrolledWindow()
1594 scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
1595 scroll.set_shadow_type(gtk.SHADOW_IN)
1596 scroll.add(layer_tv)
1597
1598 table_layer = gtk.Table(2, 10, False)
1599 hbox.pack_start(table_layer, expand=True, fill=True)
1600
1601 table_layer.attach(scroll, 0, 10, 0, 1)
1602
1603 layer_store = gtk.ListStore(gobject.TYPE_STRING)
1604 for layer in layers:
1605 layer_store.append([layer])
1606
1607 col1 = gtk.TreeViewColumn('Enabled')
1608 layer_tv.append_column(col1)
1609
1610 cell1 = CellRendererPixbufActivatable()
1611 cell1.set_fixed_size(-1,35)
1612 cell1.connect("clicked", self.del_cell_clicked_cb, layer_store)
1613 col1.pack_start(cell1, True)
1614 col1.set_cell_data_func(cell1, self.draw_delete_button_cb, layer_tv)
1615
1616 add_button = gtk.Button()
1617 add_button.set_relief(gtk.RELIEF_NONE)
1618 box = gtk.HBox(False, 6)
1619 box.show()
1620 add_button.add(box)
1621 add_button.connect("enter-notify-event", self.add_hover_cb)
1622 add_button.connect("leave-notify-event", self.add_leave_cb)
1623 self.im = gtk.Image()
1624 self.im.set_from_file(hic.ICON_INDI_ADD_FILE)
1625 self.im.show()
1626 box.pack_start(self.im, expand=False, fill=False, padding=6)
1627 lbl = gtk.Label("Add layer")
1628 lbl.set_alignment(0.0, 0.5)
1629 lbl.show()
1630 box.pack_start(lbl, expand=True, fill=True, padding=6)
1631 add_button.connect("clicked", self.layer_widget_add_clicked_cb, layer_store, window)
1632 table_layer.attach(add_button, 0, 10, 1, 2, gtk.EXPAND | gtk.FILL, 0, 0, 6)
1633 layer_tv.set_model(layer_store)
1634
1635 hbox.show_all()
1636
1637 return hbox, layer_store
1638
1639 def drag_data_get_cb(self, treeview, context, selection, target_id, etime):
1640 treeselection = treeview.get_selection()
1641 model, iter = treeselection.get_selected()
1642 data = model.get_value(iter, 0)
1643 selection.set(selection.target, 8, data)
1644
1645 def drag_data_received_cb(self, treeview, context, x, y, selection, info, etime):
1646 model = treeview.get_model()
1647 data = selection.data
1648 drop_info = treeview.get_dest_row_at_pos(x, y)
1649 if drop_info:
1650 path, position = drop_info
1651 iter = model.get_iter(path)
1652 if (position == gtk.TREE_VIEW_DROP_BEFORE or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
1653 model.insert_before(iter, [data])
1654 else:
1655 model.insert_after(iter, [data])
1656 else:
1657 model.append([data])
1658 if context.action == gtk.gdk.ACTION_MOVE:
1659 context.finish(True, True, etime)
1660 return
1661
1662 def add_hover_cb(self, button, event):
1663 self.im.set_from_file(hic.ICON_INDI_ADD_HOVER_FILE)
1664
1665 def add_leave_cb(self, button, event):
1666 self.im.set_from_file(hic.ICON_INDI_ADD_FILE)
1667
1668 def __init__(self, title, layers, layers_non_removable, all_layers, parent, flags, buttons=None):
1669 super(LayerSelectionDialog, self).__init__(title, parent, flags, buttons)
1670
1671 # class members from other objects
1672 self.layers = layers
1673 self.layers_non_removable = layers_non_removable
1674 self.all_layers = all_layers
1675 self.layers_changed = False
1676
1677 # icon for remove button in TreeView
1678 im = gtk.Image()
1679 im.set_from_file(hic.ICON_INDI_REMOVE_FILE)
1680 self.rem_icon = im.get_pixbuf()
1681
1682 # class members for internal use
1683 self.layer_store = None
1684
1685 # create visual elements on the dialog
1686 self.create_visual_elements()
1687 self.connect("response", self.response_cb)
1688
1689 def create_visual_elements(self):
1690 layer_widget, self.layer_store = self.gen_layer_widget(self.layers, self.all_layers, self, None)
1691 layer_widget.set_size_request(450, 250)
1692 self.vbox.pack_start(layer_widget, expand=True, fill=True)
1693 self.show_all()
1694
1695 def response_cb(self, dialog, response_id):
1696 model = self.layer_store
1697 it = model.get_iter_first()
1698 layers = []
1699 while it:
1700 layers.append(model.get_value(it, 0))
1701 it = model.iter_next(it)
1702
1703 self.layers_changed = (self.layers != layers)
1704 self.layers = layers
1705
1706 """
1707 A custom cell_data_func to draw a delete 'button' in the TreeView for layers
1708 other than the meta layer. The deletion of which is prevented so that the
1709 user can't shoot themselves in the foot too badly.
1710 """
1711 def draw_delete_button_cb(self, col, cell, model, it, tv):
1712 path = model.get_value(it, 0)
1713 if path in self.layers_non_removable:
1714 cell.set_sensitive(False)
1715 cell.set_property('pixbuf', None)
1716 cell.set_property('mode', gtk.CELL_RENDERER_MODE_INERT)
1717 else:
1718 cell.set_property('pixbuf', self.rem_icon)
1719 cell.set_sensitive(True)
1720 cell.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE)
1721
1722 return True
1723
1724 """
1725 A custom cell_data_func to write an extra message into the layer path cell
1726 for the meta layer. We should inform the user that they can't remove it for
1727 their own safety.
1728 """
1729 def draw_layer_path_cb(self, col, cell, model, it):
1730 path = model.get_value(it, 0)
1731 if path in self.layers_non_removable:
1732 cell.set_property('markup', "<b>It cannot be removed</b>\n%s" % path)
1733 else:
1734 cell.set_property('text', path)
1735
1736 def del_cell_clicked_cb(self, cell, path, model):
1737 it = model.get_iter_from_string(path)
1738 model.remove(it)
1739
1740class ImageSelectionDialog (CrumbsDialog):
1741
1742 __columns__ = [{
1743 'col_name' : 'Image name',
1744 'col_id' : 0,
1745 'col_style': 'text',
1746 'col_min' : 400,
1747 'col_max' : 400
1748 }, {
1749 'col_name' : 'Select',
1750 'col_id' : 1,
1751 'col_style': 'radio toggle',
1752 'col_min' : 160,
1753 'col_max' : 160
1754 }]
1755
1756
1757 def __init__(self, image_folder, image_types, title, parent, flags, buttons=None, image_extension = {}):
1758 super(ImageSelectionDialog, self).__init__(title, parent, flags, buttons)
1759 self.connect("response", self.response_cb)
1760
1761 self.image_folder = image_folder
1762 self.image_types = image_types
1763 self.image_list = []
1764 self.image_names = []
1765 self.image_extension = image_extension
1766
1767 # create visual elements on the dialog
1768 self.create_visual_elements()
1769
1770 self.image_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN)
1771 self.fill_image_store()
1772
1773 def create_visual_elements(self):
1774 hbox = gtk.HBox(False, 6)
1775
1776 self.vbox.pack_start(hbox, expand=False, fill=False)
1777
1778 entry = gtk.Entry()
1779 entry.set_text(self.image_folder)
1780 table = gtk.Table(1, 10, True)
1781 table.set_size_request(560, -1)
1782 hbox.pack_start(table, expand=False, fill=False)
1783 table.attach(entry, 0, 9, 0, 1)
1784 image = gtk.Image()
1785 image.set_from_stock(gtk.STOCK_OPEN, gtk.ICON_SIZE_BUTTON)
1786 open_button = gtk.Button()
1787 open_button.set_image(image)
1788 open_button.connect("clicked", self.select_path_cb, self, entry)
1789 table.attach(open_button, 9, 10, 0, 1)
1790
1791 self.image_table = HobViewTable(self.__columns__)
1792 self.image_table.set_size_request(-1, 300)
1793 self.image_table.connect("toggled", self.toggled_cb)
1794 self.image_table.connect_group_selection(self.table_selected_cb)
1795 self.image_table.connect("row-activated", self.row_actived_cb)
1796 self.vbox.pack_start(self.image_table, expand=True, fill=True)
1797
1798 self.show_all()
1799
1800 def change_image_cb(self, model, path, columnid):
1801 if not model:
1802 return
1803 iter = model.get_iter_first()
1804 while iter:
1805 rowpath = model.get_path(iter)
1806 model[rowpath][columnid] = False
1807 iter = model.iter_next(iter)
1808
1809 model[path][columnid] = True
1810
1811 def toggled_cb(self, table, cell, path, columnid, tree):
1812 model = tree.get_model()
1813 self.change_image_cb(model, path, columnid)
1814
1815 def table_selected_cb(self, selection):
1816 model, paths = selection.get_selected_rows()
1817 if paths:
1818 self.change_image_cb(model, paths[0], 1)
1819
1820 def row_actived_cb(self, tab, model, path):
1821 self.change_image_cb(model, path, 1)
1822 self.emit('response', gtk.RESPONSE_YES)
1823
1824 def select_path_cb(self, action, parent, entry):
1825 dialog = gtk.FileChooserDialog("", parent,
1826 gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
1827 text = entry.get_text()
1828 dialog.set_current_folder(text if len(text) > 0 else os.getcwd())
1829 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1830 HobAltButton.style_button(button)
1831 button = dialog.add_button("Open", gtk.RESPONSE_YES)
1832 HobButton.style_button(button)
1833 response = dialog.run()
1834 if response == gtk.RESPONSE_YES:
1835 path = dialog.get_filename()
1836 entry.set_text(path)
1837 self.image_folder = path
1838 self.fill_image_store()
1839
1840 dialog.destroy()
1841
1842 def fill_image_store(self):
1843 self.image_list = []
1844 self.image_store.clear()
1845 imageset = set()
1846 for root, dirs, files in os.walk(self.image_folder):
1847 # ignore the sub directories
1848 dirs[:] = []
1849 for f in files:
1850 for image_type in self.image_types:
1851 if image_type in self.image_extension:
1852 real_types = self.image_extension[image_type]
1853 else:
1854 real_types = [image_type]
1855 for real_image_type in real_types:
1856 if f.endswith('.' + real_image_type):
1857 imageset.add(f.rsplit('.' + real_image_type)[0].rsplit('.rootfs')[0])
1858 self.image_list.append(f)
1859
1860 for image in imageset:
1861 self.image_store.set(self.image_store.append(), 0, image, 1, False)
1862
1863 self.image_table.set_model(self.image_store)
1864
1865 def response_cb(self, dialog, response_id):
1866 self.image_names = []
1867 if response_id == gtk.RESPONSE_YES:
1868 iter = self.image_store.get_iter_first()
1869 while iter:
1870 path = self.image_store.get_path(iter)
1871 if self.image_store[path][1]:
1872 for f in self.image_list:
1873 if f.startswith(self.image_store[path][0] + '.'):
1874 self.image_names.append(f)
1875 break
1876 iter = self.image_store.iter_next(iter)
1877
1878#
1879# ProxyDetailsDialog
1880#
1881class ProxyDetailsDialog (CrumbsDialog):
1882
1883 def __init__(self, title, user, passwd, parent, flags, buttons=None):
1884 super(ProxyDetailsDialog, self).__init__(title, parent, flags, buttons)
1885 self.connect("response", self.response_cb)
1886
1887 self.auth = not (user == None or passwd == None or user == "")
1888 self.user = user or ""
1889 self.passwd = passwd or ""
1890
1891 # create visual elements on the dialog
1892 self.create_visual_elements()
1893
1894 def create_visual_elements(self):
1895 self.auth_checkbox = gtk.CheckButton("Use authentication")
1896 self.auth_checkbox.set_tooltip_text("Check this box to set the username and the password")
1897 self.auth_checkbox.set_active(self.auth)
1898 self.auth_checkbox.connect("toggled", self.auth_checkbox_toggled_cb)
1899 self.vbox.pack_start(self.auth_checkbox, expand=False, fill=False)
1900
1901 hbox = gtk.HBox(False, 6)
1902 self.user_label = gtk.Label("Username:")
1903 self.user_text = gtk.Entry()
1904 self.user_text.set_text(self.user)
1905 hbox.pack_start(self.user_label, expand=False, fill=False)
1906 hbox.pack_end(self.user_text, expand=False, fill=False)
1907 self.vbox.pack_start(hbox, expand=False, fill=False)
1908
1909 hbox = gtk.HBox(False, 6)
1910 self.passwd_label = gtk.Label("Password:")
1911 self.passwd_text = gtk.Entry()
1912 self.passwd_text.set_text(self.passwd)
1913 hbox.pack_start(self.passwd_label, expand=False, fill=False)
1914 hbox.pack_end(self.passwd_text, expand=False, fill=False)
1915 self.vbox.pack_start(hbox, expand=False, fill=False)
1916
1917 self.refresh_auth_components()
1918 self.show_all()
1919
1920 def refresh_auth_components(self):
1921 self.user_label.set_sensitive(self.auth)
1922 self.user_text.set_editable(self.auth)
1923 self.user_text.set_sensitive(self.auth)
1924 self.passwd_label.set_sensitive(self.auth)
1925 self.passwd_text.set_editable(self.auth)
1926 self.passwd_text.set_sensitive(self.auth)
1927
1928 def auth_checkbox_toggled_cb(self, button):
1929 self.auth = self.auth_checkbox.get_active()
1930 self.refresh_auth_components()
1931
1932 def response_cb(self, dialog, response_id):
1933 if response_id == gtk.RESPONSE_OK:
1934 if self.auth:
1935 self.user = self.user_text.get_text()
1936 self.passwd = self.passwd_text.get_text()
1937 else:
1938 self.user = None
1939 self.passwd = None
1940
1941
1942#
1943# OpeningLogDialog
1944#
1945class OpeningLogDialog (CrumbsDialog):
1946
1947 def __init__(self, title, parent, flags, buttons=None):
1948 super(OpeningLogDialog, self).__init__(title, parent, flags, buttons)
1949
1950 self.running = False
1951 # create visual elements on the dialog
1952 self.create_visual_elements()
1953
1954 def start(self):
1955 if not self.running:
1956 self.running = True
1957 gobject.timeout_add(100, self.pulse)
1958
1959 def pulse(self):
1960 self.progress_bar.pulse()
1961 return self.running
1962
1963 def create_visual_elements(self):
1964 hbox = gtk.HBox(False, 12)
1965 self.user_label = gtk.Label("The log will open in a text editor")
1966 hbox.pack_start(self.user_label, expand=False, fill=False)
1967 self.vbox.pack_start(hbox, expand=False, fill=False)
1968
1969 hbox = gtk.HBox(False, 12)
1970 # Progress bar
1971 self.progress_bar = HobProgressBar()
1972 hbox.pack_start(self.progress_bar)
1973 self.start()
1974 self.vbox.pack_start(hbox, expand=False, fill=False)
1975
1976 button = self.add_button("Cancel", gtk.RESPONSE_CANCEL)
1977 HobAltButton.style_button(button)
1978 self.show_all()
diff --git a/bitbake/lib/bb/ui/crumbs/hig/__init__.py b/bitbake/lib/bb/ui/crumbs/hig/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/__init__.py
diff --git a/bitbake/lib/bb/ui/crumbs/hig/advancedsettingsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/advancedsettingsdialog.py
new file mode 100644
index 0000000000..f5397c3ac0
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/advancedsettingsdialog.py
@@ -0,0 +1,336 @@
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
23import gtk
24import hashlib
25from bb.ui.crumbs.hobwidget import HobInfoButton, HobButton
26from bb.ui.crumbs.progressbar import HobProgressBar
27from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper
28from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
29from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
30from bb.ui.crumbs.hig.proxydetailsdialog import ProxyDetailsDialog
31
32"""
33The following are convenience classes for implementing GNOME HIG compliant
34BitBake GUI's
35In summary: spacing = 12px, border-width = 6px
36"""
37
38class 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.toolchain_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>\n\nYou need to select at least one image type."
187 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
188 button = dialog.add_button("OK", gtk.RESPONSE_OK)
189 HobButton.style_button(button)
190 response = dialog.run()
191 dialog.destroy()
192
193 def create_image_types_page(self):
194 main_vbox = gtk.VBox(False, 16)
195 main_vbox.set_border_width(6)
196
197 advanced_vbox = gtk.VBox(False, 6)
198 advanced_vbox.set_border_width(6)
199
200 distro_vbox = gtk.VBox(False, 6)
201 label = self.gen_label_widget("Distro:")
202 tooltip = "Selects the Yocto Project distribution you want"
203 try:
204 i = self.all_distros.index( "defaultsetup" )
205 except ValueError:
206 i = -1
207 if i != -1:
208 self.all_distros[ i ] = "Default"
209 if self.configuration.curr_distro == "defaultsetup":
210 self.configuration.curr_distro = "Default"
211 distro_widget, self.distro_combo = self.gen_combo_widget(self.configuration.curr_distro, self.all_distros, tooltip)
212 distro_vbox.pack_start(label, expand=False, fill=False)
213 distro_vbox.pack_start(distro_widget, expand=False, fill=False)
214 main_vbox.pack_start(distro_vbox, expand=False, fill=False)
215
216
217 rows = (len(self.image_types)+1)/3
218 table = gtk.Table(rows + 1, 10, True)
219 advanced_vbox.pack_start(table, expand=False, fill=False)
220
221 tooltip = "Image file system types you want."
222 info = HobInfoButton(tooltip, self)
223 label = self.gen_label_widget("Image types:")
224 align = gtk.Alignment(0, 0.5, 0, 0)
225 table.attach(align, 0, 4, 0, 1)
226 align.add(label)
227 table.attach(info, 4, 5, 0, 1)
228
229 i = 1
230 j = 1
231 for image_type in sorted(self.image_types):
232 self.image_types_checkbuttons[image_type] = gtk.CheckButton(image_type)
233 self.image_types_checkbuttons[image_type].connect("toggled", self.image_type_checkbutton_clicked_cb)
234 article = ""
235 if image_type.startswith(("a", "e", "i", "o", "u")):
236 article = "n"
237 self.image_types_checkbuttons[image_type].set_tooltip_text("Build a%s %s image" % (article, image_type))
238 table.attach(self.image_types_checkbuttons[image_type], j - 1, j + 3, i, i + 1)
239 if image_type in self.configuration.image_fstypes.split():
240 self.image_types_checkbuttons[image_type].set_active(True)
241 i += 1
242 if i > rows:
243 i = 1
244 j = j + 4
245
246 main_vbox.pack_start(advanced_vbox, expand=False, fill=False)
247 self.set_save_button_state()
248
249 return main_vbox
250
251 def create_output_page(self):
252 advanced_vbox = gtk.VBox(False, 6)
253 advanced_vbox.set_border_width(6)
254
255 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Package format</span>'), expand=False, fill=False)
256 sub_vbox = gtk.VBox(False, 6)
257 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
258 tooltip_combo = "Selects the package format used to generate rootfs."
259 tooltip_extra = "Selects extra package formats to build"
260 pkgfmt_widget, self.rootfs_combo, self.check_hbox = self.gen_pkgfmt_widget(self.configuration.curr_package_format, self.all_package_formats, tooltip_combo, tooltip_extra)
261 sub_vbox.pack_start(pkgfmt_widget, expand=False, fill=False)
262
263 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Image size</span>'), expand=False, fill=False)
264 sub_vbox = gtk.VBox(False, 6)
265 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
266 label = self.gen_label_widget("Image basic size (in MB)")
267 tooltip = "Sets the basic size of your target image.\nThis is the basic size of your target image unless your selected package size exceeds this value or you select \'Image Extra Size\'."
268 rootfs_size_widget, self.rootfs_size_spinner = self.gen_spinner_widget(int(self.configuration.image_rootfs_size*1.0/1024), 0, 65536, tooltip)
269 sub_vbox.pack_start(label, expand=False, fill=False)
270 sub_vbox.pack_start(rootfs_size_widget, expand=False, fill=False)
271
272 sub_vbox = gtk.VBox(False, 6)
273 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
274 label = self.gen_label_widget("Additional free space (in MB)")
275 tooltip = "Sets the extra free space of your target image.\nBy default, the system reserves 30% of your image size as free space. If your image contains zypper, it brings in 50MB more space. The maximum free space is 64GB."
276 extra_size_widget, self.extra_size_spinner = self.gen_spinner_widget(int(self.configuration.image_extra_size*1.0/1024), 0, 65536, tooltip)
277 sub_vbox.pack_start(label, expand=False, fill=False)
278 sub_vbox.pack_start(extra_size_widget, expand=False, fill=False)
279
280 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Licensing</span>'), expand=False, fill=False)
281 self.gplv3_checkbox = gtk.CheckButton("Exclude GPLv3 packages")
282 self.gplv3_checkbox.set_tooltip_text("Check this box to prevent GPLv3 packages from being included in your image")
283 if "GPLv3" in self.configuration.incompat_license.split():
284 self.gplv3_checkbox.set_active(True)
285 else:
286 self.gplv3_checkbox.set_active(False)
287 advanced_vbox.pack_start(self.gplv3_checkbox, expand=False, fill=False)
288
289 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Toolchain</span>'), expand=False, fill=False)
290 sub_hbox = gtk.HBox(False, 6)
291 advanced_vbox.pack_start(sub_hbox, expand=False, fill=False)
292 self.toolchain_checkbox = gtk.CheckButton("Build toolchain")
293 self.toolchain_checkbox.set_tooltip_text("Check this box to build the related toolchain with your image")
294 self.toolchain_checkbox.set_active(self.configuration.toolchain_build)
295 sub_hbox.pack_start(self.toolchain_checkbox, expand=False, fill=False)
296
297 tooltip = "Selects the host platform for which you want to run the toolchain"
298 sdk_machine_widget, self.sdk_machine_combo = self.gen_combo_widget(self.configuration.curr_sdk_machine, self.all_sdk_machines, tooltip)
299 sub_hbox.pack_start(sdk_machine_widget, expand=False, fill=False)
300
301 return advanced_vbox
302
303 def response_cb(self, dialog, response_id):
304 package_format = []
305 package_format.append(self.rootfs_combo.get_active_text())
306 for child in self.check_hbox:
307 if isinstance(child, gtk.CheckButton) and child.get_active():
308 package_format.append(child.get_label())
309 self.configuration.curr_package_format = " ".join(package_format)
310
311 distro = self.distro_combo.get_active_text()
312 if distro == "Default":
313 distro = "defaultsetup"
314 self.configuration.curr_distro = distro
315 self.configuration.image_rootfs_size = self.rootfs_size_spinner.get_value_as_int() * 1024
316 self.configuration.image_extra_size = self.extra_size_spinner.get_value_as_int() * 1024
317
318 self.configuration.image_fstypes = ""
319 for image_type in self.image_types:
320 if self.image_types_checkbuttons[image_type].get_active():
321 self.configuration.image_fstypes += (" " + image_type)
322 self.configuration.image_fstypes.strip()
323
324 if self.gplv3_checkbox.get_active():
325 if "GPLv3" not in self.configuration.incompat_license.split():
326 self.configuration.incompat_license += " GPLv3"
327 else:
328 if "GPLv3" in self.configuration.incompat_license.split():
329 self.configuration.incompat_license = self.configuration.incompat_license.split().remove("GPLv3")
330 self.configuration.incompat_license = " ".join(self.configuration.incompat_license or [])
331 self.configuration.incompat_license = self.configuration.incompat_license.strip()
332
333 self.configuration.toolchain_build = self.toolchain_checkbox.get_active()
334 self.configuration.curr_sdk_machine = self.sdk_machine_combo.get_active_text()
335 md5 = self.config_md5()
336 self.settings_changed = (self.md5 != md5)
diff --git a/bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py
new file mode 100644
index 0000000000..c679f9a070
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py
@@ -0,0 +1,44 @@
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
23import gtk
24
25"""
26The following are convenience classes for implementing GNOME HIG compliant
27BitBake GUI's
28In summary: spacing = 12px, border-width = 6px
29"""
30
31class CrumbsDialog(gtk.Dialog):
32 """
33 A GNOME HIG compliant dialog widget.
34 Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons
35 """
36 def __init__(self, title="", parent=None, flags=0, buttons=None):
37 super(CrumbsDialog, self).__init__(title, parent, flags, buttons)
38
39 self.set_property("has-separator", False) # note: deprecated in 2.22
40
41 self.set_border_width(6)
42 self.vbox.set_property("spacing", 12)
43 self.action_area.set_property("spacing", 12)
44 self.action_area.set_property("border-width", 6)
diff --git a/bitbake/lib/bb/ui/crumbs/hig/crumbsmessagedialog.py b/bitbake/lib/bb/ui/crumbs/hig/crumbsmessagedialog.py
new file mode 100644
index 0000000000..097ce7b027
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/crumbsmessagedialog.py
@@ -0,0 +1,95 @@
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
23import glib
24import gtk
25from bb.ui.crumbs.hobwidget import HobIconChecker
26from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
27
28"""
29The following are convenience classes for implementing GNOME HIG compliant
30BitBake GUI's
31In summary: spacing = 12px, border-width = 6px
32"""
33
34class CrumbsMessageDialog(CrumbsDialog):
35 """
36 A GNOME HIG compliant dialog widget.
37 Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons
38 """
39 def __init__(self, parent=None, label="", icon=gtk.STOCK_INFO, msg=""):
40 super(CrumbsMessageDialog, self).__init__("", parent, gtk.DIALOG_MODAL)
41
42 self.set_border_width(6)
43 self.vbox.set_property("spacing", 12)
44 self.action_area.set_property("spacing", 12)
45 self.action_area.set_property("border-width", 6)
46
47 first_column = gtk.HBox(spacing=12)
48 first_column.set_property("border-width", 6)
49 first_column.show()
50 self.vbox.add(first_column)
51
52 self.icon = gtk.Image()
53 # We have our own Info icon which should be used in preference of the stock icon
54 self.icon_chk = HobIconChecker()
55 self.icon.set_from_stock(self.icon_chk.check_stock_icon(icon), gtk.ICON_SIZE_DIALOG)
56 self.icon.set_property("yalign", 0.00)
57 self.icon.show()
58 first_column.pack_start(self.icon, expand=False, fill=True, padding=0)
59
60 if 0 <= len(msg) < 200:
61 lbl = label + "%s" % glib.markup_escape_text(msg)
62 self.label_short = gtk.Label()
63 self.label_short.set_use_markup(True)
64 self.label_short.set_line_wrap(True)
65 self.label_short.set_markup(lbl)
66 self.label_short.set_property("yalign", 0.00)
67 self.label_short.show()
68 first_column.add(self.label_short)
69 else:
70 second_row = gtk.VBox(spacing=12)
71 second_row.set_property("border-width", 6)
72 self.label_long = gtk.Label()
73 self.label_long.set_use_markup(True)
74 self.label_long.set_line_wrap(True)
75 self.label_long.set_markup(label)
76 self.label_long.set_alignment(0.0, 0.0)
77 second_row.pack_start(self.label_long, expand=False, fill=False, padding=0)
78 self.label_long.show()
79 self.textWindow = gtk.ScrolledWindow()
80 self.textWindow.set_shadow_type(gtk.SHADOW_IN)
81 self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
82 self.msgView = gtk.TextView()
83 self.msgView.set_editable(False)
84 self.msgView.set_wrap_mode(gtk.WRAP_WORD)
85 self.msgView.set_cursor_visible(False)
86 self.msgView.set_size_request(300, 300)
87 self.buf = gtk.TextBuffer()
88 self.buf.set_text(msg)
89 self.msgView.set_buffer(self.buf)
90 self.textWindow.add(self.msgView)
91 self.msgView.show()
92 second_row.add(self.textWindow)
93 self.textWindow.show()
94 first_column.add(second_row)
95 second_row.show()
diff --git a/bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py b/bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py
new file mode 100644
index 0000000000..bc1efbbfaf
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py
@@ -0,0 +1,215 @@
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
23import glob
24import gtk
25import gobject
26import os
27import re
28import shlex
29import subprocess
30import tempfile
31from bb.ui.crumbs.hobwidget import hic, HobButton
32from bb.ui.crumbs.progressbar import HobProgressBar
33import bb.ui.crumbs.utils
34import bb.process
35from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
36from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
37
38"""
39The following are convenience classes for implementing GNOME HIG compliant
40BitBake GUI's
41In summary: spacing = 12px, border-width = 6px
42"""
43
44class DeployImageDialog (CrumbsDialog):
45
46 __dummy_usb__ = "--select a usb drive--"
47
48 def __init__(self, title, image_path, parent, flags, buttons=None, standalone=False):
49 super(DeployImageDialog, self).__init__(title, parent, flags, buttons)
50
51 self.image_path = image_path
52 self.standalone = standalone
53
54 self.create_visual_elements()
55 self.connect("response", self.response_cb)
56
57 def create_visual_elements(self):
58 self.set_size_request(600, 400)
59 label = gtk.Label()
60 label.set_alignment(0.0, 0.5)
61 markup = "<span font_desc='12'>The image to be written into usb drive:</span>"
62 label.set_markup(markup)
63 self.vbox.pack_start(label, expand=False, fill=False, padding=2)
64
65 table = gtk.Table(2, 10, False)
66 table.set_col_spacings(5)
67 table.set_row_spacings(5)
68 self.vbox.pack_start(table, expand=True, fill=True)
69
70 scroll = gtk.ScrolledWindow()
71 scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
72 scroll.set_shadow_type(gtk.SHADOW_IN)
73 tv = gtk.TextView()
74 tv.set_editable(False)
75 tv.set_wrap_mode(gtk.WRAP_WORD)
76 tv.set_cursor_visible(False)
77 self.buf = gtk.TextBuffer()
78 self.buf.set_text(self.image_path)
79 tv.set_buffer(self.buf)
80 scroll.add(tv)
81 table.attach(scroll, 0, 10, 0, 1)
82
83 # There are 2 ways to use DeployImageDialog
84 # One way is that called by HOB when the 'Deploy Image' button is clicked
85 # The other way is that called by a standalone script.
86 # Following block of codes handles the latter way. It adds a 'Select Image' button and
87 # emit a signal when the button is clicked.
88 if self.standalone:
89 gobject.signal_new("select_image_clicked", self, gobject.SIGNAL_RUN_FIRST,
90 gobject.TYPE_NONE, ())
91 icon = gtk.Image()
92 pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_IMAGES_DISPLAY_FILE)
93 icon.set_from_pixbuf(pix_buffer)
94 button = gtk.Button("Select Image")
95 button.set_image(icon)
96 #button.set_size_request(140, 50)
97 table.attach(button, 9, 10, 1, 2, gtk.FILL, 0, 0, 0)
98 button.connect("clicked", self.select_image_button_clicked_cb)
99
100 separator = gtk.HSeparator()
101 self.vbox.pack_start(separator, expand=False, fill=False, padding=10)
102
103 self.usb_desc = gtk.Label()
104 self.usb_desc.set_alignment(0.0, 0.5)
105 markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>"
106 self.usb_desc.set_markup(markup)
107
108 self.usb_combo = gtk.combo_box_new_text()
109 self.usb_combo.connect("changed", self.usb_combo_changed_cb)
110 model = self.usb_combo.get_model()
111 model.clear()
112 self.usb_combo.append_text(self.__dummy_usb__)
113 for usb in self.find_all_usb_devices():
114 self.usb_combo.append_text("/dev/" + usb)
115 self.usb_combo.set_active(0)
116 self.vbox.pack_start(self.usb_combo, expand=False, fill=False)
117 self.vbox.pack_start(self.usb_desc, expand=False, fill=False, padding=2)
118
119 self.progress_bar = HobProgressBar()
120 self.vbox.pack_start(self.progress_bar, expand=False, fill=False)
121 separator = gtk.HSeparator()
122 self.vbox.pack_start(separator, expand=False, fill=True, padding=10)
123
124 self.vbox.show_all()
125 self.progress_bar.hide()
126
127 def set_image_text_buffer(self, image_path):
128 self.buf.set_text(image_path)
129
130 def set_image_path(self, image_path):
131 self.image_path = image_path
132
133 def popen_read(self, cmd):
134 tmpout, errors = bb.process.run("%s" % cmd)
135 return tmpout.strip()
136
137 def find_all_usb_devices(self):
138 usb_devs = [ os.readlink(u)
139 for u in glob.glob('/dev/disk/by-id/usb*')
140 if not re.search(r'part\d+', u) ]
141 return [ '%s' % u[u.rfind('/')+1:] for u in usb_devs ]
142
143 def get_usb_info(self, dev):
144 return "%s %s" % \
145 (self.popen_read('cat /sys/class/block/%s/device/vendor' % dev),
146 self.popen_read('cat /sys/class/block/%s/device/model' % dev))
147
148 def select_image_button_clicked_cb(self, button):
149 self.emit('select_image_clicked')
150
151 def usb_combo_changed_cb(self, usb_combo):
152 combo_item = self.usb_combo.get_active_text()
153 if not combo_item or combo_item == self.__dummy_usb__:
154 markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>"
155 self.usb_desc.set_markup(markup)
156 else:
157 markup = "<span font_desc='12'>" + self.get_usb_info(combo_item.lstrip("/dev/")) + "</span>"
158 self.usb_desc.set_markup(markup)
159
160 def response_cb(self, dialog, response_id):
161 if response_id == gtk.RESPONSE_YES:
162 lbl = ''
163 combo_item = self.usb_combo.get_active_text()
164 if combo_item and combo_item != self.__dummy_usb__ and self.image_path:
165 cmdline = bb.ui.crumbs.utils.which_terminal()
166 if cmdline:
167 tmpfile = tempfile.NamedTemporaryFile()
168 cmdline += "\"sudo dd if=" + self.image_path + \
169 " of=" + combo_item + "; echo $? > " + tmpfile.name + "\""
170 subprocess.call(shlex.split(cmdline))
171
172 if int(tmpfile.readline().strip()) == 0:
173 lbl = "<b>Deploy image successfully.</b>"
174 else:
175 lbl = "<b>Failed to deploy image.</b>\nPlease check image <b>%s</b> exists and USB device <b>%s</b> is writable." % (self.image_path, combo_item)
176 tmpfile.close()
177 else:
178 if not self.image_path:
179 lbl = "<b>No selection made.</b>\nYou have not selected an image to deploy."
180 else:
181 lbl = "<b>No selection made.</b>\nYou have not selected a USB device."
182 if len(lbl):
183 crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
184 button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK)
185 HobButton.style_button(button)
186 crumbs_dialog.run()
187 crumbs_dialog.destroy()
188
189 def update_progress_bar(self, title, fraction, status=None):
190 self.progress_bar.update(fraction)
191 self.progress_bar.set_title(title)
192 self.progress_bar.set_rcstyle(status)
193
194 def write_file(self, ifile, ofile):
195 self.progress_bar.reset()
196 self.progress_bar.show()
197
198 f_from = os.open(ifile, os.O_RDONLY)
199 f_to = os.open(ofile, os.O_WRONLY)
200
201 total_size = os.stat(ifile).st_size
202 written_size = 0
203
204 while True:
205 buf = os.read(f_from, 1024*1024)
206 if not buf:
207 break
208 os.write(f_to, buf)
209 written_size += 1024*1024
210 self.update_progress_bar("Writing to usb:", written_size * 1.0/total_size)
211
212 self.update_progress_bar("Writing completed:", 1.0)
213 os.close(f_from)
214 os.close(f_to)
215 self.progress_bar.hide()
diff --git a/bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py b/bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py
new file mode 100644
index 0000000000..17f6bffe00
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py
@@ -0,0 +1,172 @@
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
23import gtk
24import gobject
25import os
26from bb.ui.crumbs.hobwidget import HobViewTable, HobInfoButton, HobButton, HobAltButton
27from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
28from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog
29
30"""
31The following are convenience classes for implementing GNOME HIG compliant
32BitBake GUI's
33In summary: spacing = 12px, border-width = 6px
34"""
35
36class ImageSelectionDialog (CrumbsDialog):
37
38 __columns__ = [{
39 'col_name' : 'Image name',
40 'col_id' : 0,
41 'col_style': 'text',
42 'col_min' : 400,
43 'col_max' : 400
44 }, {
45 'col_name' : 'Select',
46 'col_id' : 1,
47 'col_style': 'radio toggle',
48 'col_min' : 160,
49 'col_max' : 160
50 }]
51
52
53 def __init__(self, image_folder, image_types, title, parent, flags, buttons=None, image_extension = {}):
54 super(ImageSelectionDialog, self).__init__(title, parent, flags, buttons)
55 self.connect("response", self.response_cb)
56
57 self.image_folder = image_folder
58 self.image_types = image_types
59 self.image_list = []
60 self.image_names = []
61 self.image_extension = image_extension
62
63 # create visual elements on the dialog
64 self.create_visual_elements()
65
66 self.image_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN)
67 self.fill_image_store()
68
69 def create_visual_elements(self):
70 hbox = gtk.HBox(False, 6)
71
72 self.vbox.pack_start(hbox, expand=False, fill=False)
73
74 entry = gtk.Entry()
75 entry.set_text(self.image_folder)
76 table = gtk.Table(1, 10, True)
77 table.set_size_request(560, -1)
78 hbox.pack_start(table, expand=False, fill=False)
79 table.attach(entry, 0, 9, 0, 1)
80 image = gtk.Image()
81 image.set_from_stock(gtk.STOCK_OPEN, gtk.ICON_SIZE_BUTTON)
82 open_button = gtk.Button()
83 open_button.set_image(image)
84 open_button.connect("clicked", self.select_path_cb, self, entry)
85 table.attach(open_button, 9, 10, 0, 1)
86
87 self.image_table = HobViewTable(self.__columns__)
88 self.image_table.set_size_request(-1, 300)
89 self.image_table.connect("toggled", self.toggled_cb)
90 self.image_table.connect_group_selection(self.table_selected_cb)
91 self.image_table.connect("row-activated", self.row_actived_cb)
92 self.vbox.pack_start(self.image_table, expand=True, fill=True)
93
94 self.show_all()
95
96 def change_image_cb(self, model, path, columnid):
97 if not model:
98 return
99 iter = model.get_iter_first()
100 while iter:
101 rowpath = model.get_path(iter)
102 model[rowpath][columnid] = False
103 iter = model.iter_next(iter)
104
105 model[path][columnid] = True
106
107 def toggled_cb(self, table, cell, path, columnid, tree):
108 model = tree.get_model()
109 self.change_image_cb(model, path, columnid)
110
111 def table_selected_cb(self, selection):
112 model, paths = selection.get_selected_rows()
113 if paths:
114 self.change_image_cb(model, paths[0], 1)
115
116 def row_actived_cb(self, tab, model, path):
117 self.change_image_cb(model, path, 1)
118 self.emit('response', gtk.RESPONSE_YES)
119
120 def select_path_cb(self, action, parent, entry):
121 dialog = gtk.FileChooserDialog("", parent,
122 gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
123 text = entry.get_text()
124 dialog.set_current_folder(text if len(text) > 0 else os.getcwd())
125 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
126 HobAltButton.style_button(button)
127 button = dialog.add_button("Open", gtk.RESPONSE_YES)
128 HobButton.style_button(button)
129 response = dialog.run()
130 if response == gtk.RESPONSE_YES:
131 path = dialog.get_filename()
132 entry.set_text(path)
133 self.image_folder = path
134 self.fill_image_store()
135
136 dialog.destroy()
137
138 def fill_image_store(self):
139 self.image_list = []
140 self.image_store.clear()
141 imageset = set()
142 for root, dirs, files in os.walk(self.image_folder):
143 # ignore the sub directories
144 dirs[:] = []
145 for f in files:
146 for image_type in self.image_types:
147 if image_type in self.image_extension:
148 real_types = self.image_extension[image_type]
149 else:
150 real_types = [image_type]
151 for real_image_type in real_types:
152 if f.endswith('.' + real_image_type):
153 imageset.add(f.rsplit('.' + real_image_type)[0].rsplit('.rootfs')[0])
154 self.image_list.append(f)
155
156 for image in imageset:
157 self.image_store.set(self.image_store.append(), 0, image, 1, False)
158
159 self.image_table.set_model(self.image_store)
160
161 def response_cb(self, dialog, response_id):
162 self.image_names = []
163 if response_id == gtk.RESPONSE_YES:
164 iter = self.image_store.get_iter_first()
165 while iter:
166 path = self.image_store.get_path(iter)
167 if self.image_store[path][1]:
168 for f in self.image_list:
169 if f.startswith(self.image_store[path][0] + '.'):
170 self.image_names.append(f)
171 break
172 iter = self.image_store.iter_next(iter)
diff --git a/bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py b/bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py
new file mode 100644
index 0000000000..783ee73c7a
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py
@@ -0,0 +1,296 @@
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
23import gtk
24import gobject
25import os
26import tempfile
27from bb.ui.crumbs.hobwidget import hic, HobButton, HobAltButton
28from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
29from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
30
31"""
32The following are convenience classes for implementing GNOME HIG compliant
33BitBake GUI's
34In summary: spacing = 12px, border-width = 6px
35"""
36
37class CellRendererPixbufActivatable(gtk.CellRendererPixbuf):
38 """
39 A custom CellRenderer implementation which is activatable
40 so that we can handle user clicks
41 """
42 __gsignals__ = { 'clicked' : (gobject.SIGNAL_RUN_LAST,
43 gobject.TYPE_NONE,
44 (gobject.TYPE_STRING,)), }
45
46 def __init__(self):
47 gtk.CellRendererPixbuf.__init__(self)
48 self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE)
49 self.set_property('follow-state', True)
50
51 """
52 Respond to a user click on a cell
53 """
54 def do_activate(self, even, widget, path, background_area, cell_area, flags):
55 self.emit('clicked', path)
56
57#
58# LayerSelectionDialog
59#
60class LayerSelectionDialog (CrumbsDialog):
61
62 TARGETS = [
63 ("MY_TREE_MODEL_ROW", gtk.TARGET_SAME_WIDGET, 0),
64 ("text/plain", 0, 1),
65 ("TEXT", 0, 2),
66 ("STRING", 0, 3),
67 ]
68
69 def gen_label_widget(self, content):
70 label = gtk.Label()
71 label.set_alignment(0, 0)
72 label.set_markup(content)
73 label.show()
74 return label
75
76 def layer_widget_toggled_cb(self, cell, path, layer_store):
77 name = layer_store[path][0]
78 toggle = not layer_store[path][1]
79 layer_store[path][1] = toggle
80
81 def layer_widget_add_clicked_cb(self, action, layer_store, parent):
82 dialog = gtk.FileChooserDialog("Add new layer", parent,
83 gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
84 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
85 HobAltButton.style_button(button)
86 button = dialog.add_button("Open", gtk.RESPONSE_YES)
87 HobButton.style_button(button)
88 label = gtk.Label("Select the layer you wish to add")
89 label.show()
90 dialog.set_extra_widget(label)
91 response = dialog.run()
92 path = dialog.get_filename()
93 dialog.destroy()
94
95 lbl = "<b>Error</b>\nUnable to load layer <i>%s</i> because " % path
96 if response == gtk.RESPONSE_YES:
97 import os
98 import os.path
99 layers = []
100 it = layer_store.get_iter_first()
101 while it:
102 layers.append(layer_store.get_value(it, 0))
103 it = layer_store.iter_next(it)
104
105 if not path:
106 lbl += "it is an invalid path."
107 elif not os.path.exists(path+"/conf/layer.conf"):
108 lbl += "there is no layer.conf inside the directory."
109 elif path in layers:
110 lbl += "it is already in loaded layers."
111 else:
112 layer_store.append([path])
113 return
114 dialog = CrumbsMessageDialog(parent, lbl)
115 dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
116 response = dialog.run()
117 dialog.destroy()
118
119 def layer_widget_del_clicked_cb(self, action, tree_selection, layer_store):
120 model, iter = tree_selection.get_selected()
121 if iter:
122 layer_store.remove(iter)
123
124
125 def gen_layer_widget(self, layers, layers_avail, window, tooltip=""):
126 hbox = gtk.HBox(False, 6)
127
128 layer_tv = gtk.TreeView()
129 layer_tv.set_rules_hint(True)
130 layer_tv.set_headers_visible(False)
131 tree_selection = layer_tv.get_selection()
132 tree_selection.set_mode(gtk.SELECTION_SINGLE)
133
134 # Allow enable drag and drop of rows including row move
135 layer_tv.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
136 self.TARGETS,
137 gtk.gdk.ACTION_DEFAULT|
138 gtk.gdk.ACTION_MOVE)
139 layer_tv.enable_model_drag_dest(self.TARGETS,
140 gtk.gdk.ACTION_DEFAULT)
141 layer_tv.connect("drag_data_get", self.drag_data_get_cb)
142 layer_tv.connect("drag_data_received", self.drag_data_received_cb)
143
144 col0= gtk.TreeViewColumn('Path')
145 cell0 = gtk.CellRendererText()
146 cell0.set_padding(5,2)
147 col0.pack_start(cell0, True)
148 col0.set_cell_data_func(cell0, self.draw_layer_path_cb)
149 layer_tv.append_column(col0)
150
151 scroll = gtk.ScrolledWindow()
152 scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
153 scroll.set_shadow_type(gtk.SHADOW_IN)
154 scroll.add(layer_tv)
155
156 table_layer = gtk.Table(2, 10, False)
157 hbox.pack_start(table_layer, expand=True, fill=True)
158
159 table_layer.attach(scroll, 0, 10, 0, 1)
160
161 layer_store = gtk.ListStore(gobject.TYPE_STRING)
162 for layer in layers:
163 layer_store.append([layer])
164
165 col1 = gtk.TreeViewColumn('Enabled')
166 layer_tv.append_column(col1)
167
168 cell1 = CellRendererPixbufActivatable()
169 cell1.set_fixed_size(-1,35)
170 cell1.connect("clicked", self.del_cell_clicked_cb, layer_store)
171 col1.pack_start(cell1, True)
172 col1.set_cell_data_func(cell1, self.draw_delete_button_cb, layer_tv)
173
174 add_button = gtk.Button()
175 add_button.set_relief(gtk.RELIEF_NONE)
176 box = gtk.HBox(False, 6)
177 box.show()
178 add_button.add(box)
179 add_button.connect("enter-notify-event", self.add_hover_cb)
180 add_button.connect("leave-notify-event", self.add_leave_cb)
181 self.im = gtk.Image()
182 self.im.set_from_file(hic.ICON_INDI_ADD_FILE)
183 self.im.show()
184 box.pack_start(self.im, expand=False, fill=False, padding=6)
185 lbl = gtk.Label("Add layer")
186 lbl.set_alignment(0.0, 0.5)
187 lbl.show()
188 box.pack_start(lbl, expand=True, fill=True, padding=6)
189 add_button.connect("clicked", self.layer_widget_add_clicked_cb, layer_store, window)
190 table_layer.attach(add_button, 0, 10, 1, 2, gtk.EXPAND | gtk.FILL, 0, 0, 6)
191 layer_tv.set_model(layer_store)
192
193 hbox.show_all()
194
195 return hbox, layer_store
196
197 def drag_data_get_cb(self, treeview, context, selection, target_id, etime):
198 treeselection = treeview.get_selection()
199 model, iter = treeselection.get_selected()
200 data = model.get_value(iter, 0)
201 selection.set(selection.target, 8, data)
202
203 def drag_data_received_cb(self, treeview, context, x, y, selection, info, etime):
204 model = treeview.get_model()
205 data = selection.data
206 drop_info = treeview.get_dest_row_at_pos(x, y)
207 if drop_info:
208 path, position = drop_info
209 iter = model.get_iter(path)
210 if (position == gtk.TREE_VIEW_DROP_BEFORE or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
211 model.insert_before(iter, [data])
212 else:
213 model.insert_after(iter, [data])
214 else:
215 model.append([data])
216 if context.action == gtk.gdk.ACTION_MOVE:
217 context.finish(True, True, etime)
218 return
219
220 def add_hover_cb(self, button, event):
221 self.im.set_from_file(hic.ICON_INDI_ADD_HOVER_FILE)
222
223 def add_leave_cb(self, button, event):
224 self.im.set_from_file(hic.ICON_INDI_ADD_FILE)
225
226 def __init__(self, title, layers, layers_non_removable, all_layers, parent, flags, buttons=None):
227 super(LayerSelectionDialog, self).__init__(title, parent, flags, buttons)
228
229 # class members from other objects
230 self.layers = layers
231 self.layers_non_removable = layers_non_removable
232 self.all_layers = all_layers
233 self.layers_changed = False
234
235 # icon for remove button in TreeView
236 im = gtk.Image()
237 im.set_from_file(hic.ICON_INDI_REMOVE_FILE)
238 self.rem_icon = im.get_pixbuf()
239
240 # class members for internal use
241 self.layer_store = None
242
243 # create visual elements on the dialog
244 self.create_visual_elements()
245 self.connect("response", self.response_cb)
246
247 def create_visual_elements(self):
248 layer_widget, self.layer_store = self.gen_layer_widget(self.layers, self.all_layers, self, None)
249 layer_widget.set_size_request(450, 250)
250 self.vbox.pack_start(layer_widget, expand=True, fill=True)
251 self.show_all()
252
253 def response_cb(self, dialog, response_id):
254 model = self.layer_store
255 it = model.get_iter_first()
256 layers = []
257 while it:
258 layers.append(model.get_value(it, 0))
259 it = model.iter_next(it)
260
261 self.layers_changed = (self.layers != layers)
262 self.layers = layers
263
264 """
265 A custom cell_data_func to draw a delete 'button' in the TreeView for layers
266 other than the meta layer. The deletion of which is prevented so that the
267 user can't shoot themselves in the foot too badly.
268 """
269 def draw_delete_button_cb(self, col, cell, model, it, tv):
270 path = model.get_value(it, 0)
271 if path in self.layers_non_removable:
272 cell.set_sensitive(False)
273 cell.set_property('pixbuf', None)
274 cell.set_property('mode', gtk.CELL_RENDERER_MODE_INERT)
275 else:
276 cell.set_property('pixbuf', self.rem_icon)
277 cell.set_sensitive(True)
278 cell.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE)
279
280 return True
281
282 """
283 A custom cell_data_func to write an extra message into the layer path cell
284 for the meta layer. We should inform the user that they can't remove it for
285 their own safety.
286 """
287 def draw_layer_path_cb(self, col, cell, model, it):
288 path = model.get_value(it, 0)
289 if path in self.layers_non_removable:
290 cell.set_property('markup', "<b>It cannot be removed</b>\n%s" % path)
291 else:
292 cell.set_property('text', path)
293
294 def del_cell_clicked_cb(self, cell, path, model):
295 it = model.get_iter_from_string(path)
296 model.remove(it)
diff --git a/bitbake/lib/bb/ui/crumbs/hig/openinglogdialog.py b/bitbake/lib/bb/ui/crumbs/hig/openinglogdialog.py
new file mode 100644
index 0000000000..f1733156a7
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/openinglogdialog.py
@@ -0,0 +1,68 @@
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
23import gtk
24import gobject
25from bb.ui.crumbs.hobwidget import HobAltButton
26from bb.ui.crumbs.progressbar import HobProgressBar
27from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
28
29"""
30The following are convenience classes for implementing GNOME HIG compliant
31BitBake GUI's
32In summary: spacing = 12px, border-width = 6px
33"""
34
35class OpeningLogDialog (CrumbsDialog):
36
37 def __init__(self, title, parent, flags, buttons=None):
38 super(OpeningLogDialog, self).__init__(title, parent, flags, buttons)
39
40 self.running = False
41 # create visual elements on the dialog
42 self.create_visual_elements()
43
44 def start(self):
45 if not self.running:
46 self.running = True
47 gobject.timeout_add(100, self.pulse)
48
49 def pulse(self):
50 self.progress_bar.pulse()
51 return self.running
52
53 def create_visual_elements(self):
54 hbox = gtk.HBox(False, 12)
55 self.user_label = gtk.Label("The log will open in a text editor")
56 hbox.pack_start(self.user_label, expand=False, fill=False)
57 self.vbox.pack_start(hbox, expand=False, fill=False)
58
59 hbox = gtk.HBox(False, 12)
60 # Progress bar
61 self.progress_bar = HobProgressBar()
62 hbox.pack_start(self.progress_bar)
63 self.start()
64 self.vbox.pack_start(hbox, expand=False, fill=False)
65
66 button = self.add_button("Cancel", gtk.RESPONSE_CANCEL)
67 HobAltButton.style_button(button)
68 self.show_all()
diff --git a/bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py
new file mode 100644
index 0000000000..69e7dffb6d
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py
@@ -0,0 +1,90 @@
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
23import gtk
24from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
25
26"""
27The following are convenience classes for implementing GNOME HIG compliant
28BitBake GUI's
29In summary: spacing = 12px, border-width = 6px
30"""
31
32class 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/settingsuihelper.py b/bitbake/lib/bb/ui/crumbs/hig/settingsuihelper.py
new file mode 100644
index 0000000000..e10dd064ab
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/settingsuihelper.py
@@ -0,0 +1,216 @@
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
23import gtk
24import os
25from bb.ui.crumbs.hobwidget import HobInfoButton, HobButton, HobAltButton
26
27"""
28The following are convenience classes for implementing GNOME HIG compliant
29BitBake GUI's
30In summary: spacing = 12px, border-width = 6px
31"""
32
33class SettingsUIHelper():
34
35 def gen_label_widget(self, content):
36 label = gtk.Label()
37 label.set_alignment(0, 0)
38 label.set_markup(content)
39 label.show()
40 return label
41
42 def gen_label_info_widget(self, content, tooltip):
43 table = gtk.Table(1, 10, False)
44 label = self.gen_label_widget(content)
45 info = HobInfoButton(tooltip, self)
46 table.attach(label, 0, 1, 0, 1, xoptions=gtk.FILL)
47 table.attach(info, 1, 2, 0, 1, xoptions=gtk.FILL, xpadding=10)
48 return table
49
50 def gen_spinner_widget(self, content, lower, upper, tooltip=""):
51 hbox = gtk.HBox(False, 12)
52 adjust = gtk.Adjustment(value=content, lower=lower, upper=upper, step_incr=1)
53 spinner = gtk.SpinButton(adjustment=adjust, climb_rate=1, digits=0)
54
55 spinner.set_value(content)
56 hbox.pack_start(spinner, expand=False, fill=False)
57
58 info = HobInfoButton(tooltip, self)
59 hbox.pack_start(info, expand=False, fill=False)
60
61 hbox.show_all()
62 return hbox, spinner
63
64 def gen_combo_widget(self, curr_item, all_item, tooltip=""):
65 hbox = gtk.HBox(False, 12)
66 combo = gtk.combo_box_new_text()
67 hbox.pack_start(combo, expand=False, fill=False)
68
69 index = 0
70 for item in all_item or []:
71 combo.append_text(item)
72 if item == curr_item:
73 combo.set_active(index)
74 index += 1
75
76 info = HobInfoButton(tooltip, self)
77 hbox.pack_start(info, expand=False, fill=False)
78
79 hbox.show_all()
80 return hbox, combo
81
82 def entry_widget_select_path_cb(self, action, parent, entry):
83 dialog = gtk.FileChooserDialog("", parent,
84 gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
85 text = entry.get_text()
86 dialog.set_current_folder(text if len(text) > 0 else os.getcwd())
87 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
88 HobAltButton.style_button(button)
89 button = dialog.add_button("Open", gtk.RESPONSE_YES)
90 HobButton.style_button(button)
91 response = dialog.run()
92 if response == gtk.RESPONSE_YES:
93 path = dialog.get_filename()
94 entry.set_text(path)
95
96 dialog.destroy()
97
98 def gen_entry_widget(self, content, parent, tooltip="", need_button=True):
99 hbox = gtk.HBox(False, 12)
100 entry = gtk.Entry()
101 entry.set_text(content)
102 entry.set_size_request(350,30)
103
104 if need_button:
105 table = gtk.Table(1, 10, False)
106 hbox.pack_start(table, expand=True, fill=True)
107 table.attach(entry, 0, 9, 0, 1, xoptions=gtk.SHRINK)
108 image = gtk.Image()
109 image.set_from_stock(gtk.STOCK_OPEN,gtk.ICON_SIZE_BUTTON)
110 open_button = gtk.Button()
111 open_button.set_image(image)
112 open_button.connect("clicked", self.entry_widget_select_path_cb, parent, entry)
113 table.attach(open_button, 9, 10, 0, 1, xoptions=gtk.SHRINK)
114 else:
115 hbox.pack_start(entry, expand=True, fill=True)
116
117 if tooltip != "":
118 info = HobInfoButton(tooltip, self)
119 hbox.pack_start(info, expand=False, fill=False)
120
121 hbox.show_all()
122 return hbox, entry
123
124 def gen_mirror_entry_widget(self, content, index, match_content=""):
125 hbox = gtk.HBox(False)
126 entry = gtk.Entry()
127 content = content[:-2]
128 entry.set_text(content)
129 entry.set_size_request(350,30)
130
131 entry_match = gtk.Entry()
132 entry_match.set_text(match_content)
133 entry_match.set_size_request(100,30)
134
135 table = gtk.Table(2, 5, False)
136 table.set_row_spacings(12)
137 table.set_col_spacings(6)
138 hbox.pack_start(table, expand=True, fill=True)
139
140 label_configuration = gtk.Label("Configuration")
141 label_configuration.set_alignment(0.0,0.5)
142 label_mirror_url = gtk.Label("Mirror URL")
143 label_mirror_url.set_alignment(0.0,0.5)
144 label_match = gtk.Label("Match")
145 label_match.set_alignment(0.0,0.5)
146 label_replace_with = gtk.Label("Replace with")
147 label_replace_with.set_alignment(0.0,0.5)
148
149 combo = gtk.combo_box_new_text()
150 combo.append_text("Standard")
151 combo.append_text("Custom")
152 if match_content == "":
153 combo.set_active(0)
154 else:
155 combo.set_active(1)
156 combo.connect("changed", self.on_combo_changed, index)
157 combo.set_size_request(100,30)
158
159 delete_button = HobAltButton("Delete")
160 delete_button.connect("clicked", self.delete_cb, index, entry)
161 if content == "" and index == 0 and len(self.sstatemirrors_list) == 1:
162 delete_button.set_sensitive(False)
163 delete_button.set_size_request(100, 30)
164
165 entry_match.connect("changed", self.insert_entry_match_cb, index)
166 entry.connect("changed", self.insert_entry_cb, index, delete_button)
167
168 if match_content == "":
169 table.attach(label_configuration, 1, 2, 0, 1, xoptions=gtk.SHRINK|gtk.FILL)
170 table.attach(label_mirror_url, 2, 3, 0, 1, xoptions=gtk.SHRINK|gtk.FILL)
171 table.attach(combo, 1, 2, 1, 2, xoptions=gtk.SHRINK)
172 table.attach(entry, 2, 3, 1, 2, xoptions=gtk.SHRINK)
173 table.attach(delete_button, 3, 4, 1, 2, xoptions=gtk.SHRINK)
174 else:
175 table.attach(label_configuration, 1, 2, 0, 1, xoptions=gtk.SHRINK|gtk.FILL)
176 table.attach(label_match, 2, 3, 0, 1, xoptions=gtk.SHRINK|gtk.FILL)
177 table.attach(label_replace_with, 3, 4, 0, 1, xoptions=gtk.SHRINK|gtk.FILL)
178 table.attach(combo, 1, 2, 1, 2, xoptions=gtk.SHRINK)
179 table.attach(entry_match, 2, 3, 1, 2, xoptions=gtk.SHRINK)
180 table.attach(entry, 3, 4, 1, 2, xoptions=gtk.SHRINK)
181 table.attach(delete_button, 4, 5, 1, 2, xoptions=gtk.SHRINK)
182
183 hbox.show_all()
184 return hbox
185
186 def insert_entry_match_cb(self, entry_match, index):
187 self.sstatemirrors_list[index][2] = entry_match.get_text()
188
189 def insert_entry_cb(self, entry, index, button):
190 self.sstatemirrors_list[index][1] = entry.get_text()
191 if entry.get_text() == "" and index == 0:
192 button.set_sensitive(False)
193 else:
194 button.set_sensitive(True)
195
196 def on_combo_changed(self, combo, index):
197 if combo.get_active_text() == "Standard":
198 self.sstatemirrors_list[index][0] = 0
199 self.sstatemirrors_list[index][2] = "file://(.*)"
200 else:
201 self.sstatemirrors_list[index][0] = 1
202 self.refresh_shared_state_page()
203
204 def delete_cb(self, button, index, entry):
205 if index == 0 and len(self.sstatemirrors_list)==1:
206 entry.set_text("")
207 else:
208 self.sstatemirrors_list.pop(index)
209 self.refresh_shared_state_page()
210
211 def add_mirror(self, button):
212 tooltip = "Select the pre-built mirror that will speed your build"
213 index = len(self.sstatemirrors_list)
214 sm_list = [0, "", "file://(.*)"]
215 self.sstatemirrors_list.append(sm_list)
216 self.refresh_shared_state_page()
diff --git a/bitbake/lib/bb/ui/crumbs/hig/simplesettingsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/simplesettingsdialog.py
new file mode 100644
index 0000000000..3642e9bc5c
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/simplesettingsdialog.py
@@ -0,0 +1,722 @@
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
23import gtk
24import gobject
25import hashlib
26from bb.ui.crumbs.hobwidget import hic, HobInfoButton, HobButton, HobAltButton
27from bb.ui.crumbs.progressbar import HobProgressBar
28from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper
29from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
30from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
31from bb.ui.crumbs.hig.proxydetailsdialog import ProxyDetailsDialog
32
33"""
34The following are convenience classes for implementing GNOME HIG compliant
35BitBake GUI's
36In summary: spacing = 12px, border-width = 6px
37"""
38
39class 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 def __init__(self, title, configuration, all_image_types,
54 all_package_formats, all_distros, all_sdk_machines,
55 max_threads, parent, flags, handler, buttons=None):
56 super(SimpleSettingsDialog, self).__init__(title, parent, flags, buttons)
57
58 # class members from other objects
59 # bitbake settings from Builder.Configuration
60 self.configuration = configuration
61 self.image_types = all_image_types
62 self.all_package_formats = all_package_formats
63 self.all_distros = all_distros
64 self.all_sdk_machines = all_sdk_machines
65 self.max_threads = max_threads
66
67 # class members for internal use
68 self.dldir_text = None
69 self.sstatedir_text = None
70 self.sstatemirrors_list = []
71 self.sstatemirrors_changed = 0
72 self.bb_spinner = None
73 self.pmake_spinner = None
74 self.rootfs_size_spinner = None
75 self.extra_size_spinner = None
76 self.gplv3_checkbox = None
77 self.toolchain_checkbox = None
78 self.setting_store = None
79 self.image_types_checkbuttons = {}
80
81 self.md5 = self.config_md5()
82 self.proxy_md5 = self.config_proxy_md5()
83 self.settings_changed = False
84 self.proxy_settings_changed = False
85 self.handler = handler
86 self.proxy_test_ran = False
87
88 # create visual elements on the dialog
89 self.create_visual_elements()
90 self.connect("response", self.response_cb)
91
92 def _get_sorted_value(self, var):
93 return " ".join(sorted(str(var).split())) + "\n"
94
95 def config_proxy_md5(self):
96 data = ("ENABLE_PROXY: " + self._get_sorted_value(self.configuration.enable_proxy))
97 if self.configuration.enable_proxy:
98 for protocol in self.configuration.proxies.keys():
99 data += (protocol + ": " + self._get_sorted_value(self.configuration.combine_proxy(protocol)))
100 return hashlib.md5(data).hexdigest()
101
102 def config_md5(self):
103 data = ""
104 for key in self.configuration.extra_setting.keys():
105 data += (key + ": " + self._get_sorted_value(self.configuration.extra_setting[key]))
106 return hashlib.md5(data).hexdigest()
107
108 def gen_proxy_entry_widget(self, protocol, parent, need_button=True, line=0):
109 label = gtk.Label(protocol.upper() + " proxy")
110 self.proxy_table.attach(label, 0, 1, line, line+1, xpadding=24)
111
112 proxy_entry = gtk.Entry()
113 proxy_entry.set_size_request(300, -1)
114 self.proxy_table.attach(proxy_entry, 1, 2, line, line+1, ypadding=4)
115
116 self.proxy_table.attach(gtk.Label(":"), 2, 3, line, line+1, xpadding=12, ypadding=4)
117
118 port_entry = gtk.Entry()
119 port_entry.set_size_request(60, -1)
120 self.proxy_table.attach(port_entry, 3, 4, line, line+1, ypadding=4)
121
122 details_button = HobAltButton("Details")
123 details_button.connect("clicked", self.details_cb, parent, protocol)
124 self.proxy_table.attach(details_button, 4, 5, line, line+1, xpadding=4, yoptions=gtk.EXPAND)
125
126 return proxy_entry, port_entry, details_button
127
128 def refresh_proxy_components(self):
129 self.same_checkbox.set_sensitive(self.configuration.enable_proxy)
130
131 self.http_proxy.set_text(self.configuration.combine_host_only("http"))
132 self.http_proxy.set_editable(self.configuration.enable_proxy)
133 self.http_proxy.set_sensitive(self.configuration.enable_proxy)
134 self.http_proxy_port.set_text(self.configuration.combine_port_only("http"))
135 self.http_proxy_port.set_editable(self.configuration.enable_proxy)
136 self.http_proxy_port.set_sensitive(self.configuration.enable_proxy)
137 self.http_proxy_details.set_sensitive(self.configuration.enable_proxy)
138
139 self.https_proxy.set_text(self.configuration.combine_host_only("https"))
140 self.https_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
141 self.https_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
142 self.https_proxy_port.set_text(self.configuration.combine_port_only("https"))
143 self.https_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
144 self.https_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
145 self.https_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
146
147 self.ftp_proxy.set_text(self.configuration.combine_host_only("ftp"))
148 self.ftp_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
149 self.ftp_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
150 self.ftp_proxy_port.set_text(self.configuration.combine_port_only("ftp"))
151 self.ftp_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
152 self.ftp_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
153 self.ftp_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
154
155 self.git_proxy.set_text(self.configuration.combine_host_only("git"))
156 self.git_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
157 self.git_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
158 self.git_proxy_port.set_text(self.configuration.combine_port_only("git"))
159 self.git_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
160 self.git_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
161 self.git_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
162
163 self.cvs_proxy.set_text(self.configuration.combine_host_only("cvs"))
164 self.cvs_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
165 self.cvs_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
166 self.cvs_proxy_port.set_text(self.configuration.combine_port_only("cvs"))
167 self.cvs_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
168 self.cvs_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
169 self.cvs_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
170
171 if self.configuration.same_proxy:
172 if self.http_proxy.get_text():
173 [w.set_text(self.http_proxy.get_text()) for w in self.same_proxy_addresses]
174 if self.http_proxy_port.get_text():
175 [w.set_text(self.http_proxy_port.get_text()) for w in self.same_proxy_ports]
176
177 def proxy_checkbox_toggled_cb(self, button):
178 self.configuration.enable_proxy = self.proxy_checkbox.get_active()
179 if not self.configuration.enable_proxy:
180 self.configuration.same_proxy = False
181 self.same_checkbox.set_active(self.configuration.same_proxy)
182 self.save_proxy_data()
183 self.refresh_proxy_components()
184
185 def same_checkbox_toggled_cb(self, button):
186 self.configuration.same_proxy = self.same_checkbox.get_active()
187 self.save_proxy_data()
188 self.refresh_proxy_components()
189
190 def save_proxy_data(self):
191 self.configuration.split_proxy("http", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
192 if self.configuration.same_proxy:
193 self.configuration.split_proxy("https", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
194 self.configuration.split_proxy("ftp", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
195 self.configuration.split_proxy("git", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
196 self.configuration.split_proxy("cvs", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
197 else:
198 self.configuration.split_proxy("https", self.https_proxy.get_text() + ":" + self.https_proxy_port.get_text())
199 self.configuration.split_proxy("ftp", self.ftp_proxy.get_text() + ":" + self.ftp_proxy_port.get_text())
200 self.configuration.split_proxy("git", self.git_proxy.get_text() + ":" + self.git_proxy_port.get_text())
201 self.configuration.split_proxy("cvs", self.cvs_proxy.get_text() + ":" + self.cvs_proxy_port.get_text())
202
203 def response_cb(self, dialog, response_id):
204 if response_id == gtk.RESPONSE_YES:
205 # Check that all proxy entries have a corresponding port
206 for proxy, port in zip(self.all_proxy_addresses, self.all_proxy_ports):
207 if proxy.get_text() and not port.get_text():
208 lbl = "<b>Enter all port numbers</b>\n\n"
209 msg = "Proxy servers require a port number. Please make sure you have entered a port number for each proxy server."
210 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING, msg)
211 button = dialog.add_button("Close", gtk.RESPONSE_OK)
212 HobButton.style_button(button)
213 response = dialog.run()
214 dialog.destroy()
215 self.emit_stop_by_name("response")
216 return
217
218 self.configuration.dldir = self.dldir_text.get_text()
219 self.configuration.sstatedir = self.sstatedir_text.get_text()
220 self.configuration.sstatemirror = ""
221 for mirror in self.sstatemirrors_list:
222 if mirror[1] != "":
223 if mirror[1].endswith("\\1"):
224 smirror = mirror[2] + " " + mirror[1] + " \\n "
225 else:
226 smirror = mirror[2] + " " + mirror[1] + "\\1 \\n "
227 self.configuration.sstatemirror += smirror
228 self.configuration.bbthread = self.bb_spinner.get_value_as_int()
229 self.configuration.pmake = self.pmake_spinner.get_value_as_int()
230 self.save_proxy_data()
231 self.configuration.extra_setting = {}
232 it = self.setting_store.get_iter_first()
233 while it:
234 key = self.setting_store.get_value(it, 0)
235 value = self.setting_store.get_value(it, 1)
236 self.configuration.extra_setting[key] = value
237 it = self.setting_store.iter_next(it)
238
239 md5 = self.config_md5()
240 self.settings_changed = (self.md5 != md5)
241 self.proxy_settings_changed = (self.proxy_md5 != self.config_proxy_md5())
242
243 def create_build_environment_page(self):
244 advanced_vbox = gtk.VBox(False, 6)
245 advanced_vbox.set_border_width(6)
246
247 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Parallel threads</span>'), expand=False, fill=False)
248 sub_vbox = gtk.VBox(False, 6)
249 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
250 label = self.gen_label_widget("BitBake parallel threads")
251 tooltip = "Sets the number of threads that BitBake tasks can simultaneously run. See the <a href=\""
252 tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
253 tooltip += "poky-ref-manual.html#var-BB_NUMBER_THREADS\">Poky reference manual</a> for information"
254 bbthread_widget, self.bb_spinner = self.gen_spinner_widget(self.configuration.bbthread, 1, self.max_threads, tooltip)
255 sub_vbox.pack_start(label, expand=False, fill=False)
256 sub_vbox.pack_start(bbthread_widget, expand=False, fill=False)
257
258 sub_vbox = gtk.VBox(False, 6)
259 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
260 label = self.gen_label_widget("Make parallel threads")
261 tooltip = "Sets the maximum number of threads the host can use during the build. See the <a href=\""
262 tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
263 tooltip += "poky-ref-manual.html#var-PARALLEL_MAKE\">Poky reference manual</a> for information"
264 pmake_widget, self.pmake_spinner = self.gen_spinner_widget(self.configuration.pmake, 1, self.max_threads, tooltip)
265 sub_vbox.pack_start(label, expand=False, fill=False)
266 sub_vbox.pack_start(pmake_widget, expand=False, fill=False)
267
268 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Downloaded source code</span>'), expand=False, fill=False)
269 sub_vbox = gtk.VBox(False, 6)
270 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
271 label = self.gen_label_widget("Downloads directory")
272 tooltip = "Select a folder that caches the upstream project source code"
273 dldir_widget, self.dldir_text = self.gen_entry_widget(self.configuration.dldir, self, tooltip)
274 sub_vbox.pack_start(label, expand=False, fill=False)
275 sub_vbox.pack_start(dldir_widget, expand=False, fill=False)
276
277 return advanced_vbox
278
279 def create_shared_state_page(self):
280 advanced_vbox = gtk.VBox(False)
281 advanced_vbox.set_border_width(12)
282
283 sub_vbox = gtk.VBox(False)
284 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False, padding=24)
285 content = "<span>Shared state directory</span>"
286 tooltip = "Select a folder that caches your prebuilt results"
287 label = self.gen_label_info_widget(content, tooltip)
288 sstatedir_widget, self.sstatedir_text = self.gen_entry_widget(self.configuration.sstatedir, self)
289 sub_vbox.pack_start(label, expand=False, fill=False)
290 sub_vbox.pack_start(sstatedir_widget, expand=False, fill=False, padding=12)
291
292 content = "<span weight=\"bold\">Shared state mirrors</span>"
293 tooltip = "URLs pointing to pre-built mirrors that will speed your build. "
294 tooltip += "Select the \'Standard\' configuration if the structure of your "
295 tooltip += "mirror replicates the structure of your local shared state directory. "
296 tooltip += "For more information on shared state mirrors, check the <a href=\""
297 tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
298 tooltip += "poky-ref-manual.html#shared-state\">Yocto Project Reference Manual</a>."
299 table = self.gen_label_info_widget(content, tooltip)
300 advanced_vbox.pack_start(table, expand=False, fill=False)
301
302 sub_vbox = gtk.VBox(False)
303 scroll = gtk.ScrolledWindow()
304 scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
305 scroll.add_with_viewport(sub_vbox)
306 scroll.connect('size-allocate', self.scroll_changed)
307 advanced_vbox.pack_start(scroll, gtk.TRUE, gtk.TRUE, 0)
308 searched_string = "file://"
309
310 if self.sstatemirrors_changed == 0:
311 self.sstatemirrors_changed = 1
312 sstatemirrors = self.configuration.sstatemirror
313 if sstatemirrors == "":
314 sm_list = [ 0, "", "file://(.*)"]
315 self.sstatemirrors_list.append(sm_list)
316 else:
317 while sstatemirrors.find(searched_string) != -1:
318 if sstatemirrors.find(searched_string,1) != -1:
319 sstatemirror = sstatemirrors[:sstatemirrors.find(searched_string,1)]
320 sstatemirrors = sstatemirrors[sstatemirrors.find(searched_string,1):]
321 else:
322 sstatemirror = sstatemirrors
323 sstatemirrors = sstatemirrors[1:]
324
325 sstatemirror_fields = [x for x in sstatemirror.split(' ') if x.strip()]
326 if sstatemirror_fields[0] == "file://(.*)":
327 sm_list = [ 0, sstatemirror_fields[1], "file://(.*)"]
328 else:
329 sm_list = [ 1, sstatemirror_fields[1], sstatemirror_fields[0]]
330 self.sstatemirrors_list.append(sm_list)
331
332 index = 0
333 for mirror in self.sstatemirrors_list:
334 if mirror[0] == 0:
335 sstatemirror_widget = self.gen_mirror_entry_widget(mirror[1], index)
336 else:
337 sstatemirror_widget = self.gen_mirror_entry_widget(mirror[1], index, mirror[2])
338 sub_vbox.pack_start(sstatemirror_widget, expand=False, fill=False, padding=9)
339 index += 1
340
341 table = gtk.Table(1, 1, False)
342 table.set_col_spacings(6)
343 add_mirror_button = HobAltButton("Add another mirror")
344 add_mirror_button.connect("clicked", self.add_mirror)
345 add_mirror_button.set_size_request(150,30)
346 table.attach(add_mirror_button, 1, 2, 0, 1, xoptions=gtk.SHRINK)
347 advanced_vbox.pack_start(table, expand=False, fill=False, padding=9)
348
349 return advanced_vbox
350
351 def refresh_shared_state_page(self):
352 page_num = self.nb.get_current_page()
353 self.nb.remove_page(page_num);
354 self.nb.insert_page(self.create_shared_state_page(), gtk.Label("Shared state"),page_num)
355 self.show_all()
356 self.nb.set_current_page(page_num)
357
358 def test_proxy_ended(self, passed):
359 self.proxy_test_running = False
360 self.set_test_proxy_state(self.TEST_NETWORK_PASSED if passed else self.TEST_NETWORK_FAILED)
361 self.set_sensitive(True)
362 self.refresh_proxy_components()
363
364 def timer_func(self):
365 self.test_proxy_progress.pulse()
366 return self.proxy_test_running
367
368 def test_network_button_cb(self, b):
369 self.set_test_proxy_state(self.TEST_NETWORK_RUNNING)
370 self.set_sensitive(False)
371 self.save_proxy_data()
372 if self.configuration.enable_proxy == True:
373 self.handler.set_http_proxy(self.configuration.combine_proxy("http"))
374 self.handler.set_https_proxy(self.configuration.combine_proxy("https"))
375 self.handler.set_ftp_proxy(self.configuration.combine_proxy("ftp"))
376 self.handler.set_git_proxy(self.configuration.combine_host_only("git"), self.configuration.combine_port_only("git"))
377 self.handler.set_cvs_proxy(self.configuration.combine_host_only("cvs"), self.configuration.combine_port_only("cvs"))
378 elif self.configuration.enable_proxy == False:
379 self.handler.set_http_proxy("")
380 self.handler.set_https_proxy("")
381 self.handler.set_ftp_proxy("")
382 self.handler.set_git_proxy("", "")
383 self.handler.set_cvs_proxy("", "")
384 self.proxy_test_ran = True
385 self.proxy_test_running = True
386 gobject.timeout_add(100, self.timer_func)
387 self.handler.trigger_network_test()
388
389 def test_proxy_focus_event(self, w, direction):
390 if self.test_proxy_state in [self.TEST_NETWORK_PASSED, self.TEST_NETWORK_FAILED]:
391 self.set_test_proxy_state(self.TEST_NETWORK_INITIAL)
392 return False
393
394 def http_proxy_changed(self, e):
395 if not self.configuration.same_proxy:
396 return
397 if e == self.http_proxy:
398 [w.set_text(self.http_proxy.get_text()) for w in self.same_proxy_addresses]
399 else:
400 [w.set_text(self.http_proxy_port.get_text()) for w in self.same_proxy_ports]
401
402 def proxy_address_focus_out_event(self, w, direction):
403 text = w.get_text()
404 if not text:
405 return False
406 if text.find("//") == -1:
407 w.set_text("http://" + text)
408 return False
409
410 def set_test_proxy_state(self, state):
411 if self.test_proxy_state == state:
412 return
413 [self.proxy_table.remove(w) for w in self.test_gui_elements]
414 if state == self.TEST_NETWORK_INITIAL:
415 self.proxy_table.attach(self.test_network_button, 1, 2, 5, 6)
416 self.test_network_button.show()
417 elif state == self.TEST_NETWORK_RUNNING:
418 self.test_proxy_progress.set_rcstyle("running")
419 self.test_proxy_progress.set_text("Testing network configuration")
420 self.proxy_table.attach(self.test_proxy_progress, 0, 5, 5, 6, xpadding=4)
421 self.test_proxy_progress.show()
422 else: # passed or failed
423 self.dummy_progress.update(1.0)
424 if state == self.TEST_NETWORK_PASSED:
425 self.dummy_progress.set_text("Your network is properly configured")
426 self.dummy_progress.set_rcstyle("running")
427 else:
428 self.dummy_progress.set_text("Network test failed")
429 self.dummy_progress.set_rcstyle("fail")
430 self.proxy_table.attach(self.dummy_progress, 0, 4, 5, 6)
431 self.proxy_table.attach(self.retest_network_button, 4, 5, 5, 6, xpadding=4)
432 self.dummy_progress.show()
433 self.retest_network_button.show()
434 self.test_proxy_state = state
435
436 def create_network_page(self):
437 advanced_vbox = gtk.VBox(False, 6)
438 advanced_vbox.set_border_width(6)
439 self.same_proxy_addresses = []
440 self.same_proxy_ports = []
441 self.all_proxy_ports = []
442 self.all_proxy_addresses = []
443
444 sub_vbox = gtk.VBox(False, 6)
445 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
446 label = self.gen_label_widget("<span weight=\"bold\">Set the proxies used when fetching source code</span>")
447 tooltip = "Set the proxies used when fetching source code. A blank field uses a direct internet connection."
448 info = HobInfoButton(tooltip, self)
449 hbox = gtk.HBox(False, 12)
450 hbox.pack_start(label, expand=True, fill=True)
451 hbox.pack_start(info, expand=False, fill=False)
452 sub_vbox.pack_start(hbox, expand=False, fill=False)
453
454 proxy_test_focus = []
455 self.direct_checkbox = gtk.RadioButton(None, "Direct network connection")
456 proxy_test_focus.append(self.direct_checkbox)
457 self.direct_checkbox.set_tooltip_text("Check this box to use a direct internet connection with no proxy")
458 self.direct_checkbox.set_active(not self.configuration.enable_proxy)
459 sub_vbox.pack_start(self.direct_checkbox, expand=False, fill=False)
460
461 self.proxy_checkbox = gtk.RadioButton(self.direct_checkbox, "Manual proxy configuration")
462 proxy_test_focus.append(self.proxy_checkbox)
463 self.proxy_checkbox.set_tooltip_text("Check this box to manually set up a specific proxy")
464 self.proxy_checkbox.set_active(self.configuration.enable_proxy)
465 sub_vbox.pack_start(self.proxy_checkbox, expand=False, fill=False)
466
467 self.same_checkbox = gtk.CheckButton("Use the HTTP proxy for all protocols")
468 proxy_test_focus.append(self.same_checkbox)
469 self.same_checkbox.set_tooltip_text("Check this box to use the HTTP proxy for all five proxies")
470 self.same_checkbox.set_active(self.configuration.same_proxy)
471 hbox = gtk.HBox(False, 12)
472 hbox.pack_start(self.same_checkbox, expand=False, fill=False, padding=24)
473 sub_vbox.pack_start(hbox, expand=False, fill=False)
474
475 self.proxy_table = gtk.Table(6, 5, False)
476 self.http_proxy, self.http_proxy_port, self.http_proxy_details = self.gen_proxy_entry_widget(
477 "http", self, True, 0)
478 proxy_test_focus +=[self.http_proxy, self.http_proxy_port]
479 self.http_proxy.connect("changed", self.http_proxy_changed)
480 self.http_proxy_port.connect("changed", self.http_proxy_changed)
481
482 self.https_proxy, self.https_proxy_port, self.https_proxy_details = self.gen_proxy_entry_widget(
483 "https", self, True, 1)
484 proxy_test_focus += [self.https_proxy, self.https_proxy_port]
485 self.same_proxy_addresses.append(self.https_proxy)
486 self.same_proxy_ports.append(self.https_proxy_port)
487
488 self.ftp_proxy, self.ftp_proxy_port, self.ftp_proxy_details = self.gen_proxy_entry_widget(
489 "ftp", self, True, 2)
490 proxy_test_focus += [self.ftp_proxy, self.ftp_proxy_port]
491 self.same_proxy_addresses.append(self.ftp_proxy)
492 self.same_proxy_ports.append(self.ftp_proxy_port)
493
494 self.git_proxy, self.git_proxy_port, self.git_proxy_details = self.gen_proxy_entry_widget(
495 "git", self, True, 3)
496 proxy_test_focus += [self.git_proxy, self.git_proxy_port]
497 self.same_proxy_addresses.append(self.git_proxy)
498 self.same_proxy_ports.append(self.git_proxy_port)
499
500 self.cvs_proxy, self.cvs_proxy_port, self.cvs_proxy_details = self.gen_proxy_entry_widget(
501 "cvs", self, True, 4)
502 proxy_test_focus += [self.cvs_proxy, self.cvs_proxy_port]
503 self.same_proxy_addresses.append(self.cvs_proxy)
504 self.same_proxy_ports.append(self.cvs_proxy_port)
505 self.all_proxy_ports = self.same_proxy_ports + [self.http_proxy_port]
506 self.all_proxy_addresses = self.same_proxy_addresses + [self.http_proxy]
507 sub_vbox.pack_start(self.proxy_table, expand=False, fill=False)
508 self.proxy_table.show_all()
509
510 # Create the graphical elements for the network test feature, but don't display them yet
511 self.test_network_button = HobAltButton("Test network configuration")
512 self.test_network_button.connect("clicked", self.test_network_button_cb)
513 self.test_proxy_progress = HobProgressBar()
514 self.dummy_progress = HobProgressBar()
515 self.retest_network_button = HobAltButton("Retest")
516 self.retest_network_button.connect("clicked", self.test_network_button_cb)
517 self.test_gui_elements = [self.test_network_button, self.test_proxy_progress, self.dummy_progress, self.retest_network_button]
518 # Initialize the network tester
519 self.test_proxy_state = self.TEST_NETWORK_NONE
520 self.set_test_proxy_state(self.TEST_NETWORK_INITIAL)
521 self.proxy_test_passed_id = self.handler.connect("network-passed", lambda h:self.test_proxy_ended(True))
522 self.proxy_test_failed_id = self.handler.connect("network-failed", lambda h:self.test_proxy_ended(False))
523 [w.connect("focus-in-event", self.test_proxy_focus_event) for w in proxy_test_focus]
524 [w.connect("focus-out-event", self.proxy_address_focus_out_event) for w in self.all_proxy_addresses]
525
526 self.direct_checkbox.connect("toggled", self.proxy_checkbox_toggled_cb)
527 self.proxy_checkbox.connect("toggled", self.proxy_checkbox_toggled_cb)
528 self.same_checkbox.connect("toggled", self.same_checkbox_toggled_cb)
529
530 self.refresh_proxy_components()
531 return advanced_vbox
532
533 def switch_to_page(self, page_id):
534 self.nb.set_current_page(page_id)
535
536 def details_cb(self, button, parent, protocol):
537 self.save_proxy_data()
538 dialog = ProxyDetailsDialog(title = protocol.upper() + " Proxy Details",
539 user = self.configuration.proxies[protocol][1],
540 passwd = self.configuration.proxies[protocol][2],
541 parent = parent,
542 flags = gtk.DIALOG_MODAL
543 | gtk.DIALOG_DESTROY_WITH_PARENT
544 | gtk.DIALOG_NO_SEPARATOR)
545 dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
546 response = dialog.run()
547 if response == gtk.RESPONSE_OK:
548 self.configuration.proxies[protocol][1] = dialog.user
549 self.configuration.proxies[protocol][2] = dialog.passwd
550 self.refresh_proxy_components()
551 dialog.destroy()
552
553 def rootfs_combo_changed_cb(self, rootfs_combo, all_package_format, check_hbox):
554 combo_item = self.rootfs_combo.get_active_text()
555 for child in check_hbox.get_children():
556 if isinstance(child, gtk.CheckButton):
557 check_hbox.remove(child)
558 for format in all_package_format:
559 if format != combo_item:
560 check_button = gtk.CheckButton(format)
561 check_hbox.pack_start(check_button, expand=False, fill=False)
562 check_hbox.show_all()
563
564 def gen_pkgfmt_widget(self, curr_package_format, all_package_format, tooltip_combo="", tooltip_extra=""):
565 pkgfmt_hbox = gtk.HBox(False, 24)
566
567 rootfs_vbox = gtk.VBox(False, 6)
568 pkgfmt_hbox.pack_start(rootfs_vbox, expand=False, fill=False)
569
570 label = self.gen_label_widget("Root file system package format")
571 rootfs_vbox.pack_start(label, expand=False, fill=False)
572
573 rootfs_format = ""
574 if curr_package_format:
575 rootfs_format = curr_package_format.split()[0]
576
577 rootfs_format_widget, rootfs_combo = self.gen_combo_widget(rootfs_format, all_package_format, tooltip_combo)
578 rootfs_vbox.pack_start(rootfs_format_widget, expand=False, fill=False)
579
580 extra_vbox = gtk.VBox(False, 6)
581 pkgfmt_hbox.pack_start(extra_vbox, expand=False, fill=False)
582
583 label = self.gen_label_widget("Additional package formats")
584 extra_vbox.pack_start(label, expand=False, fill=False)
585
586 check_hbox = gtk.HBox(False, 12)
587 extra_vbox.pack_start(check_hbox, expand=False, fill=False)
588 for format in all_package_format:
589 if format != rootfs_format:
590 check_button = gtk.CheckButton(format)
591 is_active = (format in curr_package_format.split())
592 check_button.set_active(is_active)
593 check_hbox.pack_start(check_button, expand=False, fill=False)
594
595 info = HobInfoButton(tooltip_extra, self)
596 check_hbox.pack_end(info, expand=False, fill=False)
597
598 rootfs_combo.connect("changed", self.rootfs_combo_changed_cb, all_package_format, check_hbox)
599
600 pkgfmt_hbox.show_all()
601
602 return pkgfmt_hbox, rootfs_combo, check_hbox
603
604 def editable_settings_cell_edited(self, cell, path_string, new_text, model):
605 it = model.get_iter_from_string(path_string)
606 column = cell.get_data("column")
607 model.set(it, column, new_text)
608
609 def editable_settings_add_item_clicked(self, button, model):
610 new_item = ["##KEY##", "##VALUE##"]
611
612 iter = model.append()
613 model.set (iter,
614 0, new_item[0],
615 1, new_item[1],
616 )
617
618 def editable_settings_remove_item_clicked(self, button, treeview):
619 selection = treeview.get_selection()
620 model, iter = selection.get_selected()
621
622 if iter:
623 path = model.get_path(iter)[0]
624 model.remove(iter)
625
626 def gen_editable_settings(self, setting, tooltip=""):
627 setting_hbox = gtk.HBox(False, 12)
628
629 vbox = gtk.VBox(False, 12)
630 setting_hbox.pack_start(vbox, expand=True, fill=True)
631
632 setting_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
633 for key in setting.keys():
634 setting_store.set(setting_store.append(), 0, key, 1, setting[key])
635
636 setting_tree = gtk.TreeView(setting_store)
637 setting_tree.set_headers_visible(True)
638 setting_tree.set_size_request(300, 100)
639
640 col = gtk.TreeViewColumn('Key')
641 col.set_min_width(100)
642 col.set_max_width(150)
643 col.set_resizable(True)
644 col1 = gtk.TreeViewColumn('Value')
645 col1.set_min_width(100)
646 col1.set_max_width(150)
647 col1.set_resizable(True)
648 setting_tree.append_column(col)
649 setting_tree.append_column(col1)
650 cell = gtk.CellRendererText()
651 cell.set_property('width-chars', 10)
652 cell.set_property('editable', True)
653 cell.set_data("column", 0)
654 cell.connect("edited", self.editable_settings_cell_edited, setting_store)
655 cell1 = gtk.CellRendererText()
656 cell1.set_property('width-chars', 10)
657 cell1.set_property('editable', True)
658 cell1.set_data("column", 1)
659 cell1.connect("edited", self.editable_settings_cell_edited, setting_store)
660 col.pack_start(cell, True)
661 col1.pack_end(cell1, True)
662 col.set_attributes(cell, text=0)
663 col1.set_attributes(cell1, text=1)
664
665 scroll = gtk.ScrolledWindow()
666 scroll.set_shadow_type(gtk.SHADOW_IN)
667 scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
668 scroll.add(setting_tree)
669 vbox.pack_start(scroll, expand=True, fill=True)
670
671 # some buttons
672 hbox = gtk.HBox(True, 6)
673 vbox.pack_start(hbox, False, False)
674
675 button = gtk.Button(stock=gtk.STOCK_ADD)
676 button.connect("clicked", self.editable_settings_add_item_clicked, setting_store)
677 hbox.pack_start(button)
678
679 button = gtk.Button(stock=gtk.STOCK_REMOVE)
680 button.connect("clicked", self.editable_settings_remove_item_clicked, setting_tree)
681 hbox.pack_start(button)
682
683 info = HobInfoButton(tooltip, self)
684 setting_hbox.pack_start(info, expand=False, fill=False)
685
686 return setting_hbox, setting_store
687
688 def create_others_page(self):
689 advanced_vbox = gtk.VBox(False, 6)
690 advanced_vbox.set_border_width(6)
691
692 sub_vbox = gtk.VBox(False, 6)
693 advanced_vbox.pack_start(sub_vbox, expand=True, fill=True)
694 label = self.gen_label_widget("<span weight=\"bold\">Add your own variables:</span>")
695 tooltip = "These are key/value pairs for your extra settings. Click \'Add\' and then directly edit the key and the value"
696 setting_widget, self.setting_store = self.gen_editable_settings(self.configuration.extra_setting, tooltip)
697 sub_vbox.pack_start(label, expand=False, fill=False)
698 sub_vbox.pack_start(setting_widget, expand=True, fill=True)
699
700 return advanced_vbox
701
702 def create_visual_elements(self):
703 self.nb = gtk.Notebook()
704 self.nb.set_show_tabs(True)
705 self.nb.append_page(self.create_build_environment_page(), gtk.Label("Build environment"))
706 self.nb.append_page(self.create_shared_state_page(), gtk.Label("Shared state"))
707 self.nb.append_page(self.create_network_page(), gtk.Label("Network"))
708 self.nb.append_page(self.create_others_page(), gtk.Label("Others"))
709 self.nb.set_current_page(0)
710 self.vbox.pack_start(self.nb, expand=True, fill=True)
711 self.vbox.pack_end(gtk.HSeparator(), expand=True, fill=True)
712
713 self.show_all()
714
715 def destroy(self):
716 self.handler.disconnect(self.proxy_test_passed_id)
717 self.handler.disconnect(self.proxy_test_failed_id)
718 super(SimpleSettingsDialog, self).destroy()
719
720 def scroll_changed(self, widget, event, data=None):
721 adj = widget.get_vadjustment()
722 adj.set_value(adj.upper - adj.page_size)
diff --git a/bitbake/lib/bb/ui/crumbs/imagedetailspage.py b/bitbake/lib/bb/ui/crumbs/imagedetailspage.py
index a1c133edee..38fbaaaa33 100755
--- a/bitbake/lib/bb/ui/crumbs/imagedetailspage.py
+++ b/bitbake/lib/bb/ui/crumbs/imagedetailspage.py
@@ -26,9 +26,9 @@ from bb.ui.crumbs.hobcolor import HobColors
26from bb.ui.crumbs.hobwidget import hic, HobViewTable, HobAltButton, HobButton 26from bb.ui.crumbs.hobwidget import hic, HobViewTable, HobAltButton, HobButton
27from bb.ui.crumbs.hobpages import HobPage 27from bb.ui.crumbs.hobpages import HobPage
28import subprocess 28import subprocess
29from bb.ui.crumbs.hig import CrumbsDialog 29from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
30from bb.ui.crumbs.hobthreads import OpeningLogThread 30from bb.ui.crumbs.hobthreads import OpeningLogThread
31from bb.ui.crumbs.hig import OpeningLogDialog 31from bb.ui.crumbs.hig.openinglogdialog import OpeningLogDialog
32 32
33# 33#
34# ImageDetailsPage 34# ImageDetailsPage
diff --git a/bitbake/lib/bb/ui/crumbs/packageselectionpage.py b/bitbake/lib/bb/ui/crumbs/packageselectionpage.py
index ac9cc7e135..2da9277bf9 100755
--- a/bitbake/lib/bb/ui/crumbs/packageselectionpage.py
+++ b/bitbake/lib/bb/ui/crumbs/packageselectionpage.py
@@ -27,7 +27,7 @@ from bb.ui.crumbs.hobwidget import HobViewTable, HobNotebook, HobAltButton, HobB
27from bb.ui.crumbs.hoblistmodel import PackageListModel 27from bb.ui.crumbs.hoblistmodel import PackageListModel
28from bb.ui.crumbs.hobpages import HobPage 28from bb.ui.crumbs.hobpages import HobPage
29from bb.ui.crumbs.hobthreads import OpeningLogThread 29from bb.ui.crumbs.hobthreads import OpeningLogThread
30from bb.ui.crumbs.hig import OpeningLogDialog 30from bb.ui.crumbs.hig.openinglogdialog import OpeningLogDialog
31 31
32# 32#
33# PackageSelectionPage 33# PackageSelectionPage