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
12 from zeroinstall
.gtkui
import gtkutils
13 from zeroinstall
.gtkui
import help_box
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 self
.refresh_button
= widgets
.get_widget('refresh')
43 self
.browser
= InterfaceBrowser(policy
, widgets
)
45 prefs
= widgets
.get_widget('preferences')
46 self
.window
.action_area
.set_child_secondary(prefs
, True)
48 # Glade won't let me add this to the template!
50 run_button
= dialog
.MixedButton("_Download", gtk
.STOCK_EXECUTE
, button
= gtk
.ToggleButton())
52 run_button
= dialog
.MixedButton("_Run", gtk
.STOCK_EXECUTE
, button
= gtk
.ToggleButton())
53 self
.window
.add_action_widget(run_button
, gtk
.RESPONSE_OK
)
55 run_button
.set_flags(gtk
.CAN_DEFAULT
)
57 self
.window
.set_default_response(gtk
.RESPONSE_OK
)
58 self
.window
.default_widget
.grab_focus()
60 def response(dialog
, resp
):
61 if resp
in (gtk
.RESPONSE_CANCEL
, gtk
.RESPONSE_DELETE_EVENT
):
64 elif resp
== gtk
.RESPONSE_OK
:
65 if self
.cancel_download_and_run
:
66 self
.cancel_download_and_run
.trigger()
67 if run_button
.get_active():
68 self
.cancel_download_and_run
= tasks
.Blocker("cancel downloads")
69 self
.download_and_run(run_button
, self
.cancel_download_and_run
)
70 elif resp
== gtk
.RESPONSE_HELP
:
72 elif resp
== SHOW_PREFERENCES
:
74 preferences
.show_preferences(policy
)
75 self
.window
.connect('response', response
)
83 def set_response_sensitive(self
, response
, sensitive
):
84 self
.window
.set_response_sensitive(response
, sensitive
)
87 def download_and_run(self
, run_button
, cancelled
):
89 downloaded
= self
.policy
.download_uncached_implementations()
92 # We need to wait until everything is downloaded...
93 blockers
= [downloaded
, cancelled
]
97 if cancelled
.happened
:
100 if self
.policy
.get_uncached_implementations():
101 dialog
.alert(self
.window
, 'Not all downloads succeeded; cannot run program.')
103 from zeroinstall
.injector
import selections
104 sels
= selections
.Selections(self
.policy
)
106 reply
= doc
.toxml('utf-8')
107 sys
.stdout
.write(('Length:%8x\n' % len(reply
)) + reply
)
108 self
.window
.destroy()
109 sys
.exit(0) # Success
110 except SafeException
, ex
:
111 run_button
.set_active(False)
112 self
.policy
.handler
.report_error(ex
)
115 except Exception, ex
:
116 run_button
.set_active(False)
118 traceback
.print_exc()
119 self
.policy
.handler
.report_error(ex
)
121 def update_download_status(self
):
122 """Called at regular intervals while there are downloads in progress,
123 and once at the end. Update the display."""
124 monitored_downloads
= self
.policy
.handler
.monitored_downloads
126 self
.browser
.update_download_status()
128 if not monitored_downloads
:
129 self
.progress_area
.hide()
130 self
.window
.window
.set_cursor(None)
133 if not self
.progress_area
.get_property('visible'):
134 self
.progress_area
.show()
135 self
.window
.window
.set_cursor(gtkutils
.get_busy_pointer())
138 done
= total
= self
.policy
.handler
.total_bytes_downloaded
# Completed downloads
139 n_downloads
= self
.policy
.handler
.n_completed_downloads
140 # Now add downloads in progress...
141 for x
in monitored_downloads
.values():
142 if x
.status
!= download
.download_fetching
: continue
146 so_far
= x
.get_bytes_downloaded_so_far()
147 total
+= x
.expected_size
or max(4096, so_far
) # Guess about 4K for feeds/icons
150 progress_text
= '%s / %s' % (pretty_size(done
), pretty_size(total
))
152 self
.progress
.set_text('Downloading one file (%s)' % progress_text
)
154 self
.progress
.set_text('Downloading %d files (%s)' % (n_downloads
, progress_text
))
156 if total
== 0 or (n_downloads
< 2 and not any_known
):
157 self
.progress
.pulse()
159 self
.progress
.set_fraction(float(done
) / total
)
161 gui_help
= help_box
.HelpBox("Injector Help",
163 A program is made up of many different components, typically written by different \
164 groups of people. Each component is available in multiple versions. Zero Install is \
165 used when starting a program. Its job is to decide which implementation of each required \
168 Zero Install starts with the program you want to run (like 'The Gimp') and chooses an \
169 implementation (like 'The Gimp 2.2.0'). However, this implementation \
170 will in turn depend on other components, such as 'GTK' (which draws the menus \
171 and buttons). Thus, it must choose implementations of \
172 each dependency (each of which may require further components, and so on)."""),
174 ('List of components', """
175 The main window displays all these components, and the version of each chosen \
176 implementation. The top-most one represents the program you tried to run, and each direct \
177 child is a dependency. The 'Fetch' column shows the amount of data that needs to be \
178 downloaded, or '(cached)' if it is already on this computer.
180 If you are happy with the choices shown, click on the Download (or Run) button to \
181 download (and run) the program."""),
183 ('Choosing different versions', """
184 To control which implementations (versions) are chosen you can click on Preferences \
185 and adjust the network policy and the overall stability policy. These settings affect \
186 all programs run using Zero Install.
188 Alternatively, you can edit the policy of an individual component by clicking on the \
189 button at the end of its line in the table and choosing "Show Versions" from the menu. \
190 See that dialog's help text for more information.
193 ('Reporting bugs', """
194 To report a bug, right-click over the component which you think contains the problem \
195 and choose 'Report a Bug...' from the menu. If you don't know which one is the cause, \
196 choose the top one (i.e. the program itself). The program's author can reassign the \
197 bug if necessary, or switch to using a different version of the library.
201 Each version of a program that is downloaded is stored in the Zero Install cache. This \
202 means that it won't need to be downloaded again each time you run the program. The \
203 "0store manage" command can be used to view the cache.