2 from logging
import warn
4 from zeroinstall
import SafeException
5 from zeroinstall
.support
import tasks
, pretty_size
6 from zeroinstall
.injector
import download
7 from iface_browser
import InterfaceBrowser
19 cancel_download_and_run
= None
22 def __init__(self
, policy
, widgets
, download_only
):
23 self
.handler
= policy
.handler
25 policy
.watchers
.append(lambda: self
.window
.set_response_sensitive(gtk
.RESPONSE_OK
, policy
.solver
.ready
))
27 self
.window
= widgets
.get_widget('main')
28 self
.window
.set_default_size(gtk
.gdk
.screen_width() * 2 / 5, 300)
30 self
.progress
= widgets
.get_widget('progress')
32 cache
= widgets
.get_widget('show_cache')
33 cache
.connect('clicked',
34 lambda b
: os
.spawnlp(os
.P_WAIT
, sys
.argv
[0], sys
.argv
[0], '-c'))
36 widgets
.get_widget('refresh').connect('clicked', lambda b
: policy
.refresh_all())
39 self
.browser
= InterfaceBrowser(policy
, widgets
)
41 prefs
= widgets
.get_widget('preferences')
42 self
.window
.action_area
.set_child_secondary(prefs
, True)
44 # Glade won't let me add this to the template!
46 run_button
= dialog
.MixedButton("_Download", gtk
.STOCK_EXECUTE
, button
= gtk
.ToggleButton())
48 run_button
= dialog
.MixedButton("_Run", gtk
.STOCK_EXECUTE
, button
= gtk
.ToggleButton())
49 self
.window
.add_action_widget(run_button
, gtk
.RESPONSE_OK
)
51 run_button
.set_flags(gtk
.CAN_DEFAULT
)
53 self
.window
.set_default_response(gtk
.RESPONSE_OK
)
54 self
.window
.default_widget
.grab_focus()
56 def response(dialog
, resp
):
57 if resp
in (gtk
.RESPONSE_CANCEL
, gtk
.RESPONSE_DELETE_EVENT
):
60 elif resp
== gtk
.RESPONSE_OK
:
61 if self
.cancel_download_and_run
:
62 self
.cancel_download_and_run
.trigger()
63 if run_button
.get_active():
64 self
.cancel_download_and_run
= tasks
.Blocker("cancel downloads")
65 self
.download_and_run(run_button
, self
.cancel_download_and_run
)
66 elif resp
== gtk
.RESPONSE_HELP
:
68 elif resp
== SHOW_PREFERENCES
:
70 preferences
.show_preferences(policy
)
71 self
.window
.connect('response', response
)
79 def set_response_sensitive(self
, response
, sensitive
):
80 self
.window
.set_response_sensitive(response
, sensitive
)
83 def download_and_run(self
, run_button
, cancelled
):
85 downloaded
= policy
.download_uncached_implementations()
88 # We need to wait until everything is downloaded...
89 blockers
= [downloaded
, cancelled
]
93 if cancelled
.happened
:
94 policy
.abort_all_downloads()
97 if self
.policy
.get_uncached_implementations():
98 dialog
.alert('Not all downloads succeeded; cannot run program.')
100 from zeroinstall
.injector
import selections
101 sels
= selections
.Selections(policy
)
103 reply
= doc
.toxml('utf-8')
104 sys
.stdout
.write(('Length:%8x\n' % len(reply
)) + reply
)
105 self
.window
.destroy()
106 sys
.exit(0) # Success
107 except SafeException
, ex
:
108 run_button
.set_active(False)
109 policy
.handler
.report_error(ex
)
110 except Exception, ex
:
111 run_button
.set_active(False)
113 traceback
.print_exc()
114 policy
.handler
.report_error(ex
)
116 def update_download_status(self
):
117 """Called at regular intervals while there are downloads in progress,
118 and once at the end. Update the display."""
119 monitored_downloads
= self
.handler
.monitored_downloads
121 if not monitored_downloads
:
128 done
= total
= self
.handler
.total_bytes_downloaded
# Completed downloads
129 n_downloads
= self
.handler
.n_completed_downloads
130 # Now add downloads in progress...
131 for x
in monitored_downloads
.values():
132 if x
.status
!= download
.download_fetching
: continue
136 so_far
= x
.get_bytes_downloaded_so_far()
137 total
+= x
.expected_size
or max(4096, so_far
) # Guess about 4K for feeds/icons
140 progress_text
= '%s / %s' % (pretty_size(done
), pretty_size(total
))
142 self
.progress
.set_text('Downloading one file (%s)' % progress_text
)
144 self
.progress
.set_text('Downloading %d files (%s)' % (n_downloads
, progress_text
))
146 if total
== 0 or (n_downloads
< 2 and not any_known
):
147 self
.progress
.pulse()
149 self
.progress
.set_fraction(float(done
) / total
)
151 gui_help
= help_box
.HelpBox("Injector Help",
153 A program is made up of many different components, typically written by different \
154 groups of people. Each component is available in multiple versions. The injector is \
155 used when starting a program. Its job is to decide which implementation of each required \
158 An interface describes what a component does. The injector starts with \
159 the interface for the program you want to run (like 'The Gimp') and chooses an \
160 implementation (like 'The Gimp 2.2.0'). However, this implementation \
161 will in turn depend on other interfaces, such as 'GTK' (which draws the menus \
162 and buttons). Thus, the injector must choose implementations of \
163 each dependency (each of which may require further interfaces, and so on)."""),
165 ('List of interfaces', """
166 The main window displays all these interfaces, and the version of each chosen \
167 implementation. The top-most one represents the program you tried to run, and each direct \
168 child is a dependency. The 'Fetch' column shows the amount of data that needs to be \
169 downloaded, or '(cached)' if it is already on this computer.
171 If you are happy with the choices shown, click on the Download (or Run) button to \
172 download (and run) the program."""),
174 ('Choosing different versions', """
175 To control which implementations (versions) are chosen you can click on Preferences \
176 and adjust the network policy and the overall stability policy. These settings affect \
177 all programs run using Zero Install.
179 Alternatively, you can edit the policy of an individual interface by selecting it \
180 and clicking on the 'Interface Properties' button. \
181 See that dialog's help text for more information.
183 Right-click on an interface in the list for a menu.
186 ('Reporting bugs', """
187 To report a bug, right-click over the interface which you think contains the problem \
188 and choose 'Report a Bug...' from the menu. If you don't know which one is the cause, \
189 choose the top one (i.e. the program itself). The program's author can reassign the \
190 bug if necessary, or switch to using a different version of the library.
194 Each version of a program that is downloaded is stored in the Zero Install cache. This \
195 means that it won't need to be downloaded again each time you run the program. Click on \
196 the 'Show Cache' button to see what is currently in the cache, or to remove versions \
197 you no longer need to save disk space."""),