1 # Copyright (C) 2008, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
5 from logging
import warn
7 from zeroinstall
import SafeException
8 from zeroinstall
.support
import tasks
, pretty_size
9 from zeroinstall
.injector
import download
10 from iface_browser
import InterfaceBrowser
13 from zeroinstall
.gtkui
import gtkutils
24 cancel_download_and_run
= None
27 def __init__(self
, policy
, widgets
, download_only
):
30 policy
.watchers
.append(lambda: self
.window
.set_response_sensitive(gtk
.RESPONSE_OK
, policy
.solver
.ready
))
32 self
.window
= widgets
.get_widget('main')
33 self
.window
.set_default_size(gtk
.gdk
.screen_width() * 2 / 5, 300)
35 self
.progress
= widgets
.get_widget('progress')
36 self
.progress_area
= widgets
.get_widget('progress_area')
38 widgets
.get_widget('stop').connect('clicked', lambda b
: policy
.handler
.abort_all_downloads())
40 cache
= widgets
.get_widget('show_cache')
41 cache
.connect('clicked',
42 lambda b
: os
.spawnlp(os
.P_WAIT
, sys
.argv
[0], sys
.argv
[0], '-c'))
44 self
.refresh_button
= widgets
.get_widget('refresh')
47 self
.browser
= InterfaceBrowser(policy
, widgets
)
49 prefs
= widgets
.get_widget('preferences')
50 self
.window
.action_area
.set_child_secondary(prefs
, True)
52 # Glade won't let me add this to the template!
54 run_button
= dialog
.MixedButton("_Download", gtk
.STOCK_EXECUTE
, button
= gtk
.ToggleButton())
56 run_button
= dialog
.MixedButton("_Run", gtk
.STOCK_EXECUTE
, button
= gtk
.ToggleButton())
57 self
.window
.add_action_widget(run_button
, gtk
.RESPONSE_OK
)
59 run_button
.set_flags(gtk
.CAN_DEFAULT
)
61 self
.window
.set_default_response(gtk
.RESPONSE_OK
)
62 self
.window
.default_widget
.grab_focus()
64 def response(dialog
, resp
):
65 if resp
in (gtk
.RESPONSE_CANCEL
, gtk
.RESPONSE_DELETE_EVENT
):
68 elif resp
== gtk
.RESPONSE_OK
:
69 if self
.cancel_download_and_run
:
70 self
.cancel_download_and_run
.trigger()
71 if run_button
.get_active():
72 self
.cancel_download_and_run
= tasks
.Blocker("cancel downloads")
73 self
.download_and_run(run_button
, self
.cancel_download_and_run
)
74 elif resp
== gtk
.RESPONSE_HELP
:
76 elif resp
== SHOW_PREFERENCES
:
78 preferences
.show_preferences(policy
)
79 self
.window
.connect('response', response
)
87 def set_response_sensitive(self
, response
, sensitive
):
88 self
.window
.set_response_sensitive(response
, sensitive
)
91 def download_and_run(self
, run_button
, cancelled
):
93 downloaded
= self
.policy
.download_uncached_implementations()
96 # We need to wait until everything is downloaded...
97 blockers
= [downloaded
, cancelled
]
101 if cancelled
.happened
:
104 if self
.policy
.get_uncached_implementations():
105 dialog
.alert(self
.window
, 'Not all downloads succeeded; cannot run program.')
107 from zeroinstall
.injector
import selections
108 sels
= selections
.Selections(self
.policy
)
110 reply
= doc
.toxml('utf-8')
111 sys
.stdout
.write(('Length:%8x\n' % len(reply
)) + reply
)
112 self
.window
.destroy()
113 sys
.exit(0) # Success
114 except SafeException
, ex
:
115 run_button
.set_active(False)
116 self
.policy
.handler
.report_error(ex
)
119 except Exception, ex
:
120 run_button
.set_active(False)
122 traceback
.print_exc()
123 self
.policy
.handler
.report_error(ex
)
125 def update_download_status(self
):
126 """Called at regular intervals while there are downloads in progress,
127 and once at the end. Update the display."""
128 monitored_downloads
= self
.policy
.handler
.monitored_downloads
130 self
.browser
.update_download_status()
132 if not monitored_downloads
:
133 self
.progress_area
.hide()
134 self
.window
.window
.set_cursor(None)
137 if not self
.progress_area
.get_property('visible'):
138 self
.progress_area
.show()
139 self
.window
.window
.set_cursor(gtkutils
.get_busy_pointer())
142 done
= total
= self
.policy
.handler
.total_bytes_downloaded
# Completed downloads
143 n_downloads
= self
.policy
.handler
.n_completed_downloads
144 # Now add downloads in progress...
145 for x
in monitored_downloads
.values():
146 if x
.status
!= download
.download_fetching
: continue
150 so_far
= x
.get_bytes_downloaded_so_far()
151 total
+= x
.expected_size
or max(4096, so_far
) # Guess about 4K for feeds/icons
154 progress_text
= '%s / %s' % (pretty_size(done
), pretty_size(total
))
156 self
.progress
.set_text('Downloading one file (%s)' % progress_text
)
158 self
.progress
.set_text('Downloading %d files (%s)' % (n_downloads
, progress_text
))
160 if total
== 0 or (n_downloads
< 2 and not any_known
):
161 self
.progress
.pulse()
163 self
.progress
.set_fraction(float(done
) / total
)
165 gui_help
= help_box
.HelpBox("Injector Help",
167 A program is made up of many different components, typically written by different \
168 groups of people. Each component is available in multiple versions. Zero Install is \
169 used when starting a program. Its job is to decide which implementation of each required \
172 Zero Install starts with the program you want to run (like 'The Gimp') and chooses an \
173 implementation (like 'The Gimp 2.2.0'). However, this implementation \
174 will in turn depend on other components, such as 'GTK' (which draws the menus \
175 and buttons). Thus, it must choose implementations of \
176 each dependency (each of which may require further components, and so on)."""),
178 ('List of components', """
179 The main window displays all these components, and the version of each chosen \
180 implementation. The top-most one represents the program you tried to run, and each direct \
181 child is a dependency. The 'Fetch' column shows the amount of data that needs to be \
182 downloaded, or '(cached)' if it is already on this computer.
184 If you are happy with the choices shown, click on the Download (or Run) button to \
185 download (and run) the program."""),
187 ('Choosing different versions', """
188 To control which implementations (versions) are chosen you can click on Preferences \
189 and adjust the network policy and the overall stability policy. These settings affect \
190 all programs run using Zero Install.
192 Alternatively, you can edit the policy of an individual component by clicking on the \
193 button at the end of its line in the table and choosing "Show Versions" from the menu. \
194 See that dialog's help text for more information.
197 ('Reporting bugs', """
198 To report a bug, right-click over the component which you think contains the problem \
199 and choose 'Report a Bug...' from the menu. If you don't know which one is the cause, \
200 choose the top one (i.e. the program itself). The program's author can reassign the \
201 bug if necessary, or switch to using a different version of the library.
205 Each version of a program that is downloaded is stored in the Zero Install cache. This \
206 means that it won't need to be downloaded again each time you run the program. Click on \
207 the 'Show Cache' button to see what is currently in the cache, or to remove versions \
208 you no longer need to save disk space."""),