Checking box closer to working.
[zeroinstall/zeroinstall-rsl.git] / zeroinstall / 0launch-gui / gui.py
blob5a841bd11a7297e380f10f104b255322e3f766d2
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 dl_callbacks = None # Download -> [ callback ]
35 pulse = None
36 policy = None
38 def __init__(self, policy):
39 handler.Handler.__init__(self)
40 self.policy = policy
42 def downloads_changed(self):
43 if self.monitored_downloads and self.pulse is None:
44 def pulse():
45 if self.policy.checking:
46 self.policy.checking.progress.pulse()
47 else:
48 self.policy.window.progress.pulse()
49 return True
50 self.pulse = gobject.timeout_add(50, pulse)
51 self.policy.window.progress.show()
52 elif len(self.monitored_downloads) == 0:
53 if self.pulse:
54 gobject.source_remove(self.pulse)
55 self.policy.window.progress.hide()
56 self.pulse = None
58 if self.policy.checking:
59 self.policy.checking.updates_done(self.policy.versions_changed())
61 def confirm_trust_keys(self, interface, sigs, iface_xml):
62 import trust_box
63 return trust_box.confirm_trust(interface, sigs, iface_xml, parent = self.policy.checking or self.policy.window.window)
65 def report_error(self, ex):
66 dialog.alert(None, str(ex))
68 class GUIPolicy(Policy):
69 window = None
70 checking = None # GtkDialog ("Checking for updates...")
71 original_implementation = None
72 download_only = None
73 widgets = None # Glade
75 def __init__(self, interface, download_only, refresh, src = False, restrictions = None):
76 Policy.__init__(self, interface, GUIHandler(self), src = src)
77 self.solver.record_details = True
78 global policy
79 assert policy is None
80 policy = self
82 self.widgets = Template('main')
84 if restrictions:
85 for r in restrictions:
86 self.root_restrictions.append(r)
88 self.download_only = download_only
90 import mainwindow
91 self.window = mainwindow.MainWindow(download_only)
92 root = iface_cache.get_interface(self.root)
93 self.window.browser.set_root(root)
95 if refresh:
96 # If we have feeds then treat this as a refresh,
97 # even if we've never seen the main interface before.
98 # Used the first time the GUI is used, for example.
99 if root.name is not None or root.feeds:
100 self.checking = CheckingBox(root)
102 self.refresh_all(force = False)
104 self.watchers.append(self.update_display)
106 def show_details(self):
107 """The checking box has disappeared. Should we show the details window, or
108 just run the program right now?"""
109 if self.checking.show_details:
110 return True # User clicked on the Details button
111 if not self.ready:
112 return True # Not ready to start (can't find an implementation)
113 if self.versions_changed():
114 return True # Confirm that the new version should be used
115 if self.get_uncached_implementations():
116 return True # Need to download something; check first
117 return False
119 def store_icon(self, interface, stream):
120 Policy.store_icon(self, interface, stream)
121 if self.window:
122 self.window.browser.build_tree()
124 def update_display(self):
125 self.window.set_response_sensitive(gtk.RESPONSE_OK, self.ready)
127 def main(self):
128 solved = tasks.Task(self.solve_with_downloads(), "solve")
130 if self.checking:
131 self.checking.show()
133 yield solved.finished # TODO: Show Details
134 tasks.check(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 from zeroinstall.injector import selections
147 sels = selections.Selections(policy)
148 doc = sels.toDOM()
149 reply = doc.toxml('utf-8')
150 sys.stdout.write(('Length:%8x\n' % len(reply)) + reply)
151 self.window.destroy()
152 sys.exit(0) # Success
153 else:
154 self.window.show()
155 yield []
157 def abort_all_downloads(self):
158 for dl in self.handler.monitored_downloads.values():
159 dl.abort()
161 def set_original_implementations(self):
162 assert self.original_implementation is None
163 self.original_implementation = policy.implementation.copy()
165 def versions_changed(self):
166 """Return whether we have now chosen any different implementations.
167 If so, we want to show the dialog to the user to confirm the new ones."""
168 if not self.ready:
169 return True
170 if not self.original_implementation:
171 return True # Shouldn't happen?
172 if len(self.original_implementation) != len(self.implementation):
173 return True
174 for iface in self.original_implementation:
175 old = self.original_implementation[iface]
176 if old is None:
177 return True
178 new = self.implementation.get(iface, None)
179 if new is None:
180 return True
181 if old.id != new.id:
182 return True
183 return False