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