Holding the pointer over an interface in the main window shows a tooltip
[zeroinstall.git] / gui.py
blobe8f3aaec4d38de1a5ef8115641d1e2db085319c5
1 import gtk, os, gobject, sys
3 from zeroinstall.injector.policy import Policy
4 from zeroinstall.injector import download
5 from zeroinstall.injector.model import SafeException
6 from zeroinstall.injector.reader import InvalidInterface
7 import dialog
8 from checking import CheckingBox
10 version = '0.8'
12 # Singleton Policy
13 policy = None
15 class GUIPolicy(Policy):
16 window = None
17 pulse = None
18 monitored_downloads = None
19 checking = None # GtkDialog ("Checking for updates...")
20 original_implementation = None
22 def __init__(self, interface, prog_args, download_only, refresh):
23 Policy.__init__(self, interface)
24 global policy
25 assert policy is None
26 policy = self
27 self.monitored_downloads = []
29 import mainwindow
30 self.window = mainwindow.MainWindow(prog_args, download_only)
31 root = policy.get_interface(policy.root)
32 self.window.browser.set_root(root)
34 if refresh:
35 if root.name is not None:
36 self.checking = CheckingBox(root)
37 def checking_destroyed(c):
38 show_details = self.checking.show_details
39 self.checking = None
40 if show_details or self.ready is False or self.versions_changed():
41 self.window.show()
42 else:
43 import download_box
44 download_box.download_with_gui(self.window, prog_args,
45 run_afterwards = not download_only)
46 self.checking.connect('destroy', checking_destroyed)
48 self.refresh_all(force = False)
50 def monitor_download(self, dl):
51 self.monitored_downloads.append(dl)
53 error_stream = dl.start()
54 def error_ready(src, cond):
55 got = os.read(src.fileno(), 100)
56 if not got:
57 error_stream.close()
58 self.monitored_downloads.remove(dl)
59 if len(self.monitored_downloads) == 0:
60 gobject.source_remove(self.pulse)
61 self.window.progress.hide()
62 self.pulse = None
63 try:
64 data = dl.error_stream_closed()
65 self.check_signed_data(dl, data)
66 except download.DownloadError, ex:
67 dialog.alert(self.window,
68 "Error downloading interface '%s':\n\n%s" %
69 (dl.interface.uri, ex))
70 except InvalidInterface, ex:
71 dialog.alert(self.window,
72 "Syntax error in downloaded interface '%s':\n\n%s" %
73 (dl.interface.uri, ex))
74 except SafeException, ex:
75 dialog.alert(self.window,
76 "Error updating interface '%s':\n\n%s" %
77 (dl.interface.uri, ex))
78 if len(self.monitored_downloads) == 0 and self.checking:
79 self.checking.updates_done(self.versions_changed())
80 return False
81 dl.error_stream_data(got)
82 return True
84 gobject.io_add_watch(error_stream,
85 gobject.IO_IN | gobject.IO_HUP,
86 error_ready)
88 if self.pulse is None:
89 def pulse():
90 if self.checking:
91 self.checking.progress.pulse()
92 else:
93 self.window.progress.pulse()
94 return True
95 self.pulse = gobject.timeout_add(50, pulse)
96 self.window.progress.show()
98 def recalculate(self):
99 Policy.recalculate(self)
100 try:
101 self.ready
102 except:
103 self.ready = True
104 print >>sys.stderr, "Your version of the injector is very old. " \
105 "Try upgrading (http://0install.net/injector.html)"
106 else:
107 self.window.set_response_sensitive(gtk.RESPONSE_OK, self.ready)
109 def confirm_trust_keys(self, interface, sigs, iface_xml):
110 import trust_box
111 trust_box.confirm_trust(interface, sigs, iface_xml)
113 def main(self):
114 if self.checking:
115 self.checking.show()
116 else:
117 self.window.show()
118 gtk.main()
120 def get_best_source(self, impl):
121 """Return the best download source for this implementation."""
122 return impl.download_sources[0]
124 # XXX: Remove this. Moved to Policy.
125 def refresh_all(self, force = True):
126 for x in self.walk_interfaces():
127 self.begin_iface_download(x, force)
129 def abort_all_downloads(self):
130 for x in self.monitored_downloads[:]:
131 x.abort()
133 def set_original_implementations(self):
134 assert self.original_implementation is None
135 self.original_implementation = policy.implementation.copy()
137 def versions_changed(self):
138 """Return whether we have now chosen any different implementations.
139 If so, we want to show the dialog to the user to confirm the new ones."""
140 assert self.ready
141 if not self.original_implementation:
142 return True # Shouldn't happen?
143 if len(self.original_implementation) != len(self.implementation):
144 return True
145 for iface in self.original_implementation:
146 old = self.original_implementation[iface]
147 if old is None:
148 return True
149 new = self.implementation.get(iface, None)
150 if new is None:
151 return True
152 if old.id != new.id:
153 return True
154 return False
156 def pretty_size(size):
157 if size is None:
158 return '?'
159 if size < 2048:
160 return '%d bytes' % size
161 size = float(size)
162 for unit in ('Kb', 'Mb', 'Gb', 'Tb'):
163 size /= 1024
164 if size < 2048:
165 break
166 return '%.1f %s' % (size, unit)