Perform GUI downloads in the main window.
[zeroinstall/zeroinstall-rsl.git] / zeroinstall / 0launch-gui / gui.py
blobc82c69924e8983e40feda6fa623324a39c4930fe
1 import gtk, os, gobject, sys
2 import gtk.glade
4 from zeroinstall.injector.iface_cache import iface_cache
5 from zeroinstall.injector.policy import Policy
6 from zeroinstall.injector import download, handler
7 from zeroinstall.injector.model import SafeException
8 from zeroinstall.injector.reader import InvalidInterface
9 from zeroinstall.support import tasks
10 import dialog
11 from checking import CheckingBox
13 version = '0.31'
15 # Singleton Policy
16 policy = None
18 gladefile = os.path.join(os.path.dirname(__file__), 'zero-install.glade')
20 # Wrapped for glade widget tree that throws a sensible exception if the widget isn't found
21 class Template:
22 def __init__(self, root):
23 self.widgets = gtk.glade.XML(gladefile, root)
24 self.root = root
26 def get_widget(self, name = None):
27 if not name:
28 name = self.root
29 widget = self.widgets.get_widget(name)
30 assert widget, "Widget '%s' not found in glade file '%s'" % (name, gladefile)
31 return widget
33 class GUIHandler(handler.Handler):
34 monitored_downloads = None
35 dl_callbacks = None # Download -> [ callback ]
36 pulse = None
37 policy = None
39 def __init__(self, policy):
40 handler.Handler.__init__(self)
41 self.policy = policy
43 def downloads_changed(self):
44 if self.monitored_downloads and self.pulse is None:
45 def pulse():
46 if self.policy.checking:
47 self.policy.checking.progress.pulse()
48 else:
49 self.policy.window.progress.pulse()
50 return True
51 self.pulse = gobject.timeout_add(50, pulse)
52 self.policy.window.progress.show()
53 elif len(self.monitored_downloads) == 0:
54 if self.pulse:
55 gobject.source_remove(self.pulse)
56 self.policy.window.progress.hide()
57 self.pulse = None
59 if self.policy.checking:
60 self.policy.checking.updates_done(self.policy.versions_changed())
62 def confirm_trust_keys(self, interface, sigs, iface_xml):
63 import trust_box
64 return trust_box.confirm_trust(interface, sigs, iface_xml, parent = self.policy.checking or self.policy.window.window)
66 def report_error(self, ex):
67 dialog.alert(None, str(ex))
69 class GUIPolicy(Policy):
70 window = None
71 checking = None # GtkDialog ("Checking for updates...")
72 original_implementation = None
73 download_only = None
74 widgets = None # Glade
76 def __init__(self, interface, download_only, refresh, src = False, restrictions = None):
77 Policy.__init__(self, interface, GUIHandler(self), src = src)
78 self.solver.record_details = True
79 global policy
80 assert policy is None
81 policy = self
83 self.widgets = Template('main')
85 if restrictions:
86 for r in restrictions:
87 self.root_restrictions.append(r)
89 self.download_only = download_only
91 import mainwindow
92 self.window = mainwindow.MainWindow(download_only)
93 root = iface_cache.get_interface(self.root)
94 self.window.browser.set_root(root)
96 if refresh:
97 # If we have feeds then treat this as a refresh,
98 # even if we've never seen the main interface before.
99 # Used the first time the GUI is used, for example.
100 if root.name is not None or root.feeds:
101 self.checking = CheckingBox(root)
103 self.refresh_all(force = False)
105 self.watchers.append(self.update_display)
107 def show_details(self):
108 """The checking box has disappeared. Should we show the details window, or
109 just run the program right now?"""
110 if self.checking.show_details:
111 return True # User clicked on the Details button
112 if not self.ready:
113 return True # Not ready to start (can't find an implementation)
114 if self.versions_changed():
115 return True # Confirm that the new version should be used
116 if self.get_uncached_implementations():
117 return True # Need to download something; check first
118 return False
120 def store_icon(self, interface, stream):
121 Policy.store_icon(self, interface, stream)
122 if self.window:
123 self.window.browser.build_tree()
125 def update_display(self):
126 self.window.set_response_sensitive(gtk.RESPONSE_OK, self.ready)
128 def main(self):
129 solved = tasks.Task(self.solve_with_downloads(), "solve")
131 if self.checking:
132 self.checking.show()
134 yield solved.finished
136 self.checking.updates_done(self.versions_changed())
138 #dialog.wait_for_no_windows()
140 show_details = self.show_details()
141 self.checking = None
142 if show_details:
143 self.window.show()
144 yield []
145 else:
146 raise Exception("STOP")
147 import download_box
148 task = tasks.Task(policy.download_impls(), "download implementations")
149 yield task.finished
150 yield []
151 else:
152 self.window.show()
153 yield []
155 def abort_all_downloads(self):
156 for dl in self.handler.monitored_downloads.values():
157 dl.abort()
159 def set_original_implementations(self):
160 assert self.original_implementation is None
161 self.original_implementation = policy.implementation.copy()
163 def versions_changed(self):
164 """Return whether we have now chosen any different implementations.
165 If so, we want to show the dialog to the user to confirm the new ones."""
166 if not self.ready:
167 return True
168 if not self.original_implementation:
169 return True # Shouldn't happen?
170 if len(self.original_implementation) != len(self.implementation):
171 return True
172 for iface in self.original_implementation:
173 old = self.original_implementation[iface]
174 if old is None:
175 return True
176 new = self.implementation.get(iface, None)
177 if new is None:
178 return True
179 if old.id != new.id:
180 return True
181 return False