Updated preferences box to support Python 3, PyGObject and GTK 3
[zeroinstall/solver.git] / zeroinstall / 0launch-gui / preferences.py
blob218d6c1b6c90ec99fa7216545e7abd86ba878f79
1 # Copyright (C) 2009, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
4 import sys
5 from zeroinstall.gtkui import gtk
6 from dialog import Template
7 from zeroinstall import _
8 from zeroinstall.gtkui import help_box
9 from zeroinstall.injector.model import network_levels
10 from zeroinstall.injector import trust, gpg
11 from freshness import freshness_levels, Freshness
13 SHOW_CACHE = 0
15 class Preferences:
16 def __init__(self, config, notify_cb = None):
17 if notify_cb is None:
18 notify_cb = lambda: None
20 def connect_toggle(widget_name, setting_name):
21 widget = widgets.get_widget(widget_name)
22 widget.set_active(getattr(config, setting_name))
23 def toggle(w, config = config, setting_name = setting_name):
24 setattr(config, setting_name, w.get_active())
25 config.save_globals()
26 notify_cb()
27 widget.connect('toggled', toggle)
29 widgets = Template('preferences_box')
31 self.window = widgets.get_widget('preferences_box')
32 self.window.connect('destroy', lambda w: self.destroyed())
34 network = widgets.get_widget('network_use')
35 network.set_active(list(network_levels).index(config.network_use))
37 def set_network_use(combo):
38 config.network_use = network_levels[network.get_active()]
39 config.save_globals()
40 notify_cb()
41 network.connect('changed', set_network_use)
43 # Freshness
44 times = [x.time for x in freshness_levels]
45 if config.freshness not in times:
46 freshness_levels.append(Freshness(config.freshness,
47 '%d seconds' % config.freshness))
48 times.append(config.freshness)
49 freshness = widgets.get_widget('freshness')
50 freshness_model = freshness.get_model()
51 for level in freshness_levels:
52 i = freshness_model.append()
53 freshness_model.set_value(i, 0, str(level))
54 freshness.set_active(times.index(config.freshness))
55 def set_freshness(combo, freshness = freshness): # (pygtk bug?)
56 config.freshness = freshness_levels[freshness.get_active()].time
57 config.save_globals()
58 notify_cb()
59 freshness.connect('changed', set_freshness)
61 connect_toggle('help_test', 'help_with_testing')
63 # Keys
64 keys_view = widgets.get_widget('trusted_keys')
65 KeyList(keys_view)
66 connect_toggle('auto_approve', 'auto_approve_keys')
68 # Responses
69 self.window.set_default_response(gtk.RESPONSE_CLOSE)
70 self.window.get_default_widget().grab_focus()
72 def response(dialog, resp):
73 if resp in (gtk.RESPONSE_CLOSE, gtk.RESPONSE_DELETE_EVENT):
74 self.window.destroy()
75 elif resp == gtk.RESPONSE_HELP:
76 gui_help.display()
77 self.window.connect('response', response)
79 self.window.set_default_size(-1, gtk.gdk.screen_height() / 3)
81 def destroyed(self):
82 global preferences_box
83 preferences_box = None
85 class KeyList:
86 def __init__(self, tv):
87 self.trusted_keys = gtk.TreeStore(str, object)
88 tv.set_model(self.trusted_keys)
89 tc = gtk.TreeViewColumn(_('Trusted keys'), gtk.CellRendererText(), text = 0)
90 tv.append_column(tc)
91 trust.trust_db.ensure_uptodate()
93 def update_keys():
94 # Remember which ones are open
95 expanded_elements = set()
96 def add_row(tv, path, unused = None):
97 if len(path) == 1:
98 domain = self.trusted_keys[path][0]
99 expanded_elements.add(domain)
100 tv.map_expanded_rows(add_row, None)
102 self.trusted_keys.clear()
103 domains = {}
105 keys = gpg.load_keys(list(trust.trust_db.keys.keys()))
107 for fingerprint in keys:
108 for domain in trust.trust_db.keys[fingerprint]:
109 if domain not in domains:
110 domains[domain] = set()
111 domains[domain].add(keys[fingerprint])
112 for domain in sorted(domains):
113 iter = self.trusted_keys.append(None, [domain, None])
114 for key in domains[domain]:
115 self.trusted_keys.append(iter, [key.name, key])
117 def may_expand(model, path, iter, unused):
118 if gtk.path_depth(path) == 1:
119 if model[iter][0] in expanded_elements:
120 tv.expand_row(path, False)
121 self.trusted_keys.foreach(may_expand, None)
123 trust.trust_db.watchers.append(update_keys)
124 tv.connect('destroy', lambda w: trust.trust_db.watchers.remove(update_keys))
126 update_keys()
128 def remove_key(fingerprint, domain):
129 trust.trust_db.untrust_key(fingerprint, domain)
130 trust.trust_db.notify()
132 def trusted_keys_button_press(tv, bev):
133 if bev.type == gtk.gdk.BUTTON_PRESS and bev.button == 3:
134 pos = tv.get_path_at_pos(int(bev.x), int(bev.y))
135 if not pos:
136 return False
137 path, col, x, y = pos
138 if gtk.path_depth(path) != 2:
139 return False
141 key = self.trusted_keys[path][1]
142 domain = self.trusted_keys[gtk.path_parent(path)][0]
144 menu = gtk.Menu()
146 item = gtk.MenuItem(_('Remove key for "%s"') % key.get_short_name())
147 item.connect('activate',
148 lambda item, fp = key.fingerprint, d = domain: remove_key(fp, d))
149 item.show()
150 menu.append(item)
152 if sys.version_info[0] > 2:
153 menu.popup(None, None, None, None, bev.button, bev.time)
154 else:
155 menu.popup(None, None, None, bev.button, bev.time)
156 return True
157 return False
158 tv.connect('button-press-event', trusted_keys_button_press)
160 preferences_box = None
161 def show_preferences(config, notify_cb = None):
162 global preferences_box
163 if preferences_box:
164 preferences_box.window.destroy()
165 preferences_box = Preferences(config, notify_cb)
166 preferences_box.window.show()
167 return preferences_box.window
169 gui_help = help_box.HelpBox(_("Zero Install Preferences Help"),
170 (_('Overview'), '\n\n' +
171 _("""There are three ways to control which implementations are chosen. You can adjust the \
172 network policy and the overall stability policy, which affect all interfaces, or you \
173 can edit the policy of individual interfaces.""")),
175 (_('Network use'), '\n' +
176 _("""The 'Network use' option controls how the injector uses the network. If off-line, \
177 the network is not used at all. If 'Minimal' is selected then the injector will use \
178 the network if needed, but only if it has no choice. It will run an out-of-date \
179 version rather than download a newer one. If 'Full' is selected, the injector won't \
180 worry about how much it downloads, but will always pick the version it thinks is best.""")),
182 (_('Freshness'), '\n' +
183 _("""The feed files, which provide the information about which versions are \
184 available, are also cached. To update them, click on 'Refresh all now'. You can also \
185 get the injector to check for new versions automatically from time to time using \
186 the Freshness setting.""")),
188 (_('Help test new versions'), '\n' +
189 _("""The overall stability policy can either be to prefer stable versions, or to help test \
190 new versions. Choose whichever suits you. Since different programmers have different \
191 ideas of what 'stable' means, you may wish to override this on a per-interface basis.
193 To set the policy for an interface individually, select it in the main window and \
194 click on 'Interface Properties'. See that dialog's help text for more information.""")),
196 (_('Security'), '\n' +
197 _("""This section lists all keys which you currently trust. When fetching a new program or \
198 updates for an existing one, the feed must be signed by one of these keys. If not, \
199 you will be prompted to confirm that you trust the new key, and it will then be added \
200 to this list.
202 If "Automatic approval for new feeds" is on, new keys will be automatically approved if \
203 you haven't used the program before and the key is known to the key information server. \
204 When updating feeds, confirmation for new keys is always required.
206 To remove a key, right-click on it and choose 'Remove' from the menu.""")),