diff options
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 | |||
