summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/ui/crumbs/hig
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/hig')
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/__init__.py0
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/advancedsettingsdialog.py340
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py44
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/crumbsmessagedialog.py95
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py215
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py172
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py296
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/parsingwarningsdialog.py163
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/propertydialog.py451
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py90
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/retrieveimagedialog.py51
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/saveimagedialog.py160
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/settingsuihelper.py122
-rw-r--r--bitbake/lib/bb/ui/crumbs/hig/simplesettingsdialog.py893
14 files changed, 3092 insertions, 0 deletions
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..5542471c7b
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/advancedsettingsdialog.py
@@ -0,0 +1,340 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011-2012 Intel Corporation
5#
6# Authored by Joshua Lock <josh@linux.intel.com>
7# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
8# Authored by Shane Wang <shane.wang@intel.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23import gtk
24import hashlib
25from bb.ui.crumbs.hobwidget import HobInfoButton, HobButton
26from bb.ui.crumbs.progressbar import HobProgressBar
27from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper
28from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
29from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
30from bb.ui.crumbs.hig.proxydetailsdialog import ProxyDetailsDialog
31
32"""
33The following are convenience classes for implementing GNOME HIG compliant
34BitBake GUI's
35In summary: spacing = 12px, border-width = 6px
36"""
37
38class AdvancedSettingsDialog (CrumbsDialog, SettingsUIHelper):
39
40 def details_cb(self, button, parent, protocol):
41 dialog = ProxyDetailsDialog(title = protocol.upper() + " Proxy Details",
42 user = self.configuration.proxies[protocol][1],
43 passwd = self.configuration.proxies[protocol][2],
44 parent = parent,
45 flags = gtk.DIALOG_MODAL
46 | gtk.DIALOG_DESTROY_WITH_PARENT
47 | gtk.DIALOG_NO_SEPARATOR)
48 dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
49 response = dialog.run()
50 if response == gtk.RESPONSE_OK:
51 self.configuration.proxies[protocol][1] = dialog.user
52 self.configuration.proxies[protocol][2] = dialog.passwd
53 self.refresh_proxy_components()
54 dialog.destroy()
55
56 def set_save_button(self, button):
57 self.save_button = button
58
59 def rootfs_combo_changed_cb(self, rootfs_combo, all_package_format, check_hbox):
60 combo_item = self.rootfs_combo.get_active_text()
61 modified = False
62 for child in check_hbox.get_children():
63 if isinstance(child, gtk.CheckButton):
64 check_hbox.remove(child)
65 modified = True
66 for format in all_package_format:
67 if format != combo_item:
68 check_button = gtk.CheckButton(format)
69 check_hbox.pack_start(check_button, expand=False, fill=False)
70 modified = True
71 if modified:
72 check_hbox.remove(self.pkgfmt_info)
73 check_hbox.pack_start(self.pkgfmt_info, expand=False, fill=False)
74 check_hbox.show_all()
75
76 def gen_pkgfmt_widget(self, curr_package_format, all_package_format, tooltip_combo="", tooltip_extra=""):
77 pkgfmt_vbox = gtk.VBox(False, 6)
78
79 label = self.gen_label_widget("Root file system package format")
80 pkgfmt_vbox.pack_start(label, expand=False, fill=False)
81
82 rootfs_format = ""
83 if curr_package_format:
84 rootfs_format = curr_package_format.split()[0]
85
86 rootfs_format_widget, rootfs_combo = self.gen_combo_widget(rootfs_format, all_package_format, tooltip_combo)
87 pkgfmt_vbox.pack_start(rootfs_format_widget, expand=False, fill=False)
88
89 label = self.gen_label_widget("Additional package formats")
90 pkgfmt_vbox.pack_start(label, expand=False, fill=False)
91
92 check_hbox = gtk.HBox(False, 12)
93 pkgfmt_vbox.pack_start(check_hbox, expand=False, fill=False)
94 for format in all_package_format:
95 if format != rootfs_format:
96 check_button = gtk.CheckButton(format)
97 is_active = (format in curr_package_format.split())
98 check_button.set_active(is_active)
99 check_hbox.pack_start(check_button, expand=False, fill=False)
100
101 self.pkgfmt_info = HobInfoButton(tooltip_extra, self)
102 check_hbox.pack_start(self.pkgfmt_info, expand=False, fill=False)
103
104 rootfs_combo.connect("changed", self.rootfs_combo_changed_cb, all_package_format, check_hbox)
105
106 pkgfmt_vbox.show_all()
107
108 return pkgfmt_vbox, rootfs_combo, check_hbox
109
110 def __init__(self, title, configuration, all_image_types,
111 all_package_formats, all_distros, all_sdk_machines,
112 max_threads, parent, flags, buttons=None):
113 super(AdvancedSettingsDialog, self).__init__(title, parent, flags, buttons)
114
115 # class members from other objects
116 # bitbake settings from Builder.Configuration
117 self.configuration = configuration
118 self.image_types = all_image_types
119 self.all_package_formats = all_package_formats
120 self.all_distros = all_distros[:]
121 self.all_sdk_machines = all_sdk_machines
122 self.max_threads = max_threads
123
124 # class members for internal use
125 self.distro_combo = None
126 self.dldir_text = None
127 self.sstatedir_text = None
128 self.sstatemirror_text = None
129 self.bb_spinner = None
130 self.pmake_spinner = None
131 self.rootfs_size_spinner = None
132 self.extra_size_spinner = None
133 self.gplv3_checkbox = None
134 self.sdk_checkbox = None
135 self.image_types_checkbuttons = {}
136
137 self.md5 = self.config_md5()
138 self.settings_changed = False
139
140 # create visual elements on the dialog
141 self.save_button = None
142 self.create_visual_elements()
143 self.connect("response", self.response_cb)
144
145 def _get_sorted_value(self, var):
146 return " ".join(sorted(str(var).split())) + "\n"
147
148 def config_md5(self):
149 data = ""
150 data += ("PACKAGE_CLASSES: " + self.configuration.curr_package_format + '\n')
151 data += ("DISTRO: " + self._get_sorted_value(self.configuration.curr_distro))
152 data += ("IMAGE_ROOTFS_SIZE: " + self._get_sorted_value(self.configuration.image_rootfs_size))
153 data += ("IMAGE_EXTRA_SIZE: " + self._get_sorted_value(self.configuration.image_extra_size))
154 data += ("INCOMPATIBLE_LICENSE: " + self._get_sorted_value(self.configuration.incompat_license))
155 data += ("SDK_MACHINE: " + self._get_sorted_value(self.configuration.curr_sdk_machine))
156 data += ("TOOLCHAIN_BUILD: " + self._get_sorted_value(self.configuration.toolchain_build))
157 data += ("IMAGE_FSTYPES: " + self._get_sorted_value(self.configuration.image_fstypes))
158 return hashlib.md5(data).hexdigest()
159
160 def create_visual_elements(self):
161 self.nb = gtk.Notebook()
162 self.nb.set_show_tabs(True)
163 self.nb.append_page(self.create_image_types_page(), gtk.Label("Image types"))
164 self.nb.append_page(self.create_output_page(), gtk.Label("Output"))
165 self.nb.set_current_page(0)
166 self.vbox.pack_start(self.nb, expand=True, fill=True)
167 self.vbox.pack_end(gtk.HSeparator(), expand=True, fill=True)
168
169 self.show_all()
170
171 def get_num_checked_image_types(self):
172 total = 0
173 for b in self.image_types_checkbuttons.values():
174 if b.get_active():
175 total = total + 1
176 return total
177
178 def set_save_button_state(self):
179 if self.save_button:
180 self.save_button.set_sensitive(self.get_num_checked_image_types() > 0)
181
182 def image_type_checkbutton_clicked_cb(self, button):
183 self.set_save_button_state()
184 if self.get_num_checked_image_types() == 0:
185 # Show an error dialog
186 lbl = "<b>Select an image type</b>\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,"<b>Distro</b>" + "*" + 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("<b>Image types</b>" + "*" + 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 if image_type == "live":
238 self.image_types_checkbuttons[image_type].set_tooltip_text("Build iso and hddimg images")
239 else:
240 self.image_types_checkbuttons[image_type].set_tooltip_text("Build a%s %s image" % (article, image_type))
241 table.attach(self.image_types_checkbuttons[image_type], j - 1, j + 3, i, i + 1)
242 if image_type in self.configuration.image_fstypes.split():
243 self.image_types_checkbuttons[image_type].set_active(True)
244 i += 1
245 if i > rows:
246 i = 1
247 j = j + 4
248
249 main_vbox.pack_start(advanced_vbox, expand=False, fill=False)
250 self.set_save_button_state()
251
252 return main_vbox
253
254 def create_output_page(self):
255 advanced_vbox = gtk.VBox(False, 6)
256 advanced_vbox.set_border_width(6)
257
258 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Package format</span>'), expand=False, fill=False)
259 sub_vbox = gtk.VBox(False, 6)
260 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
261 tooltip_combo = "Selects the package format used to generate rootfs."
262 tooltip_extra = "Selects extra package formats to build"
263 pkgfmt_widget, self.rootfs_combo, self.check_hbox = self.gen_pkgfmt_widget(self.configuration.curr_package_format, self.all_package_formats,"<b>Root file system package format</b>" + "*" + tooltip_combo,"<b>Additional package formats</b>" + "*" + tooltip_extra)
264 sub_vbox.pack_start(pkgfmt_widget, expand=False, fill=False)
265
266 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Image size</span>'), expand=False, fill=False)
267 sub_vbox = gtk.VBox(False, 6)
268 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
269 label = self.gen_label_widget("Image basic size (in MB)")
270 tooltip = "Defines the size for the generated image. The OpenEmbedded build system determines the final size for the generated image using an algorithm that takes into account the initial disk space used for the generated image, the Image basic size value, and the Additional free space value.\n\nFor more information, check the <a href=\"http://www.yoctoproject.org/docs/current/poky-ref-manual/poky-ref-manual.html#var-IMAGE_ROOTFS_SIZE\">Yocto Project Reference Manual</a>."
271 rootfs_size_widget, self.rootfs_size_spinner = self.gen_spinner_widget(int(self.configuration.image_rootfs_size*1.0/1024), 0, 65536,"<b>Image basic size</b>" + "*" + tooltip)
272 sub_vbox.pack_start(label, expand=False, fill=False)
273 sub_vbox.pack_start(rootfs_size_widget, expand=False, fill=False)
274
275 sub_vbox = gtk.VBox(False, 6)
276 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
277 label = self.gen_label_widget("Additional free space (in MB)")
278 tooltip = "Sets extra free disk space to be added to the generated image. Use this variable when you want to ensure that a specific amount of free disk space is available on a device after an image is installed and running."
279 extra_size_widget, self.extra_size_spinner = self.gen_spinner_widget(int(self.configuration.image_extra_size*1.0/1024), 0, 65536,"<b>Additional free space</b>" + "*" + tooltip)
280 sub_vbox.pack_start(label, expand=False, fill=False)
281 sub_vbox.pack_start(extra_size_widget, expand=False, fill=False)
282
283 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Licensing</span>'), expand=False, fill=False)
284 self.gplv3_checkbox = gtk.CheckButton("Exclude GPLv3 packages")
285 self.gplv3_checkbox.set_tooltip_text("Check this box to prevent GPLv3 packages from being included in your image")
286 if "GPLv3" in self.configuration.incompat_license.split():
287 self.gplv3_checkbox.set_active(True)
288 else:
289 self.gplv3_checkbox.set_active(False)
290 advanced_vbox.pack_start(self.gplv3_checkbox, expand=False, fill=False)
291
292 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">SDK</span>'), expand=False, fill=False)
293 sub_hbox = gtk.HBox(False, 6)
294 advanced_vbox.pack_start(sub_hbox, expand=False, fill=False)
295 self.sdk_checkbox = gtk.CheckButton("Populate SDK")
296 tooltip = "Check this box to generate an SDK tarball that consists of the cross-toolchain and a sysroot that contains development packages for your image."
297 self.sdk_checkbox.set_tooltip_text(tooltip)
298 self.sdk_checkbox.set_active(self.configuration.toolchain_build)
299 sub_hbox.pack_start(self.sdk_checkbox, expand=False, fill=False)
300
301 tooltip = "Select the host platform for which you want to run the toolchain contained in the SDK tarball."
302 sdk_machine_widget, self.sdk_machine_combo = self.gen_combo_widget(self.configuration.curr_sdk_machine, self.all_sdk_machines,"<b>Populate SDK</b>" + "*" + tooltip)
303 sub_hbox.pack_start(sdk_machine_widget, expand=False, fill=False)
304
305 return advanced_vbox
306
307 def response_cb(self, dialog, response_id):
308 package_format = []
309 package_format.append(self.rootfs_combo.get_active_text())
310 for child in self.check_hbox:
311 if isinstance(child, gtk.CheckButton) and child.get_active():
312 package_format.append(child.get_label())
313 self.configuration.curr_package_format = " ".join(package_format)
314
315 distro = self.distro_combo.get_active_text()
316 if distro == "Default":
317 distro = "defaultsetup"
318 self.configuration.curr_distro = distro
319 self.configuration.image_rootfs_size = self.rootfs_size_spinner.get_value_as_int() * 1024
320 self.configuration.image_extra_size = self.extra_size_spinner.get_value_as_int() * 1024
321
322 self.configuration.image_fstypes = ""
323 for image_type in self.image_types:
324 if self.image_types_checkbuttons[image_type].get_active():
325 self.configuration.image_fstypes += (" " + image_type)
326 self.configuration.image_fstypes.strip()
327
328 if self.gplv3_checkbox.get_active():
329 if "GPLv3" not in self.configuration.incompat_license.split():
330 self.configuration.incompat_license += " GPLv3"
331 else:
332 if "GPLv3" in self.configuration.incompat_license.split():
333 self.configuration.incompat_license = self.configuration.incompat_license.split().remove("GPLv3")
334 self.configuration.incompat_license = " ".join(self.configuration.incompat_license or [])
335 self.configuration.incompat_license = self.configuration.incompat_license.strip()
336
337 self.configuration.toolchain_build = self.sdk_checkbox.get_active()
338 self.configuration.curr_sdk_machine = self.sdk_machine_combo.get_active_text()
339 md5 = self.config_md5()
340 self.settings_changed = (self.md5 != md5)
diff --git a/bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py
new file mode 100644
index 0000000000..c679f9a070
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py
@@ -0,0 +1,44 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011-2012 Intel Corporation
5#
6# Authored by Joshua Lock <josh@linux.intel.com>
7# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
8# Authored by Shane Wang <shane.wang@intel.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23import gtk
24
25"""
26The following are convenience classes for implementing GNOME HIG compliant
27BitBake GUI's
28In summary: spacing = 12px, border-width = 6px
29"""
30
31class CrumbsDialog(gtk.Dialog):
32 """
33 A GNOME HIG compliant dialog widget.
34 Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons
35 """
36 def __init__(self, title="", parent=None, flags=0, buttons=None):
37 super(CrumbsDialog, self).__init__(title, parent, flags, buttons)
38
39 self.set_property("has-separator", False) # note: deprecated in 2.22
40
41 self.set_border_width(6)
42 self.vbox.set_property("spacing", 12)
43 self.action_area.set_property("spacing", 12)
44 self.action_area.set_property("border-width", 6)
diff --git a/bitbake/lib/bb/ui/crumbs/hig/crumbsmessagedialog.py b/bitbake/lib/bb/ui/crumbs/hig/crumbsmessagedialog.py
new file mode 100644
index 0000000000..097ce7b027
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/crumbsmessagedialog.py
@@ -0,0 +1,95 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011-2012 Intel Corporation
5#
6# Authored by Joshua Lock <josh@linux.intel.com>
7# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
8# Authored by Shane Wang <shane.wang@intel.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23import glib
24import gtk
25from bb.ui.crumbs.hobwidget import HobIconChecker
26from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
27
28"""
29The following are convenience classes for implementing GNOME HIG compliant
30BitBake GUI's
31In summary: spacing = 12px, border-width = 6px
32"""
33
34class CrumbsMessageDialog(CrumbsDialog):
35 """
36 A GNOME HIG compliant dialog widget.
37 Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons
38 """
39 def __init__(self, parent=None, label="", icon=gtk.STOCK_INFO, msg=""):
40 super(CrumbsMessageDialog, self).__init__("", parent, gtk.DIALOG_MODAL)
41
42 self.set_border_width(6)
43 self.vbox.set_property("spacing", 12)
44 self.action_area.set_property("spacing", 12)
45 self.action_area.set_property("border-width", 6)
46
47 first_column = gtk.HBox(spacing=12)
48 first_column.set_property("border-width", 6)
49 first_column.show()
50 self.vbox.add(first_column)
51
52 self.icon = gtk.Image()
53 # We have our own Info icon which should be used in preference of the stock icon
54 self.icon_chk = HobIconChecker()
55 self.icon.set_from_stock(self.icon_chk.check_stock_icon(icon), gtk.ICON_SIZE_DIALOG)
56 self.icon.set_property("yalign", 0.00)
57 self.icon.show()
58 first_column.pack_start(self.icon, expand=False, fill=True, padding=0)
59
60 if 0 <= len(msg) < 200:
61 lbl = label + "%s" % glib.markup_escape_text(msg)
62 self.label_short = gtk.Label()
63 self.label_short.set_use_markup(True)
64 self.label_short.set_line_wrap(True)
65 self.label_short.set_markup(lbl)
66 self.label_short.set_property("yalign", 0.00)
67 self.label_short.show()
68 first_column.add(self.label_short)
69 else:
70 second_row = gtk.VBox(spacing=12)
71 second_row.set_property("border-width", 6)
72 self.label_long = gtk.Label()
73 self.label_long.set_use_markup(True)
74 self.label_long.set_line_wrap(True)
75 self.label_long.set_markup(label)
76 self.label_long.set_alignment(0.0, 0.0)
77 second_row.pack_start(self.label_long, expand=False, fill=False, padding=0)
78 self.label_long.show()
79 self.textWindow = gtk.ScrolledWindow()
80 self.textWindow.set_shadow_type(gtk.SHADOW_IN)
81 self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
82 self.msgView = gtk.TextView()
83 self.msgView.set_editable(False)
84 self.msgView.set_wrap_mode(gtk.WRAP_WORD)
85 self.msgView.set_cursor_visible(False)
86 self.msgView.set_size_request(300, 300)
87 self.buf = gtk.TextBuffer()
88 self.buf.set_text(msg)
89 self.msgView.set_buffer(self.buf)
90 self.textWindow.add(self.msgView)
91 self.msgView.show()
92 second_row.add(self.textWindow)
93 self.textWindow.show()
94 first_column.add(second_row)
95 second_row.show()
diff --git a/bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py b/bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py
new file mode 100644
index 0000000000..bc1efbbfaf
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py
@@ -0,0 +1,215 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011-2012 Intel Corporation
5#
6# Authored by Joshua Lock <josh@linux.intel.com>
7# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
8# Authored by Shane Wang <shane.wang@intel.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23import glob
24import gtk
25import gobject
26import os
27import re
28import shlex
29import subprocess
30import tempfile
31from bb.ui.crumbs.hobwidget import hic, HobButton
32from bb.ui.crumbs.progressbar import HobProgressBar
33import bb.ui.crumbs.utils
34import bb.process
35from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
36from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
37
38"""
39The following are convenience classes for implementing GNOME HIG compliant
40BitBake GUI's
41In summary: spacing = 12px, border-width = 6px
42"""
43
44class DeployImageDialog (CrumbsDialog):
45
46 __dummy_usb__ = "--select a usb drive--"
47
48 def __init__(self, title, image_path, parent, flags, buttons=None, standalone=False):
49 super(DeployImageDialog, self).__init__(title, parent, flags, buttons)
50
51 self.image_path = image_path
52 self.standalone = standalone
53
54 self.create_visual_elements()
55 self.connect("response", self.response_cb)
56
57 def create_visual_elements(self):
58 self.set_size_request(600, 400)
59 label = gtk.Label()
60 label.set_alignment(0.0, 0.5)
61 markup = "<span font_desc='12'>The image to be written into usb drive:</span>"
62 label.set_markup(markup)
63 self.vbox.pack_start(label, expand=False, fill=False, padding=2)
64
65 table = gtk.Table(2, 10, False)
66 table.set_col_spacings(5)
67 table.set_row_spacings(5)
68 self.vbox.pack_start(table, expand=True, fill=True)
69
70 scroll = gtk.ScrolledWindow()
71 scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
72 scroll.set_shadow_type(gtk.SHADOW_IN)
73 tv = gtk.TextView()
74 tv.set_editable(False)
75 tv.set_wrap_mode(gtk.WRAP_WORD)
76 tv.set_cursor_visible(False)
77 self.buf = gtk.TextBuffer()
78 self.buf.set_text(self.image_path)
79 tv.set_buffer(self.buf)
80 scroll.add(tv)
81 table.attach(scroll, 0, 10, 0, 1)
82
83 # There are 2 ways to use DeployImageDialog
84 # One way is that called by HOB when the 'Deploy Image' button is clicked
85 # The other way is that called by a standalone script.
86 # Following block of codes handles the latter way. It adds a 'Select Image' button and
87 # emit a signal when the button is clicked.
88 if self.standalone:
89 gobject.signal_new("select_image_clicked", self, gobject.SIGNAL_RUN_FIRST,
90 gobject.TYPE_NONE, ())
91 icon = gtk.Image()
92 pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_IMAGES_DISPLAY_FILE)
93 icon.set_from_pixbuf(pix_buffer)
94 button = gtk.Button("Select Image")
95 button.set_image(icon)
96 #button.set_size_request(140, 50)
97 table.attach(button, 9, 10, 1, 2, gtk.FILL, 0, 0, 0)
98 button.connect("clicked", self.select_image_button_clicked_cb)
99
100 separator = gtk.HSeparator()
101 self.vbox.pack_start(separator, expand=False, fill=False, padding=10)
102
103 self.usb_desc = gtk.Label()
104 self.usb_desc.set_alignment(0.0, 0.5)
105 markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>"
106 self.usb_desc.set_markup(markup)
107
108 self.usb_combo = gtk.combo_box_new_text()
109 self.usb_combo.connect("changed", self.usb_combo_changed_cb)
110 model = self.usb_combo.get_model()
111 model.clear()
112 self.usb_combo.append_text(self.__dummy_usb__)
113 for usb in self.find_all_usb_devices():
114 self.usb_combo.append_text("/dev/" + usb)
115 self.usb_combo.set_active(0)
116 self.vbox.pack_start(self.usb_combo, expand=False, fill=False)
117 self.vbox.pack_start(self.usb_desc, expand=False, fill=False, padding=2)
118
119 self.progress_bar = HobProgressBar()
120 self.vbox.pack_start(self.progress_bar, expand=False, fill=False)
121 separator = gtk.HSeparator()
122 self.vbox.pack_start(separator, expand=False, fill=True, padding=10)
123
124 self.vbox.show_all()
125 self.progress_bar.hide()
126
127 def set_image_text_buffer(self, image_path):
128 self.buf.set_text(image_path)
129
130 def set_image_path(self, image_path):
131 self.image_path = image_path
132
133 def popen_read(self, cmd):
134 tmpout, errors = bb.process.run("%s" % cmd)
135 return tmpout.strip()
136
137 def find_all_usb_devices(self):
138 usb_devs = [ os.readlink(u)
139 for u in glob.glob('/dev/disk/by-id/usb*')
140 if not re.search(r'part\d+', u) ]
141 return [ '%s' % u[u.rfind('/')+1:] for u in usb_devs ]
142
143 def get_usb_info(self, dev):
144 return "%s %s" % \
145 (self.popen_read('cat /sys/class/block/%s/device/vendor' % dev),
146 self.popen_read('cat /sys/class/block/%s/device/model' % dev))
147
148 def select_image_button_clicked_cb(self, button):
149 self.emit('select_image_clicked')
150
151 def usb_combo_changed_cb(self, usb_combo):
152 combo_item = self.usb_combo.get_active_text()
153 if not combo_item or combo_item == self.__dummy_usb__:
154 markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>"
155 self.usb_desc.set_markup(markup)
156 else:
157 markup = "<span font_desc='12'>" + self.get_usb_info(combo_item.lstrip("/dev/")) + "</span>"
158 self.usb_desc.set_markup(markup)
159
160 def response_cb(self, dialog, response_id):
161 if response_id == gtk.RESPONSE_YES:
162 lbl = ''
163 combo_item = self.usb_combo.get_active_text()
164 if combo_item and combo_item != self.__dummy_usb__ and self.image_path:
165 cmdline = bb.ui.crumbs.utils.which_terminal()
166 if cmdline:
167 tmpfile = tempfile.NamedTemporaryFile()
168 cmdline += "\"sudo dd if=" + self.image_path + \
169 " of=" + combo_item + "; echo $? > " + tmpfile.name + "\""
170 subprocess.call(shlex.split(cmdline))
171
172 if int(tmpfile.readline().strip()) == 0:
173 lbl = "<b>Deploy image successfully.</b>"
174 else:
175 lbl = "<b>Failed to deploy image.</b>\nPlease check image <b>%s</b> exists and USB device <b>%s</b> is writable." % (self.image_path, combo_item)
176 tmpfile.close()
177 else:
178 if not self.image_path:
179 lbl = "<b>No selection made.</b>\nYou have not selected an image to deploy."
180 else:
181 lbl = "<b>No selection made.</b>\nYou have not selected a USB device."
182 if len(lbl):
183 crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
184 button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK)
185 HobButton.style_button(button)
186 crumbs_dialog.run()
187 crumbs_dialog.destroy()
188
189 def update_progress_bar(self, title, fraction, status=None):
190 self.progress_bar.update(fraction)
191 self.progress_bar.set_title(title)
192 self.progress_bar.set_rcstyle(status)
193
194 def write_file(self, ifile, ofile):
195 self.progress_bar.reset()
196 self.progress_bar.show()
197
198 f_from = os.open(ifile, os.O_RDONLY)
199 f_to = os.open(ofile, os.O_WRONLY)
200
201 total_size = os.stat(ifile).st_size
202 written_size = 0
203
204 while True:
205 buf = os.read(f_from, 1024*1024)
206 if not buf:
207 break
208 os.write(f_to, buf)
209 written_size += 1024*1024
210 self.update_progress_bar("Writing to usb:", written_size * 1.0/total_size)
211
212 self.update_progress_bar("Writing completed:", 1.0)
213 os.close(f_from)
214 os.close(f_to)
215 self.progress_bar.hide()
diff --git a/bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py b/bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py
new file mode 100644
index 0000000000..21216adc97
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py
@@ -0,0 +1,172 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011-2012 Intel Corporation
5#
6# Authored by Joshua Lock <josh@linux.intel.com>
7# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
8# Authored by Shane Wang <shane.wang@intel.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23import gtk
24import gobject
25import os
26from bb.ui.crumbs.hobwidget import HobViewTable, HobInfoButton, HobButton, HobAltButton
27from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
28from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog
29
30"""
31The following are convenience classes for implementing GNOME HIG compliant
32BitBake GUI's
33In summary: spacing = 12px, border-width = 6px
34"""
35
36class ImageSelectionDialog (CrumbsDialog):
37
38 __columns__ = [{
39 'col_name' : 'Image name',
40 'col_id' : 0,
41 'col_style': 'text',
42 'col_min' : 400,
43 'col_max' : 400
44 }, {
45 'col_name' : 'Select',
46 'col_id' : 1,
47 'col_style': 'radio toggle',
48 'col_min' : 160,
49 'col_max' : 160
50 }]
51
52
53 def __init__(self, image_folder, image_types, title, parent, flags, buttons=None, image_extension = {}):
54 super(ImageSelectionDialog, self).__init__(title, parent, flags, buttons)
55 self.connect("response", self.response_cb)
56
57 self.image_folder = image_folder
58 self.image_types = image_types
59 self.image_list = []
60 self.image_names = []
61 self.image_extension = image_extension
62
63 # create visual elements on the dialog
64 self.create_visual_elements()
65
66 self.image_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN)
67 self.fill_image_store()
68
69 def create_visual_elements(self):
70 hbox = gtk.HBox(False, 6)
71
72 self.vbox.pack_start(hbox, expand=False, fill=False)
73
74 entry = gtk.Entry()
75 entry.set_text(self.image_folder)
76 table = gtk.Table(1, 10, True)
77 table.set_size_request(560, -1)
78 hbox.pack_start(table, expand=False, fill=False)
79 table.attach(entry, 0, 9, 0, 1)
80 image = gtk.Image()
81 image.set_from_stock(gtk.STOCK_OPEN, gtk.ICON_SIZE_BUTTON)
82 open_button = gtk.Button()
83 open_button.set_image(image)
84 open_button.connect("clicked", self.select_path_cb, self, entry)
85 table.attach(open_button, 9, 10, 0, 1)
86
87 self.image_table = HobViewTable(self.__columns__, "Images")
88 self.image_table.set_size_request(-1, 300)
89 self.image_table.connect("toggled", self.toggled_cb)
90 self.image_table.connect_group_selection(self.table_selected_cb)
91 self.image_table.connect("row-activated", self.row_actived_cb)
92 self.vbox.pack_start(self.image_table, expand=True, fill=True)
93
94 self.show_all()
95
96 def change_image_cb(self, model, path, columnid):
97 if not model:
98 return
99 iter = model.get_iter_first()
100 while iter:
101 rowpath = model.get_path(iter)
102 model[rowpath][columnid] = False
103 iter = model.iter_next(iter)
104
105 model[path][columnid] = True
106
107 def toggled_cb(self, table, cell, path, columnid, tree):
108 model = tree.get_model()
109 self.change_image_cb(model, path, columnid)
110
111 def table_selected_cb(self, selection):
112 model, paths = selection.get_selected_rows()
113 if paths:
114 self.change_image_cb(model, paths[0], 1)
115
116 def row_actived_cb(self, tab, model, path):
117 self.change_image_cb(model, path, 1)
118 self.emit('response', gtk.RESPONSE_YES)
119
120 def select_path_cb(self, action, parent, entry):
121 dialog = gtk.FileChooserDialog("", parent,
122 gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
123 text = entry.get_text()
124 dialog.set_current_folder(text if len(text) > 0 else os.getcwd())
125 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
126 HobAltButton.style_button(button)
127 button = dialog.add_button("Open", gtk.RESPONSE_YES)
128 HobButton.style_button(button)
129 response = dialog.run()
130 if response == gtk.RESPONSE_YES:
131 path = dialog.get_filename()
132 entry.set_text(path)
133 self.image_folder = path
134 self.fill_image_store()
135
136 dialog.destroy()
137
138 def fill_image_store(self):
139 self.image_list = []
140 self.image_store.clear()
141 imageset = set()
142 for root, dirs, files in os.walk(self.image_folder):
143 # ignore the sub directories
144 dirs[:] = []
145 for f in files:
146 for image_type in self.image_types:
147 if image_type in self.image_extension:
148 real_types = self.image_extension[image_type]
149 else:
150 real_types = [image_type]
151 for real_image_type in real_types:
152 if f.endswith('.' + real_image_type):
153 imageset.add(f.rsplit('.' + real_image_type)[0].rsplit('.rootfs')[0])
154 self.image_list.append(f)
155
156 for image in imageset:
157 self.image_store.set(self.image_store.append(), 0, image, 1, False)
158
159 self.image_table.set_model(self.image_store)
160
161 def response_cb(self, dialog, response_id):
162 self.image_names = []
163 if response_id == gtk.RESPONSE_YES:
164 iter = self.image_store.get_iter_first()
165 while iter:
166 path = self.image_store.get_path(iter)
167 if self.image_store[path][1]:
168 for f in self.image_list:
169 if f.startswith(self.image_store[path][0] + '.'):
170 self.image_names.append(f)
171 break
172 iter = self.image_store.iter_next(iter)
diff --git a/bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py b/bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py
new file mode 100644
index 0000000000..783ee73c7a
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py
@@ -0,0 +1,296 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011-2012 Intel Corporation
5#
6# Authored by Joshua Lock <josh@linux.intel.com>
7# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
8# Authored by Shane Wang <shane.wang@intel.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23import gtk
24import gobject
25import os
26import tempfile
27from bb.ui.crumbs.hobwidget import hic, HobButton, HobAltButton
28from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
29from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
30
31"""
32The following are convenience classes for implementing GNOME HIG compliant
33BitBake GUI's
34In summary: spacing = 12px, border-width = 6px
35"""
36
37class CellRendererPixbufActivatable(gtk.CellRendererPixbuf):
38 """
39 A custom CellRenderer implementation which is activatable
40 so that we can handle user clicks
41 """
42 __gsignals__ = { 'clicked' : (gobject.SIGNAL_RUN_LAST,
43 gobject.TYPE_NONE,
44 (gobject.TYPE_STRING,)), }
45
46 def __init__(self):
47 gtk.CellRendererPixbuf.__init__(self)
48 self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE)
49 self.set_property('follow-state', True)
50
51 """
52 Respond to a user click on a cell
53 """
54 def do_activate(self, even, widget, path, background_area, cell_area, flags):
55 self.emit('clicked', path)
56
57#
58# LayerSelectionDialog
59#
60class LayerSelectionDialog (CrumbsDialog):
61
62 TARGETS = [
63 ("MY_TREE_MODEL_ROW", gtk.TARGET_SAME_WIDGET, 0),
64 ("text/plain", 0, 1),
65 ("TEXT", 0, 2),
66 ("STRING", 0, 3),
67 ]
68
69 def gen_label_widget(self, content):
70 label = gtk.Label()
71 label.set_alignment(0, 0)
72 label.set_markup(content)
73 label.show()
74 return label
75
76 def layer_widget_toggled_cb(self, cell, path, layer_store):
77 name = layer_store[path][0]
78 toggle = not layer_store[path][1]
79 layer_store[path][1] = toggle
80
81 def layer_widget_add_clicked_cb(self, action, layer_store, parent):
82 dialog = gtk.FileChooserDialog("Add new layer", parent,
83 gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
84 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
85 HobAltButton.style_button(button)
86 button = dialog.add_button("Open", gtk.RESPONSE_YES)
87 HobButton.style_button(button)
88 label = gtk.Label("Select the layer you wish to add")
89 label.show()
90 dialog.set_extra_widget(label)
91 response = dialog.run()
92 path = dialog.get_filename()
93 dialog.destroy()
94
95 lbl = "<b>Error</b>\nUnable to load layer <i>%s</i> because " % path
96 if response == gtk.RESPONSE_YES:
97 import os
98 import os.path
99 layers = []
100 it = layer_store.get_iter_first()
101 while it:
102 layers.append(layer_store.get_value(it, 0))
103 it = layer_store.iter_next(it)
104
105 if not path:
106 lbl += "it is an invalid path."
107 elif not os.path.exists(path+"/conf/layer.conf"):
108 lbl += "there is no layer.conf inside the directory."
109 elif path in layers:
110 lbl += "it is already in loaded layers."
111 else:
112 layer_store.append([path])
113 return
114 dialog = CrumbsMessageDialog(parent, lbl)
115 dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
116 response = dialog.run()
117 dialog.destroy()
118
119 def layer_widget_del_clicked_cb(self, action, tree_selection, layer_store):
120 model, iter = tree_selection.get_selected()
121 if iter:
122 layer_store.remove(iter)
123
124
125 def gen_layer_widget(self, layers, layers_avail, window, tooltip=""):
126 hbox = gtk.HBox(False, 6)
127
128 layer_tv = gtk.TreeView()
129 layer_tv.set_rules_hint(True)
130 layer_tv.set_headers_visible(False)
131 tree_selection = layer_tv.get_selection()
132 tree_selection.set_mode(gtk.SELECTION_SINGLE)
133
134 # Allow enable drag and drop of rows including row move
135 layer_tv.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
136 self.TARGETS,
137 gtk.gdk.ACTION_DEFAULT|
138 gtk.gdk.ACTION_MOVE)
139 layer_tv.enable_model_drag_dest(self.TARGETS,
140 gtk.gdk.ACTION_DEFAULT)
141 layer_tv.connect("drag_data_get", self.drag_data_get_cb)
142 layer_tv.connect("drag_data_received", self.drag_data_received_cb)
143
144 col0= gtk.TreeViewColumn('Path')
145 cell0 = gtk.CellRendererText()
146 cell0.set_padding(5,2)
147 col0.pack_start(cell0, True)
148 col0.set_cell_data_func(cell0, self.draw_layer_path_cb)
149 layer_tv.append_column(col0)
150
151 scroll = gtk.ScrolledWindow()
152 scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
153 scroll.set_shadow_type(gtk.SHADOW_IN)
154 scroll.add(layer_tv)
155
156 table_layer = gtk.Table(2, 10, False)
157 hbox.pack_start(table_layer, expand=True, fill=True)
158
159 table_layer.attach(scroll, 0, 10, 0, 1)
160
161 layer_store = gtk.ListStore(gobject.TYPE_STRING)
162 for layer in layers:
163 layer_store.append([layer])
164
165 col1 = gtk.TreeViewColumn('Enabled')
166 layer_tv.append_column(col1)
167
168 cell1 = CellRendererPixbufActivatable()
169 cell1.set_fixed_size(-1,35)
170 cell1.connect("clicked", self.del_cell_clicked_cb, layer_store)
171 col1.pack_start(cell1, True)
172 col1.set_cell_data_func(cell1, self.draw_delete_button_cb, layer_tv)
173
174 add_button = gtk.Button()
175 add_button.set_relief(gtk.RELIEF_NONE)
176 box = gtk.HBox(False, 6)
177 box.show()
178 add_button.add(box)
179 add_button.connect("enter-notify-event", self.add_hover_cb)
180 add_button.connect("leave-notify-event", self.add_leave_cb)
181 self.im = gtk.Image()
182 self.im.set_from_file(hic.ICON_INDI_ADD_FILE)
183 self.im.show()
184 box.pack_start(self.im, expand=False, fill=False, padding=6)
185 lbl = gtk.Label("Add layer")
186 lbl.set_alignment(0.0, 0.5)
187 lbl.show()
188 box.pack_start(lbl, expand=True, fill=True, padding=6)
189 add_button.connect("clicked", self.layer_widget_add_clicked_cb, layer_store, window)
190 table_layer.attach(add_button, 0, 10, 1, 2, gtk.EXPAND | gtk.FILL, 0, 0, 6)
191 layer_tv.set_model(layer_store)
192
193 hbox.show_all()
194
195 return hbox, layer_store
196
197 def drag_data_get_cb(self, treeview, context, selection, target_id, etime):
198 treeselection = treeview.get_selection()
199 model, iter = treeselection.get_selected()
200 data = model.get_value(iter, 0)
201 selection.set(selection.target, 8, data)
202
203 def drag_data_received_cb(self, treeview, context, x, y, selection, info, etime):
204 model = treeview.get_model()
205 data = selection.data
206 drop_info = treeview.get_dest_row_at_pos(x, y)
207 if drop_info:
208 path, position = drop_info
209 iter = model.get_iter(path)
210 if (position == gtk.TREE_VIEW_DROP_BEFORE or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
211 model.insert_before(iter, [data])
212 else:
213 model.insert_after(iter, [data])
214 else:
215 model.append([data])
216 if context.action == gtk.gdk.ACTION_MOVE:
217 context.finish(True, True, etime)
218 return
219
220 def add_hover_cb(self, button, event):
221 self.im.set_from_file(hic.ICON_INDI_ADD_HOVER_FILE)
222
223 def add_leave_cb(self, button, event):
224 self.im.set_from_file(hic.ICON_INDI_ADD_FILE)
225
226 def __init__(self, title, layers, layers_non_removable, all_layers, parent, flags, buttons=None):
227 super(LayerSelectionDialog, self).__init__(title, parent, flags, buttons)
228
229 # class members from other objects
230 self.layers = layers
231 self.layers_non_removable = layers_non_removable
232 self.all_layers = all_layers
233 self.layers_changed = False
234
235 # icon for remove button in TreeView
236 im = gtk.Image()
237 im.set_from_file(hic.ICON_INDI_REMOVE_FILE)
238 self.rem_icon = im.get_pixbuf()
239
240 # class members for internal use
241 self.layer_store = None
242
243 # create visual elements on the dialog
244 self.create_visual_elements()
245 self.connect("response", self.response_cb)
246
247 def create_visual_elements(self):
248 layer_widget, self.layer_store = self.gen_layer_widget(self.layers, self.all_layers, self, None)
249 layer_widget.set_size_request(450, 250)
250 self.vbox.pack_start(layer_widget, expand=True, fill=True)
251 self.show_all()
252
253 def response_cb(self, dialog, response_id):
254 model = self.layer_store
255 it = model.get_iter_first()
256 layers = []
257 while it:
258 layers.append(model.get_value(it, 0))
259 it = model.iter_next(it)
260
261 self.layers_changed = (self.layers != layers)
262 self.layers = layers
263
264 """
265 A custom cell_data_func to draw a delete 'button' in the TreeView for layers
266 other than the meta layer. The deletion of which is prevented so that the
267 user can't shoot themselves in the foot too badly.
268 """
269 def draw_delete_button_cb(self, col, cell, model, it, tv):
270 path = model.get_value(it, 0)
271 if path in self.layers_non_removable:
272 cell.set_sensitive(False)
273 cell.set_property('pixbuf', None)
274 cell.set_property('mode', gtk.CELL_RENDERER_MODE_INERT)
275 else:
276 cell.set_property('pixbuf', self.rem_icon)
277 cell.set_sensitive(True)
278 cell.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE)
279
280 return True
281
282 """
283 A custom cell_data_func to write an extra message into the layer path cell
284 for the meta layer. We should inform the user that they can't remove it for
285 their own safety.
286 """
287 def draw_layer_path_cb(self, col, cell, model, it):
288 path = model.get_value(it, 0)
289 if path in self.layers_non_removable:
290 cell.set_property('markup', "<b>It cannot be removed</b>\n%s" % path)
291 else:
292 cell.set_property('text', path)
293
294 def del_cell_clicked_cb(self, cell, path, model):
295 it = model.get_iter_from_string(path)
296 model.remove(it)
diff --git a/bitbake/lib/bb/ui/crumbs/hig/parsingwarningsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/parsingwarningsdialog.py
new file mode 100644
index 0000000000..33bac39db8
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/parsingwarningsdialog.py
@@ -0,0 +1,163 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011-2012 Intel Corporation
5#
6# Authored by Cristiana Voicu <cristiana.voicu@intel.com>
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21import gtk
22import gobject
23from bb.ui.crumbs.hobwidget import HobAltButton
24from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
25
26"""
27The following are convenience classes for implementing GNOME HIG compliant
28BitBake GUI's
29In summary: spacing = 12px, border-width = 6px
30"""
31
32#
33# ParsingWarningsDialog
34#
35class ParsingWarningsDialog (CrumbsDialog):
36
37 def __init__(self, title, warnings, parent, flags, buttons=None):
38 super(ParsingWarningsDialog, self).__init__(title, parent, flags, buttons)
39
40 self.warnings = warnings
41 self.warning_on = 0
42 self.warn_nb = len(warnings)
43
44 # create visual elements on the dialog
45 self.create_visual_elements()
46
47 def cancel_button_cb(self, button):
48 self.destroy()
49
50 def previous_button_cb(self, button):
51 self.warning_on = self.warning_on - 1
52 self.refresh_components()
53
54 def next_button_cb(self, button):
55 self.warning_on = self.warning_on + 1
56 self.refresh_components()
57
58 def refresh_components(self):
59 lbl = self.warnings[self.warning_on]
60 #when the warning text has more than 400 chars, it uses a scroll bar
61 if 0<= len(lbl) < 400:
62 self.warning_label.set_size_request(320, 230)
63 self.warning_label.set_use_markup(True)
64 self.warning_label.set_line_wrap(True)
65 self.warning_label.set_markup(lbl)
66 self.warning_label.set_property("yalign", 0.00)
67 else:
68 self.textWindow.set_shadow_type(gtk.SHADOW_IN)
69 self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
70 self.msgView = gtk.TextView()
71 self.msgView.set_editable(False)
72 self.msgView.set_wrap_mode(gtk.WRAP_WORD)
73 self.msgView.set_cursor_visible(False)
74 self.msgView.set_size_request(320, 230)
75 self.buf = gtk.TextBuffer()
76 self.buf.set_text(lbl)
77 self.msgView.set_buffer(self.buf)
78 self.textWindow.add(self.msgView)
79 self.msgView.show()
80
81 if self.warning_on==0:
82 self.previous_button.set_sensitive(False)
83 else:
84 self.previous_button.set_sensitive(True)
85
86 if self.warning_on==self.warn_nb-1:
87 self.next_button.set_sensitive(False)
88 else:
89 self.next_button.set_sensitive(True)
90
91 if self.warn_nb>1:
92 self.heading = "Warning " + str(self.warning_on + 1) + " of " + str(self.warn_nb)
93 self.heading_label.set_markup('<span weight="bold">%s</span>' % self.heading)
94 else:
95 self.heading = "Warning"
96 self.heading_label.set_markup('<span weight="bold">%s</span>' % self.heading)
97
98 self.show_all()
99
100 if 0<= len(lbl) < 400:
101 self.textWindow.hide()
102 else:
103 self.warning_label.hide()
104
105 def create_visual_elements(self):
106 self.set_size_request(350, 350)
107 self.heading_label = gtk.Label()
108 self.heading_label.set_alignment(0, 0)
109 self.warning_label = gtk.Label()
110 self.warning_label.set_selectable(True)
111 self.warning_label.set_alignment(0, 0)
112 self.textWindow = gtk.ScrolledWindow()
113
114 table = gtk.Table(1, 10, False)
115
116 cancel_button = gtk.Button()
117 cancel_button.set_label("Close")
118 cancel_button.connect("clicked", self.cancel_button_cb)
119 cancel_button.set_size_request(110, 30)
120
121 self.previous_button = gtk.Button()
122 image1 = gtk.image_new_from_stock(gtk.STOCK_GO_BACK, gtk.ICON_SIZE_BUTTON)
123 image1.show()
124 box = gtk.HBox(False, 6)
125 box.show()
126 self.previous_button.add(box)
127 lbl = gtk.Label("Previous")
128 lbl.show()
129 box.pack_start(image1, expand=False, fill=False, padding=3)
130 box.pack_start(lbl, expand=True, fill=True, padding=3)
131 self.previous_button.connect("clicked", self.previous_button_cb)
132 self.previous_button.set_size_request(110, 30)
133
134 self.next_button = gtk.Button()
135 image2 = gtk.image_new_from_stock(gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
136 image2.show()
137 box = gtk.HBox(False, 6)
138 box.show()
139 self.next_button.add(box)
140 lbl = gtk.Label("Next")
141 lbl.show()
142 box.pack_start(lbl, expand=True, fill=True, padding=3)
143 box.pack_start(image2, expand=False, fill=False, padding=3)
144 self.next_button.connect("clicked", self.next_button_cb)
145 self.next_button.set_size_request(110, 30)
146
147 #when there more than one warning, we need "previous" and "next" button
148 if self.warn_nb>1:
149 self.vbox.pack_start(self.heading_label, expand=False, fill=False)
150 self.vbox.pack_start(self.warning_label, expand=False, fill=False)
151 self.vbox.pack_start(self.textWindow, expand=False, fill=False)
152 table.attach(cancel_button, 6, 7, 0, 1, xoptions=gtk.SHRINK)
153 table.attach(self.previous_button, 7, 8, 0, 1, xoptions=gtk.SHRINK)
154 table.attach(self.next_button, 8, 9, 0, 1, xoptions=gtk.SHRINK)
155 self.vbox.pack_end(table, expand=False, fill=False)
156 else:
157 self.vbox.pack_start(self.heading_label, expand=False, fill=False)
158 self.vbox.pack_start(self.warning_label, expand=False, fill=False)
159 self.vbox.pack_start(self.textWindow, expand=False, fill=False)
160 cancel_button = self.add_button("Close", gtk.RESPONSE_CANCEL)
161 HobAltButton.style_button(cancel_button)
162
163 self.refresh_components()
diff --git a/bitbake/lib/bb/ui/crumbs/hig/propertydialog.py b/bitbake/lib/bb/ui/crumbs/hig/propertydialog.py
new file mode 100644
index 0000000000..bc40741bf2
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/propertydialog.py
@@ -0,0 +1,451 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011-2013 Intel Corporation
5#
6# Authored by Andrei Dinu <andrei.adrianx.dinu@intel.com>
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21import string
22import gtk
23import gobject
24import os
25import tempfile
26import glib
27from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
28from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper
29from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
30from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog
31
32"""
33The following are convenience classes for implementing GNOME HIG compliant
34BitBake GUI's
35In summary: spacing = 12px, border-width = 6px
36"""
37
38class PropertyDialog(CrumbsDialog):
39
40 def __init__(self, title, parent, information, flags, buttons=None):
41
42 super(PropertyDialog, self).__init__(title, parent, flags, buttons)
43
44 self.properties = information
45
46 if len(self.properties) == 10:
47 self.create_recipe_visual_elements()
48 elif len(self.properties) == 5:
49 self.create_package_visual_elements()
50 else:
51 self.create_information_visual_elements()
52
53
54 def create_information_visual_elements(self):
55
56 HOB_ICON_BASE_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), ("icons/"))
57 ICON_PACKAGES_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('info/info_display.png'))
58
59 self.set_resizable(False)
60
61 self.table = gtk.Table(1,1,False)
62 self.table.set_row_spacings(0)
63 self.table.set_col_spacings(0)
64
65 self.image = gtk.Image()
66 self.image.set_from_file(ICON_PACKAGES_DISPLAY_FILE)
67 self.image.set_property("xalign",0)
68 #self.vbox.add(self.image)
69
70 image_info = self.properties.split("*")[0]
71 info = self.properties.split("*")[1]
72
73 vbox = gtk.VBox(True, spacing=30)
74
75 self.label_short = gtk.Label()
76 self.label_short.set_line_wrap(False)
77 self.label_short.set_markup(image_info)
78 self.label_short.set_property("xalign", 0)
79
80 self.info_label = gtk.Label()
81 self.info_label.set_line_wrap(True)
82 self.info_label.set_markup(info)
83 self.info_label.set_property("yalign", 0.5)
84
85 self.table.attach(self.image, 0,1,0,1, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL,xpadding=5,ypadding=5)
86 self.table.attach(self.label_short, 0,1,0,1, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL,xpadding=40,ypadding=5)
87 self.table.attach(self.info_label, 0,1,1,2, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL,xpadding=40,ypadding=10)
88
89 self.vbox.add(self.table)
90 self.connect('delete-event', lambda w, e: self.destroy() or True)
91
92 def treeViewTooltip( self, widget, e, tooltips, cell, emptyText="" ):
93 try:
94 (path,col,x,y) = widget.get_path_at_pos( int(e.x), int(e.y) )
95 it = widget.get_model().get_iter(path)
96 value = widget.get_model().get_value(it,cell)
97 if value in self.tooltip_items:
98 tooltips.set_tip(widget, self.tooltip_items[value])
99 tooltips.enable()
100 else:
101 tooltips.set_tip(widget, emptyText)
102 except:
103 tooltips.set_tip(widget, emptyText)
104
105
106 def create_package_visual_elements(self):
107
108 name = self.properties['name']
109 binb = self.properties['binb']
110 size = self.properties['size']
111 recipe = self.properties['recipe']
112 file_list = self.properties['files_list']
113
114 file_list = file_list.strip("{}'")
115 files_temp = ''
116 paths_temp = ''
117 files_binb = []
118 paths_binb = []
119
120 self.tooltip_items = {}
121
122 self.set_resizable(False)
123
124 #cleaning out the recipe variable
125 recipe = recipe.split("+")[0]
126
127 vbox = gtk.VBox(True,spacing = 0)
128
129 ###################################### NAME ROW + COL #################################
130
131 self.label_short = gtk.Label()
132 self.label_short.set_size_request(300,-1)
133 self.label_short.set_selectable(True)
134 self.label_short.set_line_wrap(True)
135 self.label_short.set_markup("<span weight=\"bold\">Name: </span>" + name)
136 self.label_short.set_property("xalign", 0)
137
138 self.vbox.add(self.label_short)
139
140 ###################################### SIZE ROW + COL ######################################
141
142 self.label_short = gtk.Label()
143 self.label_short.set_size_request(300,-1)
144 self.label_short.set_selectable(True)
145 self.label_short.set_line_wrap(True)
146 self.label_short.set_markup("<span weight=\"bold\">Size: </span>" + size)
147 self.label_short.set_property("xalign", 0)
148
149 self.vbox.add(self.label_short)
150
151 ##################################### RECIPE ROW + COL #########################################
152
153 self.label_short = gtk.Label()
154 self.label_short.set_size_request(300,-1)
155 self.label_short.set_selectable(True)
156 self.label_short.set_line_wrap(True)
157 self.label_short.set_markup("<span weight=\"bold\">Recipe: </span>" + recipe)
158 self.label_short.set_property("xalign", 0)
159
160 self.vbox.add(self.label_short)
161
162 ##################################### BINB ROW + COL #######################################
163
164 if binb != '':
165 self.label_short = gtk.Label()
166 self.label_short.set_selectable(True)
167 self.label_short.set_line_wrap(True)
168 self.label_short.set_markup("<span weight=\"bold\">Brought in by: </span>")
169 self.label_short.set_property("xalign", 0)
170
171 self.label_info = gtk.Label()
172 self.label_info.set_size_request(300,-1)
173 self.label_info.set_selectable(True)
174 self.label_info.set_line_wrap(True)
175 self.label_info.set_markup(binb)
176 self.label_info.set_property("xalign", 0)
177
178 self.vbox.add(self.label_short)
179 self.vbox.add(self.label_info)
180
181 #################################### FILES BROUGHT BY PACKAGES ###################################
182
183 if file_list != '':
184
185 self.textWindow = gtk.ScrolledWindow()
186 self.textWindow.set_shadow_type(gtk.SHADOW_IN)
187 self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
188 self.textWindow.set_size_request(100, 170)
189
190 sstatemirrors_store = gtk.ListStore(str)
191
192 self.sstatemirrors_tv = gtk.TreeView()
193 self.sstatemirrors_tv.set_rules_hint(True)
194 self.sstatemirrors_tv.set_headers_visible(True)
195 self.textWindow.add(self.sstatemirrors_tv)
196
197 self.cell1 = gtk.CellRendererText()
198 col1 = gtk.TreeViewColumn('Package files', self.cell1)
199 col1.set_cell_data_func(self.cell1, self.regex_field)
200 self.sstatemirrors_tv.append_column(col1)
201
202 for items in file_list.split(']'):
203 if len(items) > 1:
204 paths_temp = items.split(":")[0]
205 paths_binb.append(paths_temp.strip(" ,'"))
206 files_temp = items.split(":")[1]
207 files_binb.append(files_temp.strip(" ['"))
208
209 unsorted_list = []
210
211 for items in range(len(paths_binb)):
212 if len(files_binb[items]) > 1:
213 for aduse in (files_binb[items].split(",")):
214 unsorted_list.append(paths_binb[items].split(name)[len(paths_binb[items].split(name))-1] + '/' + aduse.strip(" '"))
215
216
217 unsorted_list.sort()
218 for items in unsorted_list:
219 temp = items
220 while len(items) > 35:
221 items = items[:len(items)/2] + "" + items[len(items)/2+1:]
222 if len(items) == 35:
223 items = items[:len(items)/2] + "..." + items[len(items)/2+3:]
224 self.tooltip_items[items] = temp
225
226 sstatemirrors_store.append([str(items)])
227
228
229 self.sstatemirrors_tv.set_model(sstatemirrors_store)
230
231 tips = gtk.Tooltips()
232 tips.set_tip(self.sstatemirrors_tv, "")
233 self.sstatemirrors_tv.connect("motion-notify-event", self.treeViewTooltip, tips, 0)
234 self.sstatemirrors_tv.set_events(gtk.gdk.POINTER_MOTION_MASK)
235
236 self.vbox.add(self.textWindow)
237
238 self.vbox.show_all()
239
240
241 def regex_field(self, column, cell, model, iter):
242 cell.set_property('text', model.get_value(iter, 0))
243 return
244
245
246 def create_recipe_visual_elements(self):
247
248 summary = self.properties['summary']
249 name = self.properties['name']
250 version = self.properties['version']
251 revision = self.properties['revision']
252 binb = self.properties['binb']
253 group = self.properties['group']
254 license = self.properties['license']
255 homepage = self.properties['homepage']
256 bugtracker = self.properties['bugtracker']
257 description = self.properties['description']
258
259 self.set_resizable(False)
260
261 #cleaning out the version variable and also the summary
262 version = version.split(":")[1]
263 if len(version) > 30:
264 version = version.split("+")[0]
265 else:
266 version = version.split("-")[0]
267 license = license.replace("&" , "and")
268 if (homepage == ''):
269 homepage = 'unknown'
270 if (bugtracker == ''):
271 bugtracker = 'unknown'
272 summary = summary.split("+")[0]
273
274 #calculating the rows needed for the table
275 binb_items_count = len(binb.split(','))
276 binb_items = binb.split(',')
277
278 vbox = gtk.VBox(False,spacing = 0)
279
280 ######################################## SUMMARY LABEL #########################################
281
282 if summary != '':
283 self.label_short = gtk.Label()
284 self.label_short.set_width_chars(37)
285 self.label_short.set_selectable(True)
286 self.label_short.set_line_wrap(True)
287 self.label_short.set_markup("<b>" + summary + "</b>")
288 self.label_short.set_property("xalign", 0)
289
290 self.vbox.add(self.label_short)
291
292 ########################################## NAME ROW + COL #######################################
293
294 self.label_short = gtk.Label()
295 self.label_short.set_selectable(True)
296 self.label_short.set_line_wrap(True)
297 self.label_short.set_markup("<span weight=\"bold\">Name: </span>" + name)
298 self.label_short.set_property("xalign", 0)
299
300 self.vbox.add(self.label_short)
301
302 ####################################### VERSION ROW + COL ####################################
303
304 self.label_short = gtk.Label()
305 self.label_short.set_selectable(True)
306 self.label_short.set_line_wrap(True)
307 self.label_short.set_markup("<span weight=\"bold\">Version: </span>" + version)
308 self.label_short.set_property("xalign", 0)
309
310 self.vbox.add(self.label_short)
311
312 ##################################### REVISION ROW + COL #####################################
313
314 self.label_short = gtk.Label()
315 self.label_short.set_line_wrap(True)
316 self.label_short.set_selectable(True)
317 self.label_short.set_markup("<span weight=\"bold\">Revision: </span>" + revision)
318 self.label_short.set_property("xalign", 0)
319
320 self.vbox.add(self.label_short)
321
322 ################################## GROUP ROW + COL ############################################
323
324 self.label_short = gtk.Label()
325 self.label_short.set_selectable(True)
326 self.label_short.set_line_wrap(True)
327 self.label_short.set_markup("<span weight=\"bold\">Group: </span>" + group)
328 self.label_short.set_property("xalign", 0)
329
330 self.vbox.add(self.label_short)
331
332 ################################# HOMEPAGE ROW + COL ############################################
333
334 if homepage != 'unknown':
335 self.label_info = gtk.Label()
336 self.label_info.set_selectable(True)
337 self.label_info.set_line_wrap(True)
338 if len(homepage) > 35:
339 self.label_info.set_markup("<a href=\"" + homepage + "\">" + homepage[0:35] + "..." + "</a>")
340 else:
341 self.label_info.set_markup("<a href=\"" + homepage + "\">" + homepage[0:60] + "</a>")
342
343 self.label_info.set_property("xalign", 0)
344
345 self.label_short = gtk.Label()
346 self.label_short.set_selectable(True)
347 self.label_short.set_line_wrap(True)
348 self.label_short.set_markup("<b>Homepage: </b>")
349 self.label_short.set_property("xalign", 0)
350
351 self.vbox.add(self.label_short)
352 self.vbox.add(self.label_info)
353
354 ################################# BUGTRACKER ROW + COL ###########################################
355
356 if bugtracker != 'unknown':
357 self.label_info = gtk.Label()
358 self.label_info.set_selectable(True)
359 self.label_info.set_line_wrap(True)
360 if len(bugtracker) > 35:
361 self.label_info.set_markup("<a href=\"" + bugtracker + "\">" + bugtracker[0:35] + "..." + "</a>")
362 else:
363 self.label_info.set_markup("<a href=\"" + bugtracker + "\">" + bugtracker[0:60] + "</a>")
364 self.label_info.set_property("xalign", 0)
365
366 self.label_short = gtk.Label()
367 self.label_short.set_selectable(True)
368 self.label_short.set_line_wrap(True)
369 self.label_short.set_markup("<b>Bugtracker: </b>")
370 self.label_short.set_property("xalign", 0)
371
372 self.vbox.add(self.label_short)
373 self.vbox.add(self.label_info)
374
375 ################################# LICENSE ROW + COL ############################################
376
377 self.label_info = gtk.Label()
378 self.label_info.set_selectable(True)
379 self.label_info.set_line_wrap(True)
380 self.label_info.set_markup(license)
381 self.label_info.set_property("xalign", 0)
382
383 self.label_short = gtk.Label()
384 self.label_short.set_selectable(True)
385 self.label_short.set_line_wrap(True)
386 self.label_short.set_markup("<span weight=\"bold\">License: </span>")
387 self.label_short.set_property("xalign", 0)
388
389 self.vbox.add(self.label_short)
390 self.vbox.add(self.label_info)
391
392 ################################### BINB ROW+COL #############################################
393
394 if binb != '':
395 self.label_short = gtk.Label()
396 self.label_short.set_selectable(True)
397 self.label_short.set_line_wrap(True)
398 self.label_short.set_markup("<span weight=\"bold\">Brought in by: </span>")
399 self.label_short.set_property("xalign", 0)
400 self.vbox.add(self.label_short)
401 self.label_info = gtk.Label()
402 self.label_info.set_selectable(True)
403 self.label_info.set_width_chars(36)
404 if len(binb) > 200:
405 scrolled_window = gtk.ScrolledWindow()
406 scrolled_window.set_policy(gtk.POLICY_NEVER,gtk.POLICY_ALWAYS)
407 scrolled_window.set_size_request(100,100)
408 self.label_info.set_markup(binb)
409 self.label_info.set_padding(6,6)
410 self.label_info.set_alignment(0,0)
411 self.label_info.set_line_wrap(True)
412 scrolled_window.add_with_viewport(self.label_info)
413 self.vbox.add(scrolled_window)
414 else:
415 self.label_info.set_markup(binb)
416 self.label_info.set_property("xalign", 0)
417 self.label_info.set_line_wrap(True)
418 self.vbox.add(self.label_info)
419
420 ################################ DESCRIPTION TAG ROW #################################################
421
422 self.label_short = gtk.Label()
423 self.label_short.set_line_wrap(True)
424 self.label_short.set_markup("<span weight=\"bold\">Description </span>")
425 self.label_short.set_property("xalign", 0)
426 self.vbox.add(self.label_short)
427
428 ################################ DESCRIPTION INFORMATION ROW ##########################################
429
430 hbox = gtk.HBox(True,spacing = 0)
431
432 self.label_short = gtk.Label()
433 self.label_short.set_selectable(True)
434 self.label_short.set_width_chars(36)
435 if len(description) > 200:
436 scrolled_window = gtk.ScrolledWindow()
437 scrolled_window.set_policy(gtk.POLICY_NEVER,gtk.POLICY_ALWAYS)
438 scrolled_window.set_size_request(100,100)
439 self.label_short.set_markup(description)
440 self.label_short.set_padding(6,6)
441 self.label_short.set_alignment(0,0)
442 self.label_short.set_line_wrap(True)
443 scrolled_window.add_with_viewport(self.label_short)
444 self.vbox.add(scrolled_window)
445 else:
446 self.label_short.set_markup(description)
447 self.label_short.set_property("xalign", 0)
448 self.label_short.set_line_wrap(True)
449 self.vbox.add(self.label_short)
450
451 self.vbox.show_all()
diff --git a/bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py
new file mode 100644
index 0000000000..69e7dffb6d
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/proxydetailsdialog.py
@@ -0,0 +1,90 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011-2012 Intel Corporation
5#
6# Authored by Joshua Lock <josh@linux.intel.com>
7# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
8# Authored by Shane Wang <shane.wang@intel.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23import gtk
24from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
25
26"""
27The following are convenience classes for implementing GNOME HIG compliant
28BitBake GUI's
29In summary: spacing = 12px, border-width = 6px
30"""
31
32class ProxyDetailsDialog (CrumbsDialog):
33
34 def __init__(self, title, user, passwd, parent, flags, buttons=None):
35 super(ProxyDetailsDialog, self).__init__(title, parent, flags, buttons)
36 self.connect("response", self.response_cb)
37
38 self.auth = not (user == None or passwd == None or user == "")
39 self.user = user or ""
40 self.passwd = passwd or ""
41
42 # create visual elements on the dialog
43 self.create_visual_elements()
44
45 def create_visual_elements(self):
46 self.auth_checkbox = gtk.CheckButton("Use authentication")
47 self.auth_checkbox.set_tooltip_text("Check this box to set the username and the password")
48 self.auth_checkbox.set_active(self.auth)
49 self.auth_checkbox.connect("toggled", self.auth_checkbox_toggled_cb)
50 self.vbox.pack_start(self.auth_checkbox, expand=False, fill=False)
51
52 hbox = gtk.HBox(False, 6)
53 self.user_label = gtk.Label("Username:")
54 self.user_text = gtk.Entry()
55 self.user_text.set_text(self.user)
56 hbox.pack_start(self.user_label, expand=False, fill=False)
57 hbox.pack_end(self.user_text, expand=False, fill=False)
58 self.vbox.pack_start(hbox, expand=False, fill=False)
59
60 hbox = gtk.HBox(False, 6)
61 self.passwd_label = gtk.Label("Password:")
62 self.passwd_text = gtk.Entry()
63 self.passwd_text.set_text(self.passwd)
64 hbox.pack_start(self.passwd_label, expand=False, fill=False)
65 hbox.pack_end(self.passwd_text, expand=False, fill=False)
66 self.vbox.pack_start(hbox, expand=False, fill=False)
67
68 self.refresh_auth_components()
69 self.show_all()
70
71 def refresh_auth_components(self):
72 self.user_label.set_sensitive(self.auth)
73 self.user_text.set_editable(self.auth)
74 self.user_text.set_sensitive(self.auth)
75 self.passwd_label.set_sensitive(self.auth)
76 self.passwd_text.set_editable(self.auth)
77 self.passwd_text.set_sensitive(self.auth)
78
79 def auth_checkbox_toggled_cb(self, button):
80 self.auth = self.auth_checkbox.get_active()
81 self.refresh_auth_components()
82
83 def response_cb(self, dialog, response_id):
84 if response_id == gtk.RESPONSE_OK:
85 if self.auth:
86 self.user = self.user_text.get_text()
87 self.passwd = self.passwd_text.get_text()
88 else:
89 self.user = None
90 self.passwd = None
diff --git a/bitbake/lib/bb/ui/crumbs/hig/retrieveimagedialog.py b/bitbake/lib/bb/ui/crumbs/hig/retrieveimagedialog.py
new file mode 100644
index 0000000000..9017139850
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/retrieveimagedialog.py
@@ -0,0 +1,51 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2013 Intel Corporation
5#
6# Authored by Cristiana Voicu <cristiana.voicu@intel.com>
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21import gtk
22
23class RetrieveImageDialog (gtk.FileChooserDialog):
24 """
25 This class is used to create a dialog that permits to retrieve
26 a custom image saved previously from Hob.
27 """
28 def __init__(self, directory,title, parent, flags, buttons=None):
29 super(RetrieveImageDialog, self).__init__(title, None, gtk.FILE_CHOOSER_ACTION_OPEN,
30 (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN, gtk.RESPONSE_OK))
31 self.directory = directory
32
33 # create visual elements on the dialog
34 self.create_visual_elements()
35
36 def create_visual_elements(self):
37 self.set_show_hidden(True)
38 self.set_default_response(gtk.RESPONSE_OK)
39 self.set_current_folder(self.directory)
40
41 vbox = self.get_children()[0].get_children()[0].get_children()[0]
42 for child in vbox.get_children()[0].get_children()[0].get_children()[0].get_children():
43 vbox.get_children()[0].get_children()[0].get_children()[0].remove(child)
44
45 label1 = gtk.Label()
46 label1.set_text("File system" + self.directory)
47 label1.show()
48 vbox.get_children()[0].get_children()[0].get_children()[0].pack_start(label1, expand=False, fill=False, padding=0)
49 vbox.get_children()[0].get_children()[1].get_children()[0].hide()
50
51 self.get_children()[0].get_children()[1].get_children()[0].set_label("Select")
diff --git a/bitbake/lib/bb/ui/crumbs/hig/saveimagedialog.py b/bitbake/lib/bb/ui/crumbs/hig/saveimagedialog.py
new file mode 100644
index 0000000000..e940ceee43
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/saveimagedialog.py
@@ -0,0 +1,160 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2013 Intel Corporation
5#
6# Authored by Cristiana Voicu <cristiana.voicu@intel.com>
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21import gtk
22import glib
23from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
24from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
25from bb.ui.crumbs.hobwidget import HobButton
26
27class SaveImageDialog (CrumbsDialog):
28 """
29 This class is used to create a dialog that permits to save
30 a custom image in a predefined directory.
31 """
32 def __init__(self, directory, name, description, title, parent, flags, buttons=None):
33 super(SaveImageDialog, self).__init__(title, parent, flags, buttons)
34 self.directory = directory
35 self.builder = parent
36 self.name_field = name
37 self.description_field = description
38
39 # create visual elements on the dialog
40 self.create_visual_elements()
41
42 def create_visual_elements(self):
43 self.set_default_response(gtk.RESPONSE_OK)
44 self.vbox.set_border_width(6)
45
46 sub_vbox = gtk.VBox(False, 12)
47 self.vbox.pack_start(sub_vbox, expand=False, fill=False)
48 label = gtk.Label()
49 label.set_alignment(0, 0)
50 label.set_markup("<b>Name</b>")
51 sub_label = gtk.Label()
52 sub_label.set_alignment(0, 0)
53 content = "Image recipe names should be all lowercase and include only alphanumeric\n"
54 content += "characters. The only special character you can use is the ASCII hyphen (-)."
55 sub_label.set_markup(content)
56 self.name_entry = gtk.Entry()
57 self.name_entry.set_text(self.name_field)
58 self.name_entry.set_size_request(350,30)
59 self.name_entry.connect("changed", self.name_entry_changed)
60 sub_vbox.pack_start(label, expand=False, fill=False)
61 sub_vbox.pack_start(sub_label, expand=False, fill=False)
62 sub_vbox.pack_start(self.name_entry, expand=False, fill=False)
63
64 sub_vbox = gtk.VBox(False, 12)
65 self.vbox.pack_start(sub_vbox, expand=False, fill=False)
66 label = gtk.Label()
67 label.set_alignment(0, 0)
68 label.set_markup("<b>Description</b> (optional)")
69 sub_label = gtk.Label()
70 sub_label.set_alignment(0, 0)
71 sub_label.set_markup("The description should be less than 150 characters long.")
72 self.description_entry = gtk.TextView()
73 description_buffer = self.description_entry.get_buffer()
74 description_buffer.set_text(self.description_field)
75 description_buffer.connect("insert-text", self.limit_description_length)
76 self.description_entry.set_wrap_mode(gtk.WRAP_WORD)
77 self.description_entry.set_size_request(350,50)
78 sub_vbox.pack_start(label, expand=False, fill=False)
79 sub_vbox.pack_start(sub_label, expand=False, fill=False)
80 sub_vbox.pack_start(self.description_entry, expand=False, fill=False)
81
82 sub_vbox = gtk.VBox(False, 12)
83 self.vbox.pack_start(sub_vbox, expand=False, fill=False)
84 label = gtk.Label()
85 label.set_alignment(0, 0)
86 label.set_markup("Your image recipe will be saved to:")
87 sub_label = gtk.Label()
88 sub_label.set_alignment(0, 0)
89 sub_label.set_markup(self.directory)
90 sub_vbox.pack_start(label, expand=False, fill=False)
91 sub_vbox.pack_start(sub_label, expand=False, fill=False)
92
93 table = gtk.Table(1, 4, True)
94
95 cancel_button = gtk.Button()
96 cancel_button.set_label("Cancel")
97 cancel_button.connect("clicked", self.cancel_button_cb)
98 cancel_button.set_size_request(110, 30)
99
100 self.save_button = gtk.Button()
101 self.save_button.set_label("Save")
102 self.save_button.connect("clicked", self.save_button_cb)
103 self.save_button.set_size_request(110, 30)
104 if self.name_entry.get_text() == '':
105 self.save_button.set_sensitive(False)
106
107 table.attach(cancel_button, 2, 3, 0, 1)
108 table.attach(self.save_button, 3, 4, 0, 1)
109 self.vbox.pack_end(table, expand=False, fill=False)
110
111 self.show_all()
112
113 def limit_description_length(self, textbuffer, iter, text, length):
114 buffer_bounds = textbuffer.get_bounds()
115 entire_text = textbuffer.get_text(*buffer_bounds)
116 entire_text += text
117 if len(entire_text)>150 or text=="\n":
118 textbuffer.emit_stop_by_name("insert-text")
119
120 def name_entry_changed(self, entry):
121 text = entry.get_text()
122 if text == '':
123 self.save_button.set_sensitive(False)
124 else:
125 self.save_button.set_sensitive(True)
126
127 def cancel_button_cb(self, button):
128 self.destroy()
129
130 def save_button_cb(self, button):
131 text = self.name_entry.get_text()
132 new_text = text.replace("-","")
133 description_buffer = self.description_entry.get_buffer()
134 description = description_buffer.get_text(description_buffer.get_start_iter(),description_buffer.get_end_iter())
135 if new_text.islower() and new_text.isalnum():
136 self.builder.image_details_page.image_saved = True
137 self.builder.customized = False
138 self.builder.generate_new_image(self.directory+text, description)
139 self.builder.recipe_model.set_in_list(text, description)
140 self.builder.recipe_model.set_selected_image(text)
141 self.builder.image_details_page.show_page(self.builder.IMAGE_GENERATED)
142 self.builder.image_details_page.name_field_template = text
143 self.builder.image_details_page.description_field_template = description
144 self.destroy()
145 else:
146 self.show_invalid_input_error_dialog()
147
148 def show_invalid_input_error_dialog(self):
149 lbl = "<b>Invalid characters in image recipe name</b>\n"
150 msg = "Image recipe names should be all lowercase and\n"
151 msg += "include only alphanumeric characters. The only\n"
152 msg += "special character you can use is the ASCII hyphen (-)."
153 lbl = lbl + "\n%s\n" % glib.markup_escape_text(msg)
154 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_ERROR)
155 button = dialog.add_button("Close", gtk.RESPONSE_OK)
156 HobButton.style_button(button)
157
158 res = dialog.run()
159 self.name_entry.grab_focus()
160 dialog.destroy()
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..e0285c93ce
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/settingsuihelper.py
@@ -0,0 +1,122 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011-2012 Intel Corporation
5#
6# Authored by Joshua Lock <josh@linux.intel.com>
7# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
8# Authored by Shane Wang <shane.wang@intel.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23import gtk
24import os
25from bb.ui.crumbs.hobwidget import HobInfoButton, HobButton, HobAltButton
26
27"""
28The following are convenience classes for implementing GNOME HIG compliant
29BitBake GUI's
30In summary: spacing = 12px, border-width = 6px
31"""
32
33class SettingsUIHelper():
34
35 def gen_label_widget(self, content):
36 label = gtk.Label()
37 label.set_alignment(0, 0)
38 label.set_markup(content)
39 label.show()
40 return label
41
42 def gen_label_info_widget(self, content, tooltip):
43 table = gtk.Table(1, 10, False)
44 label = self.gen_label_widget(content)
45 info = HobInfoButton(tooltip, self)
46 table.attach(label, 0, 1, 0, 1, xoptions=gtk.FILL)
47 table.attach(info, 1, 2, 0, 1, xoptions=gtk.FILL, xpadding=10)
48 return table
49
50 def gen_spinner_widget(self, content, lower, upper, tooltip=""):
51 hbox = gtk.HBox(False, 12)
52 adjust = gtk.Adjustment(value=content, lower=lower, upper=upper, step_incr=1)
53 spinner = gtk.SpinButton(adjustment=adjust, climb_rate=1, digits=0)
54
55 spinner.set_value(content)
56 hbox.pack_start(spinner, expand=False, fill=False)
57
58 info = HobInfoButton(tooltip, self)
59 hbox.pack_start(info, expand=False, fill=False)
60
61 hbox.show_all()
62 return hbox, spinner
63
64 def gen_combo_widget(self, curr_item, all_item, tooltip=""):
65 hbox = gtk.HBox(False, 12)
66 combo = gtk.combo_box_new_text()
67 hbox.pack_start(combo, expand=False, fill=False)
68
69 index = 0
70 for item in all_item or []:
71 combo.append_text(item)
72 if item == curr_item:
73 combo.set_active(index)
74 index += 1
75
76 info = HobInfoButton(tooltip, self)
77 hbox.pack_start(info, expand=False, fill=False)
78
79 hbox.show_all()
80 return hbox, combo
81
82 def entry_widget_select_path_cb(self, action, parent, entry):
83 dialog = gtk.FileChooserDialog("", parent,
84 gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
85 text = entry.get_text()
86 dialog.set_current_folder(text if len(text) > 0 else os.getcwd())
87 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
88 HobAltButton.style_button(button)
89 button = dialog.add_button("Open", gtk.RESPONSE_YES)
90 HobButton.style_button(button)
91 response = dialog.run()
92 if response == gtk.RESPONSE_YES:
93 path = dialog.get_filename()
94 entry.set_text(path)
95
96 dialog.destroy()
97
98 def gen_entry_widget(self, content, parent, tooltip="", need_button=True):
99 hbox = gtk.HBox(False, 12)
100 entry = gtk.Entry()
101 entry.set_text(content)
102 entry.set_size_request(350,30)
103
104 if need_button:
105 table = gtk.Table(1, 10, False)
106 hbox.pack_start(table, expand=True, fill=True)
107 table.attach(entry, 0, 9, 0, 1, xoptions=gtk.SHRINK)
108 image = gtk.Image()
109 image.set_from_stock(gtk.STOCK_OPEN,gtk.ICON_SIZE_BUTTON)
110 open_button = gtk.Button()
111 open_button.set_image(image)
112 open_button.connect("clicked", self.entry_widget_select_path_cb, parent, entry)
113 table.attach(open_button, 9, 10, 0, 1, xoptions=gtk.SHRINK)
114 else:
115 hbox.pack_start(entry, expand=True, fill=True)
116
117 if tooltip != "":
118 info = HobInfoButton(tooltip, self)
119 hbox.pack_start(info, expand=False, fill=False)
120
121 hbox.show_all()
122 return hbox, entry
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..de924b1206
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/hig/simplesettingsdialog.py
@@ -0,0 +1,893 @@
1#
2# BitBake Graphical GTK User Interface
3#
4# Copyright (C) 2011-2012 Intel Corporation
5#
6# Authored by Joshua Lock <josh@linux.intel.com>
7# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
8# Authored by Shane Wang <shane.wang@intel.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23import gtk
24import gobject
25import hashlib
26from bb.ui.crumbs.hobwidget import hic, HobInfoButton, HobButton, HobAltButton
27from bb.ui.crumbs.progressbar import HobProgressBar
28from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper
29from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
30from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
31from bb.ui.crumbs.hig.proxydetailsdialog import ProxyDetailsDialog
32
33"""
34The following are convenience classes for implementing GNOME HIG compliant
35BitBake GUI's
36In summary: spacing = 12px, border-width = 6px
37"""
38
39class SimpleSettingsDialog (CrumbsDialog, SettingsUIHelper):
40
41 (BUILD_ENV_PAGE_ID,
42 SHARED_STATE_PAGE_ID,
43 PROXIES_PAGE_ID,
44 OTHERS_PAGE_ID) = range(4)
45
46 (TEST_NETWORK_NONE,
47 TEST_NETWORK_INITIAL,
48 TEST_NETWORK_RUNNING,
49 TEST_NETWORK_PASSED,
50 TEST_NETWORK_FAILED,
51 TEST_NETWORK_CANCELED) = range(6)
52
53 TARGETS = [
54 ("MY_TREE_MODEL_ROW", gtk.TARGET_SAME_WIDGET, 0),
55 ("text/plain", 0, 1),
56 ("TEXT", 0, 2),
57 ("STRING", 0, 3),
58 ]
59
60 def __init__(self, title, configuration, all_image_types,
61 all_package_formats, all_distros, all_sdk_machines,
62 max_threads, parent, flags, handler, buttons=None):
63 super(SimpleSettingsDialog, self).__init__(title, parent, flags, buttons)
64
65 # class members from other objects
66 # bitbake settings from Builder.Configuration
67 self.configuration = configuration
68 self.image_types = all_image_types
69 self.all_package_formats = all_package_formats
70 self.all_distros = all_distros
71 self.all_sdk_machines = all_sdk_machines
72 self.max_threads = max_threads
73
74 # class members for internal use
75 self.dldir_text = None
76 self.sstatedir_text = None
77 self.sstatemirrors_list = []
78 self.sstatemirrors_changed = 0
79 self.bb_spinner = None
80 self.pmake_spinner = None
81 self.rootfs_size_spinner = None
82 self.extra_size_spinner = None
83 self.gplv3_checkbox = None
84 self.toolchain_checkbox = None
85 self.setting_store = None
86 self.image_types_checkbuttons = {}
87
88 self.md5 = self.config_md5()
89 self.proxy_md5 = self.config_proxy_md5()
90 self.settings_changed = False
91 self.proxy_settings_changed = False
92 self.handler = handler
93 self.proxy_test_ran = False
94 self.selected_mirror_row = 0
95 self.new_mirror = False
96
97 # create visual elements on the dialog
98 self.create_visual_elements()
99 self.connect("response", self.response_cb)
100
101 def _get_sorted_value(self, var):
102 return " ".join(sorted(str(var).split())) + "\n"
103
104 def config_proxy_md5(self):
105 data = ("ENABLE_PROXY: " + self._get_sorted_value(self.configuration.enable_proxy))
106 if self.configuration.enable_proxy:
107 for protocol in self.configuration.proxies.keys():
108 data += (protocol + ": " + self._get_sorted_value(self.configuration.combine_proxy(protocol)))
109 return hashlib.md5(data).hexdigest()
110
111 def config_md5(self):
112 data = ""
113 for key in self.configuration.extra_setting.keys():
114 data += (key + ": " + self._get_sorted_value(self.configuration.extra_setting[key]))
115 return hashlib.md5(data).hexdigest()
116
117 def gen_proxy_entry_widget(self, protocol, parent, need_button=True, line=0):
118 label = gtk.Label(protocol.upper() + " proxy")
119 self.proxy_table.attach(label, 0, 1, line, line+1, xpadding=24)
120
121 proxy_entry = gtk.Entry()
122 proxy_entry.set_size_request(300, -1)
123 self.proxy_table.attach(proxy_entry, 1, 2, line, line+1, ypadding=4)
124
125 self.proxy_table.attach(gtk.Label(":"), 2, 3, line, line+1, xpadding=12, ypadding=4)
126
127 port_entry = gtk.Entry()
128 port_entry.set_size_request(60, -1)
129 self.proxy_table.attach(port_entry, 3, 4, line, line+1, ypadding=4)
130
131 details_button = HobAltButton("Details")
132 details_button.connect("clicked", self.details_cb, parent, protocol)
133 self.proxy_table.attach(details_button, 4, 5, line, line+1, xpadding=4, yoptions=gtk.EXPAND)
134
135 return proxy_entry, port_entry, details_button
136
137 def refresh_proxy_components(self):
138 self.same_checkbox.set_sensitive(self.configuration.enable_proxy)
139
140 self.http_proxy.set_text(self.configuration.combine_host_only("http"))
141 self.http_proxy.set_editable(self.configuration.enable_proxy)
142 self.http_proxy.set_sensitive(self.configuration.enable_proxy)
143 self.http_proxy_port.set_text(self.configuration.combine_port_only("http"))
144 self.http_proxy_port.set_editable(self.configuration.enable_proxy)
145 self.http_proxy_port.set_sensitive(self.configuration.enable_proxy)
146 self.http_proxy_details.set_sensitive(self.configuration.enable_proxy)
147
148 self.https_proxy.set_text(self.configuration.combine_host_only("https"))
149 self.https_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
150 self.https_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
151 self.https_proxy_port.set_text(self.configuration.combine_port_only("https"))
152 self.https_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
153 self.https_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
154 self.https_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
155
156 self.ftp_proxy.set_text(self.configuration.combine_host_only("ftp"))
157 self.ftp_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
158 self.ftp_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
159 self.ftp_proxy_port.set_text(self.configuration.combine_port_only("ftp"))
160 self.ftp_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
161 self.ftp_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
162 self.ftp_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
163
164 self.socks_proxy.set_text(self.configuration.combine_host_only("socks"))
165 self.socks_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
166 self.socks_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
167 self.socks_proxy_port.set_text(self.configuration.combine_port_only("socks"))
168 self.socks_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
169 self.socks_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
170 self.socks_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
171
172 self.cvs_proxy.set_text(self.configuration.combine_host_only("cvs"))
173 self.cvs_proxy.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
174 self.cvs_proxy.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
175 self.cvs_proxy_port.set_text(self.configuration.combine_port_only("cvs"))
176 self.cvs_proxy_port.set_editable(self.configuration.enable_proxy and (not self.configuration.same_proxy))
177 self.cvs_proxy_port.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
178 self.cvs_proxy_details.set_sensitive(self.configuration.enable_proxy and (not self.configuration.same_proxy))
179
180 if self.configuration.same_proxy:
181 if self.http_proxy.get_text():
182 [w.set_text(self.http_proxy.get_text()) for w in self.same_proxy_addresses]
183 if self.http_proxy_port.get_text():
184 [w.set_text(self.http_proxy_port.get_text()) for w in self.same_proxy_ports]
185
186 def proxy_checkbox_toggled_cb(self, button):
187 self.configuration.enable_proxy = self.proxy_checkbox.get_active()
188 if not self.configuration.enable_proxy:
189 self.configuration.same_proxy = False
190 self.same_checkbox.set_active(self.configuration.same_proxy)
191 self.save_proxy_data()
192 self.refresh_proxy_components()
193
194 def same_checkbox_toggled_cb(self, button):
195 self.configuration.same_proxy = self.same_checkbox.get_active()
196 self.save_proxy_data()
197 self.refresh_proxy_components()
198
199 def save_proxy_data(self):
200 self.configuration.split_proxy("http", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
201 if self.configuration.same_proxy:
202 self.configuration.split_proxy("https", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
203 self.configuration.split_proxy("ftp", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
204 self.configuration.split_proxy("socks", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
205 self.configuration.split_proxy("cvs", self.http_proxy.get_text() + ":" + self.http_proxy_port.get_text())
206 else:
207 self.configuration.split_proxy("https", self.https_proxy.get_text() + ":" + self.https_proxy_port.get_text())
208 self.configuration.split_proxy("ftp", self.ftp_proxy.get_text() + ":" + self.ftp_proxy_port.get_text())
209 self.configuration.split_proxy("socks", self.socks_proxy.get_text() + ":" + self.socks_proxy_port.get_text())
210 self.configuration.split_proxy("cvs", self.cvs_proxy.get_text() + ":" + self.cvs_proxy_port.get_text())
211
212 def response_cb(self, dialog, response_id):
213 if response_id == gtk.RESPONSE_YES:
214 # Check that all proxy entries have a corresponding port
215 for proxy, port in zip(self.all_proxy_addresses, self.all_proxy_ports):
216 if proxy.get_text() and not port.get_text():
217 lbl = "<b>Enter all port numbers</b>\n\n"
218 msg = "Proxy servers require a port number. Please make sure you have entered a port number for each proxy server."
219 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING, msg)
220 button = dialog.add_button("Close", gtk.RESPONSE_OK)
221 HobButton.style_button(button)
222 response = dialog.run()
223 dialog.destroy()
224 self.emit_stop_by_name("response")
225 return
226
227 self.configuration.dldir = self.dldir_text.get_text()
228 self.configuration.sstatedir = self.sstatedir_text.get_text()
229 self.configuration.sstatemirror = ""
230 for mirror in self.sstatemirrors_list:
231 if mirror[1] != "" and mirror[2].startswith("file://"):
232 if mirror[1].endswith("\\1"):
233 smirror = mirror[2] + " " + mirror[1] + " \\n "
234 else:
235 smirror = mirror[2] + " " + mirror[1] + "\\1 \\n "
236 self.configuration.sstatemirror += smirror
237 self.configuration.bbthread = self.bb_spinner.get_value_as_int()
238 self.configuration.pmake = self.pmake_spinner.get_value_as_int()
239 self.save_proxy_data()
240 self.configuration.extra_setting = {}
241 it = self.setting_store.get_iter_first()
242 while it:
243 key = self.setting_store.get_value(it, 0)
244 value = self.setting_store.get_value(it, 1)
245 self.configuration.extra_setting[key] = value
246 it = self.setting_store.iter_next(it)
247
248 md5 = self.config_md5()
249 self.settings_changed = (self.md5 != md5)
250 self.proxy_settings_changed = (self.proxy_md5 != self.config_proxy_md5())
251
252 def create_build_environment_page(self):
253 advanced_vbox = gtk.VBox(False, 6)
254 advanced_vbox.set_border_width(6)
255
256 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Parallel threads</span>'), expand=False, fill=False)
257 sub_vbox = gtk.VBox(False, 6)
258 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
259 label = self.gen_label_widget("BitBake parallel threads")
260 tooltip = "Sets the number of threads that BitBake tasks can simultaneously run. See the <a href=\""
261 tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
262 tooltip += "poky-ref-manual.html#var-BB_NUMBER_THREADS\">Poky reference manual</a> for information"
263 bbthread_widget, self.bb_spinner = self.gen_spinner_widget(self.configuration.bbthread, 1, self.max_threads,"<b>BitBake prallalel threads</b>" + "*" + tooltip)
264 sub_vbox.pack_start(label, expand=False, fill=False)
265 sub_vbox.pack_start(bbthread_widget, expand=False, fill=False)
266
267 sub_vbox = gtk.VBox(False, 6)
268 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
269 label = self.gen_label_widget("Make parallel threads")
270 tooltip = "Sets the maximum number of threads the host can use during the build. See the <a href=\""
271 tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
272 tooltip += "poky-ref-manual.html#var-PARALLEL_MAKE\">Poky reference manual</a> for information"
273 pmake_widget, self.pmake_spinner = self.gen_spinner_widget(self.configuration.pmake, 1, self.max_threads,"<b>Make parallel threads</b>" + "*" + tooltip)
274 sub_vbox.pack_start(label, expand=False, fill=False)
275 sub_vbox.pack_start(pmake_widget, expand=False, fill=False)
276
277 advanced_vbox.pack_start(self.gen_label_widget('<span weight="bold">Downloaded source code</span>'), expand=False, fill=False)
278 sub_vbox = gtk.VBox(False, 6)
279 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
280 label = self.gen_label_widget("Downloads directory")
281 tooltip = "Select a folder that caches the upstream project source code"
282 dldir_widget, self.dldir_text = self.gen_entry_widget(self.configuration.dldir, self,"<b>Downloaded source code</b>" + "*" + tooltip)
283 sub_vbox.pack_start(label, expand=False, fill=False)
284 sub_vbox.pack_start(dldir_widget, expand=False, fill=False)
285
286 return advanced_vbox
287
288 def create_shared_state_page(self):
289 advanced_vbox = gtk.VBox(False)
290 advanced_vbox.set_border_width(12)
291
292 sub_vbox = gtk.VBox(False)
293 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False, padding=24)
294 content = "<span>Shared state directory</span>"
295 tooltip = "Select a folder that caches your prebuilt results"
296 label = self.gen_label_info_widget(content,"<b>Shared state directory</b>" + "*" + tooltip)
297 sstatedir_widget, self.sstatedir_text = self.gen_entry_widget(self.configuration.sstatedir, self)
298 sub_vbox.pack_start(label, expand=False, fill=False)
299 sub_vbox.pack_start(sstatedir_widget, expand=False, fill=False, padding=6)
300
301 content = "<span weight=\"bold\">Shared state mirrors</span>"
302 tooltip = "URLs pointing to pre-built mirrors that will speed your build. "
303 tooltip += "Select the \'Standard\' configuration if the structure of your "
304 tooltip += "mirror replicates the structure of your local shared state directory. "
305 tooltip += "For more information on shared state mirrors, check the <a href=\""
306 tooltip += "http://www.yoctoproject.org/docs/current/poky-ref-manual/"
307 tooltip += "poky-ref-manual.html#shared-state\">Yocto Project Reference Manual</a>."
308 table = self.gen_label_info_widget(content,"<b>Shared state mirrors</b>" + "*" + tooltip)
309 advanced_vbox.pack_start(table, expand=False, fill=False, padding=6)
310
311 sub_vbox = gtk.VBox(False)
312 advanced_vbox.pack_start(sub_vbox, gtk.TRUE, gtk.TRUE, 0)
313
314 if self.sstatemirrors_changed == 0:
315 self.sstatemirrors_changed = 1
316 sstatemirrors = self.configuration.sstatemirror
317 if sstatemirrors == "":
318 sm_list = ["Standard", "", "file://(.*)"]
319 self.sstatemirrors_list.append(sm_list)
320 else:
321 sstatemirrors = [x for x in sstatemirrors.split('\\n')]
322 for sstatemirror in sstatemirrors:
323 sstatemirror_fields = [x for x in sstatemirror.split(' ') if x.strip()]
324 if len(sstatemirror_fields) == 2:
325 if sstatemirror_fields[0] == "file://(.*)" or sstatemirror_fields[0] == "file://.*":
326 sm_list = ["Standard", sstatemirror_fields[1], sstatemirror_fields[0]]
327 else:
328 sm_list = ["Custom", sstatemirror_fields[1], sstatemirror_fields[0]]
329 self.sstatemirrors_list.append(sm_list)
330
331 sstatemirrors_widget, sstatemirrors_store = self.gen_shared_sstate_widget(self.sstatemirrors_list, self)
332 sub_vbox.pack_start(sstatemirrors_widget, expand=True, fill=True)
333
334 table = gtk.Table(1, 10, False)
335 table.set_col_spacings(6)
336 add_mirror_button = HobAltButton("Add mirror")
337 add_mirror_button.connect("clicked", self.add_mirror)
338 add_mirror_button.set_size_request(120,30)
339 table.attach(add_mirror_button, 1, 2, 0, 1, xoptions=gtk.SHRINK)
340
341 self.delete_button = HobAltButton("Delete mirror")
342 self.delete_button.connect("clicked", self.delete_cb)
343 self.delete_button.set_size_request(120, 30)
344 table.attach(self.delete_button, 3, 4, 0, 1, xoptions=gtk.SHRINK)
345
346 advanced_vbox.pack_start(table, expand=False, fill=False, padding=6)
347
348 return advanced_vbox
349
350 def gen_shared_sstate_widget(self, sstatemirrors_list, window):
351 hbox = gtk.HBox(False)
352
353 sstatemirrors_store = gtk.ListStore(str, str, str)
354 for sstatemirror in sstatemirrors_list:
355 sstatemirrors_store.append(sstatemirror)
356
357 self.sstatemirrors_tv = gtk.TreeView()
358 self.sstatemirrors_tv.set_rules_hint(True)
359 self.sstatemirrors_tv.set_headers_visible(True)
360 tree_selection = self.sstatemirrors_tv.get_selection()
361 tree_selection.set_mode(gtk.SELECTION_SINGLE)
362
363 # Allow enable drag and drop of rows including row move
364 self.sstatemirrors_tv.enable_model_drag_source( gtk.gdk.BUTTON1_MASK,
365 self.TARGETS,
366 gtk.gdk.ACTION_DEFAULT|
367 gtk.gdk.ACTION_MOVE)
368 self.sstatemirrors_tv.enable_model_drag_dest(self.TARGETS,
369 gtk.gdk.ACTION_DEFAULT)
370 self.sstatemirrors_tv.connect("drag_data_get", self.drag_data_get_cb)
371 self.sstatemirrors_tv.connect("drag_data_received", self.drag_data_received_cb)
372
373
374 self.scroll = gtk.ScrolledWindow()
375 self.scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
376 self.scroll.set_shadow_type(gtk.SHADOW_IN)
377 self.scroll.connect('size-allocate', self.scroll_changed)
378 self.scroll.add(self.sstatemirrors_tv)
379
380 #list store for cell renderer
381 m = gtk.ListStore(gobject.TYPE_STRING)
382 m.append(["Standard"])
383 m.append(["Custom"])
384
385 cell0 = gtk.CellRendererCombo()
386 cell0.set_property("model",m)
387 cell0.set_property("text-column", 0)
388 cell0.set_property("editable", True)
389 cell0.set_property("has-entry", False)
390 col0 = gtk.TreeViewColumn("Configuration")
391 col0.pack_start(cell0, False)
392 col0.add_attribute(cell0, "text", 0)
393 col0.set_cell_data_func(cell0, self.configuration_field)
394 self.sstatemirrors_tv.append_column(col0)
395
396 cell0.connect("edited", self.combo_changed, sstatemirrors_store)
397
398 self.cell1 = gtk.CellRendererText()
399 self.cell1.set_padding(5,2)
400 col1 = gtk.TreeViewColumn('Regex', self.cell1)
401 col1.set_cell_data_func(self.cell1, self.regex_field)
402 self.sstatemirrors_tv.append_column(col1)
403
404 self.cell1.connect("edited", self.regex_changed, sstatemirrors_store)
405
406 cell2 = gtk.CellRendererText()
407 cell2.set_padding(5,2)
408 cell2.set_property("editable", True)
409 col2 = gtk.TreeViewColumn('URL', cell2)
410 col2.set_cell_data_func(cell2, self.url_field)
411 self.sstatemirrors_tv.append_column(col2)
412
413 cell2.connect("edited", self.url_changed, sstatemirrors_store)
414
415 self.sstatemirrors_tv.set_model(sstatemirrors_store)
416 self.sstatemirrors_tv.set_cursor(self.selected_mirror_row)
417 hbox.pack_start(self.scroll, expand=True, fill=True)
418 hbox.show_all()
419
420 return hbox, sstatemirrors_store
421
422 def drag_data_get_cb(self, treeview, context, selection, target_id, etime):
423 treeselection = treeview.get_selection()
424 model, iter = treeselection.get_selected()
425 data = model.get_string_from_iter(iter)
426 selection.set(selection.target, 8, data)
427
428 def drag_data_received_cb(self, treeview, context, x, y, selection, info, etime):
429 model = treeview.get_model()
430 data = []
431 tree_iter = model.get_iter_from_string(selection.data)
432 data.append(model.get_value(tree_iter, 0))
433 data.append(model.get_value(tree_iter, 1))
434 data.append(model.get_value(tree_iter, 2))
435
436 drop_info = treeview.get_dest_row_at_pos(x, y)
437 if drop_info:
438 path, position = drop_info
439 iter = model.get_iter(path)
440 if (position == gtk.TREE_VIEW_DROP_BEFORE or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE):
441 model.insert_before(iter, data)
442 else:
443 model.insert_after(iter, data)
444 else:
445 model.append(data)
446 if context.action == gtk.gdk.ACTION_MOVE:
447 context.finish(True, True, etime)
448 return
449
450 def delete_cb(self, button):
451 selection = self.sstatemirrors_tv.get_selection()
452 tree_model, tree_iter = selection.get_selected()
453 index = int(tree_model.get_string_from_iter(tree_iter))
454 if index == 0:
455 self.selected_mirror_row = index
456 else:
457 self.selected_mirror_row = index - 1
458 self.sstatemirrors_list.pop(index)
459 self.refresh_shared_state_page()
460 if not self.sstatemirrors_list:
461 self.delete_button.set_sensitive(False)
462
463 def add_mirror(self, button):
464 self.new_mirror = True
465 tooltip = "Select the pre-built mirror that will speed your build"
466 index = len(self.sstatemirrors_list)
467 self.selected_mirror_row = index
468 sm_list = ["Standard", "", "file://(.*)"]
469 self.sstatemirrors_list.append(sm_list)
470 self.refresh_shared_state_page()
471
472 def scroll_changed(self, widget, event, data=None):
473 if self.new_mirror == True:
474 adj = widget.get_vadjustment()
475 adj.set_value(adj.upper - adj.page_size)
476 self.new_mirror = False
477
478 def combo_changed(self, widget, path, text, model):
479 model[path][0] = text
480 selection = self.sstatemirrors_tv.get_selection()
481 tree_model, tree_iter = selection.get_selected()
482 index = int(tree_model.get_string_from_iter(tree_iter))
483 self.sstatemirrors_list[index][0] = text
484
485 def regex_changed(self, cell, path, new_text, user_data):
486 user_data[path][2] = new_text
487 selection = self.sstatemirrors_tv.get_selection()
488 tree_model, tree_iter = selection.get_selected()
489 index = int(tree_model.get_string_from_iter(tree_iter))
490 self.sstatemirrors_list[index][2] = new_text
491 return
492
493 def url_changed(self, cell, path, new_text, user_data):
494 if new_text!="Enter the mirror URL" and new_text!="Match regex and replace it with this URL":
495 user_data[path][1] = new_text
496 selection = self.sstatemirrors_tv.get_selection()
497 tree_model, tree_iter = selection.get_selected()
498 index = int(tree_model.get_string_from_iter(tree_iter))
499 self.sstatemirrors_list[index][1] = new_text
500 return
501
502 def configuration_field(self, column, cell, model, iter):
503 cell.set_property('text', model.get_value(iter, 0))
504 if model.get_value(iter, 0) == "Standard":
505 self.cell1.set_property("sensitive", False)
506 self.cell1.set_property("editable", False)
507 else:
508 self.cell1.set_property("sensitive", True)
509 self.cell1.set_property("editable", True)
510 return
511
512 def regex_field(self, column, cell, model, iter):
513 cell.set_property('text', model.get_value(iter, 2))
514 return
515
516 def url_field(self, column, cell, model, iter):
517 text = model.get_value(iter, 1)
518 if text == "":
519 if model.get_value(iter, 0) == "Standard":
520 text = "Enter the mirror URL"
521 else:
522 text = "Match regex and replace it with this URL"
523 cell.set_property('text', text)
524 return
525
526 def refresh_shared_state_page(self):
527 page_num = self.nb.get_current_page()
528 self.nb.remove_page(page_num);
529 self.nb.insert_page(self.create_shared_state_page(), gtk.Label("Shared state"),page_num)
530 self.show_all()
531 self.nb.set_current_page(page_num)
532
533 def test_proxy_ended(self, passed):
534 self.proxy_test_running = False
535 self.set_test_proxy_state(self.TEST_NETWORK_PASSED if passed else self.TEST_NETWORK_FAILED)
536 self.set_sensitive(True)
537 self.refresh_proxy_components()
538
539 def timer_func(self):
540 self.test_proxy_progress.pulse()
541 return self.proxy_test_running
542
543 def test_network_button_cb(self, b):
544 self.set_test_proxy_state(self.TEST_NETWORK_RUNNING)
545 self.set_sensitive(False)
546 self.save_proxy_data()
547 if self.configuration.enable_proxy == True:
548 self.handler.set_http_proxy(self.configuration.combine_proxy("http"))
549 self.handler.set_https_proxy(self.configuration.combine_proxy("https"))
550 self.handler.set_ftp_proxy(self.configuration.combine_proxy("ftp"))
551 self.handler.set_socks_proxy(self.configuration.combine_proxy("socks"))
552 self.handler.set_cvs_proxy(self.configuration.combine_host_only("cvs"), self.configuration.combine_port_only("cvs"))
553 elif self.configuration.enable_proxy == False:
554 self.handler.set_http_proxy("")
555 self.handler.set_https_proxy("")
556 self.handler.set_ftp_proxy("")
557 self.handler.set_socks_proxy("")
558 self.handler.set_cvs_proxy("", "")
559 self.proxy_test_ran = True
560 self.proxy_test_running = True
561 gobject.timeout_add(100, self.timer_func)
562 self.handler.trigger_network_test()
563
564 def test_proxy_focus_event(self, w, direction):
565 if self.test_proxy_state in [self.TEST_NETWORK_PASSED, self.TEST_NETWORK_FAILED]:
566 self.set_test_proxy_state(self.TEST_NETWORK_INITIAL)
567 return False
568
569 def http_proxy_changed(self, e):
570 if not self.configuration.same_proxy:
571 return
572 if e == self.http_proxy:
573 [w.set_text(self.http_proxy.get_text()) for w in self.same_proxy_addresses]
574 else:
575 [w.set_text(self.http_proxy_port.get_text()) for w in self.same_proxy_ports]
576
577 def proxy_address_focus_out_event(self, w, direction):
578 text = w.get_text()
579 if not text:
580 return False
581 if text.find("//") == -1:
582 w.set_text("http://" + text)
583 return False
584
585 def set_test_proxy_state(self, state):
586 if self.test_proxy_state == state:
587 return
588 [self.proxy_table.remove(w) for w in self.test_gui_elements]
589 if state == self.TEST_NETWORK_INITIAL:
590 self.proxy_table.attach(self.test_network_button, 1, 2, 5, 6)
591 self.test_network_button.show()
592 elif state == self.TEST_NETWORK_RUNNING:
593 self.test_proxy_progress.set_rcstyle("running")
594 self.test_proxy_progress.set_text("Testing network configuration")
595 self.proxy_table.attach(self.test_proxy_progress, 0, 5, 5, 6, xpadding=4)
596 self.test_proxy_progress.show()
597 else: # passed or failed
598 self.dummy_progress.update(1.0)
599 if state == self.TEST_NETWORK_PASSED:
600 self.dummy_progress.set_text("Your network is properly configured")
601 self.dummy_progress.set_rcstyle("running")
602 else:
603 self.dummy_progress.set_text("Network test failed")
604 self.dummy_progress.set_rcstyle("fail")
605 self.proxy_table.attach(self.dummy_progress, 0, 4, 5, 6)
606 self.proxy_table.attach(self.retest_network_button, 4, 5, 5, 6, xpadding=4)
607 self.dummy_progress.show()
608 self.retest_network_button.show()
609 self.test_proxy_state = state
610
611 def create_network_page(self):
612 advanced_vbox = gtk.VBox(False, 6)
613 advanced_vbox.set_border_width(6)
614 self.same_proxy_addresses = []
615 self.same_proxy_ports = []
616 self.all_proxy_ports = []
617 self.all_proxy_addresses = []
618
619 sub_vbox = gtk.VBox(False, 6)
620 advanced_vbox.pack_start(sub_vbox, expand=False, fill=False)
621 label = self.gen_label_widget("<span weight=\"bold\">Set the proxies used when fetching source code</span>")
622 tooltip = "Set the proxies used when fetching source code. A blank field uses a direct internet connection."
623 info = HobInfoButton("<span weight=\"bold\">Set the proxies used when fetching source code</span>" + "*" + tooltip, self)
624 hbox = gtk.HBox(False, 12)
625 hbox.pack_start(label, expand=True, fill=True)
626 hbox.pack_start(info, expand=False, fill=False)
627 sub_vbox.pack_start(hbox, expand=False, fill=False)
628
629 proxy_test_focus = []
630 self.direct_checkbox = gtk.RadioButton(None, "Direct network connection")
631 proxy_test_focus.append(self.direct_checkbox)
632 self.direct_checkbox.set_tooltip_text("Check this box to use a direct internet connection with no proxy")
633 self.direct_checkbox.set_active(not self.configuration.enable_proxy)
634 sub_vbox.pack_start(self.direct_checkbox, expand=False, fill=False)
635
636 self.proxy_checkbox = gtk.RadioButton(self.direct_checkbox, "Manual proxy configuration")
637 proxy_test_focus.append(self.proxy_checkbox)
638 self.proxy_checkbox.set_tooltip_text("Check this box to manually set up a specific proxy")
639 self.proxy_checkbox.set_active(self.configuration.enable_proxy)
640 sub_vbox.pack_start(self.proxy_checkbox, expand=False, fill=False)
641
642 self.same_checkbox = gtk.CheckButton("Use the HTTP proxy for all protocols")
643 proxy_test_focus.append(self.same_checkbox)
644 self.same_checkbox.set_tooltip_text("Check this box to use the HTTP proxy for all five proxies")
645 self.same_checkbox.set_active(self.configuration.same_proxy)
646 hbox = gtk.HBox(False, 12)
647 hbox.pack_start(self.same_checkbox, expand=False, fill=False, padding=24)
648 sub_vbox.pack_start(hbox, expand=False, fill=False)
649
650 self.proxy_table = gtk.Table(6, 5, False)
651 self.http_proxy, self.http_proxy_port, self.http_proxy_details = self.gen_proxy_entry_widget(
652 "http", self, True, 0)
653 proxy_test_focus +=[self.http_proxy, self.http_proxy_port]
654 self.http_proxy.connect("changed", self.http_proxy_changed)
655 self.http_proxy_port.connect("changed", self.http_proxy_changed)
656
657 self.https_proxy, self.https_proxy_port, self.https_proxy_details = self.gen_proxy_entry_widget(
658 "https", self, True, 1)
659 proxy_test_focus += [self.https_proxy, self.https_proxy_port]
660 self.same_proxy_addresses.append(self.https_proxy)
661 self.same_proxy_ports.append(self.https_proxy_port)
662
663 self.ftp_proxy, self.ftp_proxy_port, self.ftp_proxy_details = self.gen_proxy_entry_widget(
664 "ftp", self, True, 2)
665 proxy_test_focus += [self.ftp_proxy, self.ftp_proxy_port]
666 self.same_proxy_addresses.append(self.ftp_proxy)
667 self.same_proxy_ports.append(self.ftp_proxy_port)
668
669 self.socks_proxy, self.socks_proxy_port, self.socks_proxy_details = self.gen_proxy_entry_widget(
670 "socks", self, True, 3)
671 proxy_test_focus += [self.socks_proxy, self.socks_proxy_port]
672 self.same_proxy_addresses.append(self.socks_proxy)
673 self.same_proxy_ports.append(self.socks_proxy_port)
674
675 self.cvs_proxy, self.cvs_proxy_port, self.cvs_proxy_details = self.gen_proxy_entry_widget(
676 "cvs", self, True, 4)
677 proxy_test_focus += [self.cvs_proxy, self.cvs_proxy_port]
678 self.same_proxy_addresses.append(self.cvs_proxy)
679 self.same_proxy_ports.append(self.cvs_proxy_port)
680 self.all_proxy_ports = self.same_proxy_ports + [self.http_proxy_port]
681 self.all_proxy_addresses = self.same_proxy_addresses + [self.http_proxy]
682 sub_vbox.pack_start(self.proxy_table, expand=False, fill=False)
683 self.proxy_table.show_all()
684
685 # Create the graphical elements for the network test feature, but don't display them yet
686 self.test_network_button = HobAltButton("Test network configuration")
687 self.test_network_button.connect("clicked", self.test_network_button_cb)
688 self.test_proxy_progress = HobProgressBar()
689 self.dummy_progress = HobProgressBar()
690 self.retest_network_button = HobAltButton("Retest")
691 self.retest_network_button.connect("clicked", self.test_network_button_cb)
692 self.test_gui_elements = [self.test_network_button, self.test_proxy_progress, self.dummy_progress, self.retest_network_button]
693 # Initialize the network tester
694 self.test_proxy_state = self.TEST_NETWORK_NONE
695 self.set_test_proxy_state(self.TEST_NETWORK_INITIAL)
696 self.proxy_test_passed_id = self.handler.connect("network-passed", lambda h:self.test_proxy_ended(True))
697 self.proxy_test_failed_id = self.handler.connect("network-failed", lambda h:self.test_proxy_ended(False))
698 [w.connect("focus-in-event", self.test_proxy_focus_event) for w in proxy_test_focus]
699 [w.connect("focus-out-event", self.proxy_address_focus_out_event) for w in self.all_proxy_addresses]
700
701 self.direct_checkbox.connect("toggled", self.proxy_checkbox_toggled_cb)
702 self.proxy_checkbox.connect("toggled", self.proxy_checkbox_toggled_cb)
703 self.same_checkbox.connect("toggled", self.same_checkbox_toggled_cb)
704
705 self.refresh_proxy_components()
706 return advanced_vbox
707
708 def switch_to_page(self, page_id):
709 self.nb.set_current_page(page_id)
710
711 def details_cb(self, button, parent, protocol):
712 self.save_proxy_data()
713 dialog = ProxyDetailsDialog(title = protocol.upper() + " Proxy Details",
714 user = self.configuration.proxies[protocol][1],
715 passwd = self.configuration.proxies[protocol][2],
716 parent = parent,
717 flags = gtk.DIALOG_MODAL
718 | gtk.DIALOG_DESTROY_WITH_PARENT
719 | gtk.DIALOG_NO_SEPARATOR)
720 dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK)
721 response = dialog.run()
722 if response == gtk.RESPONSE_OK:
723 self.configuration.proxies[protocol][1] = dialog.user
724 self.configuration.proxies[protocol][2] = dialog.passwd
725 self.refresh_proxy_components()
726 dialog.destroy()
727
728 def rootfs_combo_changed_cb(self, rootfs_combo, all_package_format, check_hbox):
729 combo_item = self.rootfs_combo.get_active_text()
730 for child in check_hbox.get_children():
731 if isinstance(child, gtk.CheckButton):
732 check_hbox.remove(child)
733 for format in all_package_format:
734 if format != combo_item:
735 check_button = gtk.CheckButton(format)
736 check_hbox.pack_start(check_button, expand=False, fill=False)
737 check_hbox.show_all()
738
739 def gen_pkgfmt_widget(self, curr_package_format, all_package_format, tooltip_combo="", tooltip_extra=""):
740 pkgfmt_hbox = gtk.HBox(False, 24)
741
742 rootfs_vbox = gtk.VBox(False, 6)
743 pkgfmt_hbox.pack_start(rootfs_vbox, expand=False, fill=False)
744
745 label = self.gen_label_widget("Root file system package format")
746 rootfs_vbox.pack_start(label, expand=False, fill=False)
747
748 rootfs_format = ""
749 if curr_package_format:
750 rootfs_format = curr_package_format.split()[0]
751
752 rootfs_format_widget, rootfs_combo = self.gen_combo_widget(rootfs_format, all_package_format, tooltip_combo)
753 rootfs_vbox.pack_start(rootfs_format_widget, expand=False, fill=False)
754
755 extra_vbox = gtk.VBox(False, 6)
756 pkgfmt_hbox.pack_start(extra_vbox, expand=False, fill=False)
757
758 label = self.gen_label_widget("Additional package formats")
759 extra_vbox.pack_start(label, expand=False, fill=False)
760
761 check_hbox = gtk.HBox(False, 12)
762 extra_vbox.pack_start(check_hbox, expand=False, fill=False)
763 for format in all_package_format:
764 if format != rootfs_format:
765 check_button = gtk.CheckButton(format)
766 is_active = (format in curr_package_format.split())
767 check_button.set_active(is_active)
768 check_hbox.pack_start(check_button, expand=False, fill=False)
769
770 info = HobInfoButton(tooltip_extra, self)
771 check_hbox.pack_end(info, expand=False, fill=False)
772
773 rootfs_combo.connect("changed", self.rootfs_combo_changed_cb, all_package_format, check_hbox)
774
775 pkgfmt_hbox.show_all()
776
777 return pkgfmt_hbox, rootfs_combo, check_hbox
778
779 def editable_settings_cell_edited(self, cell, path_string, new_text, model):
780 it = model.get_iter_from_string(path_string)
781 column = cell.get_data("column")
782 model.set(it, column, new_text)
783
784 def editable_settings_add_item_clicked(self, button, model):
785 new_item = ["##KEY##", "##VALUE##"]
786
787 iter = model.append()
788 model.set (iter,
789 0, new_item[0],
790 1, new_item[1],
791 )
792
793 def editable_settings_remove_item_clicked(self, button, treeview):
794 selection = treeview.get_selection()
795 model, iter = selection.get_selected()
796
797 if iter:
798 path = model.get_path(iter)[0]
799 model.remove(iter)
800
801 def gen_editable_settings(self, setting, tooltip=""):
802 setting_hbox = gtk.HBox(False, 12)
803
804 vbox = gtk.VBox(False, 12)
805 setting_hbox.pack_start(vbox, expand=True, fill=True)
806
807 setting_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
808 for key in setting.keys():
809 setting_store.set(setting_store.append(), 0, key, 1, setting[key])
810
811 setting_tree = gtk.TreeView(setting_store)
812 setting_tree.set_headers_visible(True)
813 setting_tree.set_size_request(300, 100)
814
815 col = gtk.TreeViewColumn('Key')
816 col.set_min_width(100)
817 col.set_max_width(150)
818 col.set_resizable(True)
819 col1 = gtk.TreeViewColumn('Value')
820 col1.set_min_width(100)
821 col1.set_max_width(150)
822 col1.set_resizable(True)
823 setting_tree.append_column(col)
824 setting_tree.append_column(col1)
825 cell = gtk.CellRendererText()
826 cell.set_property('width-chars', 10)
827 cell.set_property('editable', True)
828 cell.set_data("column", 0)
829 cell.connect("edited", self.editable_settings_cell_edited, setting_store)
830 cell1 = gtk.CellRendererText()
831 cell1.set_property('width-chars', 10)
832 cell1.set_property('editable', True)
833 cell1.set_data("column", 1)
834 cell1.connect("edited", self.editable_settings_cell_edited, setting_store)
835 col.pack_start(cell, True)
836 col1.pack_end(cell1, True)
837 col.set_attributes(cell, text=0)
838 col1.set_attributes(cell1, text=1)
839
840 scroll = gtk.ScrolledWindow()
841 scroll.set_shadow_type(gtk.SHADOW_IN)
842 scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
843 scroll.add(setting_tree)
844 vbox.pack_start(scroll, expand=True, fill=True)
845
846 # some buttons
847 hbox = gtk.HBox(True, 6)
848 vbox.pack_start(hbox, False, False)
849
850 button = gtk.Button(stock=gtk.STOCK_ADD)
851 button.connect("clicked", self.editable_settings_add_item_clicked, setting_store)
852 hbox.pack_start(button)
853
854 button = gtk.Button(stock=gtk.STOCK_REMOVE)
855 button.connect("clicked", self.editable_settings_remove_item_clicked, setting_tree)
856 hbox.pack_start(button)
857
858 info = HobInfoButton(tooltip, self)
859 setting_hbox.pack_start(info, expand=False, fill=False)
860
861 return setting_hbox, setting_store
862
863 def create_others_page(self):
864 advanced_vbox = gtk.VBox(False, 6)
865 advanced_vbox.set_border_width(6)
866
867 sub_vbox = gtk.VBox(False, 6)
868 advanced_vbox.pack_start(sub_vbox, expand=True, fill=True)
869 label = self.gen_label_widget("<span weight=\"bold\">Add your own variables:</span>")
870 tooltip = "These are key/value pairs for your extra settings. Click \'Add\' and then directly edit the key and the value"
871 setting_widget, self.setting_store = self.gen_editable_settings(self.configuration.extra_setting,"<b>Add your own variables</b>" + "*" + tooltip)
872 sub_vbox.pack_start(label, expand=False, fill=False)
873 sub_vbox.pack_start(setting_widget, expand=True, fill=True)
874
875 return advanced_vbox
876
877 def create_visual_elements(self):
878 self.nb = gtk.Notebook()
879 self.nb.set_show_tabs(True)
880 self.nb.append_page(self.create_build_environment_page(), gtk.Label("Build environment"))
881 self.nb.append_page(self.create_shared_state_page(), gtk.Label("Shared state"))
882 self.nb.append_page(self.create_network_page(), gtk.Label("Network"))
883 self.nb.append_page(self.create_others_page(), gtk.Label("Others"))
884 self.nb.set_current_page(0)
885 self.vbox.pack_start(self.nb, expand=True, fill=True)
886 self.vbox.pack_end(gtk.HSeparator(), expand=True, fill=True)
887
888 self.show_all()
889
890 def destroy(self):
891 self.handler.disconnect(self.proxy_test_passed_id)
892 self.handler.disconnect(self.proxy_test_failed_id)
893 super(SimpleSettingsDialog, self).destroy()