diff options
author | Bogdan Marinescu <bogdan.a.marinescu@intel.com> | 2013-01-10 13:08:02 +0200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2013-01-16 12:51:33 +0000 |
commit | 7bfb98568a1d7ba8dbd95332d65cd19faec6c725 (patch) | |
tree | 6a6d18d67a80e8ca862435d09c3ae63215659c7a | |
parent | a746719a46e9277a118fd7d4a6342bb667034132 (diff) | |
download | poky-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>
-rwxr-xr-x | bitbake/bin/image-writer | 4 | ||||
-rwxr-xr-x | bitbake/lib/bb/ui/crumbs/builddetailspage.py | 2 | ||||
-rwxr-xr-x | bitbake/lib/bb/ui/crumbs/builder.py | 11 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig.py | 1978 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/__init__.py | 0 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/advancedsettingsdialog.py | 336 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py | 44 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/crumbsmessagedialog.py | 95 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py | 215 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py | 172 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py | 296 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/openinglogdialog.py | 68 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py | 90 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/settingsuihelper.py | 216 | ||||
-rw-r--r-- | bitbake/lib/bb/ui/crumbs/hig/simplesettingsdialog.py | 722 | ||||
-rwxr-xr-x | bitbake/lib/bb/ui/crumbs/imagedetailspage.py | 4 | ||||
-rwxr-xr-x | bitbake/lib/bb/ui/crumbs/packageselectionpage.py | 2 |
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 | |||
28 | import optparse | 28 | import optparse |
29 | import pygtk | 29 | import pygtk |
30 | 30 | ||
31 | from bb.ui.crumbs.hig import DeployImageDialog, ImageSelectionDialog, CrumbsMessageDialog | ||
32 | from bb.ui.crumbs.hobwidget import HobAltButton, HobButton | 31 | from bb.ui.crumbs.hobwidget import HobAltButton, HobButton |
32 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
33 | from bb.ui.crumbs.hig.deployimagedialog import DeployImageDialog | ||
34 | from 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. |
35 | DEPLOYABLE_IMAGE_TYPES = ["jffs2", "cramfs", "ext2", "ext3", "btrfs", "squashfs", "ubi", "vmdk"] | 37 | DEPLOYABLE_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 | |||
31 | from bb.ui.crumbs.hobpages import HobPage | 31 | from bb.ui.crumbs.hobpages import HobPage |
32 | from bb.ui.crumbs.hobcolor import HobColors | 32 | from bb.ui.crumbs.hobcolor import HobColors |
33 | from bb.ui.crumbs.hobthreads import OpeningLogThread | 33 | from bb.ui.crumbs.hobthreads import OpeningLogThread |
34 | from bb.ui.crumbs.hig import OpeningLogDialog | 34 | from bb.ui.crumbs.hig.openinglogdialog import OpeningLogDialog |
35 | 35 | ||
36 | class BuildConfigurationTreeView(gtk.TreeView): | 36 | class 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 | |||
38 | from bb.ui.crumbs.imagedetailspage import ImageDetailsPage | 38 | from bb.ui.crumbs.imagedetailspage import ImageDetailsPage |
39 | from bb.ui.crumbs.sanitycheckpage import SanityCheckPage | 39 | from bb.ui.crumbs.sanitycheckpage import SanityCheckPage |
40 | from bb.ui.crumbs.hobwidget import hwc, HobButton, HobAltButton | 40 | from bb.ui.crumbs.hobwidget import hwc, HobButton, HobAltButton |
41 | from bb.ui.crumbs.hig import CrumbsMessageDialog, ImageSelectionDialog, \ | ||
42 | AdvancedSettingDialog, SimpleSettingsDialog, \ | ||
43 | LayerSelectionDialog, DeployImageDialog | ||
44 | from bb.ui.crumbs.persistenttooltip import PersistentTooltip | 41 | from bb.ui.crumbs.persistenttooltip import PersistentTooltip |
45 | import bb.ui.crumbs.utils | 42 | import bb.ui.crumbs.utils |
43 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
44 | from bb.ui.crumbs.hig.simplesettingsdialog import SimpleSettingsDialog | ||
45 | from bb.ui.crumbs.hig.advancedsettingsdialog import AdvancedSettingsDialog | ||
46 | from bb.ui.crumbs.hig.deployimagedialog import DeployImageDialog | ||
47 | from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog | ||
48 | from bb.ui.crumbs.hig.imageselectiondialog import ImageSelectionDialog | ||
46 | 49 | ||
47 | hobVer = 20120808 | 50 | hobVer = 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 | |||
23 | import glob | ||
24 | import glib | ||
25 | import gtk | ||
26 | import gobject | ||
27 | import hashlib | ||
28 | import os | ||
29 | import re | ||
30 | import shlex | ||
31 | import subprocess | ||
32 | import tempfile | ||
33 | from bb.ui.crumbs.hobcolor import HobColors | ||
34 | from bb.ui.crumbs.hobwidget import hic, HobViewTable, HobInfoButton, HobButton, HobAltButton, HobIconChecker | ||
35 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
36 | import bb.ui.crumbs.utils | ||
37 | import bb.process | ||
38 | |||
39 | """ | ||
40 | The following are convenience classes for implementing GNOME HIG compliant | ||
41 | BitBake GUI's | ||
42 | In summary: spacing = 12px, border-width = 6px | ||
43 | """ | ||
44 | |||
45 | |||
46 | class 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 | # | ||
234 | class 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 | |||
249 | class 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 | # | ||
315 | class 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 | # | ||
1003 | class 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 | # | ||
1306 | class 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 | |||
1479 | class 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 | # | ||
1502 | class 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 | |||
1740 | class 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 | # | ||
1881 | class 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 | # | ||
1945 | class 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 | |||
23 | import gtk | ||
24 | import hashlib | ||
25 | from bb.ui.crumbs.hobwidget import HobInfoButton, HobButton | ||
26 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
27 | from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper | ||
28 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
29 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
30 | from bb.ui.crumbs.hig.proxydetailsdialog import ProxyDetailsDialog | ||
31 | |||
32 | """ | ||
33 | The following are convenience classes for implementing GNOME HIG compliant | ||
34 | BitBake GUI's | ||
35 | In summary: spacing = 12px, border-width = 6px | ||
36 | """ | ||
37 | |||
38 | class AdvancedSettingsDialog (CrumbsDialog, SettingsUIHelper): | ||
39 | |||
40 | def details_cb(self, button, parent, protocol): | ||
41 | dialog = ProxyDetailsDialog(title = protocol.upper() + " Proxy Details", | ||
42 | user = self.configuration.proxies[protocol][1], | ||
43 | passwd = self.configuration.proxies[protocol][2], | ||
44 | parent = parent, | ||
45 | flags = gtk.DIALOG_MODAL | ||
46 | | gtk.DIALOG_DESTROY_WITH_PARENT | ||
47 | | gtk.DIALOG_NO_SEPARATOR) | ||
48 | dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK) | ||
49 | response = dialog.run() | ||
50 | if response == gtk.RESPONSE_OK: | ||
51 | self.configuration.proxies[protocol][1] = dialog.user | ||
52 | self.configuration.proxies[protocol][2] = dialog.passwd | ||
53 | self.refresh_proxy_components() | ||
54 | dialog.destroy() | ||
55 | |||
56 | def set_save_button(self, button): | ||
57 | self.save_button = button | ||
58 | |||
59 | def rootfs_combo_changed_cb(self, rootfs_combo, all_package_format, check_hbox): | ||
60 | combo_item = self.rootfs_combo.get_active_text() | ||
61 | modified = False | ||
62 | for child in check_hbox.get_children(): | ||
63 | if isinstance(child, gtk.CheckButton): | ||
64 | check_hbox.remove(child) | ||
65 | modified = True | ||
66 | for format in all_package_format: | ||
67 | if format != combo_item: | ||
68 | check_button = gtk.CheckButton(format) | ||
69 | check_hbox.pack_start(check_button, expand=False, fill=False) | ||
70 | modified = True | ||
71 | if modified: | ||
72 | check_hbox.remove(self.pkgfmt_info) | ||
73 | check_hbox.pack_start(self.pkgfmt_info, expand=False, fill=False) | ||
74 | check_hbox.show_all() | ||
75 | |||
76 | def gen_pkgfmt_widget(self, curr_package_format, all_package_format, tooltip_combo="", tooltip_extra=""): | ||
77 | pkgfmt_vbox = gtk.VBox(False, 6) | ||
78 | |||
79 | label = self.gen_label_widget("Root file system package format") | ||
80 | pkgfmt_vbox.pack_start(label, expand=False, fill=False) | ||
81 | |||
82 | rootfs_format = "" | ||
83 | if curr_package_format: | ||
84 | rootfs_format = curr_package_format.split()[0] | ||
85 | |||
86 | rootfs_format_widget, rootfs_combo = self.gen_combo_widget(rootfs_format, all_package_format, tooltip_combo) | ||
87 | pkgfmt_vbox.pack_start(rootfs_format_widget, expand=False, fill=False) | ||
88 | |||
89 | label = self.gen_label_widget("Additional package formats") | ||
90 | pkgfmt_vbox.pack_start(label, expand=False, fill=False) | ||
91 | |||
92 | check_hbox = gtk.HBox(False, 12) | ||
93 | pkgfmt_vbox.pack_start(check_hbox, expand=False, fill=False) | ||
94 | for format in all_package_format: | ||
95 | if format != rootfs_format: | ||
96 | check_button = gtk.CheckButton(format) | ||
97 | is_active = (format in curr_package_format.split()) | ||
98 | check_button.set_active(is_active) | ||
99 | check_hbox.pack_start(check_button, expand=False, fill=False) | ||
100 | |||
101 | self.pkgfmt_info = HobInfoButton(tooltip_extra, self) | ||
102 | check_hbox.pack_start(self.pkgfmt_info, expand=False, fill=False) | ||
103 | |||
104 | rootfs_combo.connect("changed", self.rootfs_combo_changed_cb, all_package_format, check_hbox) | ||
105 | |||
106 | pkgfmt_vbox.show_all() | ||
107 | |||
108 | return pkgfmt_vbox, rootfs_combo, check_hbox | ||
109 | |||
110 | def __init__(self, title, configuration, all_image_types, | ||
111 | all_package_formats, all_distros, all_sdk_machines, | ||
112 | max_threads, parent, flags, buttons=None): | ||
113 | super(AdvancedSettingsDialog, self).__init__(title, parent, flags, buttons) | ||
114 | |||
115 | # class members from other objects | ||
116 | # bitbake settings from Builder.Configuration | ||
117 | self.configuration = configuration | ||
118 | self.image_types = all_image_types | ||
119 | self.all_package_formats = all_package_formats | ||
120 | self.all_distros = all_distros[:] | ||
121 | self.all_sdk_machines = all_sdk_machines | ||
122 | self.max_threads = max_threads | ||
123 | |||
124 | # class members for internal use | ||
125 | self.distro_combo = None | ||
126 | self.dldir_text = None | ||
127 | self.sstatedir_text = None | ||
128 | self.sstatemirror_text = None | ||
129 | self.bb_spinner = None | ||
130 | self.pmake_spinner = None | ||
131 | self.rootfs_size_spinner = None | ||
132 | self.extra_size_spinner = None | ||
133 | self.gplv3_checkbox = None | ||
134 | self.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 | |||
23 | import gtk | ||
24 | |||
25 | """ | ||
26 | The following are convenience classes for implementing GNOME HIG compliant | ||
27 | BitBake GUI's | ||
28 | In summary: spacing = 12px, border-width = 6px | ||
29 | """ | ||
30 | |||
31 | class 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 | |||
23 | import glib | ||
24 | import gtk | ||
25 | from bb.ui.crumbs.hobwidget import HobIconChecker | ||
26 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
27 | |||
28 | """ | ||
29 | The following are convenience classes for implementing GNOME HIG compliant | ||
30 | BitBake GUI's | ||
31 | In summary: spacing = 12px, border-width = 6px | ||
32 | """ | ||
33 | |||
34 | class 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 | |||
23 | import glob | ||
24 | import gtk | ||
25 | import gobject | ||
26 | import os | ||
27 | import re | ||
28 | import shlex | ||
29 | import subprocess | ||
30 | import tempfile | ||
31 | from bb.ui.crumbs.hobwidget import hic, HobButton | ||
32 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
33 | import bb.ui.crumbs.utils | ||
34 | import bb.process | ||
35 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
36 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
37 | |||
38 | """ | ||
39 | The following are convenience classes for implementing GNOME HIG compliant | ||
40 | BitBake GUI's | ||
41 | In summary: spacing = 12px, border-width = 6px | ||
42 | """ | ||
43 | |||
44 | class 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 | |||
23 | import gtk | ||
24 | import gobject | ||
25 | import os | ||
26 | from bb.ui.crumbs.hobwidget import HobViewTable, HobInfoButton, HobButton, HobAltButton | ||
27 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
28 | from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog | ||
29 | |||
30 | """ | ||
31 | The following are convenience classes for implementing GNOME HIG compliant | ||
32 | BitBake GUI's | ||
33 | In summary: spacing = 12px, border-width = 6px | ||
34 | """ | ||
35 | |||
36 | class 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 | |||
23 | import gtk | ||
24 | import gobject | ||
25 | import os | ||
26 | import tempfile | ||
27 | from bb.ui.crumbs.hobwidget import hic, HobButton, HobAltButton | ||
28 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
29 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
30 | |||
31 | """ | ||
32 | The following are convenience classes for implementing GNOME HIG compliant | ||
33 | BitBake GUI's | ||
34 | In summary: spacing = 12px, border-width = 6px | ||
35 | """ | ||
36 | |||
37 | class 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 | # | ||
60 | class 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 | |||
23 | import gtk | ||
24 | import gobject | ||
25 | from bb.ui.crumbs.hobwidget import HobAltButton | ||
26 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
27 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
28 | |||
29 | """ | ||
30 | The following are convenience classes for implementing GNOME HIG compliant | ||
31 | BitBake GUI's | ||
32 | In summary: spacing = 12px, border-width = 6px | ||
33 | """ | ||
34 | |||
35 | class 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 | |||
23 | import gtk | ||
24 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
25 | |||
26 | """ | ||
27 | The following are convenience classes for implementing GNOME HIG compliant | ||
28 | BitBake GUI's | ||
29 | In summary: spacing = 12px, border-width = 6px | ||
30 | """ | ||
31 | |||
32 | class ProxyDetailsDialog (CrumbsDialog): | ||
33 | |||
34 | def __init__(self, title, user, passwd, parent, flags, buttons=None): | ||
35 | super(ProxyDetailsDialog, self).__init__(title, parent, flags, buttons) | ||
36 | self.connect("response", self.response_cb) | ||
37 | |||
38 | self.auth = not (user == None or passwd == None or user == "") | ||
39 | self.user = user or "" | ||
40 | self.passwd = passwd or "" | ||
41 | |||
42 | # create visual elements on the dialog | ||
43 | self.create_visual_elements() | ||
44 | |||
45 | def create_visual_elements(self): | ||
46 | self.auth_checkbox = gtk.CheckButton("Use authentication") | ||
47 | self.auth_checkbox.set_tooltip_text("Check this box to set the username and the password") | ||
48 | self.auth_checkbox.set_active(self.auth) | ||
49 | self.auth_checkbox.connect("toggled", self.auth_checkbox_toggled_cb) | ||
50 | self.vbox.pack_start(self.auth_checkbox, expand=False, fill=False) | ||
51 | |||
52 | hbox = gtk.HBox(False, 6) | ||
53 | self.user_label = gtk.Label("Username:") | ||
54 | self.user_text = gtk.Entry() | ||
55 | self.user_text.set_text(self.user) | ||
56 | hbox.pack_start(self.user_label, expand=False, fill=False) | ||
57 | hbox.pack_end(self.user_text, expand=False, fill=False) | ||
58 | self.vbox.pack_start(hbox, expand=False, fill=False) | ||
59 | |||
60 | hbox = gtk.HBox(False, 6) | ||
61 | self.passwd_label = gtk.Label("Password:") | ||
62 | self.passwd_text = gtk.Entry() | ||
63 | self.passwd_text.set_text(self.passwd) | ||
64 | hbox.pack_start(self.passwd_label, expand=False, fill=False) | ||
65 | hbox.pack_end(self.passwd_text, expand=False, fill=False) | ||
66 | self.vbox.pack_start(hbox, expand=False, fill=False) | ||
67 | |||
68 | self.refresh_auth_components() | ||
69 | self.show_all() | ||
70 | |||
71 | def refresh_auth_components(self): | ||
72 | self.user_label.set_sensitive(self.auth) | ||
73 | self.user_text.set_editable(self.auth) | ||
74 | self.user_text.set_sensitive(self.auth) | ||
75 | self.passwd_label.set_sensitive(self.auth) | ||
76 | self.passwd_text.set_editable(self.auth) | ||
77 | self.passwd_text.set_sensitive(self.auth) | ||
78 | |||
79 | def auth_checkbox_toggled_cb(self, button): | ||
80 | self.auth = self.auth_checkbox.get_active() | ||
81 | self.refresh_auth_components() | ||
82 | |||
83 | def response_cb(self, dialog, response_id): | ||
84 | if response_id == gtk.RESPONSE_OK: | ||
85 | if self.auth: | ||
86 | self.user = self.user_text.get_text() | ||
87 | self.passwd = self.passwd_text.get_text() | ||
88 | else: | ||
89 | self.user = None | ||
90 | self.passwd = None | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/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 | |||
23 | import gtk | ||
24 | import os | ||
25 | from bb.ui.crumbs.hobwidget import HobInfoButton, HobButton, HobAltButton | ||
26 | |||
27 | """ | ||
28 | The following are convenience classes for implementing GNOME HIG compliant | ||
29 | BitBake GUI's | ||
30 | In summary: spacing = 12px, border-width = 6px | ||
31 | """ | ||
32 | |||
33 | class 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 | |||
23 | import gtk | ||
24 | import gobject | ||
25 | import hashlib | ||
26 | from bb.ui.crumbs.hobwidget import hic, HobInfoButton, HobButton, HobAltButton | ||
27 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
28 | from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper | ||
29 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
30 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
31 | from bb.ui.crumbs.hig.proxydetailsdialog import ProxyDetailsDialog | ||
32 | |||
33 | """ | ||
34 | The following are convenience classes for implementing GNOME HIG compliant | ||
35 | BitBake GUI's | ||
36 | In summary: spacing = 12px, border-width = 6px | ||
37 | """ | ||
38 | |||
39 | class SimpleSettingsDialog (CrumbsDialog, SettingsUIHelper): | ||
40 | |||
41 | (BUILD_ENV_PAGE_ID, | ||
42 | SHARED_STATE_PAGE_ID, | ||
43 | PROXIES_PAGE_ID, | ||
44 | OTHERS_PAGE_ID) = range(4) | ||
45 | |||
46 | (TEST_NETWORK_NONE, | ||
47 | TEST_NETWORK_INITIAL, | ||
48 | TEST_NETWORK_RUNNING, | ||
49 | TEST_NETWORK_PASSED, | ||
50 | TEST_NETWORK_FAILED, | ||
51 | TEST_NETWORK_CANCELED) = range(6) | ||
52 | |||
53 | 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 | |||
26 | from bb.ui.crumbs.hobwidget import hic, HobViewTable, HobAltButton, HobButton | 26 | from bb.ui.crumbs.hobwidget import hic, HobViewTable, HobAltButton, HobButton |
27 | from bb.ui.crumbs.hobpages import HobPage | 27 | from bb.ui.crumbs.hobpages import HobPage |
28 | import subprocess | 28 | import subprocess |
29 | from bb.ui.crumbs.hig import CrumbsDialog | 29 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog |
30 | from bb.ui.crumbs.hobthreads import OpeningLogThread | 30 | from bb.ui.crumbs.hobthreads import OpeningLogThread |
31 | from bb.ui.crumbs.hig import OpeningLogDialog | 31 | from 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 | |||
27 | from bb.ui.crumbs.hoblistmodel import PackageListModel | 27 | from bb.ui.crumbs.hoblistmodel import PackageListModel |
28 | from bb.ui.crumbs.hobpages import HobPage | 28 | from bb.ui.crumbs.hobpages import HobPage |
29 | from bb.ui.crumbs.hobthreads import OpeningLogThread | 29 | from bb.ui.crumbs.hobthreads import OpeningLogThread |
30 | from bb.ui.crumbs.hig import OpeningLogDialog | 30 | from bb.ui.crumbs.hig.openinglogdialog import OpeningLogDialog |
31 | 31 | ||
32 | # | 32 | # |
33 | # PackageSelectionPage | 33 | # PackageSelectionPage |