Updated preferences box to support Python 3, PyGObject and GTK 3
[zeroinstall.git] / zeroinstall / 0launch-gui / main.py
blob30b35b3040e1ea32d65d91ae3e6327dc48c7c5d9
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.driver import Driver
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 from zeroinstall.gtkui 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 @tasks.async
82 def prefs_main():
83 import preferences
84 box = preferences.show_preferences(config)
85 done = tasks.Blocker('close preferences')
86 box.connect('destroy', lambda w: done.trigger())
87 yield done
88 tasks.wait_for_blocker(prefs_main())
89 sys.exit(0)
91 interface_uri = args[0]
93 if len(args) > 1:
94 parser.print_help()
95 sys.exit(1)
97 import mainwindow, dialog
99 r = requirements.Requirements(interface_uri)
100 r.parse_options(options)
102 widgets = dialog.Template('main')
104 driver = Driver(config = config, requirements = r)
105 root_iface = config.iface_cache.get_interface(interface_uri)
106 driver.solver.record_details = True
108 window = mainwindow.MainWindow(driver, widgets, download_only = bool(options.download_only), select_only = bool(options.select_only))
109 handler.mainwindow = window
111 if options.message:
112 window.set_message(options.message)
114 root = config.iface_cache.get_interface(r.interface_uri)
115 window.browser.set_root(root)
117 window.window.connect('destroy', lambda w: handler.abort_all_downloads())
119 if options.systray:
120 window.use_systray_icon()
122 @tasks.async
123 def main():
124 force_refresh = bool(options.refresh)
125 while True:
126 window.refresh_button.set_sensitive(False)
127 window.browser.set_update_icons(force_refresh)
129 solved = driver.solve_with_downloads(force = force_refresh, update_local = True)
131 if not window.systray_icon:
132 window.show()
133 yield solved
134 try:
135 window.refresh_button.set_sensitive(True)
136 window.browser.highlight_problems()
137 tasks.check(solved)
138 except Exception as ex:
139 window.report_exception(ex)
141 if window.systray_icon and window.systray_icon.get_visible() and \
142 window.systray_icon.is_embedded():
143 if driver.solver.ready:
144 window.systray_icon.set_tooltip(_('Downloading updates for %s') % root_iface.get_name())
145 window.run_button.set_active(True)
146 else:
147 # Should already be reporting an error, but
148 # blink it again just in case
149 window.systray_icon.set_blinking(True)
151 refresh_clicked = dialog.ButtonClickedBlocker(window.refresh_button)
152 yield refresh_clicked, _recalculate
154 if refresh_clicked.happened:
155 force_refresh = True
157 tasks.wait_for_blocker(main())