Package zeroinstall :: Package gtkui :: Module addbox
[frames] | no frames]

Source Code for Module zeroinstall.gtkui.addbox

  1  """A GTK dialog which lets the user add a new application to their desktop.""" 
  2   
  3  # Copyright (C) 2009, Thomas Leonard 
  4  # See the README file for details, or visit http://0install.net. 
  5   
  6  from zeroinstall import _, gobject 
  7  import os, sys 
  8  import gtk 
  9   
 10  from zeroinstall import SafeException 
 11  from zeroinstall.injector import model 
 12  from zeroinstall.injector.namespaces import XMLNS_IFACE 
 13  from zeroinstall.injector.iface_cache import iface_cache 
 14   
 15  _URI_LIST = 0 
 16  _UTF_16 = 1 
 17   
 18  _RESPONSE_PREV = 0 
 19  _RESPONSE_NEXT = 1 
 20   
21 -def N_(message): return message
22 23 categories = [ 24 N_('AudioVideo'), 25 N_('Audio'), 26 N_('Video'), 27 N_('Development'), 28 N_('Education'), 29 N_('Game'), 30 N_('Graphics'), 31 N_('Network'), 32 N_('Office'), 33 N_('Settings'), 34 N_('System'), 35 N_('Utility'), 36 ] 37
38 -class AddBox(object):
39 """A dialog box which prompts the user to choose the program to be added."""
40 - def __init__(self, interface_uri = None):
41 builderfile = os.path.join(os.path.dirname(__file__), 'desktop.ui') 42 43 builder = gtk.Builder() 44 builder.set_translation_domain('zero-install') 45 builder.add_from_file(builderfile) 46 self.window = builder.get_object('main') 47 self.set_keep_above(True) 48 49 def set_uri_ok(uri): 50 text = uri.get_text() 51 self.window.set_response_sensitive(_RESPONSE_NEXT, bool(text))
52 53 uri = builder.get_object('interface_uri') 54 about = builder.get_object('about') 55 icon_widget = builder.get_object('icon') 56 category = builder.get_object('category') 57 dialog_next = builder.get_object('dialog_next') 58 dialog_ok = builder.get_object('dialog_ok') 59 60 if interface_uri: 61 uri.set_text(interface_uri) 62 63 uri.connect('changed', set_uri_ok) 64 set_uri_ok(uri) 65 66 for c in categories: 67 category.append_text(_(c)) 68 category.set_active(11) 69 70 def uri_dropped(eb, drag_context, x, y, selection_data, info, timestamp): 71 uris = selection_data.get_uris() 72 if uris: 73 assert len(uris) == 1, uris 74 data, = uris 75 else: 76 if info == _UTF_16: 77 import codecs 78 data = codecs.getdecoder('utf16')(selection_data.get_data())[0] 79 data = data.split('\n', 1)[0].strip() 80 else: 81 data = selection_data.get_text().split('\n', 1)[0].strip() 82 if self._sanity_check(data): 83 uri.set_text(data) 84 drag_context.finish(True, False, timestamp) 85 self.window.response(_RESPONSE_NEXT) 86 return True
87 if sys.version_info[0] < 3: 88 def TargetEntry(*args): return args 89 else: 90 TargetEntry = gtk.TargetEntry.new 91 self.window.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_DROP | gtk.DEST_DEFAULT_HIGHLIGHT, 92 [TargetEntry('text/uri-list', 0, _URI_LIST), 93 TargetEntry('text/x-moz-url', 0, _UTF_16)], 94 gtk.gdk.ACTION_COPY) 95 self.window.drag_dest_add_uri_targets() # Needed for GTK 3 96 self.window.connect('drag-data-received', uri_dropped) 97 98 nb = builder.get_object('notebook1') 99 100 def update_details_page(): 101 iface = iface_cache.get_interface(model.canonical_iface_uri(uri.get_text())) 102 about.set_text('%s - %s' % (iface.get_name(), iface.summary)) 103 icon_path = iface_cache.get_icon_path(iface) 104 from zeroinstall.gtkui import icon 105 icon_pixbuf = icon.load_icon(icon_path) 106 if icon_pixbuf: 107 icon_widget.set_from_pixbuf(icon_pixbuf) 108 109 feed_category = None 110 for meta in iface.get_metadata(XMLNS_IFACE, 'category'): 111 feed_category = meta.content 112 break 113 if feed_category: 114 i = 0 115 for row in categories: 116 if row.lower() == feed_category.lower(): 117 category.set_active(i) 118 break 119 i += 1 120 self.window.set_response_sensitive(_RESPONSE_PREV, True) 121 122 def finish(): 123 from . import xdgutils 124 iface = iface_cache.get_interface(model.canonical_iface_uri(uri.get_text())) 125 126 try: 127 icon_path = iface_cache.get_icon_path(iface) 128 xdgutils.add_to_menu(iface, icon_path, categories[category.get_active()]) 129 except SafeException as ex: 130 box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, str(ex)) 131 box.run() 132 box.destroy() 133 else: 134 self.window.destroy() 135 136 def response(box, resp): 137 if resp == _RESPONSE_NEXT: 138 iface = uri.get_text() 139 if not self._sanity_check(iface): 140 return 141 self.window.set_sensitive(False) 142 self.set_keep_above(False) 143 import subprocess 144 child = subprocess.Popen(['0launch', 145 '--gui', '--download-only', 146 '--', iface], 147 stdout = subprocess.PIPE, 148 stderr = subprocess.STDOUT) 149 errors = [b''] 150 def output_ready(src, cond): 151 got = os.read(src.fileno(), 100) 152 if got: 153 errors[0] += got 154 else: 155 status = child.wait() 156 self.window.set_sensitive(True) 157 self.set_keep_above(True) 158 if status == 0: 159 update_details_page() 160 nb.next_page() 161 dialog_next.set_property('visible', False) 162 dialog_ok.set_property('visible', True) 163 dialog_ok.grab_focus() 164 else: 165 box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, 166 _('Failed to run 0launch.\n') + errors[0].decode('utf-8')) 167 box.run() 168 box.destroy() 169 return False 170 return True 171 gobject.io_add_watch(child.stdout, 172 gobject.IO_IN | gobject.IO_HUP, 173 output_ready) 174 elif resp == gtk.RESPONSE_OK: 175 finish() 176 elif resp == _RESPONSE_PREV: 177 dialog_next.set_property('visible', True) 178 dialog_ok.set_property('visible', False) 179 dialog_next.grab_focus() 180 nb.prev_page() 181 self.window.set_response_sensitive(_RESPONSE_PREV, False) 182 else: 183 box.destroy() 184 self.window.connect('response', response) 185 186 if interface_uri: 187 self.window.response(_RESPONSE_NEXT) 188
189 - def set_keep_above(self, above):
190 if hasattr(self.window, 'set_keep_above'): 191 # This isn't very nice, but GNOME defaults to 192 # click-to-raise and in that mode drag-and-drop 193 # is useless without this... 194 self.window.set_keep_above(above)
195
196 - def _sanity_check(self, uri):
197 if uri.endswith('.tar.bz2') or \ 198 uri.endswith('.tar.gz') or \ 199 uri.endswith('.exe') or \ 200 uri.endswith('.rpm') or \ 201 uri.endswith('.deb') or \ 202 uri.endswith('.tgz'): 203 box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, 204 _("This URI (%s) looks like an archive, not a Zero Install feed. Make sure you're using the feed link!") % uri) 205 box.run() 206 box.destroy() 207 return False 208 return True
209