Added "0desktop --manage".
[zeroinstall/zeroinstall-mseaborn.git] / zeroinstall / gtkui / addbox.py
blobac32afea28199ded94d189a0c58e27d8d4b3385a
1 """A GTK dialog which lets the user add a new application to their desktop."""
2 # Copyright (C) 2008, Thomas Leonard
3 # See the README file for details, or visit http://0install.net.
5 import os, sys
6 import gtk, gobject
7 import gtk.glade
9 from zeroinstall import SafeException
10 from zeroinstall.injector.namespaces import XMLNS_IFACE
11 from zeroinstall.injector.iface_cache import iface_cache
13 _URI_LIST = 0
14 _UTF_16 = 1
16 _RESPONSE_PREV = 0
17 _RESPONSE_NEXT = 1
19 class AddBox:
20 """A dialog box which prompts the user to choose the program to be added."""
21 def __init__(self, interface_uri = None):
22 gladefile = os.path.join(os.path.dirname(__file__), 'desktop.glade')
24 widgets = gtk.glade.XML(gladefile, 'main')
25 self.window = widgets.get_widget('main')
26 self.set_keep_above(True)
28 def set_uri_ok(uri):
29 text = uri.get_text()
30 self.window.set_response_sensitive(_RESPONSE_NEXT, bool(text))
32 uri = widgets.get_widget('interface_uri')
33 about = widgets.get_widget('about')
34 icon_widget = widgets.get_widget('icon')
35 category = widgets.get_widget('category')
36 dialog_next = widgets.get_widget('dialog_next')
37 dialog_ok = widgets.get_widget('dialog_ok')
39 if interface_uri:
40 uri.set_text(interface_uri)
42 uri.connect('changed', set_uri_ok)
43 set_uri_ok(uri)
45 category.set_active(11)
47 def uri_dropped(eb, drag_context, x, y, selection_data, info, timestamp):
48 if info == _UTF_16:
49 import codecs
50 data = codecs.getdecoder('utf16')(selection_data.data)[0]
51 data = data.split('\n', 1)[0].strip()
52 else:
53 data = selection_data.data.split('\n', 1)[0].strip()
54 uri.set_text(data)
55 drag_context.finish(True, False, timestamp)
56 self.window.response(_RESPONSE_NEXT)
57 return True
58 self.window.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_DROP | gtk.DEST_DEFAULT_HIGHLIGHT,
59 [('text/uri-list', 0, _URI_LIST),
60 ('text/x-moz-url', 0, _UTF_16)],
61 gtk.gdk.ACTION_COPY)
62 self.window.connect('drag-data-received', uri_dropped)
64 nb = widgets.get_widget('notebook1')
66 def update_details_page():
67 iface = iface_cache.get_interface(uri.get_text())
68 about.set_text('%s - %s' % (iface.get_name(), iface.summary))
69 icon_path = iface_cache.get_icon_path(iface)
70 from zeroinstall.gtkui import icon
71 icon_pixbuf = icon.load_icon(icon_path)
72 if icon_pixbuf:
73 icon_widget.set_from_pixbuf(icon_pixbuf)
75 feed_category = None
76 for meta in iface.get_metadata(XMLNS_IFACE, 'category'):
77 feed_category = meta.content
78 break
79 if feed_category:
80 i = 0
81 for row in category.get_model():
82 if row[0].lower() == feed_category.lower():
83 category.set_active(i)
84 break
85 i += 1
86 self.window.set_response_sensitive(_RESPONSE_PREV, True)
88 def finish():
89 import xdgutils
90 iface = iface_cache.get_interface(uri.get_text())
92 try:
93 icon_path = iface_cache.get_icon_path(iface)
94 xdgutils.add_to_menu(iface, icon_path, category.get_active_text())
95 except SafeException, ex:
96 box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, str(ex))
97 box.run()
98 box.destroy()
99 else:
100 self.window.destroy()
102 def response(box, resp):
103 if resp == _RESPONSE_NEXT:
104 iface = uri.get_text()
105 self.window.set_sensitive(False)
106 self.set_keep_above(False)
107 import popen2
108 child = popen2.Popen4(['0launch',
109 '--gui', '--download-only',
110 '--', iface])
111 child.tochild.close()
112 errors = ['']
113 def output_ready(src, cond):
114 got = os.read(src.fileno(), 100)
115 if got:
116 errors[0] += got
117 else:
118 status = child.wait()
119 self.window.set_sensitive(True)
120 self.set_keep_above(True)
121 if status == 0:
122 update_details_page()
123 nb.next_page()
124 dialog_next.set_property('visible', False)
125 dialog_ok.set_property('visible', True)
126 dialog_ok.grab_focus()
127 else:
128 box = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
129 'Failed to run 0launch.\n' + errors[0])
130 box.run()
131 box.destroy()
132 return False
133 return True
134 gobject.io_add_watch(child.fromchild,
135 gobject.IO_IN | gobject.IO_HUP,
136 output_ready)
137 elif resp == gtk.RESPONSE_OK:
138 finish()
139 elif resp == _RESPONSE_PREV:
140 dialog_next.set_property('visible', True)
141 dialog_ok.set_property('visible', False)
142 dialog_next.grab_focus()
143 nb.prev_page()
144 self.window.set_response_sensitive(_RESPONSE_PREV, False)
145 else:
146 box.destroy()
147 self.window.connect('response', response)
149 if len(sys.argv) > 1:
150 self.window.response(_RESPONSE_NEXT)
152 def set_keep_above(self, above):
153 if hasattr(self.window, 'set_keep_above'):
154 # This isn't very nice, but GNOME defaults to
155 # click-to-raise and in that mode drag-and-drop
156 # is useless without this...
157 self.window.set_keep_above(above)