Release 1.4
[zeroinstall.git] / zeroinstall / 0launch-gui / main.py
bloba21c38e7b0e9acbe052929ba18a7ae10704a0aa7
1 # Copyright (C) 2009, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
4 from __future__ import print_function
6 import os, sys
8 from optparse import OptionParser
10 from zeroinstall import _
11 from zeroinstall.injector import requirements
12 from zeroinstall.injector.policy import Policy
13 from zeroinstall.injector.config import load_config
14 from zeroinstall.support import tasks
16 _recalculate = tasks.Blocker('recalculate')
18 def recalculate():
19 """Ask the mainloop to recalculate. If we're already recalculating, wait for that to finish
20 and then do it again."""
21 global _recalculate
22 _recalculate.trigger()
23 _recalculate = tasks.Blocker('recalculate')
25 def run_gui(args):
26 parser = OptionParser(usage=_("usage: %prog [options] interface"))
27 parser.add_option("", "--before", help=_("choose a version before this"), metavar='VERSION')
28 parser.add_option("", "--cpu", help=_("target CPU type"), metavar='CPU')
29 parser.add_option("", "--command", help=_("command to select"), metavar='COMMAND')
30 parser.add_option("-d", "--download-only", help=_("fetch but don't run"), action='store_true')
31 parser.add_option("", "--message", help=_("message to display when interacting with user"))
32 parser.add_option("", "--not-before", help=_("minimum version to choose"), metavar='VERSION')
33 parser.add_option("", "--os", help=_("target operation system type"), metavar='OS')
34 parser.add_option("-r", "--refresh", help=_("check for updates of all interfaces"), action='store_true')
35 parser.add_option("", "--select-only", help=_("only download the feeds"), action='store_true')
36 parser.add_option("-s", "--source", help=_("select source code"), action='store_true')
37 parser.add_option("", "--systray", help=_("download in the background"), action='store_true')
38 parser.add_option("-v", "--verbose", help=_("more verbose output"), action='count')
39 parser.add_option("-V", "--version", help=_("display version information"), action='store_true')
40 parser.add_option("", "--with-store", help=_("add an implementation cache"), action='append', metavar='DIR')
42 parser.disable_interspersed_args()
44 (options, args) = parser.parse_args(args)
46 if options.verbose:
47 import logging
48 logger = logging.getLogger()
49 if options.verbose == 1:
50 logger.setLevel(logging.INFO)
51 else:
52 logger.setLevel(logging.DEBUG)
54 import gui
56 if options.version:
57 print("0launch-gui (zero-install) " + gui.version)
58 print("Copyright (C) 2010 Thomas Leonard")
59 print(_("This program comes with ABSOLUTELY NO WARRANTY,"
60 "\nto the extent permitted by law."
61 "\nYou may redistribute copies of this program"
62 "\nunder the terms of the GNU Lesser General Public License."
63 "\nFor more information about these matters, see the file named COPYING."))
64 sys.exit(0)
66 import gtk
67 if gtk.gdk.get_display() is None:
68 print("Failed to connect to display. Aborting.", file=sys.stderr)
69 sys.exit(1)
71 handler = gui.GUIHandler()
73 config = load_config(handler)
75 if options.with_store:
76 from zeroinstall import zerostore
77 for x in options.with_store:
78 config.stores.stores.append(zerostore.Store(os.path.abspath(x)))
80 if len(args) < 1:
81 import preferences
82 box = preferences.show_preferences(config)
83 box.connect('destroy', gtk.main_quit)
84 gtk.main()
85 sys.exit(0)
87 interface_uri = args[0]
89 if len(args) > 1:
90 parser.print_help()
91 sys.exit(1)
93 import mainwindow, dialog
95 r = requirements.Requirements(interface_uri)
96 r.parse_options(options)
98 widgets = dialog.Template('main')
100 policy = Policy(config = config, requirements = r)
101 root_iface = config.iface_cache.get_interface(interface_uri)
102 policy.solver.record_details = True
104 window = mainwindow.MainWindow(policy, widgets, download_only = bool(options.download_only), select_only = bool(options.select_only))
105 handler.mainwindow = window
107 if options.message:
108 window.set_message(options.message)
110 root = config.iface_cache.get_interface(policy.root)
111 window.browser.set_root(root)
113 window.window.connect('destroy', lambda w: handler.abort_all_downloads())
115 if options.systray:
116 window.use_systray_icon()
118 @tasks.async
119 def main():
120 force_refresh = bool(options.refresh)
121 while True:
122 window.refresh_button.set_sensitive(False)
123 window.browser.set_update_icons(force_refresh)
125 solved = policy.solve_with_downloads(force = force_refresh, update_local = True)
127 if not window.systray_icon:
128 window.show()
129 yield solved
130 try:
131 window.refresh_button.set_sensitive(True)
132 window.browser.highlight_problems()
133 tasks.check(solved)
134 except Exception as ex:
135 window.report_exception(ex)
137 if window.systray_icon and window.systray_icon.get_visible() and \
138 window.systray_icon.is_embedded():
139 if policy.ready:
140 window.systray_icon.set_tooltip(_('Downloading updates for %s') % root_iface.get_name())
141 window.run_button.set_active(True)
142 else:
143 # Should already be reporting an error, but
144 # blink it again just in case
145 window.systray_icon.set_blinking(True)
147 refresh_clicked = dialog.ButtonClickedBlocker(window.refresh_button)
148 yield refresh_clicked, _recalculate
150 if refresh_clicked.happened:
151 force_refresh = True
153 tasks.wait_for_blocker(main())