diff options
author | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-05-13 14:11:02 +0100 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-06-02 08:24:03 +0100 |
commit | 8a93f5f32e141b4d153156152b9aeb1af25325ba (patch) | |
tree | 53e312db1ade4f78829221fb16c8cb713a846f53 /bitbake | |
parent | 685628ebc459dd1a09ce0dafc88a159aaaead732 (diff) | |
download | poky-8a93f5f32e141b4d153156152b9aeb1af25325ba.tar.gz |
bitbake: goggle/image-writer: Drop since bitrotting and no longer used
The upgrade to python3 is the final nail in the coffin for image-writer
and the goggle UI. Neither seem used or recieve patches and are based
on old versions of GTK+ so drop them, and the remaining crumbs support
pieces.
(Bitbake rev: ee7df1ca00c76f755057c157c093294efb9078d8)
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
19 files changed, 0 insertions, 4034 deletions
diff --git a/bitbake/bin/image-writer b/bitbake/bin/image-writer deleted file mode 100755 index 40e284d59c..0000000000 --- a/bitbake/bin/image-writer +++ /dev/null | |||
@@ -1,127 +0,0 @@ | |||
1 | #!/usr/bin/env python3 | ||
2 | |||
3 | # Copyright (c) 2012 Wind River Systems, Inc. | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License version 2 as | ||
7 | # published by the Free Software Foundation. | ||
8 | # | ||
9 | # This program is distributed in the hope that it will be useful, | ||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
12 | # See the GNU General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with this program; if not, write to the Free Software | ||
16 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | |||
18 | import os | ||
19 | import sys | ||
20 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname( \ | ||
21 | os.path.abspath(__file__))), 'lib')) | ||
22 | try: | ||
23 | import bb | ||
24 | except RuntimeError as exc: | ||
25 | sys.exit(str(exc)) | ||
26 | |||
27 | from gi import pygtkcompat | ||
28 | |||
29 | pygtkcompat.enable() | ||
30 | pygtkcompat.enable_gtk(version='3.0') | ||
31 | |||
32 | import gtk | ||
33 | import optparse | ||
34 | |||
35 | from bb.ui.crumbs.hobwidget import HobAltButton, HobButton | ||
36 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
37 | from bb.ui.crumbs.hig.deployimagedialog import DeployImageDialog | ||
38 | from bb.ui.crumbs.hig.imageselectiondialog import ImageSelectionDialog | ||
39 | |||
40 | # I put all the fs bitbake supported here. Need more test. | ||
41 | DEPLOYABLE_IMAGE_TYPES = ["jffs2", "cramfs", "ext2", "ext3", "ext4", "btrfs", "squashfs", "ubi", "vmdk"] | ||
42 | Title = "USB Image Writer" | ||
43 | |||
44 | class DeployWindow(gtk.Window): | ||
45 | def __init__(self, image_path=''): | ||
46 | super(DeployWindow, self).__init__() | ||
47 | |||
48 | if len(image_path) > 0: | ||
49 | valid = True | ||
50 | if not os.path.exists(image_path): | ||
51 | valid = False | ||
52 | lbl = "<b>Invalid image file path: %s.</b>\nPress <b>Select Image</b> to select an image." % image_path | ||
53 | else: | ||
54 | image_path = os.path.abspath(image_path) | ||
55 | extend_name = os.path.splitext(image_path)[1][1:] | ||
56 | if extend_name not in DEPLOYABLE_IMAGE_TYPES: | ||
57 | valid = False | ||
58 | lbl = "<b>Undeployable imge type: %s</b>\nPress <b>Select Image</b> to select an image." % extend_name | ||
59 | |||
60 | if not valid: | ||
61 | image_path = '' | ||
62 | crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
63 | button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK) | ||
64 | HobButton.style_button(button) | ||
65 | crumbs_dialog.run() | ||
66 | crumbs_dialog.destroy() | ||
67 | |||
68 | self.deploy_dialog = DeployImageDialog(Title, image_path, self, | ||
69 | gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | ||
70 | , None, standalone=True) | ||
71 | #FIXME | gtk.DIALOG_NO_SEPARATOR | ||
72 | close_button = self.deploy_dialog.add_button("Close", gtk.RESPONSE_NO) | ||
73 | HobAltButton.style_button(close_button) | ||
74 | close_button.connect('clicked', gtk.main_quit) | ||
75 | |||
76 | write_button = self.deploy_dialog.add_button("Write USB image", gtk.RESPONSE_YES) | ||
77 | HobAltButton.style_button(write_button) | ||
78 | |||
79 | self.deploy_dialog.connect('select_image_clicked', self.select_image_clicked_cb) | ||
80 | self.deploy_dialog.connect('destroy', gtk.main_quit) | ||
81 | response = self.deploy_dialog.show() | ||
82 | |||
83 | def select_image_clicked_cb(self, dialog): | ||
84 | cwd = os.getcwd() | ||
85 | dialog = ImageSelectionDialog(cwd, DEPLOYABLE_IMAGE_TYPES, Title, self, gtk.FILE_CHOOSER_ACTION_SAVE ) | ||
86 | button = dialog.add_button("Cancel", gtk.RESPONSE_NO) | ||
87 | HobAltButton.style_button(button) | ||
88 | button = dialog.add_button("Open", gtk.RESPONSE_YES) | ||
89 | HobAltButton.style_button(button) | ||
90 | response = dialog.run() | ||
91 | |||
92 | if response == gtk.RESPONSE_YES: | ||
93 | if not dialog.image_names: | ||
94 | lbl = "<b>No selections made</b>\nClicked the radio button to select a image." | ||
95 | crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
96 | button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK) | ||
97 | HobButton.style_button(button) | ||
98 | crumbs_dialog.run() | ||
99 | crumbs_dialog.destroy() | ||
100 | dialog.destroy() | ||
101 | return | ||
102 | |||
103 | # get the full path of image | ||
104 | image_path = os.path.join(dialog.image_folder, dialog.image_names[0]) | ||
105 | self.deploy_dialog.set_image_text_buffer(image_path) | ||
106 | self.deploy_dialog.set_image_path(image_path) | ||
107 | |||
108 | dialog.destroy() | ||
109 | |||
110 | def main(): | ||
111 | parser = optparse.OptionParser( | ||
112 | usage = """%prog [-h] [image_file] | ||
113 | |||
114 | %prog writes bootable images to USB devices. You can | ||
115 | provide the image file on the command line or select it using the GUI.""") | ||
116 | |||
117 | options, args = parser.parse_args(sys.argv) | ||
118 | image_file = args[1] if len(args) > 1 else '' | ||
119 | dw = DeployWindow(image_file) | ||
120 | |||
121 | if __name__ == '__main__': | ||
122 | try: | ||
123 | main() | ||
124 | gtk.main() | ||
125 | except Exception: | ||
126 | import traceback | ||
127 | traceback.print_exc() | ||
diff --git a/bitbake/lib/bb/ui/crumbs/__init__.py b/bitbake/lib/bb/ui/crumbs/__init__.py deleted file mode 100644 index b7cbe1a4f3..0000000000 --- a/bitbake/lib/bb/ui/crumbs/__init__.py +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | # | ||
2 | # Gtk+ UI pieces for BitBake | ||
3 | # | ||
4 | # Copyright (C) 2006-2007 Richard Purdie | ||
5 | # | ||
6 | # This program is free software; you can redistribute it and/or modify | ||
7 | # it under the terms of the GNU General Public License version 2 as | ||
8 | # published by the Free Software Foundation. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License along | ||
16 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/__init__.py b/bitbake/lib/bb/ui/crumbs/hig/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/__init__.py +++ /dev/null | |||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py b/bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py deleted file mode 100644 index 73b9234c27..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/crumbsdialog.py +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011-2012 Intel Corporation | ||
5 | # | ||
6 | # Authored by Joshua Lock <josh@linux.intel.com> | ||
7 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | ||
8 | # Authored by Shane Wang <shane.wang@intel.com> | ||
9 | # | ||
10 | # This program is free software; you can redistribute it and/or modify | ||
11 | # it under the terms of the GNU General Public License version 2 as | ||
12 | # published by the Free Software Foundation. | ||
13 | # | ||
14 | # This program is distributed in the hope that it will be useful, | ||
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | # GNU General Public License for more details. | ||
18 | # | ||
19 | # You should have received a copy of the GNU General Public License along | ||
20 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
22 | |||
23 | import gtk | ||
24 | |||
25 | """ | ||
26 | The following are convenience classes for implementing GNOME HIG compliant | ||
27 | BitBake GUI's | ||
28 | In summary: spacing = 12px, border-width = 6px | ||
29 | """ | ||
30 | |||
31 | class CrumbsDialog(gtk.Dialog): | ||
32 | """ | ||
33 | A GNOME HIG compliant dialog widget. | ||
34 | Add buttons with gtk.Dialog.add_button or gtk.Dialog.add_buttons | ||
35 | """ | ||
36 | def __init__(self, title="", parent=None, flags=0, buttons=None): | ||
37 | super(CrumbsDialog, self).__init__(title, parent, flags, buttons) | ||
38 | |||
39 | #FIXME 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 deleted file mode 100644 index 3b998e4637..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/crumbsmessagedialog.py +++ /dev/null | |||
@@ -1,70 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011-2012 Intel Corporation | ||
5 | # | ||
6 | # Authored by Joshua Lock <josh@linux.intel.com> | ||
7 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | ||
8 | # Authored by Shane Wang <shane.wang@intel.com> | ||
9 | # | ||
10 | # This program is free software; you can redistribute it and/or modify | ||
11 | # it under the terms of the GNU General Public License version 2 as | ||
12 | # published by the Free Software Foundation. | ||
13 | # | ||
14 | # This program is distributed in the hope that it will be useful, | ||
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | # GNU General Public License for more details. | ||
18 | # | ||
19 | # You should have received a copy of the GNU General Public License along | ||
20 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
22 | |||
23 | import glib | ||
24 | import gtk | ||
25 | from bb.ui.crumbs.hobwidget import HobIconChecker | ||
26 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
27 | |||
28 | """ | ||
29 | The following are convenience classes for implementing GNOME HIG compliant | ||
30 | BitBake GUI's | ||
31 | In summary: spacing = 12px, border-width = 6px | ||
32 | """ | ||
33 | |||
34 | class CrumbsMessageDialog(gtk.MessageDialog): | ||
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="", dialog_type = gtk.MESSAGE_QUESTION, msg=""): | ||
40 | super(CrumbsMessageDialog, self).__init__(None, | ||
41 | gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, | ||
42 | dialog_type, | ||
43 | gtk.BUTTONS_NONE, | ||
44 | None) | ||
45 | |||
46 | self.set_skip_taskbar_hint(False) | ||
47 | |||
48 | self.set_markup(label) | ||
49 | |||
50 | if 0 <= len(msg) < 300: | ||
51 | self.format_secondary_markup(msg) | ||
52 | else: | ||
53 | vbox = self.get_message_area() | ||
54 | vbox.set_border_width(1) | ||
55 | vbox.set_property("spacing", 12) | ||
56 | self.textWindow = gtk.ScrolledWindow() | ||
57 | self.textWindow.set_shadow_type(gtk.SHADOW_IN) | ||
58 | self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | ||
59 | self.msgView = gtk.TextView() | ||
60 | self.msgView.set_editable(False) | ||
61 | self.msgView.set_wrap_mode(gtk.WRAP_WORD) | ||
62 | self.msgView.set_cursor_visible(False) | ||
63 | self.msgView.set_size_request(300, 300) | ||
64 | self.buf = gtk.TextBuffer() | ||
65 | self.buf.set_text(msg) | ||
66 | self.msgView.set_buffer(self.buf) | ||
67 | self.textWindow.add(self.msgView) | ||
68 | self.msgView.show() | ||
69 | vbox.add(self.textWindow) | ||
70 | self.textWindow.show() | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py b/bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py deleted file mode 100644 index a13fff906a..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/deployimagedialog.py +++ /dev/null | |||
@@ -1,219 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011-2012 Intel Corporation | ||
5 | # | ||
6 | # Authored by Joshua Lock <josh@linux.intel.com> | ||
7 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | ||
8 | # Authored by Shane Wang <shane.wang@intel.com> | ||
9 | # | ||
10 | # This program is free software; you can redistribute it and/or modify | ||
11 | # it under the terms of the GNU General Public License version 2 as | ||
12 | # published by the Free Software Foundation. | ||
13 | # | ||
14 | # This program is distributed in the hope that it will be useful, | ||
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | # GNU General Public License for more details. | ||
18 | # | ||
19 | # You should have received a copy of the GNU General Public License along | ||
20 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
22 | |||
23 | import glob | ||
24 | import gtk | ||
25 | import gobject | ||
26 | import os | ||
27 | import re | ||
28 | import shlex | ||
29 | import subprocess | ||
30 | import tempfile | ||
31 | from bb.ui.crumbs.hobwidget import hic, HobButton | ||
32 | from bb.ui.crumbs.progressbar import HobProgressBar | ||
33 | import bb.ui.crumbs.utils | ||
34 | import bb.process | ||
35 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
36 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
37 | |||
38 | """ | ||
39 | The following are convenience classes for implementing GNOME HIG compliant | ||
40 | BitBake GUI's | ||
41 | In summary: spacing = 12px, border-width = 6px | ||
42 | """ | ||
43 | |||
44 | class DeployImageDialog (CrumbsDialog): | ||
45 | |||
46 | __dummy_usb__ = "--select a usb drive--" | ||
47 | |||
48 | def __init__(self, title, image_path, parent, flags, buttons=None, standalone=False): | ||
49 | super(DeployImageDialog, self).__init__(title, parent, flags, buttons) | ||
50 | |||
51 | self.image_path = image_path | ||
52 | self.standalone = standalone | ||
53 | |||
54 | self.create_visual_elements() | ||
55 | self.connect("response", self.response_cb) | ||
56 | |||
57 | def create_visual_elements(self): | ||
58 | self.set_size_request(600, 400) | ||
59 | label = gtk.Label() | ||
60 | label.set_alignment(0.0, 0.5) | ||
61 | markup = "<span font_desc='12'>The image to be written into usb drive:</span>" | ||
62 | label.set_markup(markup) | ||
63 | self.vbox.pack_start(label, expand=False, fill=False, padding=2) | ||
64 | |||
65 | table = gtk.Table(2, 10, False) | ||
66 | table.set_col_spacings(5) | ||
67 | table.set_row_spacings(5) | ||
68 | self.vbox.pack_start(table, expand=True, fill=True) | ||
69 | |||
70 | scroll = gtk.ScrolledWindow() | ||
71 | scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) | ||
72 | scroll.set_shadow_type(gtk.SHADOW_IN) | ||
73 | tv = gtk.TextView() | ||
74 | tv.set_editable(False) | ||
75 | tv.set_wrap_mode(gtk.WRAP_WORD) | ||
76 | tv.set_cursor_visible(False) | ||
77 | self.buf = gtk.TextBuffer() | ||
78 | self.buf.set_text(self.image_path) | ||
79 | tv.set_buffer(self.buf) | ||
80 | scroll.add(tv) | ||
81 | table.attach(scroll, 0, 10, 0, 1) | ||
82 | |||
83 | # There are 2 ways to use DeployImageDialog | ||
84 | # One way is that called by HOB when the 'Deploy Image' button is clicked | ||
85 | # The other way is that called by a standalone script. | ||
86 | # Following block of codes handles the latter way. It adds a 'Select Image' button and | ||
87 | # emit a signal when the button is clicked. | ||
88 | if self.standalone: | ||
89 | gobject.signal_new("select_image_clicked", self, gobject.SIGNAL_RUN_FIRST, | ||
90 | gobject.TYPE_NONE, ()) | ||
91 | icon = gtk.Image() | ||
92 | pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_IMAGES_DISPLAY_FILE) | ||
93 | icon.set_from_pixbuf(pix_buffer) | ||
94 | button = gtk.Button("Select Image") | ||
95 | button.set_image(icon) | ||
96 | #button.set_size_request(140, 50) | ||
97 | table.attach(button, 9, 10, 1, 2, gtk.FILL, 0, 0, 0) | ||
98 | button.connect("clicked", self.select_image_button_clicked_cb) | ||
99 | |||
100 | separator = gtk.HSeparator() | ||
101 | self.vbox.pack_start(separator, expand=False, fill=False, padding=10) | ||
102 | |||
103 | self.usb_desc = gtk.Label() | ||
104 | self.usb_desc.set_alignment(0.0, 0.5) | ||
105 | markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>" | ||
106 | self.usb_desc.set_markup(markup) | ||
107 | |||
108 | self.usb_combo = gtk.combo_box_new_text() | ||
109 | self.usb_combo.connect("changed", self.usb_combo_changed_cb) | ||
110 | model = self.usb_combo.get_model() | ||
111 | model.clear() | ||
112 | self.usb_combo.append_text(self.__dummy_usb__) | ||
113 | for usb in self.find_all_usb_devices(): | ||
114 | self.usb_combo.append_text("/dev/" + usb) | ||
115 | self.usb_combo.set_active(0) | ||
116 | self.vbox.pack_start(self.usb_combo, expand=False, fill=False) | ||
117 | self.vbox.pack_start(self.usb_desc, expand=False, fill=False, padding=2) | ||
118 | |||
119 | self.progress_bar = HobProgressBar() | ||
120 | self.vbox.pack_start(self.progress_bar, expand=False, fill=False) | ||
121 | separator = gtk.HSeparator() | ||
122 | self.vbox.pack_start(separator, expand=False, fill=True, padding=10) | ||
123 | |||
124 | self.vbox.show_all() | ||
125 | self.progress_bar.hide() | ||
126 | |||
127 | def set_image_text_buffer(self, image_path): | ||
128 | self.buf.set_text(image_path) | ||
129 | |||
130 | def set_image_path(self, image_path): | ||
131 | self.image_path = image_path | ||
132 | |||
133 | def popen_read(self, cmd): | ||
134 | tmpout, errors = bb.process.run("%s" % cmd) | ||
135 | return tmpout.strip() | ||
136 | |||
137 | def find_all_usb_devices(self): | ||
138 | usb_devs = [ os.readlink(u) | ||
139 | for u in glob.glob('/dev/disk/by-id/usb*') | ||
140 | if not re.search(r'part\d+', u) ] | ||
141 | return [ '%s' % u[u.rfind('/')+1:] for u in usb_devs ] | ||
142 | |||
143 | def get_usb_info(self, dev): | ||
144 | return "%s %s" % \ | ||
145 | (self.popen_read('cat /sys/class/block/%s/device/vendor' % dev), | ||
146 | self.popen_read('cat /sys/class/block/%s/device/model' % dev)) | ||
147 | |||
148 | def select_image_button_clicked_cb(self, button): | ||
149 | self.emit('select_image_clicked') | ||
150 | |||
151 | def usb_combo_changed_cb(self, usb_combo): | ||
152 | combo_item = self.usb_combo.get_active_text() | ||
153 | if not combo_item or combo_item == self.__dummy_usb__: | ||
154 | markup = "<span font_desc='12'>You haven't chosen any USB drive.</span>" | ||
155 | self.usb_desc.set_markup(markup) | ||
156 | else: | ||
157 | markup = "<span font_desc='12'>" + self.get_usb_info(combo_item.lstrip("/dev/")) + "</span>" | ||
158 | self.usb_desc.set_markup(markup) | ||
159 | |||
160 | def response_cb(self, dialog, response_id): | ||
161 | if response_id == gtk.RESPONSE_YES: | ||
162 | lbl = '' | ||
163 | msg = '' | ||
164 | combo_item = self.usb_combo.get_active_text() | ||
165 | if combo_item and combo_item != self.__dummy_usb__ and self.image_path: | ||
166 | cmdline = bb.ui.crumbs.utils.which_terminal() | ||
167 | if cmdline: | ||
168 | tmpfile = tempfile.NamedTemporaryFile() | ||
169 | cmdline += "\"sudo dd if=" + self.image_path + \ | ||
170 | " of=" + combo_item + " && sync; echo $? > " + tmpfile.name + "\"" | ||
171 | subprocess.call(shlex.split(cmdline)) | ||
172 | |||
173 | if int(tmpfile.readline().strip()) == 0: | ||
174 | lbl = "<b>Deploy image successfully.</b>" | ||
175 | else: | ||
176 | lbl = "<b>Failed to deploy image.</b>" | ||
177 | msg = "Please check image <b>%s</b> exists and USB device <b>%s</b> is writable." % (self.image_path, combo_item) | ||
178 | tmpfile.close() | ||
179 | else: | ||
180 | if not self.image_path: | ||
181 | lbl = "<b>No selection made.</b>" | ||
182 | msg = "You have not selected an image to deploy." | ||
183 | else: | ||
184 | lbl = "<b>No selection made.</b>" | ||
185 | msg = "You have not selected a USB device." | ||
186 | if len(lbl): | ||
187 | crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg) | ||
188 | button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK) | ||
189 | HobButton.style_button(button) | ||
190 | crumbs_dialog.run() | ||
191 | crumbs_dialog.destroy() | ||
192 | |||
193 | def update_progress_bar(self, title, fraction, status=None): | ||
194 | self.progress_bar.update(fraction) | ||
195 | self.progress_bar.set_title(title) | ||
196 | self.progress_bar.set_rcstyle(status) | ||
197 | |||
198 | def write_file(self, ifile, ofile): | ||
199 | self.progress_bar.reset() | ||
200 | self.progress_bar.show() | ||
201 | |||
202 | f_from = os.open(ifile, os.O_RDONLY) | ||
203 | f_to = os.open(ofile, os.O_WRONLY) | ||
204 | |||
205 | total_size = os.stat(ifile).st_size | ||
206 | written_size = 0 | ||
207 | |||
208 | while True: | ||
209 | buf = os.read(f_from, 1024*1024) | ||
210 | if not buf: | ||
211 | break | ||
212 | os.write(f_to, buf) | ||
213 | written_size += 1024*1024 | ||
214 | self.update_progress_bar("Writing to usb:", written_size * 1.0/total_size) | ||
215 | |||
216 | self.update_progress_bar("Writing completed:", 1.0) | ||
217 | os.close(f_from) | ||
218 | os.close(f_to) | ||
219 | self.progress_bar.hide() | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py b/bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py deleted file mode 100644 index 21216adc97..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/imageselectiondialog.py +++ /dev/null | |||
@@ -1,172 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011-2012 Intel Corporation | ||
5 | # | ||
6 | # Authored by Joshua Lock <josh@linux.intel.com> | ||
7 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | ||
8 | # Authored by Shane Wang <shane.wang@intel.com> | ||
9 | # | ||
10 | # This program is free software; you can redistribute it and/or modify | ||
11 | # it under the terms of the GNU General Public License version 2 as | ||
12 | # published by the Free Software Foundation. | ||
13 | # | ||
14 | # This program is distributed in the hope that it will be useful, | ||
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | # GNU General Public License for more details. | ||
18 | # | ||
19 | # You should have received a copy of the GNU General Public License along | ||
20 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
22 | |||
23 | import gtk | ||
24 | import gobject | ||
25 | import os | ||
26 | from bb.ui.crumbs.hobwidget import HobViewTable, HobInfoButton, HobButton, HobAltButton | ||
27 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
28 | from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog | ||
29 | |||
30 | """ | ||
31 | The following are convenience classes for implementing GNOME HIG compliant | ||
32 | BitBake GUI's | ||
33 | In summary: spacing = 12px, border-width = 6px | ||
34 | """ | ||
35 | |||
36 | class ImageSelectionDialog (CrumbsDialog): | ||
37 | |||
38 | __columns__ = [{ | ||
39 | 'col_name' : 'Image name', | ||
40 | 'col_id' : 0, | ||
41 | 'col_style': 'text', | ||
42 | 'col_min' : 400, | ||
43 | 'col_max' : 400 | ||
44 | }, { | ||
45 | 'col_name' : 'Select', | ||
46 | 'col_id' : 1, | ||
47 | 'col_style': 'radio toggle', | ||
48 | 'col_min' : 160, | ||
49 | 'col_max' : 160 | ||
50 | }] | ||
51 | |||
52 | |||
53 | def __init__(self, image_folder, image_types, title, parent, flags, buttons=None, image_extension = {}): | ||
54 | super(ImageSelectionDialog, self).__init__(title, parent, flags, buttons) | ||
55 | self.connect("response", self.response_cb) | ||
56 | |||
57 | self.image_folder = image_folder | ||
58 | self.image_types = image_types | ||
59 | self.image_list = [] | ||
60 | self.image_names = [] | ||
61 | self.image_extension = image_extension | ||
62 | |||
63 | # create visual elements on the dialog | ||
64 | self.create_visual_elements() | ||
65 | |||
66 | self.image_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN) | ||
67 | self.fill_image_store() | ||
68 | |||
69 | def create_visual_elements(self): | ||
70 | hbox = gtk.HBox(False, 6) | ||
71 | |||
72 | self.vbox.pack_start(hbox, expand=False, fill=False) | ||
73 | |||
74 | entry = gtk.Entry() | ||
75 | entry.set_text(self.image_folder) | ||
76 | table = gtk.Table(1, 10, True) | ||
77 | table.set_size_request(560, -1) | ||
78 | hbox.pack_start(table, expand=False, fill=False) | ||
79 | table.attach(entry, 0, 9, 0, 1) | ||
80 | image = gtk.Image() | ||
81 | image.set_from_stock(gtk.STOCK_OPEN, gtk.ICON_SIZE_BUTTON) | ||
82 | open_button = gtk.Button() | ||
83 | open_button.set_image(image) | ||
84 | open_button.connect("clicked", self.select_path_cb, self, entry) | ||
85 | table.attach(open_button, 9, 10, 0, 1) | ||
86 | |||
87 | self.image_table = HobViewTable(self.__columns__, "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 deleted file mode 100644 index 52d57b6738..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/layerselectiondialog.py +++ /dev/null | |||
@@ -1,298 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011-2012 Intel Corporation | ||
5 | # | ||
6 | # Authored by Joshua Lock <josh@linux.intel.com> | ||
7 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | ||
8 | # Authored by Shane Wang <shane.wang@intel.com> | ||
9 | # | ||
10 | # This program is free software; you can redistribute it and/or modify | ||
11 | # it under the terms of the GNU General Public License version 2 as | ||
12 | # published by the Free Software Foundation. | ||
13 | # | ||
14 | # This program is distributed in the hope that it will be useful, | ||
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | # GNU General Public License for more details. | ||
18 | # | ||
19 | # You should have received a copy of the GNU General Public License along | ||
20 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
22 | |||
23 | import gtk | ||
24 | import gobject | ||
25 | import os | ||
26 | import tempfile | ||
27 | from bb.ui.crumbs.hobwidget import hic, HobButton, HobAltButton | ||
28 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
29 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
30 | |||
31 | """ | ||
32 | The following are convenience classes for implementing GNOME HIG compliant | ||
33 | BitBake GUI's | ||
34 | In summary: spacing = 12px, border-width = 6px | ||
35 | """ | ||
36 | |||
37 | class CellRendererPixbufActivatable(gtk.CellRendererPixbuf): | ||
38 | """ | ||
39 | A custom CellRenderer implementation which is activatable | ||
40 | so that we can handle user clicks | ||
41 | """ | ||
42 | __gsignals__ = { 'clicked' : (gobject.SIGNAL_RUN_LAST, | ||
43 | gobject.TYPE_NONE, | ||
44 | (gobject.TYPE_STRING,)), } | ||
45 | |||
46 | def __init__(self): | ||
47 | gtk.CellRendererPixbuf.__init__(self) | ||
48 | self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE) | ||
49 | self.set_property('follow-state', True) | ||
50 | |||
51 | """ | ||
52 | Respond to a user click on a cell | ||
53 | """ | ||
54 | def do_activate(self, even, widget, path, background_area, cell_area, flags): | ||
55 | self.emit('clicked', path) | ||
56 | |||
57 | # | ||
58 | # LayerSelectionDialog | ||
59 | # | ||
60 | class LayerSelectionDialog (CrumbsDialog): | ||
61 | |||
62 | TARGETS = [ | ||
63 | ("MY_TREE_MODEL_ROW", gtk.TARGET_SAME_WIDGET, 0), | ||
64 | ("text/plain", 0, 1), | ||
65 | ("TEXT", 0, 2), | ||
66 | ("STRING", 0, 3), | ||
67 | ] | ||
68 | |||
69 | def gen_label_widget(self, content): | ||
70 | label = gtk.Label() | ||
71 | label.set_alignment(0, 0) | ||
72 | label.set_markup(content) | ||
73 | label.show() | ||
74 | return label | ||
75 | |||
76 | def layer_widget_toggled_cb(self, cell, path, layer_store): | ||
77 | name = layer_store[path][0] | ||
78 | toggle = not layer_store[path][1] | ||
79 | layer_store[path][1] = toggle | ||
80 | |||
81 | def layer_widget_add_clicked_cb(self, action, layer_store, parent): | ||
82 | dialog = gtk.FileChooserDialog("Add new layer", parent, | ||
83 | gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) | ||
84 | button = dialog.add_button("Cancel", gtk.RESPONSE_NO) | ||
85 | HobAltButton.style_button(button) | ||
86 | button = dialog.add_button("Open", gtk.RESPONSE_YES) | ||
87 | HobButton.style_button(button) | ||
88 | label = gtk.Label("Select the layer you wish to add") | ||
89 | label.show() | ||
90 | dialog.set_extra_widget(label) | ||
91 | response = dialog.run() | ||
92 | path = dialog.get_filename() | ||
93 | dialog.destroy() | ||
94 | |||
95 | lbl = "<b>Error</b>" | ||
96 | msg = "Unable to load layer <i>%s</i> because " % path | ||
97 | if response == gtk.RESPONSE_YES: | ||
98 | import os | ||
99 | import os.path | ||
100 | layers = [] | ||
101 | it = layer_store.get_iter_first() | ||
102 | while it: | ||
103 | layers.append(layer_store.get_value(it, 0)) | ||
104 | it = layer_store.iter_next(it) | ||
105 | |||
106 | if not path: | ||
107 | msg += "it is an invalid path." | ||
108 | elif not os.path.exists(path+"/conf/layer.conf"): | ||
109 | msg += "there is no layer.conf inside the directory." | ||
110 | elif path in layers: | ||
111 | msg += "it is already in loaded layers." | ||
112 | else: | ||
113 | layer_store.append([path]) | ||
114 | return | ||
115 | dialog = CrumbsMessageDialog(parent, lbl, gtk.MESSAGE_ERROR, msg) | ||
116 | dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_OK) | ||
117 | response = dialog.run() | ||
118 | dialog.destroy() | ||
119 | |||
120 | def layer_widget_del_clicked_cb(self, action, tree_selection, layer_store): | ||
121 | model, iter = tree_selection.get_selected() | ||
122 | if iter: | ||
123 | layer_store.remove(iter) | ||
124 | |||
125 | |||
126 | def gen_layer_widget(self, layers, layers_avail, window, tooltip=""): | ||
127 | hbox = gtk.HBox(False, 6) | ||
128 | |||
129 | layer_tv = gtk.TreeView() | ||
130 | layer_tv.set_rules_hint(True) | ||
131 | layer_tv.set_headers_visible(False) | ||
132 | tree_selection = layer_tv.get_selection() | ||
133 | tree_selection.set_mode(gtk.SELECTION_SINGLE) | ||
134 | |||
135 | # Allow enable drag and drop of rows including row move | ||
136 | dnd_internal_target = '' | ||
137 | dnd_targets = [(dnd_internal_target, gtk.TARGET_SAME_WIDGET, 0)] | ||
138 | layer_tv.enable_model_drag_source( gtk.gdk.BUTTON1_MASK, | ||
139 | dnd_targets, | ||
140 | gtk.gdk.ACTION_MOVE) | ||
141 | layer_tv.enable_model_drag_dest(dnd_targets, | ||
142 | gtk.gdk.ACTION_MOVE) | ||
143 | layer_tv.connect("drag_data_get", self.drag_data_get_cb) | ||
144 | layer_tv.connect("drag_data_received", self.drag_data_received_cb) | ||
145 | |||
146 | col0= gtk.TreeViewColumn('Path') | ||
147 | cell0 = gtk.CellRendererText() | ||
148 | cell0.set_padding(5,2) | ||
149 | col0.pack_start(cell0, True) | ||
150 | col0.set_cell_data_func(cell0, self.draw_layer_path_cb) | ||
151 | layer_tv.append_column(col0) | ||
152 | |||
153 | scroll = gtk.ScrolledWindow() | ||
154 | scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) | ||
155 | scroll.set_shadow_type(gtk.SHADOW_IN) | ||
156 | scroll.add(layer_tv) | ||
157 | |||
158 | table_layer = gtk.Table(2, 10, False) | ||
159 | hbox.pack_start(table_layer, expand=True, fill=True) | ||
160 | |||
161 | table_layer.attach(scroll, 0, 10, 0, 1) | ||
162 | |||
163 | layer_store = gtk.ListStore(gobject.TYPE_STRING) | ||
164 | for layer in layers: | ||
165 | layer_store.append([layer]) | ||
166 | |||
167 | col1 = gtk.TreeViewColumn('Enabled') | ||
168 | layer_tv.append_column(col1) | ||
169 | |||
170 | cell1 = CellRendererPixbufActivatable() | ||
171 | cell1.set_fixed_size(-1,35) | ||
172 | cell1.connect("clicked", self.del_cell_clicked_cb, layer_store) | ||
173 | col1.pack_start(cell1, True) | ||
174 | col1.set_cell_data_func(cell1, self.draw_delete_button_cb, layer_tv) | ||
175 | |||
176 | add_button = gtk.Button() | ||
177 | add_button.set_relief(gtk.RELIEF_NONE) | ||
178 | box = gtk.HBox(False, 6) | ||
179 | box.show() | ||
180 | add_button.add(box) | ||
181 | add_button.connect("enter-notify-event", self.add_hover_cb) | ||
182 | add_button.connect("leave-notify-event", self.add_leave_cb) | ||
183 | self.im = gtk.Image() | ||
184 | self.im.set_from_file(hic.ICON_INDI_ADD_FILE) | ||
185 | self.im.show() | ||
186 | box.pack_start(self.im, expand=False, fill=False, padding=6) | ||
187 | lbl = gtk.Label("Add layer") | ||
188 | lbl.set_alignment(0.0, 0.5) | ||
189 | lbl.show() | ||
190 | box.pack_start(lbl, expand=True, fill=True, padding=6) | ||
191 | add_button.connect("clicked", self.layer_widget_add_clicked_cb, layer_store, window) | ||
192 | table_layer.attach(add_button, 0, 10, 1, 2, gtk.EXPAND | gtk.FILL, 0, 0, 6) | ||
193 | layer_tv.set_model(layer_store) | ||
194 | |||
195 | hbox.show_all() | ||
196 | |||
197 | return hbox, layer_store | ||
198 | |||
199 | def drag_data_get_cb(self, treeview, context, selection, target_id, etime): | ||
200 | treeselection = treeview.get_selection() | ||
201 | model, iter = treeselection.get_selected() | ||
202 | data = model.get_value(iter, 0) | ||
203 | selection.set(selection.target, 8, data) | ||
204 | |||
205 | def drag_data_received_cb(self, treeview, context, x, y, selection, info, etime): | ||
206 | model = treeview.get_model() | ||
207 | data = selection.data | ||
208 | drop_info = treeview.get_dest_row_at_pos(x, y) | ||
209 | if drop_info: | ||
210 | path, position = drop_info | ||
211 | iter = model.get_iter(path) | ||
212 | if (position == gtk.TREE_VIEW_DROP_BEFORE or position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): | ||
213 | model.insert_before(iter, [data]) | ||
214 | else: | ||
215 | model.insert_after(iter, [data]) | ||
216 | else: | ||
217 | model.append([data]) | ||
218 | if context.action == gtk.gdk.ACTION_MOVE: | ||
219 | context.finish(True, True, etime) | ||
220 | return | ||
221 | |||
222 | def add_hover_cb(self, button, event): | ||
223 | self.im.set_from_file(hic.ICON_INDI_ADD_HOVER_FILE) | ||
224 | |||
225 | def add_leave_cb(self, button, event): | ||
226 | self.im.set_from_file(hic.ICON_INDI_ADD_FILE) | ||
227 | |||
228 | def __init__(self, title, layers, layers_non_removable, all_layers, parent, flags, buttons=None): | ||
229 | super(LayerSelectionDialog, self).__init__(title, parent, flags, buttons) | ||
230 | |||
231 | # class members from other objects | ||
232 | self.layers = layers | ||
233 | self.layers_non_removable = layers_non_removable | ||
234 | self.all_layers = all_layers | ||
235 | self.layers_changed = False | ||
236 | |||
237 | # icon for remove button in TreeView | ||
238 | im = gtk.Image() | ||
239 | im.set_from_file(hic.ICON_INDI_REMOVE_FILE) | ||
240 | self.rem_icon = im.get_pixbuf() | ||
241 | |||
242 | # class members for internal use | ||
243 | self.layer_store = None | ||
244 | |||
245 | # create visual elements on the dialog | ||
246 | self.create_visual_elements() | ||
247 | self.connect("response", self.response_cb) | ||
248 | |||
249 | def create_visual_elements(self): | ||
250 | layer_widget, self.layer_store = self.gen_layer_widget(self.layers, self.all_layers, self, None) | ||
251 | layer_widget.set_size_request(450, 250) | ||
252 | self.vbox.pack_start(layer_widget, expand=True, fill=True) | ||
253 | self.show_all() | ||
254 | |||
255 | def response_cb(self, dialog, response_id): | ||
256 | model = self.layer_store | ||
257 | it = model.get_iter_first() | ||
258 | layers = [] | ||
259 | while it: | ||
260 | layers.append(model.get_value(it, 0)) | ||
261 | it = model.iter_next(it) | ||
262 | |||
263 | self.layers_changed = (self.layers != layers) | ||
264 | self.layers = layers | ||
265 | |||
266 | """ | ||
267 | A custom cell_data_func to draw a delete 'button' in the TreeView for layers | ||
268 | other than the meta layer. The deletion of which is prevented so that the | ||
269 | user can't shoot themselves in the foot too badly. | ||
270 | """ | ||
271 | def draw_delete_button_cb(self, col, cell, model, it, tv): | ||
272 | path = model.get_value(it, 0) | ||
273 | if path in self.layers_non_removable: | ||
274 | cell.set_sensitive(False) | ||
275 | cell.set_property('pixbuf', None) | ||
276 | cell.set_property('mode', gtk.CELL_RENDERER_MODE_INERT) | ||
277 | else: | ||
278 | cell.set_property('pixbuf', self.rem_icon) | ||
279 | cell.set_sensitive(True) | ||
280 | cell.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE) | ||
281 | |||
282 | return True | ||
283 | |||
284 | """ | ||
285 | A custom cell_data_func to write an extra message into the layer path cell | ||
286 | for the meta layer. We should inform the user that they can't remove it for | ||
287 | their own safety. | ||
288 | """ | ||
289 | def draw_layer_path_cb(self, col, cell, model, it): | ||
290 | path = model.get_value(it, 0) | ||
291 | if path in self.layers_non_removable: | ||
292 | cell.set_property('markup', "<b>It cannot be removed</b>\n%s" % path) | ||
293 | else: | ||
294 | cell.set_property('text', path) | ||
295 | |||
296 | def del_cell_clicked_cb(self, cell, path, model): | ||
297 | it = model.get_iter_from_string(path) | ||
298 | model.remove(it) | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/propertydialog.py b/bitbake/lib/bb/ui/crumbs/hig/propertydialog.py deleted file mode 100644 index 09b9ce6de3..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/propertydialog.py +++ /dev/null | |||
@@ -1,437 +0,0 @@ | |||
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 | |||
21 | import string | ||
22 | import gtk | ||
23 | import gobject | ||
24 | import os | ||
25 | import tempfile | ||
26 | import glib | ||
27 | from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog | ||
28 | from bb.ui.crumbs.hig.settingsuihelper import SettingsUIHelper | ||
29 | from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog | ||
30 | from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog | ||
31 | |||
32 | """ | ||
33 | The following are convenience classes for implementing GNOME HIG compliant | ||
34 | BitBake GUI's | ||
35 | In summary: spacing = 12px, border-width = 6px | ||
36 | """ | ||
37 | |||
38 | class 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 | import json | ||
109 | |||
110 | name = self.properties['name'] | ||
111 | binb = self.properties['binb'] | ||
112 | size = self.properties['size'] | ||
113 | recipe = self.properties['recipe'] | ||
114 | file_list = json.loads(self.properties['files_list']) | ||
115 | |||
116 | files_temp = '' | ||
117 | paths_temp = '' | ||
118 | files_binb = [] | ||
119 | paths_binb = [] | ||
120 | |||
121 | self.tooltip_items = {} | ||
122 | |||
123 | self.set_resizable(False) | ||
124 | |||
125 | #cleaning out the recipe variable | ||
126 | recipe = recipe.split("+")[0] | ||
127 | |||
128 | vbox = gtk.VBox(True,spacing = 0) | ||
129 | |||
130 | ###################################### NAME ROW + COL ################################# | ||
131 | |||
132 | self.label_short = gtk.Label() | ||
133 | self.label_short.set_size_request(300,-1) | ||
134 | self.label_short.set_selectable(True) | ||
135 | self.label_short.set_line_wrap(True) | ||
136 | self.label_short.set_markup("<span weight=\"bold\">Name: </span>" + name) | ||
137 | self.label_short.set_property("xalign", 0) | ||
138 | |||
139 | self.vbox.add(self.label_short) | ||
140 | |||
141 | ###################################### SIZE ROW + COL ###################################### | ||
142 | |||
143 | self.label_short = gtk.Label() | ||
144 | self.label_short.set_size_request(300,-1) | ||
145 | self.label_short.set_selectable(True) | ||
146 | self.label_short.set_line_wrap(True) | ||
147 | self.label_short.set_markup("<span weight=\"bold\">Size: </span>" + size) | ||
148 | self.label_short.set_property("xalign", 0) | ||
149 | |||
150 | self.vbox.add(self.label_short) | ||
151 | |||
152 | ##################################### RECIPE ROW + COL ######################################### | ||
153 | |||
154 | self.label_short = gtk.Label() | ||
155 | self.label_short.set_size_request(300,-1) | ||
156 | self.label_short.set_selectable(True) | ||
157 | self.label_short.set_line_wrap(True) | ||
158 | self.label_short.set_markup("<span weight=\"bold\">Recipe: </span>" + recipe) | ||
159 | self.label_short.set_property("xalign", 0) | ||
160 | |||
161 | self.vbox.add(self.label_short) | ||
162 | |||
163 | ##################################### BINB ROW + COL ####################################### | ||
164 | |||
165 | if binb != '': | ||
166 | self.label_short = gtk.Label() | ||
167 | self.label_short.set_selectable(True) | ||
168 | self.label_short.set_line_wrap(True) | ||
169 | self.label_short.set_markup("<span weight=\"bold\">Brought in by: </span>") | ||
170 | self.label_short.set_property("xalign", 0) | ||
171 | |||
172 | self.label_info = gtk.Label() | ||
173 | self.label_info.set_size_request(300,-1) | ||
174 | self.label_info.set_selectable(True) | ||
175 | self.label_info.set_line_wrap(True) | ||
176 | self.label_info.set_markup(binb) | ||
177 | self.label_info.set_property("xalign", 0) | ||
178 | |||
179 | self.vbox.add(self.label_short) | ||
180 | self.vbox.add(self.label_info) | ||
181 | |||
182 | #################################### FILES BROUGHT BY PACKAGES ################################### | ||
183 | |||
184 | if file_list: | ||
185 | |||
186 | self.textWindow = gtk.ScrolledWindow() | ||
187 | self.textWindow.set_shadow_type(gtk.SHADOW_IN) | ||
188 | self.textWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | ||
189 | self.textWindow.set_size_request(100, 170) | ||
190 | |||
191 | packagefiles_store = gtk.ListStore(str) | ||
192 | |||
193 | self.packagefiles_tv = gtk.TreeView() | ||
194 | self.packagefiles_tv.set_rules_hint(True) | ||
195 | self.packagefiles_tv.set_headers_visible(True) | ||
196 | self.textWindow.add(self.packagefiles_tv) | ||
197 | |||
198 | self.cell1 = gtk.CellRendererText() | ||
199 | col1 = gtk.TreeViewColumn('Package files', self.cell1) | ||
200 | col1.set_cell_data_func(self.cell1, self.regex_field) | ||
201 | self.packagefiles_tv.append_column(col1) | ||
202 | |||
203 | items = file_list.keys() | ||
204 | items.sort() | ||
205 | for item in items: | ||
206 | fullpath = item | ||
207 | while len(item) > 35: | ||
208 | item = item[:len(item)/2] + "" + item[len(item)/2+1:] | ||
209 | if len(item) == 35: | ||
210 | item = item[:len(item)/2] + "..." + item[len(item)/2+3:] | ||
211 | self.tooltip_items[item] = fullpath | ||
212 | |||
213 | packagefiles_store.append([str(item)]) | ||
214 | |||
215 | self.packagefiles_tv.set_model(packagefiles_store) | ||
216 | |||
217 | tips = gtk.Tooltips() | ||
218 | tips.set_tip(self.packagefiles_tv, "") | ||
219 | self.packagefiles_tv.connect("motion-notify-event", self.treeViewTooltip, tips, 0) | ||
220 | self.packagefiles_tv.set_events(gtk.gdk.POINTER_MOTION_MASK) | ||
221 | |||
222 | self.vbox.add(self.textWindow) | ||
223 | |||
224 | self.vbox.show_all() | ||
225 | |||
226 | |||
227 | def regex_field(self, column, cell, model, iter): | ||
228 | cell.set_property('text', model.get_value(iter, 0)) | ||
229 | return | ||
230 | |||
231 | |||
232 | def create_recipe_visual_elements(self): | ||
233 | |||
234 | summary = self.properties['summary'] | ||
235 | name = self.properties['name'] | ||
236 | version = self.properties['version'] | ||
237 | revision = self.properties['revision'] | ||
238 | binb = self.properties['binb'] | ||
239 | group = self.properties['group'] | ||
240 | license = self.properties['license'] | ||
241 | homepage = self.properties['homepage'] | ||
242 | bugtracker = self.properties['bugtracker'] | ||
243 | description = self.properties['description'] | ||
244 | |||
245 | self.set_resizable(False) | ||
246 | |||
247 | #cleaning out the version variable and also the summary | ||
248 | version = version.split(":")[1] | ||
249 | if len(version) > 30: | ||
250 | version = version.split("+")[0] | ||
251 | else: | ||
252 | version = version.split("-")[0] | ||
253 | license = license.replace("&" , "and") | ||
254 | if (homepage == ''): | ||
255 | homepage = 'unknown' | ||
256 | if (bugtracker == ''): | ||
257 | bugtracker = 'unknown' | ||
258 | summary = summary.split("+")[0] | ||
259 | |||
260 | #calculating the rows needed for the table | ||
261 | binb_items_count = len(binb.split(',')) | ||
262 | binb_items = binb.split(',') | ||
263 | |||
264 | vbox = gtk.VBox(False,spacing = 0) | ||
265 | |||
266 | ######################################## SUMMARY LABEL ######################################### | ||
267 | |||
268 | if summary != '': | ||
269 | self.label_short = gtk.Label() | ||
270 | self.label_short.set_width_chars(37) | ||
271 | self.label_short.set_selectable(True) | ||
272 | self.label_short.set_line_wrap(True) | ||
273 | self.label_short.set_markup("<b>" + summary + "</b>") | ||
274 | self.label_short.set_property("xalign", 0) | ||
275 | |||
276 | self.vbox.add(self.label_short) | ||
277 | |||
278 | ########################################## NAME ROW + COL ####################################### | ||
279 | |||
280 | self.label_short = gtk.Label() | ||
281 | self.label_short.set_selectable(True) | ||
282 | self.label_short.set_line_wrap(True) | ||
283 | self.label_short.set_markup("<span weight=\"bold\">Name: </span>" + name) | ||
284 | self.label_short.set_property("xalign", 0) | ||
285 | |||
286 | self.vbox.add(self.label_short) | ||
287 | |||
288 | ####################################### VERSION ROW + COL #################################### | ||
289 | |||
290 | self.label_short = gtk.Label() | ||
291 | self.label_short.set_selectable(True) | ||
292 | self.label_short.set_line_wrap(True) | ||
293 | self.label_short.set_markup("<span weight=\"bold\">Version: </span>" + version) | ||
294 | self.label_short.set_property("xalign", 0) | ||
295 | |||
296 | self.vbox.add(self.label_short) | ||
297 | |||
298 | ##################################### REVISION ROW + COL ##################################### | ||
299 | |||
300 | self.label_short = gtk.Label() | ||
301 | self.label_short.set_line_wrap(True) | ||
302 | self.label_short.set_selectable(True) | ||
303 | self.label_short.set_markup("<span weight=\"bold\">Revision: </span>" + revision) | ||
304 | self.label_short.set_property("xalign", 0) | ||
305 | |||
306 | self.vbox.add(self.label_short) | ||
307 | |||
308 | ################################## GROUP ROW + COL ############################################ | ||
309 | |||
310 | self.label_short = gtk.Label() | ||
311 | self.label_short.set_selectable(True) | ||
312 | self.label_short.set_line_wrap(True) | ||
313 | self.label_short.set_markup("<span weight=\"bold\">Group: </span>" + group) | ||
314 | self.label_short.set_property("xalign", 0) | ||
315 | |||
316 | self.vbox.add(self.label_short) | ||
317 | |||
318 | ################################# HOMEPAGE ROW + COL ############################################ | ||
319 | |||
320 | if homepage != 'unknown': | ||
321 | self.label_info = gtk.Label() | ||
322 | self.label_info.set_selectable(True) | ||
323 | self.label_info.set_line_wrap(True) | ||
324 | if len(homepage) > 35: | ||
325 | self.label_info.set_markup("<a href=\"" + homepage + "\">" + homepage[0:35] + "..." + "</a>") | ||
326 | else: | ||
327 | self.label_info.set_markup("<a href=\"" + homepage + "\">" + homepage[0:60] + "</a>") | ||
328 | |||
329 | self.label_info.set_property("xalign", 0) | ||
330 | |||
331 | self.label_short = gtk.Label() | ||
332 | self.label_short.set_selectable(True) | ||
333 | self.label_short.set_line_wrap(True) | ||
334 | self.label_short.set_markup("<b>Homepage: </b>") | ||
335 | self.label_short.set_property("xalign", 0) | ||
336 | |||
337 | self.vbox.add(self.label_short) | ||
338 | self.vbox.add(self.label_info) | ||
339 | |||
340 | ################################# BUGTRACKER ROW + COL ########################################### | ||
341 | |||
342 | if bugtracker != 'unknown': | ||
343 | self.label_info = gtk.Label() | ||
344 | self.label_info.set_selectable(True) | ||
345 | self.label_info.set_line_wrap(True) | ||
346 | if len(bugtracker) > 35: | ||
347 | self.label_info.set_markup("<a href=\"" + bugtracker + "\">" + bugtracker[0:35] + "..." + "</a>") | ||
348 | else: | ||
349 | self.label_info.set_markup("<a href=\"" + bugtracker + "\">" + bugtracker[0:60] + "</a>") | ||
350 | self.label_info.set_property("xalign", 0) | ||
351 | |||
352 | self.label_short = gtk.Label() | ||
353 | self.label_short.set_selectable(True) | ||
354 | self.label_short.set_line_wrap(True) | ||
355 | self.label_short.set_markup("<b>Bugtracker: </b>") | ||
356 | self.label_short.set_property("xalign", 0) | ||
357 | |||
358 | self.vbox.add(self.label_short) | ||
359 | self.vbox.add(self.label_info) | ||
360 | |||
361 | ################################# LICENSE ROW + COL ############################################ | ||
362 | |||
363 | self.label_info = gtk.Label() | ||
364 | self.label_info.set_selectable(True) | ||
365 | self.label_info.set_line_wrap(True) | ||
366 | self.label_info.set_markup(license) | ||
367 | self.label_info.set_property("xalign", 0) | ||
368 | |||
369 | self.label_short = gtk.Label() | ||
370 | self.label_short.set_selectable(True) | ||
371 | self.label_short.set_line_wrap(True) | ||
372 | self.label_short.set_markup("<span weight=\"bold\">License: </span>") | ||
373 | self.label_short.set_property("xalign", 0) | ||
374 | |||
375 | self.vbox.add(self.label_short) | ||
376 | self.vbox.add(self.label_info) | ||
377 | |||
378 | ################################### BINB ROW+COL ############################################# | ||
379 | |||
380 | if binb != '': | ||
381 | self.label_short = gtk.Label() | ||
382 | self.label_short.set_selectable(True) | ||
383 | self.label_short.set_line_wrap(True) | ||
384 | self.label_short.set_markup("<span weight=\"bold\">Brought in by: </span>") | ||
385 | self.label_short.set_property("xalign", 0) | ||
386 | self.vbox.add(self.label_short) | ||
387 | self.label_info = gtk.Label() | ||
388 | self.label_info.set_selectable(True) | ||
389 | self.label_info.set_width_chars(36) | ||
390 | if len(binb) > 200: | ||
391 | scrolled_window = gtk.ScrolledWindow() | ||
392 | scrolled_window.set_policy(gtk.POLICY_NEVER,gtk.POLICY_ALWAYS) | ||
393 | scrolled_window.set_size_request(100,100) | ||
394 | self.label_info.set_markup(binb) | ||
395 | self.label_info.set_padding(6,6) | ||
396 | self.label_info.set_alignment(0,0) | ||
397 | self.label_info.set_line_wrap(True) | ||
398 | scrolled_window.add_with_viewport(self.label_info) | ||
399 | self.vbox.add(scrolled_window) | ||
400 | else: | ||
401 | self.label_info.set_markup(binb) | ||
402 | self.label_info.set_property("xalign", 0) | ||
403 | self.label_info.set_line_wrap(True) | ||
404 | self.vbox.add(self.label_info) | ||
405 | |||
406 | ################################ DESCRIPTION TAG ROW ################################################# | ||
407 | |||
408 | self.label_short = gtk.Label() | ||
409 | self.label_short.set_line_wrap(True) | ||
410 | self.label_short.set_markup("<span weight=\"bold\">Description </span>") | ||
411 | self.label_short.set_property("xalign", 0) | ||
412 | self.vbox.add(self.label_short) | ||
413 | |||
414 | ################################ DESCRIPTION INFORMATION ROW ########################################## | ||
415 | |||
416 | hbox = gtk.HBox(True,spacing = 0) | ||
417 | |||
418 | self.label_short = gtk.Label() | ||
419 | self.label_short.set_selectable(True) | ||
420 | self.label_short.set_width_chars(36) | ||
421 | if len(description) > 200: | ||
422 | scrolled_window = gtk.ScrolledWindow() | ||
423 | scrolled_window.set_policy(gtk.POLICY_NEVER,gtk.POLICY_ALWAYS) | ||
424 | scrolled_window.set_size_request(100,100) | ||
425 | self.label_short.set_markup(description) | ||
426 | self.label_short.set_padding(6,6) | ||
427 | self.label_short.set_alignment(0,0) | ||
428 | self.label_short.set_line_wrap(True) | ||
429 | scrolled_window.add_with_viewport(self.label_short) | ||
430 | self.vbox.add(scrolled_window) | ||
431 | else: | ||
432 | self.label_short.set_markup(description) | ||
433 | self.label_short.set_property("xalign", 0) | ||
434 | self.label_short.set_line_wrap(True) | ||
435 | self.vbox.add(self.label_short) | ||
436 | |||
437 | self.vbox.show_all() | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hig/settingsuihelper.py b/bitbake/lib/bb/ui/crumbs/hig/settingsuihelper.py deleted file mode 100644 index e0285c93ce..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hig/settingsuihelper.py +++ /dev/null | |||
@@ -1,122 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2011-2012 Intel Corporation | ||
5 | # | ||
6 | # Authored by Joshua Lock <josh@linux.intel.com> | ||
7 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | ||
8 | # Authored by Shane Wang <shane.wang@intel.com> | ||
9 | # | ||
10 | # This program is free software; you can redistribute it and/or modify | ||
11 | # it under the terms of the GNU General Public License version 2 as | ||
12 | # published by the Free Software Foundation. | ||
13 | # | ||
14 | # This program is distributed in the hope that it will be useful, | ||
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | # GNU General Public License for more details. | ||
18 | # | ||
19 | # You should have received a copy of the GNU General Public License along | ||
20 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
22 | |||
23 | import gtk | ||
24 | import os | ||
25 | from bb.ui.crumbs.hobwidget import HobInfoButton, HobButton, HobAltButton | ||
26 | |||
27 | """ | ||
28 | The following are convenience classes for implementing GNOME HIG compliant | ||
29 | BitBake GUI's | ||
30 | In summary: spacing = 12px, border-width = 6px | ||
31 | """ | ||
32 | |||
33 | class SettingsUIHelper(): | ||
34 | |||
35 | def gen_label_widget(self, content): | ||
36 | label = gtk.Label() | ||
37 | label.set_alignment(0, 0) | ||
38 | label.set_markup(content) | ||
39 | label.show() | ||
40 | return label | ||
41 | |||
42 | def gen_label_info_widget(self, content, tooltip): | ||
43 | table = gtk.Table(1, 10, False) | ||
44 | label = self.gen_label_widget(content) | ||
45 | info = HobInfoButton(tooltip, self) | ||
46 | table.attach(label, 0, 1, 0, 1, xoptions=gtk.FILL) | ||
47 | table.attach(info, 1, 2, 0, 1, xoptions=gtk.FILL, xpadding=10) | ||
48 | return table | ||
49 | |||
50 | def gen_spinner_widget(self, content, lower, upper, tooltip=""): | ||
51 | hbox = gtk.HBox(False, 12) | ||
52 | adjust = gtk.Adjustment(value=content, lower=lower, upper=upper, step_incr=1) | ||
53 | spinner = gtk.SpinButton(adjustment=adjust, climb_rate=1, digits=0) | ||
54 | |||
55 | spinner.set_value(content) | ||
56 | hbox.pack_start(spinner, expand=False, fill=False) | ||
57 | |||
58 | info = HobInfoButton(tooltip, self) | ||
59 | hbox.pack_start(info, expand=False, fill=False) | ||
60 | |||
61 | hbox.show_all() | ||
62 | return hbox, spinner | ||
63 | |||
64 | def gen_combo_widget(self, curr_item, all_item, tooltip=""): | ||
65 | hbox = gtk.HBox(False, 12) | ||
66 | combo = gtk.combo_box_new_text() | ||
67 | hbox.pack_start(combo, expand=False, fill=False) | ||
68 | |||
69 | index = 0 | ||
70 | for item in all_item or []: | ||
71 | combo.append_text(item) | ||
72 | if item == curr_item: | ||
73 | combo.set_active(index) | ||
74 | index += 1 | ||
75 | |||
76 | info = HobInfoButton(tooltip, self) | ||
77 | hbox.pack_start(info, expand=False, fill=False) | ||
78 | |||
79 | hbox.show_all() | ||
80 | return hbox, combo | ||
81 | |||
82 | def entry_widget_select_path_cb(self, action, parent, entry): | ||
83 | dialog = gtk.FileChooserDialog("", parent, | ||
84 | gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) | ||
85 | text = entry.get_text() | ||
86 | dialog.set_current_folder(text if len(text) > 0 else os.getcwd()) | ||
87 | button = dialog.add_button("Cancel", gtk.RESPONSE_NO) | ||
88 | HobAltButton.style_button(button) | ||
89 | button = dialog.add_button("Open", gtk.RESPONSE_YES) | ||
90 | HobButton.style_button(button) | ||
91 | response = dialog.run() | ||
92 | if response == gtk.RESPONSE_YES: | ||
93 | path = dialog.get_filename() | ||
94 | entry.set_text(path) | ||
95 | |||
96 | dialog.destroy() | ||
97 | |||
98 | def gen_entry_widget(self, content, parent, tooltip="", need_button=True): | ||
99 | hbox = gtk.HBox(False, 12) | ||
100 | entry = gtk.Entry() | ||
101 | entry.set_text(content) | ||
102 | entry.set_size_request(350,30) | ||
103 | |||
104 | if need_button: | ||
105 | table = gtk.Table(1, 10, False) | ||
106 | hbox.pack_start(table, expand=True, fill=True) | ||
107 | table.attach(entry, 0, 9, 0, 1, xoptions=gtk.SHRINK) | ||
108 | image = gtk.Image() | ||
109 | image.set_from_stock(gtk.STOCK_OPEN,gtk.ICON_SIZE_BUTTON) | ||
110 | open_button = gtk.Button() | ||
111 | open_button.set_image(image) | ||
112 | open_button.connect("clicked", self.entry_widget_select_path_cb, parent, entry) | ||
113 | table.attach(open_button, 9, 10, 0, 1, xoptions=gtk.SHRINK) | ||
114 | else: | ||
115 | hbox.pack_start(entry, expand=True, fill=True) | ||
116 | |||
117 | if tooltip != "": | ||
118 | info = HobInfoButton(tooltip, self) | ||
119 | hbox.pack_start(info, expand=False, fill=False) | ||
120 | |||
121 | hbox.show_all() | ||
122 | return hbox, entry | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hobcolor.py b/bitbake/lib/bb/ui/crumbs/hobcolor.py deleted file mode 100644 index 3316542a20..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hobcolor.py +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2012 Intel Corporation | ||
5 | # | ||
6 | # Authored by Shane Wang <shane.wang@intel.com> | ||
7 | # | ||
8 | # This program is free software; you can redistribute it and/or modify | ||
9 | # it under the terms of the GNU General Public License version 2 as | ||
10 | # published by the Free Software Foundation. | ||
11 | # | ||
12 | # This program is distributed in the hope that it will be useful, | ||
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | # GNU General Public License for more details. | ||
16 | # | ||
17 | # You should have received a copy of the GNU General Public License along | ||
18 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
20 | |||
21 | class HobColors: | ||
22 | WHITE = "#ffffff" | ||
23 | PALE_GREEN = "#aaffaa" | ||
24 | ORANGE = "#eb8e68" | ||
25 | PALE_RED = "#ffaaaa" | ||
26 | GRAY = "#aaaaaa" | ||
27 | LIGHT_GRAY = "#dddddd" | ||
28 | SLIGHT_DARK = "#5f5f5f" | ||
29 | DARK = "#3c3b37" | ||
30 | BLACK = "#000000" | ||
31 | PALE_BLUE = "#53b8ff" | ||
32 | DEEP_RED = "#aa3e3e" | ||
33 | KHAKI = "#fff68f" | ||
34 | |||
35 | OK = WHITE | ||
36 | RUNNING = PALE_GREEN | ||
37 | WARNING = ORANGE | ||
38 | ERROR = PALE_RED | ||
diff --git a/bitbake/lib/bb/ui/crumbs/hobwidget.py b/bitbake/lib/bb/ui/crumbs/hobwidget.py deleted file mode 100644 index 3f6138b277..0000000000 --- a/bitbake/lib/bb/ui/crumbs/hobwidget.py +++ /dev/null | |||
@@ -1,904 +0,0 @@ | |||
1 | # BitBake Graphical GTK User Interface | ||
2 | # | ||
3 | # Copyright (C) 2011-2012 Intel Corporation | ||
4 | # | ||
5 | # Authored by Dongxiao Xu <dongxiao.xu@intel.com> | ||
6 | # Authored by Shane Wang <shane.wang@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 | import gtk | ||
21 | import gobject | ||
22 | import os | ||
23 | import os.path | ||
24 | import sys | ||
25 | import pango, pangocairo | ||
26 | import cairo | ||
27 | import math | ||
28 | |||
29 | from bb.ui.crumbs.hobcolor import HobColors | ||
30 | from bb.ui.crumbs.persistenttooltip import PersistentTooltip | ||
31 | |||
32 | class hwc: | ||
33 | |||
34 | MAIN_WIN_WIDTH = 1024 | ||
35 | MAIN_WIN_HEIGHT = 700 | ||
36 | |||
37 | class hic: | ||
38 | |||
39 | HOB_ICON_BASE_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), ("ui/icons/")) | ||
40 | |||
41 | ICON_RCIPE_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('recipe/recipe_display.png')) | ||
42 | ICON_RCIPE_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('recipe/recipe_hover.png')) | ||
43 | ICON_PACKAGES_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('packages/packages_display.png')) | ||
44 | ICON_PACKAGES_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('packages/packages_hover.png')) | ||
45 | ICON_LAYERS_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('layers/layers_display.png')) | ||
46 | ICON_LAYERS_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('layers/layers_hover.png')) | ||
47 | ICON_IMAGES_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('images/images_display.png')) | ||
48 | ICON_IMAGES_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('images/images_hover.png')) | ||
49 | ICON_SETTINGS_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('settings/settings_display.png')) | ||
50 | ICON_SETTINGS_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('settings/settings_hover.png')) | ||
51 | ICON_INFO_DISPLAY_FILE = os.path.join(HOB_ICON_BASE_DIR, ('info/info_display.png')) | ||
52 | ICON_INFO_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('info/info_hover.png')) | ||
53 | ICON_INDI_CONFIRM_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/confirmation.png')) | ||
54 | ICON_INDI_ERROR_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/denied.png')) | ||
55 | ICON_INDI_REMOVE_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/remove.png')) | ||
56 | ICON_INDI_REMOVE_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/remove-hover.png')) | ||
57 | ICON_INDI_ADD_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/add.png')) | ||
58 | ICON_INDI_ADD_HOVER_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/add-hover.png')) | ||
59 | ICON_INDI_REFRESH_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/refresh.png')) | ||
60 | ICON_INDI_ALERT_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/alert.png')) | ||
61 | ICON_INDI_TICK_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/tick.png')) | ||
62 | ICON_INDI_INFO_FILE = os.path.join(HOB_ICON_BASE_DIR, ('indicators/info.png')) | ||
63 | |||
64 | class HobViewTable (gtk.VBox): | ||
65 | """ | ||
66 | A VBox to contain the table for different recipe views and package view | ||
67 | """ | ||
68 | __gsignals__ = { | ||
69 | "toggled" : (gobject.SIGNAL_RUN_LAST, | ||
70 | gobject.TYPE_NONE, | ||
71 | (gobject.TYPE_PYOBJECT, | ||
72 | gobject.TYPE_STRING, | ||
73 | gobject.TYPE_INT, | ||
74 | gobject.TYPE_PYOBJECT,)), | ||
75 | "row-activated" : (gobject.SIGNAL_RUN_LAST, | ||
76 | gobject.TYPE_NONE, | ||
77 | (gobject.TYPE_PYOBJECT, | ||
78 | gobject.TYPE_PYOBJECT,)), | ||
79 | "cell-fadeinout-stopped" : (gobject.SIGNAL_RUN_LAST, | ||
80 | gobject.TYPE_NONE, | ||
81 | (gobject.TYPE_PYOBJECT, | ||
82 | gobject.TYPE_PYOBJECT, | ||
83 | gobject.TYPE_PYOBJECT,)), | ||
84 | } | ||
85 | |||
86 | def __init__(self, columns, name): | ||
87 | gtk.VBox.__init__(self, False, 6) | ||
88 | self.table_tree = gtk.TreeView() | ||
89 | self.table_tree.set_headers_visible(True) | ||
90 | self.table_tree.set_headers_clickable(True) | ||
91 | self.table_tree.set_rules_hint(True) | ||
92 | self.table_tree.set_enable_tree_lines(True) | ||
93 | self.table_tree.get_selection().set_mode(gtk.SELECTION_SINGLE) | ||
94 | self.toggle_columns = [] | ||
95 | self.table_tree.connect("row-activated", self.row_activated_cb) | ||
96 | self.top_bar = None | ||
97 | self.tab_name = name | ||
98 | |||
99 | for i, column in enumerate(columns): | ||
100 | col_name = column['col_name'] | ||
101 | col = gtk.TreeViewColumn(col_name) | ||
102 | col.set_clickable(True) | ||
103 | col.set_resizable(True) | ||
104 | if self.tab_name.startswith('Included'): | ||
105 | if col_name!='Included': | ||
106 | col.set_sort_column_id(column['col_id']) | ||
107 | else: | ||
108 | col.set_sort_column_id(column['col_id']) | ||
109 | if 'col_min' in column.keys(): | ||
110 | col.set_min_width(column['col_min']) | ||
111 | if 'col_max' in column.keys(): | ||
112 | col.set_max_width(column['col_max']) | ||
113 | if 'expand' in column.keys(): | ||
114 | col.set_expand(True) | ||
115 | self.table_tree.append_column(col) | ||
116 | |||
117 | if (not 'col_style' in column.keys()) or column['col_style'] == 'text': | ||
118 | cell = gtk.CellRendererText() | ||
119 | col.pack_start(cell, True) | ||
120 | col.set_attributes(cell, text=column['col_id']) | ||
121 | if 'col_t_id' in column.keys(): | ||
122 | col.add_attribute(cell, 'font', column['col_t_id']) | ||
123 | elif column['col_style'] == 'check toggle': | ||
124 | cell = HobCellRendererToggle() | ||
125 | cell.set_property('activatable', True) | ||
126 | cell.connect("toggled", self.toggled_cb, i, self.table_tree) | ||
127 | cell.connect_render_state_changed(self.stop_cell_fadeinout_cb, self.table_tree) | ||
128 | self.toggle_id = i | ||
129 | col.pack_end(cell, True) | ||
130 | col.set_attributes(cell, active=column['col_id']) | ||
131 | self.toggle_columns.append(col_name) | ||
132 | if 'col_group' in column.keys(): | ||
133 | col.set_cell_data_func(cell, self.set_group_number_cb) | ||
134 | elif column['col_style'] == 'radio toggle': | ||
135 | cell = gtk.CellRendererToggle() | ||
136 | cell.set_property('activatable', True) | ||
137 | cell.set_radio(True) | ||
138 | cell.connect("toggled", self.toggled_cb, i, self.table_tree) | ||
139 | self.toggle_id = i | ||
140 | col.pack_end(cell, True) | ||
141 | col.set_attributes(cell, active=column['col_id']) | ||
142 | self.toggle_columns.append(col_name) | ||
143 | elif column['col_style'] == 'binb': | ||
144 | cell = gtk.CellRendererText() | ||
145 | col.pack_start(cell, True) | ||
146 | col.set_cell_data_func(cell, self.display_binb_cb, column['col_id']) | ||
147 | if 'col_t_id' in column.keys(): | ||
148 | col.add_attribute(cell, 'font', column['col_t_id']) | ||
149 | |||
150 | self.scroll = gtk.ScrolledWindow() | ||
151 | self.scroll.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) | ||
152 | self.scroll.add(self.table_tree) | ||
153 | |||
154 | self.pack_end(self.scroll, True, True, 0) | ||
155 | |||
156 | def add_no_result_bar(self, entry): | ||
157 | color = HobColors.KHAKI | ||
158 | self.top_bar = gtk.EventBox() | ||
159 | self.top_bar.set_size_request(-1, 70) | ||
160 | self.top_bar.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) | ||
161 | self.top_bar.set_flags(gtk.CAN_DEFAULT) | ||
162 | self.top_bar.grab_default() | ||
163 | |||
164 | no_result_tab = gtk.Table(5, 20, True) | ||
165 | self.top_bar.add(no_result_tab) | ||
166 | |||
167 | label = gtk.Label() | ||
168 | label.set_alignment(0.0, 0.5) | ||
169 | title = "No results matching your search" | ||
170 | label.set_markup("<span size='x-large'><b>%s</b></span>" % title) | ||
171 | no_result_tab.attach(label, 1, 14, 1, 4) | ||
172 | |||
173 | clear_button = HobButton("Clear search") | ||
174 | clear_button.set_tooltip_text("Clear search query") | ||
175 | clear_button.connect('clicked', self.set_search_entry_clear_cb, entry) | ||
176 | no_result_tab.attach(clear_button, 16, 19, 1, 4) | ||
177 | |||
178 | self.pack_start(self.top_bar, False, True, 12) | ||
179 | self.top_bar.show_all() | ||
180 | |||
181 | def set_search_entry_clear_cb(self, button, search): | ||
182 | if search.get_editable() == True: | ||
183 | search.set_text("") | ||
184 | search.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False) | ||
185 | search.grab_focus() | ||
186 | |||
187 | def display_binb_cb(self, col, cell, model, it, col_id): | ||
188 | binb = model.get_value(it, col_id) | ||
189 | # Just display the first item | ||
190 | if binb: | ||
191 | bin = binb.split(', ') | ||
192 | total_no = len(bin) | ||
193 | if total_no > 1 and bin[0] == "User Selected": | ||
194 | if total_no > 2: | ||
195 | present_binb = bin[1] + ' (+' + str(total_no - 1) + ')' | ||
196 | else: | ||
197 | present_binb = bin[1] | ||
198 | else: | ||
199 | if total_no > 1: | ||
200 | present_binb = bin[0] + ' (+' + str(total_no - 1) + ')' | ||
201 | else: | ||
202 | present_binb = bin[0] | ||
203 | cell.set_property('text', present_binb) | ||
204 | else: | ||
205 | cell.set_property('text', "") | ||
206 | return True | ||
207 | |||
208 | def set_model(self, tree_model): | ||
209 | self.table_tree.set_model(tree_model) | ||
210 | |||
211 | def toggle_default(self): | ||
212 | model = self.table_tree.get_model() | ||
213 | if not model: | ||
214 | return | ||
215 | iter = model.get_iter_first() | ||
216 | if iter: | ||
217 | rowpath = model.get_path(iter) | ||
218 | model[rowpath][self.toggle_id] = True | ||
219 | |||
220 | def toggled_cb(self, cell, path, columnid, tree): | ||
221 | self.emit("toggled", cell, path, columnid, tree) | ||
222 | |||
223 | def row_activated_cb(self, tree, path, view_column): | ||
224 | if not view_column.get_title() in self.toggle_columns: | ||
225 | self.emit("row-activated", tree.get_model(), path) | ||
226 | |||
227 | def stop_cell_fadeinout_cb(self, ctrl, cell, tree): | ||
228 | self.emit("cell-fadeinout-stopped", ctrl, cell, tree) | ||
229 | |||
230 | def set_group_number_cb(self, col, cell, model, iter): | ||
231 | if model and (model.iter_parent(iter) == None): | ||
232 | cell.cell_attr["number_of_children"] = model.iter_n_children(iter) | ||
233 | else: | ||
234 | cell.cell_attr["number_of_children"] = 0 | ||
235 | |||
236 | def connect_group_selection(self, cb_func): | ||
237 | self.table_tree.get_selection().connect("changed", cb_func) | ||
238 | |||
239 | """ | ||
240 | A method to calculate a softened value for the colour of widget when in the | ||
241 | provided state. | ||
242 | |||
243 | widget: the widget whose style to use | ||
244 | state: the state of the widget to use the style for | ||
245 | |||
246 | Returns a string value representing the softened colour | ||
247 | """ | ||
248 | def soften_color(widget, state=gtk.STATE_NORMAL): | ||
249 | # this colour munging routine is heavily inspired bu gdu_util_get_mix_color() | ||
250 | # from gnome-disk-utility: | ||
251 | # http://git.gnome.org/browse/gnome-disk-utility/tree/src/gdu-gtk/gdu-gtk.c?h=gnome-3-0 | ||
252 | blend = 0.7 | ||
253 | style = widget.get_style() | ||
254 | color = style.text[state] | ||
255 | color.red = color.red * blend + style.base[state].red * (1.0 - blend) | ||
256 | color.green = color.green * blend + style.base[state].green * (1.0 - blend) | ||
257 | color.blue = color.blue * blend + style.base[state].blue * (1.0 - blend) | ||
258 | return color.to_string() | ||
259 | |||
260 | class BaseHobButton(gtk.Button): | ||
261 | """ | ||
262 | A gtk.Button subclass which follows the visual design of Hob for primary | ||
263 | action buttons | ||
264 | |||
265 | label: the text to display as the button's label | ||
266 | """ | ||
267 | def __init__(self, label): | ||
268 | gtk.Button.__init__(self, label) | ||
269 | HobButton.style_button(self) | ||
270 | |||
271 | @staticmethod | ||
272 | def style_button(button): | ||
273 | style = button.get_style() | ||
274 | style = gtk.rc_get_style_by_paths(gtk.settings_get_default(), 'gtk-button', 'gtk-button', gobject.TYPE_NONE) | ||
275 | |||
276 | #FIXME button.set_flags(gtk.CAN_DEFAULT) | ||
277 | button.grab_default() | ||
278 | |||
279 | # label = "<span size='x-large'><b>%s</b></span>" % gobject.markup_escape_text(button.get_label()) | ||
280 | label = button.get_label() | ||
281 | button.set_label(label) | ||
282 | #FIXME button.child.set_use_markup(True) | ||
283 | |||
284 | class HobButton(BaseHobButton): | ||
285 | """ | ||
286 | A gtk.Button subclass which follows the visual design of Hob for primary | ||
287 | action buttons | ||
288 | |||
289 | label: the text to display as the button's label | ||
290 | """ | ||
291 | def __init__(self, label): | ||
292 | BaseHobButton.__init__(self, label) | ||
293 | HobButton.style_button(self) | ||
294 | |||
295 | class HobAltButton(BaseHobButton): | ||
296 | """ | ||
297 | A gtk.Button subclass which has no relief, and so is more discrete | ||
298 | """ | ||
299 | def __init__(self, label): | ||
300 | BaseHobButton.__init__(self, label) | ||
301 | HobAltButton.style_button(self) | ||
302 | |||
303 | """ | ||
304 | A callback for the state-changed event to ensure the text is displayed | ||
305 | differently when the widget is not sensitive | ||
306 | """ | ||
307 | @staticmethod | ||
308 | def desensitise_on_state_change_cb(button, state): | ||
309 | if not button.get_property("sensitive"): | ||
310 | HobAltButton.set_text(button, False) | ||
311 | else: | ||
312 | HobAltButton.set_text(button, True) | ||
313 | |||
314 | """ | ||
315 | Set the button label with an appropriate colour for the current widget state | ||
316 | """ | ||
317 | @staticmethod | ||
318 | def set_text(button, sensitive=True): | ||
319 | if sensitive: | ||
320 | colour = HobColors.PALE_BLUE | ||
321 | else: | ||
322 | colour = HobColors.LIGHT_GRAY | ||
323 | button.set_label("<span size='large' color='%s'><b>%s</b></span>" % (colour, gobject.markup_escape_text(button.text))) | ||
324 | button.child.set_use_markup(True) | ||
325 | |||
326 | class HobImageButton(gtk.Button): | ||
327 | """ | ||
328 | A gtk.Button with an icon and two rows of text, the second of which is | ||
329 | displayed in a blended colour. | ||
330 | |||
331 | primary_text: the main button label | ||
332 | secondary_text: optional second line of text | ||
333 | icon_path: path to the icon file to display on the button | ||
334 | """ | ||
335 | def __init__(self, primary_text, secondary_text="", icon_path="", hover_icon_path=""): | ||
336 | gtk.Button.__init__(self) | ||
337 | self.set_relief(gtk.RELIEF_NONE) | ||
338 | |||
339 | self.icon_path = icon_path | ||
340 | self.hover_icon_path = hover_icon_path | ||
341 | |||
342 | hbox = gtk.HBox(False, 10) | ||
343 | hbox.show() | ||
344 | self.add(hbox) | ||
345 | self.icon = gtk.Image() | ||
346 | self.icon.set_from_file(self.icon_path) | ||
347 | self.icon.set_alignment(0.5, 0.0) | ||
348 | self.icon.show() | ||
349 | if self.hover_icon_path and len(self.hover_icon_path): | ||
350 | self.connect("enter-notify-event", self.set_hover_icon_cb) | ||
351 | self.connect("leave-notify-event", self.set_icon_cb) | ||
352 | hbox.pack_start(self.icon, False, False, 0) | ||
353 | label = gtk.Label() | ||
354 | label.set_alignment(0.0, 0.5) | ||
355 | colour = soften_color(label) | ||
356 | mark = "<span size='x-large'>%s</span>\n<span size='medium' fgcolor='%s' weight='ultralight'>%s</span>" % (primary_text, colour, secondary_text) | ||
357 | label.set_markup(mark) | ||
358 | label.show() | ||
359 | hbox.pack_start(label, True, True, 0) | ||
360 | |||
361 | def set_hover_icon_cb(self, widget, event): | ||
362 | self.icon.set_from_file(self.hover_icon_path) | ||
363 | |||
364 | def set_icon_cb(self, widget, event): | ||
365 | self.icon.set_from_file(self.icon_path) | ||
366 | |||
367 | class HobInfoButton(gtk.EventBox): | ||
368 | """ | ||
369 | This class implements a button-like widget per the Hob visual and UX designs | ||
370 | which will display a persistent tooltip, with the contents of tip_markup, when | ||
371 | clicked. | ||
372 | |||
373 | tip_markup: the Pango Markup to be displayed in the persistent tooltip | ||
374 | """ | ||
375 | def __init__(self, tip_markup, parent=None): | ||
376 | gtk.EventBox.__init__(self) | ||
377 | self.image = gtk.Image() | ||
378 | self.image.set_from_file( | ||
379 | hic.ICON_INFO_DISPLAY_FILE) | ||
380 | self.image.show() | ||
381 | self.add(self.image) | ||
382 | self.tip_markup = tip_markup | ||
383 | self.my_parent = parent | ||
384 | |||
385 | self.set_events(gtk.gdk.BUTTON_RELEASE | | ||
386 | gtk.gdk.ENTER_NOTIFY_MASK | | ||
387 | gtk.gdk.LEAVE_NOTIFY_MASK) | ||
388 | |||
389 | self.connect("button-release-event", self.button_release_cb) | ||
390 | self.connect("enter-notify-event", self.mouse_in_cb) | ||
391 | self.connect("leave-notify-event", self.mouse_out_cb) | ||
392 | |||
393 | """ | ||
394 | When the mouse click is released emulate a button-click and show the associated | ||
395 | PersistentTooltip | ||
396 | """ | ||
397 | def button_release_cb(self, widget, event): | ||
398 | from bb.ui.crumbs.hig.propertydialog import PropertyDialog | ||
399 | self.dialog = PropertyDialog(title = '', | ||
400 | parent = self.my_parent, | ||
401 | information = self.tip_markup, | ||
402 | flags = gtk.DIALOG_DESTROY_WITH_PARENT) | ||
403 | #FMXIE | gtk.DIALOG_NO_SEPARATOR | ||
404 | |||
405 | button = self.dialog.add_button("Close", gtk.RESPONSE_CANCEL) | ||
406 | HobAltButton.style_button(button) | ||
407 | button.connect("clicked", lambda w: self.dialog.destroy()) | ||
408 | self.dialog.show_all() | ||
409 | self.dialog.run() | ||
410 | |||
411 | """ | ||
412 | Change to the prelight image when the mouse enters the widget | ||
413 | """ | ||
414 | def mouse_in_cb(self, widget, event): | ||
415 | self.image.set_from_file(hic.ICON_INFO_HOVER_FILE) | ||
416 | |||
417 | """ | ||
418 | Change to the stock image when the mouse enters the widget | ||
419 | """ | ||
420 | def mouse_out_cb(self, widget, event): | ||
421 | self.image.set_from_file(hic.ICON_INFO_DISPLAY_FILE) | ||
422 | |||
423 | class HobIndicator(gtk.DrawingArea): | ||
424 | def __init__(self, count): | ||
425 | gtk.DrawingArea.__init__(self) | ||
426 | # Set no window for transparent background | ||
427 | self.set_has_window(False) | ||
428 | self.set_size_request(38,38) | ||
429 | # We need to pass through button clicks | ||
430 | self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK) | ||
431 | |||
432 | self.connect('expose-event', self.expose) | ||
433 | |||
434 | self.count = count | ||
435 | self.color = HobColors.GRAY | ||
436 | |||
437 | def expose(self, widget, event): | ||
438 | if self.count and self.count > 0: | ||
439 | ctx = widget.window.cairo_create() | ||
440 | |||
441 | x, y, w, h = self.allocation | ||
442 | |||
443 | ctx.set_operator(cairo.OPERATOR_OVER) | ||
444 | ctx.set_source_color(gtk.gdk.color_parse(self.color)) | ||
445 | ctx.translate(w/2, h/2) | ||
446 | ctx.arc(x, y, min(w,h)/2 - 2, 0, 2*math.pi) | ||
447 | ctx.fill_preserve() | ||
448 | |||
449 | layout = self.create_pango_layout(str(self.count)) | ||
450 | textw, texth = layout.get_pixel_size() | ||
451 | x = (w/2)-(textw/2) + x | ||
452 | y = (h/2) - (texth/2) + y | ||
453 | ctx.move_to(x, y) | ||
454 | self.window.draw_layout(self.style.light_gc[gtk.STATE_NORMAL], int(x), int(y), layout) | ||
455 | |||
456 | def set_count(self, count): | ||
457 | self.count = count | ||
458 | |||
459 | def set_active(self, active): | ||
460 | if active: | ||
461 | self.color = HobColors.DEEP_RED | ||
462 | else: | ||
463 | self.color = HobColors.GRAY | ||
464 | |||
465 | class HobTabLabel(gtk.HBox): | ||
466 | def __init__(self, text, count=0): | ||
467 | gtk.HBox.__init__(self, False, 0) | ||
468 | self.indicator = HobIndicator(count) | ||
469 | self.indicator.show() | ||
470 | self.pack_end(self.indicator, False, False) | ||
471 | self.lbl = gtk.Label(text) | ||
472 | self.lbl.set_alignment(0.0, 0.5) | ||
473 | self.lbl.show() | ||
474 | self.pack_end(self.lbl, True, True, 6) | ||
475 | |||
476 | def set_count(self, count): | ||
477 | self.indicator.set_count(count) | ||
478 | |||
479 | def set_active(self, active=True): | ||
480 | self.indicator.set_active(active) | ||
481 | |||
482 | class HobNotebook(gtk.Notebook): | ||
483 | def __init__(self): | ||
484 | gtk.Notebook.__init__(self) | ||
485 | self.set_property('homogeneous', True) | ||
486 | |||
487 | self.pages = [] | ||
488 | |||
489 | self.search = None | ||
490 | self.search_focus = False | ||
491 | self.page_changed = False | ||
492 | |||
493 | self.connect("switch-page", self.page_changed_cb) | ||
494 | |||
495 | self.show_all() | ||
496 | |||
497 | def page_changed_cb(self, nb, page, page_num): | ||
498 | for p, lbl in enumerate(self.pages): | ||
499 | if p == page_num: | ||
500 | lbl.set_active() | ||
501 | else: | ||
502 | lbl.set_active(False) | ||
503 | |||
504 | if self.search: | ||
505 | self.page_changed = True | ||
506 | self.reset_entry(self.search, page_num) | ||
507 | |||
508 | def append_page(self, child, tab_label, tab_tooltip=None): | ||
509 | label = HobTabLabel(tab_label) | ||
510 | if tab_tooltip: | ||
511 | label.set_tooltip_text(tab_tooltip) | ||
512 | label.set_active(False) | ||
513 | self.pages.append(label) | ||
514 | gtk.Notebook.append_page(self, child, label) | ||
515 | |||
516 | def set_entry(self, names, tips): | ||
517 | self.search = gtk.Entry() | ||
518 | self.search_names = names | ||
519 | self.search_tips = tips | ||
520 | style = self.search.get_style() | ||
521 | style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.GRAY, False, False) | ||
522 | self.search.set_style(style) | ||
523 | self.search.set_text(names[0]) | ||
524 | self.search.set_tooltip_text(self.search_tips[0]) | ||
525 | self.search.props.has_tooltip = True | ||
526 | |||
527 | self.search.set_editable(False) | ||
528 | self.search.set_icon_from_stock(gtk.ENTRY_ICON_SECONDARY, gtk.STOCK_CLEAR) | ||
529 | self.search.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False) | ||
530 | self.search.connect("icon-release", self.set_search_entry_clear_cb) | ||
531 | self.search.set_width_chars(30) | ||
532 | self.search.show() | ||
533 | |||
534 | self.search.connect("focus-in-event", self.set_search_entry_editable_cb) | ||
535 | self.search.connect("focus-out-event", self.set_search_entry_reset_cb) | ||
536 | self.set_action_widget(self.search, gtk.PACK_END) | ||
537 | |||
538 | def show_indicator_icon(self, title, number): | ||
539 | for child in self.pages: | ||
540 | if child.lbl.get_label() == title: | ||
541 | child.set_count(number) | ||
542 | |||
543 | def hide_indicator_icon(self, title): | ||
544 | for child in self.pages: | ||
545 | if child.lbl.get_label() == title: | ||
546 | child.set_count(0) | ||
547 | |||
548 | def set_search_entry_editable_cb(self, search, event): | ||
549 | self.search_focus = True | ||
550 | search.set_editable(True) | ||
551 | text = search.get_text() | ||
552 | if text in self.search_names: | ||
553 | search.set_text("") | ||
554 | style = self.search.get_style() | ||
555 | style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.BLACK, False, False) | ||
556 | search.set_style(style) | ||
557 | |||
558 | def set_search_entry_reset_cb(self, search, event): | ||
559 | page_num = self.get_current_page() | ||
560 | text = search.get_text() | ||
561 | if not text: | ||
562 | self.reset_entry(search, page_num) | ||
563 | |||
564 | def reset_entry(self, entry, page_num): | ||
565 | style = entry.get_style() | ||
566 | style.text[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(HobColors.GRAY, False, False) | ||
567 | entry.set_style(style) | ||
568 | entry.set_text(self.search_names[page_num]) | ||
569 | entry.set_tooltip_text(self.search_tips[page_num]) | ||
570 | entry.set_editable(False) | ||
571 | entry.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False) | ||
572 | |||
573 | def set_search_entry_clear_cb(self, search, icon_pos, event): | ||
574 | if search.get_editable() == True: | ||
575 | search.set_text("") | ||
576 | search.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, False) | ||
577 | search.grab_focus() | ||
578 | |||
579 | def set_page(self, title): | ||
580 | for child in self.pages: | ||
581 | if child.lbl.get_label() == title: | ||
582 | child.grab_focus() | ||
583 | self.set_current_page(self.pages.index(child)) | ||
584 | return | ||
585 | |||
586 | class HobWarpCellRendererText(gtk.CellRendererText): | ||
587 | def __init__(self, col_number): | ||
588 | gtk.CellRendererText.__init__(self) | ||
589 | self.set_property("wrap-mode", pango.WRAP_WORD_CHAR) | ||
590 | self.set_property("wrap-width", 300) # default value wrap width is 300 | ||
591 | self.col_n = col_number | ||
592 | |||
593 | def do_render(self, window, widget, background_area, cell_area, expose_area, flags): | ||
594 | if widget: | ||
595 | self.props.wrap_width = self.get_resized_wrap_width(widget, widget.get_column(self.col_n)) | ||
596 | return gtk.CellRendererText.do_render(self, window, widget, background_area, cell_area, expose_area, flags) | ||
597 | |||
598 | def get_resized_wrap_width(self, treeview, column): | ||
599 | otherCols = [] | ||
600 | for col in treeview.get_columns(): | ||
601 | if col != column: | ||
602 | otherCols.append(col) | ||
603 | adjwidth = treeview.allocation.width - sum(c.get_width() for c in otherCols) | ||
604 | adjwidth -= treeview.style_get_property("horizontal-separator") * 4 | ||
605 | if self.props.wrap_width == adjwidth or adjwidth <= 0: | ||
606 | adjwidth = self.props.wrap_width | ||
607 | return adjwidth | ||
608 | |||
609 | gobject.type_register(HobWarpCellRendererText) | ||
610 | |||
611 | class HobIconChecker(hic): | ||
612 | def set_hob_icon_to_stock_icon(self, file_path, stock_id=""): | ||
613 | try: | ||
614 | pixbuf = gtk.gdk.pixbuf_new_from_file(file_path) | ||
615 | except Exception as e: | ||
616 | return None | ||
617 | |||
618 | if stock_id and (gtk.icon_factory_lookup_default(stock_id) == None): | ||
619 | icon_factory = gtk.IconFactory() | ||
620 | icon_factory.add_default() | ||
621 | icon_factory.add(stock_id, gtk.IconSet(pixbuf)) | ||
622 | gtk.stock_add([(stock_id, '_label', 0, 0, '')]) | ||
623 | |||
624 | return icon_factory.lookup(stock_id) | ||
625 | |||
626 | return None | ||
627 | |||
628 | """ | ||
629 | For make hob icon consistently by request, and avoid icon view diff by system or gtk version, we use some 'hob icon' to replace the 'gtk icon'. | ||
630 | this function check the stock_id and make hob_id to replaced the gtk_id then return it or "" | ||
631 | """ | ||
632 | def check_stock_icon(self, stock_name=""): | ||
633 | HOB_CHECK_STOCK_NAME = { | ||
634 | ('hic-dialog-info', 'gtk-dialog-info', 'dialog-info') : self.ICON_INDI_INFO_FILE, | ||
635 | ('hic-ok', 'gtk-ok', 'ok') : self.ICON_INDI_TICK_FILE, | ||
636 | ('hic-dialog-error', 'gtk-dialog-error', 'dialog-error') : self.ICON_INDI_ERROR_FILE, | ||
637 | ('hic-dialog-warning', 'gtk-dialog-warning', 'dialog-warning') : self.ICON_INDI_ALERT_FILE, | ||
638 | ('hic-task-refresh', 'gtk-execute', 'execute') : self.ICON_INDI_REFRESH_FILE, | ||
639 | } | ||
640 | valid_stock_id = stock_name | ||
641 | if stock_name: | ||
642 | for names, path in HOB_CHECK_STOCK_NAME.iteritems(): | ||
643 | if stock_name in names: | ||
644 | valid_stock_id = names[0] | ||
645 | if not gtk.icon_factory_lookup_default(valid_stock_id): | ||
646 | self.set_hob_icon_to_stock_icon(path, valid_stock_id) | ||
647 | |||
648 | return valid_stock_id | ||
649 | |||
650 | class HobCellRendererController(gobject.GObject): | ||
651 | (MODE_CYCLE_RUNNING, MODE_ONE_SHORT) = range(2) | ||
652 | __gsignals__ = { | ||
653 | "run-timer-stopped" : (gobject.SIGNAL_RUN_LAST, | ||
654 | gobject.TYPE_NONE, | ||
655 | ()), | ||
656 | } | ||
657 | def __init__(self, runningmode=MODE_CYCLE_RUNNING, is_draw_row=False): | ||
658 | gobject.GObject.__init__(self) | ||
659 | self.timeout_id = None | ||
660 | self.current_angle_pos = 0.0 | ||
661 | self.step_angle = 0.0 | ||
662 | self.tree_headers_height = 0 | ||
663 | self.running_cell_areas = [] | ||
664 | self.running_mode = runningmode | ||
665 | self.is_queue_draw_row_area = is_draw_row | ||
666 | self.force_stop_enable = False | ||
667 | |||
668 | def is_active(self): | ||
669 | if self.timeout_id: | ||
670 | return True | ||
671 | else: | ||
672 | return False | ||
673 | |||
674 | def reset_run(self): | ||
675 | self.force_stop() | ||
676 | self.running_cell_areas = [] | ||
677 | self.current_angle_pos = 0.0 | ||
678 | self.step_angle = 0.0 | ||
679 | |||
680 | ''' time_iterval: (1~1000)ms, which will be as the basic interval count for timer | ||
681 | init_usrdata: the current data which related the progress-bar will be at | ||
682 | min_usrdata: the range of min of user data | ||
683 | max_usrdata: the range of max of user data | ||
684 | step: each step which you want to progress | ||
685 | Note: the init_usrdata should in the range of from min to max, and max should > min | ||
686 | step should < (max - min) | ||
687 | ''' | ||
688 | def start_run(self, time_iterval, init_usrdata, min_usrdata, max_usrdata, step, tree): | ||
689 | if (not time_iterval) or (not max_usrdata): | ||
690 | return | ||
691 | usr_range = (max_usrdata - min_usrdata) * 1.0 | ||
692 | self.current_angle_pos = (init_usrdata * 1.0) / usr_range | ||
693 | self.step_angle = (step * 1) / usr_range | ||
694 | self.timeout_id = gobject.timeout_add(int(time_iterval), | ||
695 | self.make_image_on_progressing_cb, tree) | ||
696 | self.tree_headers_height = self.get_treeview_headers_height(tree) | ||
697 | self.force_stop_enable = False | ||
698 | |||
699 | def force_stop(self): | ||
700 | self.emit("run-timer-stopped") | ||
701 | self.force_stop_enable = True | ||
702 | if self.timeout_id: | ||
703 | if gobject.source_remove(self.timeout_id): | ||
704 | self.timeout_id = None | ||
705 | |||
706 | def on_draw_pixbuf_cb(self, pixbuf, cr, x, y, img_width, img_height, do_refresh=True): | ||
707 | if pixbuf: | ||
708 | r = max(img_width/2, img_height/2) | ||
709 | cr.translate(x + r, y + r) | ||
710 | if do_refresh: | ||
711 | cr.rotate(2 * math.pi * self.current_angle_pos) | ||
712 | |||
713 | cr.set_source_pixbuf(pixbuf, -img_width/2, -img_height/2) | ||
714 | cr.paint() | ||
715 | |||
716 | def on_draw_fadeinout_cb(self, cr, color, x, y, width, height, do_fadeout=True): | ||
717 | if do_fadeout: | ||
718 | alpha = self.current_angle_pos * 0.8 | ||
719 | else: | ||
720 | alpha = (1.0 - self.current_angle_pos) * 0.8 | ||
721 | |||
722 | cr.set_source_rgba(color.red, color.green, color.blue, alpha) | ||
723 | cr.rectangle(x, y, width, height) | ||
724 | cr.fill() | ||
725 | |||
726 | def get_treeview_headers_height(self, tree): | ||
727 | if tree and (tree.get_property("headers-visible") == True): | ||
728 | height = tree.get_allocation().height - tree.get_bin_window().get_size()[1] | ||
729 | return height | ||
730 | |||
731 | return 0 | ||
732 | |||
733 | def make_image_on_progressing_cb(self, tree): | ||
734 | self.current_angle_pos += self.step_angle | ||
735 | if self.running_mode == self.MODE_CYCLE_RUNNING: | ||
736 | if (self.current_angle_pos >= 1): | ||
737 | self.current_angle_pos = 0 | ||
738 | else: | ||
739 | if self.current_angle_pos > 1: | ||
740 | self.force_stop() | ||
741 | return False | ||
742 | |||
743 | if self.is_queue_draw_row_area: | ||
744 | for path in self.running_cell_areas: | ||
745 | rect = tree.get_cell_area(path, tree.get_column(0)) | ||
746 | row_x, _, row_width, _ = tree.get_visible_rect() | ||
747 | tree.queue_draw_area(row_x, rect.y + self.tree_headers_height, row_width, rect.height) | ||
748 | else: | ||
749 | for rect in self.running_cell_areas: | ||
750 | tree.queue_draw_area(rect.x, rect.y + self.tree_headers_height, rect.width, rect.height) | ||
751 | |||
752 | return (not self.force_stop_enable) | ||
753 | |||
754 | def append_running_cell_area(self, cell_area): | ||
755 | if cell_area and (cell_area not in self.running_cell_areas): | ||
756 | self.running_cell_areas.append(cell_area) | ||
757 | |||
758 | def remove_running_cell_area(self, cell_area): | ||
759 | if cell_area in self.running_cell_areas: | ||
760 | self.running_cell_areas.remove(cell_area) | ||
761 | if not self.running_cell_areas: | ||
762 | self.reset_run() | ||
763 | |||
764 | gobject.type_register(HobCellRendererController) | ||
765 | |||
766 | class HobCellRendererPixbuf(gtk.CellRendererPixbuf): | ||
767 | def __init__(self): | ||
768 | gtk.CellRendererPixbuf.__init__(self) | ||
769 | self.control = HobCellRendererController() | ||
770 | # add icon checker for make the gtk-icon transfer to hob-icon | ||
771 | self.checker = HobIconChecker() | ||
772 | self.set_property("stock-size", gtk.ICON_SIZE_DND) | ||
773 | |||
774 | def get_pixbuf_from_stock_icon(self, widget, stock_id="", size=gtk.ICON_SIZE_DIALOG): | ||
775 | if widget and stock_id and gtk.icon_factory_lookup_default(stock_id): | ||
776 | return widget.render_icon(stock_id, size) | ||
777 | |||
778 | return None | ||
779 | |||
780 | def set_icon_name_to_id(self, new_name): | ||
781 | if new_name and type(new_name) == str: | ||
782 | # check the name is need to transfer to hob icon or not | ||
783 | name = self.checker.check_stock_icon(new_name) | ||
784 | if name.startswith("hic") or name.startswith("gtk"): | ||
785 | stock_id = name | ||
786 | else: | ||
787 | stock_id = 'gtk-' + name | ||
788 | |||
789 | return stock_id | ||
790 | |||
791 | ''' render cell exactly, "icon-name" is priority | ||
792 | if use the 'hic-task-refresh' will make the pix animation | ||
793 | if 'pix' will change the pixbuf for it from the pixbuf or image. | ||
794 | ''' | ||
795 | def do_render(self, window, tree, background_area,cell_area, expose_area, flags): | ||
796 | if (not self.control) or (not tree): | ||
797 | return | ||
798 | |||
799 | x, y, w, h = self.on_get_size(tree, cell_area) | ||
800 | x += cell_area.x | ||
801 | y += cell_area.y | ||
802 | w -= 2 * self.get_property("xpad") | ||
803 | h -= 2 * self.get_property("ypad") | ||
804 | |||
805 | stock_id = "" | ||
806 | if self.props.icon_name: | ||
807 | stock_id = self.set_icon_name_to_id(self.props.icon_name) | ||
808 | elif self.props.stock_id: | ||
809 | stock_id = self.props.stock_id | ||
810 | elif self.props.pixbuf: | ||
811 | pix = self.props.pixbuf | ||
812 | else: | ||
813 | return | ||
814 | |||
815 | if stock_id: | ||
816 | pix = self.get_pixbuf_from_stock_icon(tree, stock_id, self.props.stock_size) | ||
817 | if stock_id == 'hic-task-refresh': | ||
818 | self.control.append_running_cell_area(cell_area) | ||
819 | if self.control.is_active(): | ||
820 | self.control.on_draw_pixbuf_cb(pix, window.cairo_create(), x, y, w, h, True) | ||
821 | else: | ||
822 | self.control.start_run(200, 0, 0, 1000, 150, tree) | ||
823 | else: | ||
824 | self.control.remove_running_cell_area(cell_area) | ||
825 | self.control.on_draw_pixbuf_cb(pix, window.cairo_create(), x, y, w, h, False) | ||
826 | |||
827 | def on_get_size(self, widget, cell_area): | ||
828 | if self.props.icon_name or self.props.pixbuf or self.props.stock_id: | ||
829 | w, h = gtk.icon_size_lookup(self.props.stock_size) | ||
830 | calc_width = self.get_property("xpad") * 2 + w | ||
831 | calc_height = self.get_property("ypad") * 2 + h | ||
832 | x_offset = 0 | ||
833 | y_offset = 0 | ||
834 | if cell_area and w > 0 and h > 0: | ||
835 | x_offset = self.get_property("xalign") * (cell_area.width - calc_width - self.get_property("xpad")) | ||
836 | y_offset = self.get_property("yalign") * (cell_area.height - calc_height - self.get_property("ypad")) | ||
837 | |||
838 | return x_offset, y_offset, w, h | ||
839 | |||
840 | return 0, 0, 0, 0 | ||
841 | |||
842 | gobject.type_register(HobCellRendererPixbuf) | ||
843 | |||
844 | class HobCellRendererToggle(gtk.CellRendererToggle): | ||
845 | def __init__(self): | ||
846 | gtk.CellRendererToggle.__init__(self) | ||
847 | self.ctrl = HobCellRendererController(is_draw_row=True) | ||
848 | self.ctrl.running_mode = self.ctrl.MODE_ONE_SHORT | ||
849 | self.cell_attr = {"fadeout": False, "number_of_children": 0} | ||
850 | |||
851 | def do_render(self, window, widget, background_area, cell_area, expose_area, flags): | ||
852 | if (not self.ctrl) or (not widget): | ||
853 | return | ||
854 | |||
855 | if flags & gtk.CELL_RENDERER_SELECTED: | ||
856 | state = gtk.STATE_SELECTED | ||
857 | else: | ||
858 | state = gtk.STATE_NORMAL | ||
859 | |||
860 | if self.ctrl.is_active(): | ||
861 | path = widget.get_path_at_pos(cell_area.x + cell_area.width/2, cell_area.y + cell_area.height/2) | ||
862 | # sometimes the parameters of cell_area will be a negative number,such as pull up down the scroll bar | ||
863 | # it's over the tree container range, so the path will be bad | ||
864 | if not path: return | ||
865 | path = path[0] | ||
866 | if path in self.ctrl.running_cell_areas: | ||
867 | cr = window.cairo_create() | ||
868 | color = widget.get_style().base[state] | ||
869 | |||
870 | row_x, _, row_width, _ = widget.get_visible_rect() | ||
871 | border_y = self.get_property("ypad") | ||
872 | self.ctrl.on_draw_fadeinout_cb(cr, color, row_x, cell_area.y - border_y, row_width, \ | ||
873 | cell_area.height + border_y * 2, self.cell_attr["fadeout"]) | ||
874 | # draw number of a group | ||
875 | if self.cell_attr["number_of_children"]: | ||
876 | text = "%d pkg" % self.cell_attr["number_of_children"] | ||
877 | pangolayout = widget.create_pango_layout(text) | ||
878 | textw, texth = pangolayout.get_pixel_size() | ||
879 | x = cell_area.x + (cell_area.width/2) - (textw/2) | ||
880 | y = cell_area.y + (cell_area.height/2) - (texth/2) | ||
881 | |||
882 | widget.style.paint_layout(window, state, True, cell_area, widget, "checkbox", x, y, pangolayout) | ||
883 | else: | ||
884 | return gtk.CellRendererToggle.do_render(self, window, widget, background_area, cell_area, expose_area, flags) | ||
885 | |||
886 | '''delay: normally delay time is 1000ms | ||
887 | cell_list: whilch cells need to be render | ||
888 | ''' | ||
889 | def fadeout(self, tree, delay, cell_list=None): | ||
890 | if (delay < 200) or (not tree): | ||
891 | return | ||
892 | self.cell_attr["fadeout"] = True | ||
893 | self.ctrl.running_cell_areas = cell_list | ||
894 | self.ctrl.start_run(200, 0, 0, delay, (delay * 200 / 1000), tree) | ||
895 | |||
896 | def connect_render_state_changed(self, func, usrdata=None): | ||
897 | if not func: | ||
898 | return | ||
899 | if usrdata: | ||
900 | self.ctrl.connect("run-timer-stopped", func, self, usrdata) | ||
901 | else: | ||
902 | self.ctrl.connect("run-timer-stopped", func, self) | ||
903 | |||
904 | gobject.type_register(HobCellRendererToggle) | ||
diff --git a/bitbake/lib/bb/ui/crumbs/persistenttooltip.py b/bitbake/lib/bb/ui/crumbs/persistenttooltip.py deleted file mode 100644 index 927c194292..0000000000 --- a/bitbake/lib/bb/ui/crumbs/persistenttooltip.py +++ /dev/null | |||
@@ -1,186 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2012 Intel Corporation | ||
5 | # | ||
6 | # Authored by Joshua Lock <josh@linux.intel.com> | ||
7 | # | ||
8 | # This program is free software; you can redistribute it and/or modify | ||
9 | # it under the terms of the GNU General Public License version 2 as | ||
10 | # published by the Free Software Foundation. | ||
11 | # | ||
12 | # This program is distributed in the hope that it will be useful, | ||
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | # GNU General Public License for more details. | ||
16 | # | ||
17 | # You should have received a copy of the GNU General Public License along | ||
18 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
20 | |||
21 | import gobject | ||
22 | import gtk | ||
23 | try: | ||
24 | import gconf | ||
25 | except: | ||
26 | pass | ||
27 | |||
28 | class PersistentTooltip(gtk.Window): | ||
29 | """ | ||
30 | A tooltip which persists once shown until the user dismisses it with the Esc | ||
31 | key or by clicking the close button. | ||
32 | |||
33 | # FIXME: the PersistentTooltip should be disabled when the user clicks anywhere off | ||
34 | # it. We can't do this with focus-out-event becuase modal ensures we have focus? | ||
35 | |||
36 | markup: some Pango text markup to display in the tooltip | ||
37 | """ | ||
38 | def __init__(self, markup, parent_win=None): | ||
39 | gtk.Window.__init__(self, gtk.WINDOW_POPUP) | ||
40 | |||
41 | # Inherit the system theme for a tooltip | ||
42 | style = gtk.rc_get_style_by_paths(gtk.settings_get_default(), | ||
43 | 'gtk-tooltip', 'gtk-tooltip', gobject.TYPE_NONE) | ||
44 | self.set_style(style) | ||
45 | |||
46 | # The placement of the close button on the tip should reflect how the | ||
47 | # window manager of the users system places close buttons. Try to read | ||
48 | # the metacity gconf key to determine whether the close button is on the | ||
49 | # left or the right. | ||
50 | # In the case that we can't determine the users configuration we default | ||
51 | # to close buttons being on the right. | ||
52 | __button_right = True | ||
53 | try: | ||
54 | client = gconf.client_get_default() | ||
55 | order = client.get_string("/apps/metacity/general/button_layout") | ||
56 | if order and order.endswith(":"): | ||
57 | __button_right = False | ||
58 | except NameError: | ||
59 | pass | ||
60 | |||
61 | # We need to ensure we're only shown once | ||
62 | self.shown = False | ||
63 | |||
64 | # We don't want any WM decorations | ||
65 | self.set_decorated(False) | ||
66 | # We don't want to show in the taskbar or window switcher | ||
67 | self.set_skip_pager_hint(True) | ||
68 | self.set_skip_taskbar_hint(True) | ||
69 | # We must be modal to ensure we grab focus when presented from a gtk.Dialog | ||
70 | self.set_modal(True) | ||
71 | |||
72 | self.set_border_width(0) | ||
73 | self.set_position(gtk.WIN_POS_MOUSE) | ||
74 | self.set_opacity(0.95) | ||
75 | |||
76 | # Ensure a reasonable minimum size | ||
77 | self.set_geometry_hints(self, 100, 50) | ||
78 | |||
79 | # Set this window as a transient window for parent(main window) | ||
80 | if parent_win: | ||
81 | self.set_transient_for(parent_win) | ||
82 | self.set_destroy_with_parent(True) | ||
83 | # Draw our label and close buttons | ||
84 | hbox = gtk.HBox(False, 0) | ||
85 | hbox.show() | ||
86 | self.add(hbox) | ||
87 | |||
88 | img = gtk.Image() | ||
89 | img.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_BUTTON) | ||
90 | |||
91 | self.button = gtk.Button() | ||
92 | self.button.set_image(img) | ||
93 | self.button.connect("clicked", self._dismiss_cb) | ||
94 | self.button.set_flags(gtk.CAN_DEFAULT) | ||
95 | self.button.grab_focus() | ||
96 | self.button.show() | ||
97 | vbox = gtk.VBox(False, 0) | ||
98 | vbox.show() | ||
99 | vbox.pack_start(self.button, False, False, 0) | ||
100 | if __button_right: | ||
101 | hbox.pack_end(vbox, True, True, 0) | ||
102 | else: | ||
103 | hbox.pack_start(vbox, True, True, 0) | ||
104 | |||
105 | self.set_default(self.button) | ||
106 | |||
107 | bin = gtk.HBox(True, 6) | ||
108 | bin.set_border_width(6) | ||
109 | bin.show() | ||
110 | self.label = gtk.Label() | ||
111 | self.label.set_line_wrap(True) | ||
112 | # We want to match the colours of the normal tooltips, as dictated by | ||
113 | # the users gtk+-2.0 theme, wherever possible - on some systems this | ||
114 | # requires explicitly setting a fg_color for the label which matches the | ||
115 | # tooltip_fg_color | ||
116 | settings = gtk.settings_get_default() | ||
117 | colours = settings.get_property('gtk-color-scheme').split('\n') | ||
118 | # remove any empty lines, there's likely to be a trailing one after | ||
119 | # calling split on a dictionary-like string | ||
120 | colours = filter(None, colours) | ||
121 | for col in colours: | ||
122 | item, val = col.split(': ') | ||
123 | if item == 'tooltip_fg_color': | ||
124 | style = self.label.get_style() | ||
125 | style.fg[gtk.STATE_NORMAL] = gtk.gdk.color_parse(val) | ||
126 | self.label.set_style(style) | ||
127 | break # we only care for the tooltip_fg_color | ||
128 | |||
129 | self.label.set_markup(markup) | ||
130 | self.label.show() | ||
131 | bin.add(self.label) | ||
132 | hbox.pack_end(bin, True, True, 6) | ||
133 | |||
134 | # add the original URL display for user reference | ||
135 | if 'a href' in markup: | ||
136 | hbox.set_tooltip_text(self.get_markup_url(markup)) | ||
137 | hbox.show() | ||
138 | |||
139 | self.connect("key-press-event", self._catch_esc_cb) | ||
140 | |||
141 | """ | ||
142 | Callback when the PersistentTooltip's close button is clicked. | ||
143 | Hides the PersistentTooltip. | ||
144 | """ | ||
145 | def _dismiss_cb(self, button): | ||
146 | self.hide() | ||
147 | return True | ||
148 | |||
149 | """ | ||
150 | Callback when the Esc key is detected. Hides the PersistentTooltip. | ||
151 | """ | ||
152 | def _catch_esc_cb(self, widget, event): | ||
153 | keyname = gtk.gdk.keyval_name(event.keyval) | ||
154 | if keyname == "Escape": | ||
155 | self.hide() | ||
156 | return True | ||
157 | |||
158 | """ | ||
159 | Called to present the PersistentTooltip. | ||
160 | Overrides the superclasses show() method to include state tracking. | ||
161 | """ | ||
162 | def show(self): | ||
163 | if not self.shown: | ||
164 | self.shown = True | ||
165 | gtk.Window.show(self) | ||
166 | |||
167 | """ | ||
168 | Called to hide the PersistentTooltip. | ||
169 | Overrides the superclasses hide() method to include state tracking. | ||
170 | """ | ||
171 | def hide(self): | ||
172 | self.shown = False | ||
173 | gtk.Window.hide(self) | ||
174 | |||
175 | """ | ||
176 | Called to get the hyperlink URL from markup text. | ||
177 | """ | ||
178 | def get_markup_url(self, markup): | ||
179 | url = "http:" | ||
180 | if markup and type(markup) == str: | ||
181 | s = markup | ||
182 | if 'http:' in s: | ||
183 | import re | ||
184 | url = re.search('(http:[^,\\ "]+)', s).group(0) | ||
185 | |||
186 | return url | ||
diff --git a/bitbake/lib/bb/ui/crumbs/progress.py b/bitbake/lib/bb/ui/crumbs/progress.py deleted file mode 100644 index 1d28a111b3..0000000000 --- a/bitbake/lib/bb/ui/crumbs/progress.py +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | import gtk | ||
2 | |||
3 | class ProgressBar(gtk.Dialog): | ||
4 | def __init__(self, parent): | ||
5 | |||
6 | gtk.Dialog.__init__(self, flags=(gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)) | ||
7 | self.set_title("Parsing metadata, please wait...") | ||
8 | self.set_default_size(500, 0) | ||
9 | self.set_transient_for(parent) | ||
10 | self.progress = gtk.ProgressBar() | ||
11 | self.vbox.pack_start(self.progress) | ||
12 | self.show_all() | ||
13 | |||
14 | def set_text(self, msg): | ||
15 | self.progress.set_text(msg) | ||
16 | |||
17 | def update(self, x, y): | ||
18 | self.progress.set_fraction(float(x)/float(y)) | ||
19 | self.progress.set_text("%2d %%" % (x*100/y)) | ||
20 | |||
21 | def pulse(self): | ||
22 | self.progress.set_text("Loading...") | ||
23 | self.progress.pulse() | ||
diff --git a/bitbake/lib/bb/ui/crumbs/progressbar.py b/bitbake/lib/bb/ui/crumbs/progressbar.py deleted file mode 100644 index ba3c7a0754..0000000000 --- a/bitbake/lib/bb/ui/crumbs/progressbar.py +++ /dev/null | |||
@@ -1,60 +0,0 @@ | |||
1 | # BitBake Graphical GTK User Interface | ||
2 | # | ||
3 | # Copyright (C) 2011 Intel Corporation | ||
4 | # | ||
5 | # Authored by Shane Wang <shane.wang@intel.com> | ||
6 | # | ||
7 | # This program is free software; you can redistribute it and/or modify | ||
8 | # it under the terms of the GNU General Public License version 2 as | ||
9 | # published by the Free Software Foundation. | ||
10 | # | ||
11 | # This program is distributed in the hope that it will be useful, | ||
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | # GNU General Public License for more details. | ||
15 | # | ||
16 | # You should have received a copy of the GNU General Public License along | ||
17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | |||
20 | import gtk | ||
21 | from bb.ui.crumbs.hobcolor import HobColors | ||
22 | |||
23 | class HobProgressBar (gtk.ProgressBar): | ||
24 | def __init__(self): | ||
25 | gtk.ProgressBar.__init__(self) | ||
26 | self.set_rcstyle(True) | ||
27 | self.percentage = 0 | ||
28 | |||
29 | def set_rcstyle(self, status): | ||
30 | rcstyle = gtk.RcStyle() | ||
31 | #FIXME | ||
32 | # rcstyle.fg[2] = gtk.gdk.Color(HobColors.BLACK) | ||
33 | # if status == "stop": | ||
34 | # rcstyle.bg[3] = gtk.gdk.Color(HobColors.WARNING) | ||
35 | # elif status == "fail": | ||
36 | # rcstyle.bg[3] = gtk.gdk.Color(HobColors.ERROR) | ||
37 | # else: | ||
38 | # rcstyle.bg[3] = gtk.gdk.Color(HobColors.RUNNING) | ||
39 | self.modify_style(rcstyle) | ||
40 | |||
41 | def set_title(self, text=None): | ||
42 | if not text: | ||
43 | text = "" | ||
44 | text += " %.0f%%" % self.percentage | ||
45 | self.set_text(text) | ||
46 | |||
47 | def set_stop_title(self, text=None): | ||
48 | if not text: | ||
49 | text = "" | ||
50 | self.set_text(text) | ||
51 | |||
52 | def reset(self): | ||
53 | self.set_fraction(0) | ||
54 | self.set_text("") | ||
55 | self.set_rcstyle(True) | ||
56 | self.percentage = 0 | ||
57 | |||
58 | def update(self, fraction): | ||
59 | self.percentage = int(fraction * 100) | ||
60 | self.set_fraction(fraction) | ||
diff --git a/bitbake/lib/bb/ui/crumbs/puccho.glade b/bitbake/lib/bb/ui/crumbs/puccho.glade deleted file mode 100644 index d7553a6e14..0000000000 --- a/bitbake/lib/bb/ui/crumbs/puccho.glade +++ /dev/null | |||
@@ -1,606 +0,0 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
2 | <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> | ||
3 | <!--Generated with glade3 3.4.5 on Mon Nov 10 12:24:12 2008 --> | ||
4 | <glade-interface> | ||
5 | <widget class="GtkDialog" id="build_dialog"> | ||
6 | <property name="title" translatable="yes">Start a build</property> | ||
7 | <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> | ||
8 | <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> | ||
9 | <property name="has_separator">False</property> | ||
10 | <child internal-child="vbox"> | ||
11 | <widget class="GtkVBox" id="dialog-vbox1"> | ||
12 | <property name="visible">True</property> | ||
13 | <property name="spacing">2</property> | ||
14 | <child> | ||
15 | <widget class="GtkTable" id="build_table"> | ||
16 | <property name="visible">True</property> | ||
17 | <property name="border_width">6</property> | ||
18 | <property name="n_rows">7</property> | ||
19 | <property name="n_columns">3</property> | ||
20 | <property name="column_spacing">5</property> | ||
21 | <property name="row_spacing">6</property> | ||
22 | <child> | ||
23 | <widget class="GtkAlignment" id="status_alignment"> | ||
24 | <property name="visible">True</property> | ||
25 | <property name="left_padding">12</property> | ||
26 | <child> | ||
27 | <widget class="GtkHBox" id="status_hbox"> | ||
28 | <property name="spacing">6</property> | ||
29 | <child> | ||
30 | <widget class="GtkImage" id="status_image"> | ||
31 | <property name="visible">True</property> | ||
32 | <property name="no_show_all">True</property> | ||
33 | <property name="xalign">0</property> | ||
34 | <property name="stock">gtk-dialog-error</property> | ||
35 | </widget> | ||
36 | <packing> | ||
37 | <property name="expand">False</property> | ||
38 | <property name="fill">False</property> | ||
39 | </packing> | ||
40 | </child> | ||
41 | <child> | ||
42 | <widget class="GtkLabel" id="status_label"> | ||
43 | <property name="visible">True</property> | ||
44 | <property name="xalign">0</property> | ||
45 | <property name="label" translatable="yes">If you see this text something is wrong...</property> | ||
46 | <property name="use_markup">True</property> | ||
47 | <property name="use_underline">True</property> | ||
48 | </widget> | ||
49 | <packing> | ||
50 | <property name="position">1</property> | ||
51 | </packing> | ||
52 | </child> | ||
53 | </widget> | ||
54 | </child> | ||
55 | </widget> | ||
56 | <packing> | ||
57 | <property name="right_attach">3</property> | ||
58 | <property name="top_attach">2</property> | ||
59 | <property name="bottom_attach">3</property> | ||
60 | </packing> | ||
61 | </child> | ||
62 | <child> | ||
63 | <widget class="GtkLabel" id="label2"> | ||
64 | <property name="visible">True</property> | ||
65 | <property name="xalign">0</property> | ||
66 | <property name="label" translatable="yes"><b>Build configuration</b></property> | ||
67 | <property name="use_markup">True</property> | ||
68 | </widget> | ||
69 | <packing> | ||
70 | <property name="right_attach">3</property> | ||
71 | <property name="top_attach">3</property> | ||
72 | <property name="bottom_attach">4</property> | ||
73 | <property name="y_options"></property> | ||
74 | </packing> | ||
75 | </child> | ||
76 | <child> | ||
77 | <widget class="GtkComboBox" id="image_combo"> | ||
78 | <property name="visible">True</property> | ||
79 | <property name="sensitive">False</property> | ||
80 | </widget> | ||
81 | <packing> | ||
82 | <property name="left_attach">1</property> | ||
83 | <property name="right_attach">2</property> | ||
84 | <property name="top_attach">6</property> | ||
85 | <property name="bottom_attach">7</property> | ||
86 | <property name="y_options"></property> | ||
87 | </packing> | ||
88 | </child> | ||
89 | <child> | ||
90 | <widget class="GtkLabel" id="image_label"> | ||
91 | <property name="visible">True</property> | ||
92 | <property name="sensitive">False</property> | ||
93 | <property name="xalign">0</property> | ||
94 | <property name="xpad">12</property> | ||
95 | <property name="label" translatable="yes">Image:</property> | ||
96 | </widget> | ||
97 | <packing> | ||
98 | <property name="top_attach">6</property> | ||
99 | <property name="bottom_attach">7</property> | ||
100 | <property name="y_options"></property> | ||
101 | </packing> | ||
102 | </child> | ||
103 | <child> | ||
104 | <widget class="GtkComboBox" id="distribution_combo"> | ||
105 | <property name="visible">True</property> | ||
106 | <property name="sensitive">False</property> | ||
107 | </widget> | ||
108 | <packing> | ||
109 | <property name="left_attach">1</property> | ||
110 | <property name="right_attach">2</property> | ||
111 | <property name="top_attach">5</property> | ||
112 | <property name="bottom_attach">6</property> | ||
113 | <property name="y_options"></property> | ||
114 | </packing> | ||
115 | </child> | ||
116 | <child> | ||
117 | <widget class="GtkLabel" id="distribution_label"> | ||
118 | <property name="visible">True</property> | ||
119 | <property name="sensitive">False</property> | ||
120 | <property name="xalign">0</property> | ||
121 | <property name="xpad">12</property> | ||
122 | <property name="label" translatable="yes">Distribution:</property> | ||
123 | </widget> | ||
124 | <packing> | ||
125 | <property name="top_attach">5</property> | ||
126 | <property name="bottom_attach">6</property> | ||
127 | <property name="y_options"></property> | ||
128 | </packing> | ||
129 | </child> | ||
130 | <child> | ||
131 | <widget class="GtkComboBox" id="machine_combo"> | ||
132 | <property name="visible">True</property> | ||
133 | <property name="sensitive">False</property> | ||
134 | </widget> | ||
135 | <packing> | ||
136 | <property name="left_attach">1</property> | ||
137 | <property name="right_attach">2</property> | ||
138 | <property name="top_attach">4</property> | ||
139 | <property name="bottom_attach">5</property> | ||
140 | <property name="y_options"></property> | ||
141 | </packing> | ||
142 | </child> | ||
143 | <child> | ||
144 | <widget class="GtkLabel" id="machine_label"> | ||
145 | <property name="visible">True</property> | ||
146 | <property name="sensitive">False</property> | ||
147 | <property name="xalign">0</property> | ||
148 | <property name="xpad">12</property> | ||
149 | <property name="label" translatable="yes">Machine:</property> | ||
150 | </widget> | ||
151 | <packing> | ||
152 | <property name="top_attach">4</property> | ||
153 | <property name="bottom_attach">5</property> | ||
154 | <property name="y_options"></property> | ||
155 | </packing> | ||
156 | </child> | ||
157 | <child> | ||
158 | <widget class="GtkButton" id="refresh_button"> | ||
159 | <property name="visible">True</property> | ||
160 | <property name="sensitive">False</property> | ||
161 | <property name="can_focus">True</property> | ||
162 | <property name="receives_default">True</property> | ||
163 | <property name="label" translatable="yes">gtk-refresh</property> | ||
164 | <property name="use_stock">True</property> | ||
165 | <property name="response_id">0</property> | ||
166 | </widget> | ||
167 | <packing> | ||
168 | <property name="left_attach">2</property> | ||
169 | <property name="right_attach">3</property> | ||
170 | <property name="top_attach">1</property> | ||
171 | <property name="bottom_attach">2</property> | ||
172 | <property name="y_options"></property> | ||
173 | </packing> | ||
174 | </child> | ||
175 | <child> | ||
176 | <widget class="GtkEntry" id="location_entry"> | ||
177 | <property name="visible">True</property> | ||
178 | <property name="can_focus">True</property> | ||
179 | <property name="width_chars">32</property> | ||
180 | </widget> | ||
181 | <packing> | ||
182 | <property name="left_attach">1</property> | ||
183 | <property name="right_attach">2</property> | ||
184 | <property name="top_attach">1</property> | ||
185 | <property name="bottom_attach">2</property> | ||
186 | <property name="y_options"></property> | ||
187 | </packing> | ||
188 | </child> | ||
189 | <child> | ||
190 | <widget class="GtkLabel" id="label3"> | ||
191 | <property name="visible">True</property> | ||
192 | <property name="xalign">0</property> | ||
193 | <property name="xpad">12</property> | ||
194 | <property name="label" translatable="yes">Location:</property> | ||
195 | </widget> | ||
196 | <packing> | ||
197 | <property name="top_attach">1</property> | ||
198 | <property name="bottom_attach">2</property> | ||
199 | <property name="y_options"></property> | ||
200 | </packing> | ||
201 | </child> | ||
202 | <child> | ||
203 | <widget class="GtkLabel" id="label1"> | ||
204 | <property name="visible">True</property> | ||
205 | <property name="xalign">0</property> | ||
206 | <property name="label" translatable="yes"><b>Repository</b></property> | ||
207 | <property name="use_markup">True</property> | ||
208 | </widget> | ||
209 | <packing> | ||
210 | <property name="right_attach">3</property> | ||
211 | <property name="y_options"></property> | ||
212 | </packing> | ||
213 | </child> | ||
214 | <child> | ||
215 | <widget class="GtkAlignment" id="alignment1"> | ||
216 | <property name="visible">True</property> | ||
217 | <child> | ||
218 | <placeholder/> | ||
219 | </child> | ||
220 | </widget> | ||
221 | <packing> | ||
222 | <property name="left_attach">2</property> | ||
223 | <property name="right_attach">3</property> | ||
224 | <property name="top_attach">4</property> | ||
225 | <property name="bottom_attach">5</property> | ||
226 | <property name="y_options"></property> | ||
227 | </packing> | ||
228 | </child> | ||
229 | <child> | ||
230 | <widget class="GtkAlignment" id="alignment2"> | ||
231 | <property name="visible">True</property> | ||
232 | <child> | ||
233 | <placeholder/> | ||
234 | </child> | ||
235 | </widget> | ||
236 | <packing> | ||
237 | <property name="left_attach">2</property> | ||
238 | <property name="right_attach">3</property> | ||
239 | <property name="top_attach">5</property> | ||
240 | <property name="bottom_attach">6</property> | ||
241 | <property name="y_options"></property> | ||
242 | </packing> | ||
243 | </child> | ||
244 | <child> | ||
245 | <widget class="GtkAlignment" id="alignment3"> | ||
246 | <property name="visible">True</property> | ||
247 | <child> | ||
248 | <placeholder/> | ||
249 | </child> | ||
250 | </widget> | ||
251 | <packing> | ||
252 | <property name="left_attach">2</property> | ||
253 | <property name="right_attach">3</property> | ||
254 | <property name="top_attach">6</property> | ||
255 | <property name="bottom_attach">7</property> | ||
256 | <property name="y_options"></property> | ||
257 | </packing> | ||
258 | </child> | ||
259 | </widget> | ||
260 | <packing> | ||
261 | <property name="position">1</property> | ||
262 | </packing> | ||
263 | </child> | ||
264 | <child internal-child="action_area"> | ||
265 | <widget class="GtkHButtonBox" id="dialog-action_area1"> | ||
266 | <property name="visible">True</property> | ||
267 | <property name="layout_style">GTK_BUTTONBOX_END</property> | ||
268 | <child> | ||
269 | <placeholder/> | ||
270 | </child> | ||
271 | <child> | ||
272 | <placeholder/> | ||
273 | </child> | ||
274 | <child> | ||
275 | <placeholder/> | ||
276 | </child> | ||
277 | </widget> | ||
278 | <packing> | ||
279 | <property name="expand">False</property> | ||
280 | <property name="pack_type">GTK_PACK_END</property> | ||
281 | </packing> | ||
282 | </child> | ||
283 | </widget> | ||
284 | </child> | ||
285 | </widget> | ||
286 | <widget class="GtkDialog" id="dialog2"> | ||
287 | <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> | ||
288 | <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> | ||
289 | <property name="has_separator">False</property> | ||
290 | <child internal-child="vbox"> | ||
291 | <widget class="GtkVBox" id="dialog-vbox2"> | ||
292 | <property name="visible">True</property> | ||
293 | <property name="spacing">2</property> | ||
294 | <child> | ||
295 | <widget class="GtkTable" id="table2"> | ||
296 | <property name="visible">True</property> | ||
297 | <property name="border_width">6</property> | ||
298 | <property name="n_rows">7</property> | ||
299 | <property name="n_columns">3</property> | ||
300 | <property name="column_spacing">6</property> | ||
301 | <property name="row_spacing">6</property> | ||
302 | <child> | ||
303 | <widget class="GtkLabel" id="label7"> | ||
304 | <property name="visible">True</property> | ||
305 | <property name="xalign">0</property> | ||
306 | <property name="label" translatable="yes"><b>Repositories</b></property> | ||
307 | <property name="use_markup">True</property> | ||
308 | </widget> | ||
309 | <packing> | ||
310 | <property name="right_attach">3</property> | ||
311 | <property name="y_options"></property> | ||
312 | </packing> | ||
313 | </child> | ||
314 | <child> | ||
315 | <widget class="GtkAlignment" id="alignment4"> | ||
316 | <property name="visible">True</property> | ||
317 | <property name="xalign">0</property> | ||
318 | <property name="left_padding">12</property> | ||
319 | <child> | ||
320 | <widget class="GtkScrolledWindow" id="scrolledwindow1"> | ||
321 | <property name="visible">True</property> | ||
322 | <property name="can_focus">True</property> | ||
323 | <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> | ||
324 | <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> | ||
325 | <child> | ||
326 | <widget class="GtkTreeView" id="treeview1"> | ||
327 | <property name="visible">True</property> | ||
328 | <property name="can_focus">True</property> | ||
329 | <property name="headers_clickable">True</property> | ||
330 | </widget> | ||
331 | </child> | ||
332 | </widget> | ||
333 | </child> | ||
334 | </widget> | ||
335 | <packing> | ||
336 | <property name="right_attach">3</property> | ||
337 | <property name="top_attach">2</property> | ||
338 | <property name="bottom_attach">3</property> | ||
339 | <property name="y_options"></property> | ||
340 | </packing> | ||
341 | </child> | ||
342 | <child> | ||
343 | <widget class="GtkEntry" id="entry1"> | ||
344 | <property name="visible">True</property> | ||
345 | <property name="can_focus">True</property> | ||
346 | </widget> | ||
347 | <packing> | ||
348 | <property name="left_attach">1</property> | ||
349 | <property name="right_attach">3</property> | ||
350 | <property name="top_attach">1</property> | ||
351 | <property name="bottom_attach">2</property> | ||
352 | <property name="y_options"></property> | ||
353 | </packing> | ||
354 | </child> | ||
355 | <child> | ||
356 | <widget class="GtkLabel" id="label9"> | ||
357 | <property name="visible">True</property> | ||
358 | <property name="xalign">0</property> | ||
359 | <property name="label" translatable="yes"><b>Additional packages</b></property> | ||
360 | <property name="use_markup">True</property> | ||
361 | </widget> | ||
362 | <packing> | ||
363 | <property name="right_attach">3</property> | ||
364 | <property name="top_attach">4</property> | ||
365 | <property name="bottom_attach">5</property> | ||
366 | <property name="y_options"></property> | ||
367 | </packing> | ||
368 | </child> | ||
369 | <child> | ||
370 | <widget class="GtkAlignment" id="alignment6"> | ||
371 | <property name="visible">True</property> | ||
372 | <property name="xalign">0</property> | ||
373 | <property name="xscale">0</property> | ||
374 | <child> | ||
375 | <widget class="GtkLabel" id="label8"> | ||
376 | <property name="visible">True</property> | ||
377 | <property name="xalign">0</property> | ||
378 | <property name="yalign">0</property> | ||
379 | <property name="xpad">12</property> | ||
380 | <property name="label" translatable="yes">Location: </property> | ||
381 | </widget> | ||
382 | </child> | ||
383 | </widget> | ||
384 | <packing> | ||
385 | <property name="top_attach">1</property> | ||
386 | <property name="bottom_attach">2</property> | ||
387 | <property name="y_options"></property> | ||
388 | </packing> | ||
389 | </child> | ||
390 | <child> | ||
391 | <widget class="GtkAlignment" id="alignment7"> | ||
392 | <property name="visible">True</property> | ||
393 | <property name="xalign">1</property> | ||
394 | <property name="xscale">0</property> | ||
395 | <child> | ||
396 | <widget class="GtkHButtonBox" id="hbuttonbox1"> | ||
397 | <property name="visible">True</property> | ||
398 | <property name="spacing">5</property> | ||
399 | <child> | ||
400 | <widget class="GtkButton" id="button7"> | ||
401 | <property name="visible">True</property> | ||
402 | <property name="can_focus">True</property> | ||
403 | <property name="receives_default">True</property> | ||
404 | <property name="label" translatable="yes">gtk-remove</property> | ||
405 | <property name="use_stock">True</property> | ||
406 | <property name="response_id">0</property> | ||
407 | </widget> | ||
408 | </child> | ||
409 | <child> | ||
410 | <widget class="GtkButton" id="button6"> | ||
411 | <property name="visible">True</property> | ||
412 | <property name="can_focus">True</property> | ||
413 | <property name="receives_default">True</property> | ||
414 | <property name="label" translatable="yes">gtk-edit</property> | ||
415 | <property name="use_stock">True</property> | ||
416 | <property name="response_id">0</property> | ||
417 | </widget> | ||
418 | <packing> | ||
419 | <property name="position">1</property> | ||
420 | </packing> | ||
421 | </child> | ||
422 | <child> | ||
423 | <widget class="GtkButton" id="button5"> | ||
424 | <property name="visible">True</property> | ||
425 | <property name="can_focus">True</property> | ||
426 | <property name="receives_default">True</property> | ||
427 | <property name="label" translatable="yes">gtk-add</property> | ||
428 | <property name="use_stock">True</property> | ||
429 | <property name="response_id">0</property> | ||
430 | </widget> | ||
431 | <packing> | ||
432 | <property name="position">2</property> | ||
433 | </packing> | ||
434 | </child> | ||
435 | </widget> | ||
436 | </child> | ||
437 | </widget> | ||
438 | <packing> | ||
439 | <property name="left_attach">1</property> | ||
440 | <property name="right_attach">3</property> | ||
441 | <property name="top_attach">3</property> | ||
442 | <property name="bottom_attach">4</property> | ||
443 | <property name="y_options"></property> | ||
444 | </packing> | ||
445 | </child> | ||
446 | <child> | ||
447 | <widget class="GtkAlignment" id="alignment5"> | ||
448 | <property name="visible">True</property> | ||
449 | <child> | ||
450 | <placeholder/> | ||
451 | </child> | ||
452 | </widget> | ||
453 | <packing> | ||
454 | <property name="top_attach">3</property> | ||
455 | <property name="bottom_attach">4</property> | ||
456 | <property name="y_options"></property> | ||
457 | </packing> | ||
458 | </child> | ||
459 | <child> | ||
460 | <widget class="GtkLabel" id="label10"> | ||
461 | <property name="visible">True</property> | ||
462 | <property name="xalign">0</property> | ||
463 | <property name="yalign">0</property> | ||
464 | <property name="xpad">12</property> | ||
465 | <property name="label" translatable="yes">Search:</property> | ||
466 | </widget> | ||
467 | <packing> | ||
468 | <property name="top_attach">5</property> | ||
469 | <property name="bottom_attach">6</property> | ||
470 | <property name="y_options"></property> | ||
471 | </packing> | ||
472 | </child> | ||
473 | <child> | ||
474 | <widget class="GtkEntry" id="entry2"> | ||
475 | <property name="visible">True</property> | ||
476 | <property name="can_focus">True</property> | ||
477 | </widget> | ||
478 | <packing> | ||
479 | <property name="left_attach">1</property> | ||
480 | <property name="right_attach">3</property> | ||
481 | <property name="top_attach">5</property> | ||
482 | <property name="bottom_attach">6</property> | ||
483 | <property name="y_options"></property> | ||
484 | </packing> | ||
485 | </child> | ||
486 | <child> | ||
487 | <widget class="GtkAlignment" id="alignment8"> | ||
488 | <property name="visible">True</property> | ||
489 | <property name="xalign">0</property> | ||
490 | <property name="left_padding">12</property> | ||
491 | <child> | ||
492 | <widget class="GtkScrolledWindow" id="scrolledwindow2"> | ||
493 | <property name="visible">True</property> | ||
494 | <property name="can_focus">True</property> | ||
495 | <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> | ||
496 | <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> | ||
497 | <child> | ||
498 | <widget class="GtkTreeView" id="treeview2"> | ||
499 | <property name="visible">True</property> | ||
500 | <property name="can_focus">True</property> | ||
501 | <property name="headers_clickable">True</property> | ||
502 | </widget> | ||
503 | </child> | ||
504 | </widget> | ||
505 | </child> | ||
506 | </widget> | ||
507 | <packing> | ||
508 | <property name="right_attach">3</property> | ||
509 | <property name="top_attach">6</property> | ||
510 | <property name="bottom_attach">7</property> | ||
511 | <property name="y_options"></property> | ||
512 | </packing> | ||
513 | </child> | ||
514 | </widget> | ||
515 | <packing> | ||
516 | <property name="position">1</property> | ||
517 | </packing> | ||
518 | </child> | ||
519 | <child internal-child="action_area"> | ||
520 | <widget class="GtkHButtonBox" id="dialog-action_area2"> | ||
521 | <property name="visible">True</property> | ||
522 | <property name="layout_style">GTK_BUTTONBOX_END</property> | ||
523 | <child> | ||
524 | <widget class="GtkButton" id="button4"> | ||
525 | <property name="visible">True</property> | ||
526 | <property name="can_focus">True</property> | ||
527 | <property name="receives_default">True</property> | ||
528 | <property name="label" translatable="yes">gtk-close</property> | ||
529 | <property name="use_stock">True</property> | ||
530 | <property name="response_id">0</property> | ||
531 | </widget> | ||
532 | </child> | ||
533 | </widget> | ||
534 | <packing> | ||
535 | <property name="expand">False</property> | ||
536 | <property name="pack_type">GTK_PACK_END</property> | ||
537 | </packing> | ||
538 | </child> | ||
539 | </widget> | ||
540 | </child> | ||
541 | </widget> | ||
542 | <widget class="GtkWindow" id="main_window"> | ||
543 | <child> | ||
544 | <widget class="GtkVBox" id="main_window_vbox"> | ||
545 | <property name="visible">True</property> | ||
546 | <child> | ||
547 | <widget class="GtkToolbar" id="main_toolbar"> | ||
548 | <property name="visible">True</property> | ||
549 | <child> | ||
550 | <widget class="GtkToolButton" id="main_toolbutton_build"> | ||
551 | <property name="visible">True</property> | ||
552 | <property name="label" translatable="yes">Build</property> | ||
553 | <property name="stock_id">gtk-execute</property> | ||
554 | </widget> | ||
555 | <packing> | ||
556 | <property name="expand">False</property> | ||
557 | </packing> | ||
558 | </child> | ||
559 | </widget> | ||
560 | <packing> | ||
561 | <property name="expand">False</property> | ||
562 | </packing> | ||
563 | </child> | ||
564 | <child> | ||
565 | <widget class="GtkVPaned" id="vpaned1"> | ||
566 | <property name="visible">True</property> | ||
567 | <property name="can_focus">True</property> | ||
568 | <child> | ||
569 | <widget class="GtkScrolledWindow" id="results_scrolledwindow"> | ||
570 | <property name="visible">True</property> | ||
571 | <property name="can_focus">True</property> | ||
572 | <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> | ||
573 | <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> | ||
574 | <child> | ||
575 | <placeholder/> | ||
576 | </child> | ||
577 | </widget> | ||
578 | <packing> | ||
579 | <property name="resize">False</property> | ||
580 | <property name="shrink">True</property> | ||
581 | </packing> | ||
582 | </child> | ||
583 | <child> | ||
584 | <widget class="GtkScrolledWindow" id="progress_scrolledwindow"> | ||
585 | <property name="visible">True</property> | ||
586 | <property name="can_focus">True</property> | ||
587 | <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> | ||
588 | <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> | ||
589 | <child> | ||
590 | <placeholder/> | ||
591 | </child> | ||
592 | </widget> | ||
593 | <packing> | ||
594 | <property name="resize">True</property> | ||
595 | <property name="shrink">True</property> | ||
596 | </packing> | ||
597 | </child> | ||
598 | </widget> | ||
599 | <packing> | ||
600 | <property name="position">1</property> | ||
601 | </packing> | ||
602 | </child> | ||
603 | </widget> | ||
604 | </child> | ||
605 | </widget> | ||
606 | </glade-interface> | ||
diff --git a/bitbake/lib/bb/ui/crumbs/runningbuild.py b/bitbake/lib/bb/ui/crumbs/runningbuild.py deleted file mode 100644 index 9b695ac2ed..0000000000 --- a/bitbake/lib/bb/ui/crumbs/runningbuild.py +++ /dev/null | |||
@@ -1,551 +0,0 @@ | |||
1 | |||
2 | # | ||
3 | # BitBake Graphical GTK User Interface | ||
4 | # | ||
5 | # Copyright (C) 2008 Intel Corporation | ||
6 | # | ||
7 | # Authored by Rob Bradford <rob@linux.intel.com> | ||
8 | # | ||
9 | # This program is free software; you can redistribute it and/or modify | ||
10 | # it under the terms of the GNU General Public License version 2 as | ||
11 | # published by the Free Software Foundation. | ||
12 | # | ||
13 | # This program is distributed in the hope that it will be useful, | ||
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | # GNU General Public License for more details. | ||
17 | # | ||
18 | # You should have received a copy of the GNU General Public License along | ||
19 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | |||
22 | import gtk | ||
23 | import gobject | ||
24 | import logging | ||
25 | import time | ||
26 | import urllib.request, urllib.parse, urllib.error | ||
27 | import urllib.request, urllib.error, urllib.parse | ||
28 | import pango | ||
29 | from bb.ui.crumbs.hobcolor import HobColors | ||
30 | from bb.ui.crumbs.hobwidget import HobWarpCellRendererText, HobCellRendererPixbuf | ||
31 | |||
32 | class RunningBuildModel (gtk.TreeStore): | ||
33 | (COL_LOG, COL_PACKAGE, COL_TASK, COL_MESSAGE, COL_ICON, COL_COLOR, COL_NUM_ACTIVE) = list(range(7)) | ||
34 | |||
35 | def __init__ (self): | ||
36 | gtk.TreeStore.__init__ (self, | ||
37 | gobject.TYPE_STRING, | ||
38 | gobject.TYPE_STRING, | ||
39 | gobject.TYPE_STRING, | ||
40 | gobject.TYPE_STRING, | ||
41 | gobject.TYPE_STRING, | ||
42 | gobject.TYPE_STRING, | ||
43 | gobject.TYPE_INT) | ||
44 | |||
45 | def failure_model_filter(self, model, it): | ||
46 | color = model.get(it, self.COL_COLOR)[0] | ||
47 | if not color: | ||
48 | return False | ||
49 | if color == HobColors.ERROR or color == HobColors.WARNING: | ||
50 | return True | ||
51 | return False | ||
52 | |||
53 | def failure_model(self): | ||
54 | model = self.filter_new() | ||
55 | model.set_visible_func(self.failure_model_filter) | ||
56 | return model | ||
57 | |||
58 | def foreach_cell_func(self, model, path, iter, usr_data=None): | ||
59 | if model.get_value(iter, self.COL_ICON) == "gtk-execute": | ||
60 | model.set(iter, self.COL_ICON, "") | ||
61 | |||
62 | def close_task_refresh(self): | ||
63 | self.foreach(self.foreach_cell_func, None) | ||
64 | |||
65 | class RunningBuild (gobject.GObject): | ||
66 | __gsignals__ = { | ||
67 | 'build-started' : (gobject.SIGNAL_RUN_LAST, | ||
68 | gobject.TYPE_NONE, | ||
69 | ()), | ||
70 | 'build-succeeded' : (gobject.SIGNAL_RUN_LAST, | ||
71 | gobject.TYPE_NONE, | ||
72 | ()), | ||
73 | 'build-failed' : (gobject.SIGNAL_RUN_LAST, | ||
74 | gobject.TYPE_NONE, | ||
75 | ()), | ||
76 | 'build-complete' : (gobject.SIGNAL_RUN_LAST, | ||
77 | gobject.TYPE_NONE, | ||
78 | ()), | ||
79 | 'build-aborted' : (gobject.SIGNAL_RUN_LAST, | ||
80 | gobject.TYPE_NONE, | ||
81 | ()), | ||
82 | 'task-started' : (gobject.SIGNAL_RUN_LAST, | ||
83 | gobject.TYPE_NONE, | ||
84 | (gobject.TYPE_PYOBJECT,)), | ||
85 | 'log-error' : (gobject.SIGNAL_RUN_LAST, | ||
86 | gobject.TYPE_NONE, | ||
87 | ()), | ||
88 | 'log-warning' : (gobject.SIGNAL_RUN_LAST, | ||
89 | gobject.TYPE_NONE, | ||
90 | ()), | ||
91 | 'disk-full' : (gobject.SIGNAL_RUN_LAST, | ||
92 | gobject.TYPE_NONE, | ||
93 | ()), | ||
94 | 'no-provider' : (gobject.SIGNAL_RUN_LAST, | ||
95 | gobject.TYPE_NONE, | ||
96 | (gobject.TYPE_PYOBJECT,)), | ||
97 | 'log' : (gobject.SIGNAL_RUN_LAST, | ||
98 | gobject.TYPE_NONE, | ||
99 | (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT,)), | ||
100 | } | ||
101 | pids_to_task = {} | ||
102 | tasks_to_iter = {} | ||
103 | |||
104 | def __init__ (self, sequential=False): | ||
105 | gobject.GObject.__init__ (self) | ||
106 | self.model = RunningBuildModel() | ||
107 | self.sequential = sequential | ||
108 | self.buildaborted = False | ||
109 | |||
110 | def reset (self): | ||
111 | self.pids_to_task.clear() | ||
112 | self.tasks_to_iter.clear() | ||
113 | self.model.clear() | ||
114 | |||
115 | def handle_event (self, event, pbar=None): | ||
116 | # Handle an event from the event queue, this may result in updating | ||
117 | # the model and thus the UI. Or it may be to tell us that the build | ||
118 | # has finished successfully (or not, as the case may be.) | ||
119 | |||
120 | parent = None | ||
121 | pid = 0 | ||
122 | package = None | ||
123 | task = None | ||
124 | |||
125 | # If we have a pid attached to this message/event try and get the | ||
126 | # (package, task) pair for it. If we get that then get the parent iter | ||
127 | # for the message. | ||
128 | if hasattr(event, 'pid'): | ||
129 | pid = event.pid | ||
130 | if hasattr(event, 'process'): | ||
131 | pid = event.process | ||
132 | |||
133 | if pid and pid in self.pids_to_task: | ||
134 | (package, task) = self.pids_to_task[pid] | ||
135 | parent = self.tasks_to_iter[(package, task)] | ||
136 | |||
137 | if(isinstance(event, logging.LogRecord)): | ||
138 | if event.taskpid == 0 or event.levelno > logging.INFO: | ||
139 | self.emit("log", "handle", event) | ||
140 | # FIXME: this is a hack! More info in Yocto #1433 | ||
141 | # http://bugzilla.pokylinux.org/show_bug.cgi?id=1433, temporarily | ||
142 | # mask the error message as it's not informative for the user. | ||
143 | if event.msg.startswith("Execution of event handler 'run_buildstats' failed"): | ||
144 | return | ||
145 | |||
146 | if (event.levelno < logging.INFO or | ||
147 | event.msg.startswith("Running task")): | ||
148 | return # don't add these to the list | ||
149 | |||
150 | if event.levelno >= logging.ERROR: | ||
151 | icon = "dialog-error" | ||
152 | color = HobColors.ERROR | ||
153 | self.emit("log-error") | ||
154 | elif event.levelno >= logging.WARNING: | ||
155 | icon = "dialog-warning" | ||
156 | color = HobColors.WARNING | ||
157 | self.emit("log-warning") | ||
158 | else: | ||
159 | icon = None | ||
160 | color = HobColors.OK | ||
161 | |||
162 | # if we know which package we belong to, we'll append onto its list. | ||
163 | # otherwise, we'll jump to the top of the master list | ||
164 | if self.sequential or not parent: | ||
165 | tree_add = self.model.append | ||
166 | else: | ||
167 | tree_add = self.model.prepend | ||
168 | tree_add(parent, | ||
169 | (None, | ||
170 | package, | ||
171 | task, | ||
172 | event.getMessage(), | ||
173 | icon, | ||
174 | color, | ||
175 | 0)) | ||
176 | |||
177 | # if there are warnings while processing a package | ||
178 | # (parent), mark the task with warning color; | ||
179 | # in case there are errors, the updates will be | ||
180 | # handled on TaskFailed. | ||
181 | if color == HobColors.WARNING and parent: | ||
182 | self.model.set(parent, self.model.COL_COLOR, color) | ||
183 | if task: #then we have a parent (package), and update it's color | ||
184 | self.model.set(self.tasks_to_iter[(package, None)], self.model.COL_COLOR, color) | ||
185 | |||
186 | elif isinstance(event, bb.build.TaskStarted): | ||
187 | (package, task) = (event._package, event._task) | ||
188 | |||
189 | # Save out this PID. | ||
190 | self.pids_to_task[pid] = (package, task) | ||
191 | |||
192 | # Check if we already have this package in our model. If so then | ||
193 | # that can be the parent for the task. Otherwise we create a new | ||
194 | # top level for the package. | ||
195 | if ((package, None) in self.tasks_to_iter): | ||
196 | parent = self.tasks_to_iter[(package, None)] | ||
197 | else: | ||
198 | if self.sequential: | ||
199 | add = self.model.append | ||
200 | else: | ||
201 | add = self.model.prepend | ||
202 | parent = add(None, (None, | ||
203 | package, | ||
204 | None, | ||
205 | "Package: %s" % (package), | ||
206 | None, | ||
207 | HobColors.OK, | ||
208 | 0)) | ||
209 | self.tasks_to_iter[(package, None)] = parent | ||
210 | |||
211 | # Because this parent package now has an active child mark it as | ||
212 | # such. | ||
213 | self.model.set(parent, self.model.COL_ICON, "gtk-execute") | ||
214 | parent_color = self.model.get(parent, self.model.COL_COLOR)[0] | ||
215 | if parent_color != HobColors.ERROR and parent_color != HobColors.WARNING: | ||
216 | self.model.set(parent, self.model.COL_COLOR, HobColors.RUNNING) | ||
217 | |||
218 | # Add an entry in the model for this task | ||
219 | i = self.model.append (parent, (None, | ||
220 | package, | ||
221 | task, | ||
222 | "Task: %s" % (task), | ||
223 | "gtk-execute", | ||
224 | HobColors.RUNNING, | ||
225 | 0)) | ||
226 | |||
227 | # update the parent's active task count | ||
228 | num_active = self.model.get(parent, self.model.COL_NUM_ACTIVE)[0] + 1 | ||
229 | self.model.set(parent, self.model.COL_NUM_ACTIVE, num_active) | ||
230 | |||
231 | # Save out the iter so that we can find it when we have a message | ||
232 | # that we need to attach to a task. | ||
233 | self.tasks_to_iter[(package, task)] = i | ||
234 | |||
235 | elif isinstance(event, bb.build.TaskBase): | ||
236 | self.emit("log", "info", event._message) | ||
237 | current = self.tasks_to_iter[(package, task)] | ||
238 | parent = self.tasks_to_iter[(package, None)] | ||
239 | |||
240 | # remove this task from the parent's active count | ||
241 | num_active = self.model.get(parent, self.model.COL_NUM_ACTIVE)[0] - 1 | ||
242 | self.model.set(parent, self.model.COL_NUM_ACTIVE, num_active) | ||
243 | |||
244 | if isinstance(event, bb.build.TaskFailed): | ||
245 | # Mark the task and parent as failed | ||
246 | icon = "dialog-error" | ||
247 | color = HobColors.ERROR | ||
248 | |||
249 | logfile = event.logfile | ||
250 | if logfile and os.path.exists(logfile): | ||
251 | with open(logfile) as f: | ||
252 | logdata = f.read() | ||
253 | self.model.append(current, ('pastebin', None, None, logdata, 'gtk-error', HobColors.OK, 0)) | ||
254 | |||
255 | for i in (current, parent): | ||
256 | self.model.set(i, self.model.COL_ICON, icon, | ||
257 | self.model.COL_COLOR, color) | ||
258 | else: | ||
259 | # Mark the parent package and the task as inactive, | ||
260 | # but make sure to preserve error, warnings and active | ||
261 | # states | ||
262 | parent_color = self.model.get(parent, self.model.COL_COLOR)[0] | ||
263 | task_color = self.model.get(current, self.model.COL_COLOR)[0] | ||
264 | |||
265 | # Mark the task as inactive | ||
266 | self.model.set(current, self.model.COL_ICON, None) | ||
267 | if task_color != HobColors.ERROR: | ||
268 | if task_color == HobColors.WARNING: | ||
269 | self.model.set(current, self.model.COL_ICON, 'dialog-warning') | ||
270 | else: | ||
271 | self.model.set(current, self.model.COL_COLOR, HobColors.OK) | ||
272 | |||
273 | # Mark the parent as inactive | ||
274 | if parent_color != HobColors.ERROR: | ||
275 | if parent_color == HobColors.WARNING: | ||
276 | self.model.set(parent, self.model.COL_ICON, "dialog-warning") | ||
277 | else: | ||
278 | self.model.set(parent, self.model.COL_ICON, None) | ||
279 | if num_active == 0: | ||
280 | self.model.set(parent, self.model.COL_COLOR, HobColors.OK) | ||
281 | |||
282 | # Clear the iters and the pids since when the task goes away the | ||
283 | # pid will no longer be used for messages | ||
284 | del self.tasks_to_iter[(package, task)] | ||
285 | del self.pids_to_task[pid] | ||
286 | |||
287 | elif isinstance(event, bb.event.BuildStarted): | ||
288 | |||
289 | self.emit("build-started") | ||
290 | self.model.prepend(None, (None, | ||
291 | None, | ||
292 | None, | ||
293 | "Build Started (%s)" % time.strftime('%m/%d/%Y %H:%M:%S'), | ||
294 | None, | ||
295 | HobColors.OK, | ||
296 | 0)) | ||
297 | if pbar: | ||
298 | pbar.update(0, self.progress_total) | ||
299 | pbar.set_title(bb.event.getName(event)) | ||
300 | |||
301 | elif isinstance(event, bb.event.BuildCompleted): | ||
302 | failures = int (event._failures) | ||
303 | self.model.prepend(None, (None, | ||
304 | None, | ||
305 | None, | ||
306 | "Build Completed (%s)" % time.strftime('%m/%d/%Y %H:%M:%S'), | ||
307 | None, | ||
308 | HobColors.OK, | ||
309 | 0)) | ||
310 | |||
311 | # Emit the appropriate signal depending on the number of failures | ||
312 | if self.buildaborted: | ||
313 | self.emit ("build-aborted") | ||
314 | self.buildaborted = False | ||
315 | elif (failures >= 1): | ||
316 | self.emit ("build-failed") | ||
317 | else: | ||
318 | self.emit ("build-succeeded") | ||
319 | # Emit a generic "build-complete" signal for things wishing to | ||
320 | # handle when the build is finished | ||
321 | self.emit("build-complete") | ||
322 | # reset the all cell's icon indicator | ||
323 | self.model.close_task_refresh() | ||
324 | if pbar: | ||
325 | pbar.set_text(event.msg) | ||
326 | |||
327 | elif isinstance(event, bb.event.DiskFull): | ||
328 | self.buildaborted = True | ||
329 | self.emit("disk-full") | ||
330 | |||
331 | elif isinstance(event, bb.command.CommandFailed): | ||
332 | self.emit("log", "error", "Command execution failed: %s" % (event.error)) | ||
333 | if event.error.startswith("Exited with"): | ||
334 | # If the command fails with an exit code we're done, emit the | ||
335 | # generic signal for the UI to notify the user | ||
336 | self.emit("build-complete") | ||
337 | # reset the all cell's icon indicator | ||
338 | self.model.close_task_refresh() | ||
339 | |||
340 | elif isinstance(event, bb.event.CacheLoadStarted) and pbar: | ||
341 | pbar.set_title("Loading cache") | ||
342 | self.progress_total = event.total | ||
343 | pbar.update(0, self.progress_total) | ||
344 | elif isinstance(event, bb.event.CacheLoadProgress) and pbar: | ||
345 | pbar.update(event.current, self.progress_total) | ||
346 | elif isinstance(event, bb.event.CacheLoadCompleted) and pbar: | ||
347 | pbar.update(self.progress_total, self.progress_total) | ||
348 | pbar.hide() | ||
349 | elif isinstance(event, bb.event.ParseStarted) and pbar: | ||
350 | if event.total == 0: | ||
351 | return | ||
352 | pbar.set_title("Processing recipes") | ||
353 | self.progress_total = event.total | ||
354 | pbar.update(0, self.progress_total) | ||
355 | elif isinstance(event, bb.event.ParseProgress) and pbar: | ||
356 | pbar.update(event.current, self.progress_total) | ||
357 | elif isinstance(event, bb.event.ParseCompleted) and pbar: | ||
358 | pbar.hide() | ||
359 | #using runqueue events as many as possible to update the progress bar | ||
360 | elif isinstance(event, bb.runqueue.runQueueTaskFailed): | ||
361 | self.emit("log", "error", "Task %s (%s) failed with exit code '%s'" % (event.taskid, event.taskstring, event.exitcode)) | ||
362 | elif isinstance(event, bb.runqueue.sceneQueueTaskFailed): | ||
363 | self.emit("log", "warn", "Setscene task %s (%s) failed with exit code '%s' - real task will be run instead" \ | ||
364 | % (event.taskid, event.taskstring, event.exitcode)) | ||
365 | elif isinstance(event, (bb.runqueue.runQueueTaskStarted, bb.runqueue.sceneQueueTaskStarted)): | ||
366 | if isinstance(event, bb.runqueue.sceneQueueTaskStarted): | ||
367 | self.emit("log", "info", "Running setscene task %d of %d (%s)" % \ | ||
368 | (event.stats.completed + event.stats.active + event.stats.failed + 1, | ||
369 | event.stats.total, event.taskstring)) | ||
370 | else: | ||
371 | if event.noexec: | ||
372 | tasktype = 'noexec task' | ||
373 | else: | ||
374 | tasktype = 'task' | ||
375 | self.emit("log", "info", "Running %s %s of %s (ID: %s, %s)" % \ | ||
376 | (tasktype, event.stats.completed + event.stats.active + event.stats.failed + 1, | ||
377 | event.stats.total, event.taskid, event.taskstring)) | ||
378 | message = {} | ||
379 | message["eventname"] = bb.event.getName(event) | ||
380 | num_of_completed = event.stats.completed + event.stats.failed | ||
381 | message["current"] = num_of_completed | ||
382 | message["total"] = event.stats.total | ||
383 | message["title"] = "" | ||
384 | message["task"] = event.taskstring | ||
385 | self.emit("task-started", message) | ||
386 | elif isinstance(event, bb.event.MultipleProviders): | ||
387 | self.emit("log", "info", "multiple providers are available for %s%s (%s)" \ | ||
388 | % (event._is_runtime and "runtime " or "", event._item, ", ".join(event._candidates))) | ||
389 | self.emit("log", "info", "consider defining a PREFERRED_PROVIDER entry to match %s" % (event._item)) | ||
390 | elif isinstance(event, bb.event.NoProvider): | ||
391 | msg = "" | ||
392 | if event._runtime: | ||
393 | r = "R" | ||
394 | else: | ||
395 | r = "" | ||
396 | |||
397 | extra = '' | ||
398 | if not event._reasons: | ||
399 | if event._close_matches: | ||
400 | extra = ". Close matches:\n %s" % '\n '.join(event._close_matches) | ||
401 | |||
402 | if event._dependees: | ||
403 | msg = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)%s\n" % (r, event._item, ", ".join(event._dependees), r, extra) | ||
404 | else: | ||
405 | msg = "Nothing %sPROVIDES '%s'%s\n" % (r, event._item, extra) | ||
406 | if event._reasons: | ||
407 | for reason in event._reasons: | ||
408 | msg += ("%s\n" % reason) | ||
409 | self.emit("no-provider", msg) | ||
410 | self.emit("log", "error", msg) | ||
411 | elif isinstance(event, bb.event.LogExecTTY): | ||
412 | icon = "dialog-warning" | ||
413 | color = HobColors.WARNING | ||
414 | if self.sequential or not parent: | ||
415 | tree_add = self.model.append | ||
416 | else: | ||
417 | tree_add = self.model.prepend | ||
418 | tree_add(parent, | ||
419 | (None, | ||
420 | package, | ||
421 | task, | ||
422 | event.msg, | ||
423 | icon, | ||
424 | color, | ||
425 | 0)) | ||
426 | else: | ||
427 | if not isinstance(event, (bb.event.BuildBase, | ||
428 | bb.event.StampUpdate, | ||
429 | bb.event.ConfigParsed, | ||
430 | bb.event.RecipeParsed, | ||
431 | bb.event.RecipePreFinalise, | ||
432 | bb.runqueue.runQueueEvent, | ||
433 | bb.runqueue.runQueueExitWait, | ||
434 | bb.event.OperationStarted, | ||
435 | bb.event.OperationCompleted, | ||
436 | bb.event.OperationProgress)): | ||
437 | self.emit("log", "error", "Unknown event: %s" % (event.error if hasattr(event, 'error') else 'error')) | ||
438 | |||
439 | return | ||
440 | |||
441 | |||
442 | def do_pastebin(text): | ||
443 | url = 'http://pastebin.com/api_public.php' | ||
444 | params = {'paste_code': text, 'paste_format': 'text'} | ||
445 | |||
446 | req = urllib.request.Request(url, urllib.parse.urlencode(params)) | ||
447 | response = urllib.request.urlopen(req) | ||
448 | paste_url = response.read() | ||
449 | |||
450 | return paste_url | ||
451 | |||
452 | |||
453 | class RunningBuildTreeView (gtk.TreeView): | ||
454 | __gsignals__ = { | ||
455 | "button_press_event" : "override" | ||
456 | } | ||
457 | def __init__ (self, readonly=False, hob=False): | ||
458 | gtk.TreeView.__init__ (self) | ||
459 | self.readonly = readonly | ||
460 | |||
461 | # The icon that indicates whether we're building or failed. | ||
462 | # add 'hob' flag because there has not only hob to share this code | ||
463 | if hob: | ||
464 | renderer = HobCellRendererPixbuf () | ||
465 | else: | ||
466 | renderer = gtk.CellRendererPixbuf() | ||
467 | col = gtk.TreeViewColumn ("Status", renderer) | ||
468 | col.add_attribute (renderer, "icon-name", 4) | ||
469 | self.append_column (col) | ||
470 | |||
471 | # The message of the build. | ||
472 | # add 'hob' flag because there has not only hob to share this code | ||
473 | if hob: | ||
474 | self.message_renderer = HobWarpCellRendererText (col_number=1) | ||
475 | else: | ||
476 | self.message_renderer = gtk.CellRendererText () | ||
477 | self.message_column = gtk.TreeViewColumn ("Message", self.message_renderer, text=3) | ||
478 | self.message_column.add_attribute(self.message_renderer, 'background', 5) | ||
479 | self.message_renderer.set_property('editable', (not self.readonly)) | ||
480 | self.append_column (self.message_column) | ||
481 | |||
482 | def do_button_press_event(self, event): | ||
483 | gtk.TreeView.do_button_press_event(self, event) | ||
484 | |||
485 | if event.button == 3: | ||
486 | selection = super(RunningBuildTreeView, self).get_selection() | ||
487 | (model, it) = selection.get_selected() | ||
488 | if it is not None: | ||
489 | can_paste = model.get(it, model.COL_LOG)[0] | ||
490 | if can_paste == 'pastebin': | ||
491 | # build a simple menu with a pastebin option | ||
492 | menu = gtk.Menu() | ||
493 | menuitem = gtk.MenuItem("Copy") | ||
494 | menu.append(menuitem) | ||
495 | menuitem.connect("activate", self.clipboard_handler, (model, it)) | ||
496 | menuitem.show() | ||
497 | menuitem = gtk.MenuItem("Send log to pastebin") | ||
498 | menu.append(menuitem) | ||
499 | menuitem.connect("activate", self.pastebin_handler, (model, it)) | ||
500 | menuitem.show() | ||
501 | menu.show() | ||
502 | menu.popup(None, None, None, event.button, event.time) | ||
503 | |||
504 | def _add_to_clipboard(self, clipping): | ||
505 | """ | ||
506 | Add the contents of clipping to the system clipboard. | ||
507 | """ | ||
508 | clipboard = gtk.clipboard_get() | ||
509 | clipboard.set_text(clipping) | ||
510 | clipboard.store() | ||
511 | |||
512 | def pastebin_handler(self, widget, data): | ||
513 | """ | ||
514 | Send the log data to pastebin, then add the new paste url to the | ||
515 | clipboard. | ||
516 | """ | ||
517 | (model, it) = data | ||
518 | paste_url = do_pastebin(model.get(it, model.COL_MESSAGE)[0]) | ||
519 | |||
520 | # @todo Provide visual feedback to the user that it is done and that | ||
521 | # it worked. | ||
522 | print(paste_url) | ||
523 | |||
524 | self._add_to_clipboard(paste_url) | ||
525 | |||
526 | def clipboard_handler(self, widget, data): | ||
527 | """ | ||
528 | """ | ||
529 | (model, it) = data | ||
530 | message = model.get(it, model.COL_MESSAGE)[0] | ||
531 | |||
532 | self._add_to_clipboard(message) | ||
533 | |||
534 | class BuildFailureTreeView(gtk.TreeView): | ||
535 | |||
536 | def __init__ (self): | ||
537 | gtk.TreeView.__init__(self) | ||
538 | self.set_rules_hint(False) | ||
539 | self.set_headers_visible(False) | ||
540 | self.get_selection().set_mode(gtk.SELECTION_SINGLE) | ||
541 | |||
542 | # The icon that indicates whether we're building or failed. | ||
543 | renderer = HobCellRendererPixbuf () | ||
544 | col = gtk.TreeViewColumn ("Status", renderer) | ||
545 | col.add_attribute (renderer, "icon-name", RunningBuildModel.COL_ICON) | ||
546 | self.append_column (col) | ||
547 | |||
548 | # The message of the build. | ||
549 | self.message_renderer = HobWarpCellRendererText (col_number=1) | ||
550 | self.message_column = gtk.TreeViewColumn ("Message", self.message_renderer, text=RunningBuildModel.COL_MESSAGE, background=RunningBuildModel.COL_COLOR) | ||
551 | self.append_column (self.message_column) | ||
diff --git a/bitbake/lib/bb/ui/crumbs/utils.py b/bitbake/lib/bb/ui/crumbs/utils.py deleted file mode 100644 index 939864fa6f..0000000000 --- a/bitbake/lib/bb/ui/crumbs/utils.py +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | # | ||
2 | # BitBake UI Utils | ||
3 | # | ||
4 | # Copyright (C) 2012 Intel Corporation | ||
5 | # | ||
6 | # This program is free software; you can redistribute it and/or modify | ||
7 | # it under the terms of the GNU General Public License version 2 as | ||
8 | # published by the Free Software Foundation. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License along | ||
16 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | |||
19 | # This utility method looks for xterm or vte and return the | ||
20 | # frist to exist, currently we are keeping this simple, but | ||
21 | # we will likely move the oe.terminal implementation into | ||
22 | # bitbake which will allow more flexibility. | ||
23 | |||
24 | import os | ||
25 | import bb | ||
26 | |||
27 | def which_terminal(): | ||
28 | term = bb.utils.which(os.environ["PATH"], "xterm") | ||
29 | if term: | ||
30 | return term + " -e " | ||
31 | term = bb.utils.which(os.environ["PATH"], "vte") | ||
32 | if term: | ||
33 | return term + " -c " | ||
34 | return None | ||
diff --git a/bitbake/lib/bb/ui/goggle.py b/bitbake/lib/bb/ui/goggle.py deleted file mode 100644 index f5f8f1668f..0000000000 --- a/bitbake/lib/bb/ui/goggle.py +++ /dev/null | |||
@@ -1,126 +0,0 @@ | |||
1 | # | ||
2 | # BitBake Graphical GTK User Interface | ||
3 | # | ||
4 | # Copyright (C) 2008 Intel Corporation | ||
5 | # | ||
6 | # Authored by Rob Bradford <rob@linux.intel.com> | ||
7 | # | ||
8 | # This program is free software; you can redistribute it and/or modify | ||
9 | # it under the terms of the GNU General Public License version 2 as | ||
10 | # published by the Free Software Foundation. | ||
11 | # | ||
12 | # This program is distributed in the hope that it will be useful, | ||
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | # GNU General Public License for more details. | ||
16 | # | ||
17 | # You should have received a copy of the GNU General Public License along | ||
18 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
20 | |||
21 | from gi import pygtkcompat | ||
22 | |||
23 | pygtkcompat.enable() | ||
24 | pygtkcompat.enable_gtk(version='3.0') | ||
25 | |||
26 | import gobject | ||
27 | import gtk | ||
28 | import xmlrpc.client | ||
29 | from bb.ui.crumbs.runningbuild import RunningBuildTreeView, RunningBuild | ||
30 | from bb.ui.crumbs.progress import ProgressBar | ||
31 | |||
32 | import queue | ||
33 | |||
34 | |||
35 | def event_handle_idle_func (eventHandler, build, pbar): | ||
36 | |||
37 | # Consume as many messages as we can in the time available to us | ||
38 | event = eventHandler.getEvent() | ||
39 | while event: | ||
40 | build.handle_event (event, pbar) | ||
41 | event = eventHandler.getEvent() | ||
42 | |||
43 | return True | ||
44 | |||
45 | def scroll_tv_cb (model, path, iter, view): | ||
46 | view.scroll_to_cell (path) | ||
47 | |||
48 | |||
49 | # @todo hook these into the GUI so the user has feedback... | ||
50 | def running_build_failed_cb (running_build): | ||
51 | pass | ||
52 | |||
53 | |||
54 | def running_build_succeeded_cb (running_build): | ||
55 | pass | ||
56 | |||
57 | |||
58 | class MainWindow (gtk.Window): | ||
59 | def __init__ (self): | ||
60 | gtk.Window.__init__ (self, gtk.WINDOW_TOPLEVEL) | ||
61 | |||
62 | # Setup tree view and the scrolled window | ||
63 | scrolled_window = gtk.ScrolledWindow () | ||
64 | self.add (scrolled_window) | ||
65 | self.cur_build_tv = RunningBuildTreeView() | ||
66 | self.connect("delete-event", gtk.main_quit) | ||
67 | self.set_default_size(640, 480) | ||
68 | scrolled_window.add (self.cur_build_tv) | ||
69 | |||
70 | |||
71 | def main (server, eventHandler, params): | ||
72 | gobject.threads_init() | ||
73 | gtk.gdk.threads_init() | ||
74 | |||
75 | window = MainWindow () | ||
76 | window.show_all () | ||
77 | pbar = ProgressBar(window) | ||
78 | pbar.connect("delete-event", gtk.main_quit) | ||
79 | |||
80 | # Create the object for the current build | ||
81 | running_build = RunningBuild () | ||
82 | window.cur_build_tv.set_model (running_build.model) | ||
83 | running_build.model.connect("row-inserted", scroll_tv_cb, window.cur_build_tv) | ||
84 | running_build.connect ("build-succeeded", running_build_succeeded_cb) | ||
85 | running_build.connect ("build-failed", running_build_failed_cb) | ||
86 | |||
87 | try: | ||
88 | params.updateFromServer(server) | ||
89 | cmdline = params.parseActions() | ||
90 | if not cmdline: | ||
91 | print("Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.") | ||
92 | return 1 | ||
93 | if 'msg' in cmdline and cmdline['msg']: | ||
94 | logger.error(cmdline['msg']) | ||
95 | return 1 | ||
96 | cmdline = cmdline['action'] | ||
97 | ret, error = server.runCommand(cmdline) | ||
98 | if error: | ||
99 | print("Error running command '%s': %s" % (cmdline, error)) | ||
100 | return 1 | ||
101 | elif ret != True: | ||
102 | print("Error running command '%s': returned %s" % (cmdline, ret)) | ||
103 | return 1 | ||
104 | except xmlrpcclient.Fault as x: | ||
105 | print("XMLRPC Fault getting commandline:\n %s" % x) | ||
106 | return 1 | ||
107 | |||
108 | # Use a timeout function for probing the event queue to find out if we | ||
109 | # have a message waiting for us. | ||
110 | gobject.timeout_add (100, | ||
111 | event_handle_idle_func, | ||
112 | eventHandler, | ||
113 | running_build, | ||
114 | pbar) | ||
115 | |||
116 | try: | ||
117 | gtk.main() | ||
118 | except EnvironmentError as ioerror: | ||
119 | # ignore interrupted io | ||
120 | if ioerror.args[0] == 4: | ||
121 | pass | ||
122 | except KeyboardInterrupt: | ||
123 | pass | ||
124 | finally: | ||
125 | server.runCommand(["stateForceShutdown"]) | ||
126 | |||