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