GUI Preferences works again
[zeroinstall.git] / zeroinstall / 0launch-gui / preferences.py
blobea1fa72095da371870fccc41ea3ab41c1f2a35f3
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.gtkui import help_box
7 from zeroinstall.injector.model import network_levels
8 from zeroinstall.injector import trust, gpg
9 from freshness import freshness_levels, Freshness
11 SHOW_CACHE = 0
13 class Preferences:
14 def __init__(self, config, notify_cb = None):
15 if notify_cb is None:
16 notify_cb = lambda: None
18 widgets = Template('preferences_box')
20 self.window = widgets.get_widget('preferences_box')
21 self.window.connect('destroy', lambda w: self.destroyed())
23 network = widgets.get_widget('network_use')
24 network.set_active(list(network_levels).index(config.network_use))
26 def set_network_use(combo):
27 config.network_use = network_levels[network.get_active()]
28 config.save_globals()
29 notify_cb()
30 network.connect('changed', set_network_use)
32 # Freshness
33 times = [x.time for x in freshness_levels]
34 if config.freshness not in times:
35 freshness_levels.append(Freshness(config.freshness,
36 '%d seconds' % config.freshness))
37 times.append(config.freshness)
38 eb = gtk.EventBox() # For the tooltip
39 freshness = widgets.get_widget('freshness')
40 for level in freshness_levels:
41 freshness.append_text(str(level))
42 freshness.set_active(times.index(config.freshness))
43 def set_freshness(combo, freshness = freshness): # (pygtk bug?)
44 config.freshness = freshness_levels[freshness.get_active()].time
45 config.save_globals()
46 notify_cb()
47 freshness.connect('changed', set_freshness)
49 stable_toggle = widgets.get_widget('help_test')
50 stable_toggle.set_active(config.help_with_testing)
51 def toggle_stability(toggle):
52 config.help_with_testing = toggle.get_active()
53 config.save_globals()
54 notify_cb()
55 stable_toggle.connect('toggled', toggle_stability)
57 # Keys
58 keys_view = widgets.get_widget('trusted_keys')
59 KeyList(keys_view)
61 # Responses
62 self.window.set_default_response(gtk.RESPONSE_CLOSE)
63 self.window.default_widget.grab_focus()
65 def response(dialog, resp):
66 if resp in (gtk.RESPONSE_CLOSE, gtk.RESPONSE_DELETE_EVENT):
67 self.window.destroy()
68 elif resp == gtk.RESPONSE_HELP:
69 gui_help.display()
70 self.window.connect('response', response)
72 self.window.set_default_size(-1, gtk.gdk.screen_height() / 3)
74 def destroyed(self):
75 global preferences_box
76 preferences_box = None
78 class KeyList:
79 def __init__(self, tv):
80 self.trusted_keys = gtk.TreeStore(str, object)
81 tv.set_model(self.trusted_keys)
82 tc = gtk.TreeViewColumn(_('Trusted keys'), gtk.CellRendererText(), text = 0)
83 tv.append_column(tc)
84 trust.trust_db.ensure_uptodate()
86 def update_keys():
87 # Remember which ones are open
88 expanded_elements = set()
89 def add_row(tv, path):
90 if len(path) == 1:
91 domain = self.trusted_keys[path][0]
92 expanded_elements.add(domain)
93 tv.map_expanded_rows(add_row)
95 self.trusted_keys.clear()
96 domains = {}
98 keys = gpg.load_keys(trust.trust_db.keys.keys())
100 for fingerprint in keys:
101 for domain in trust.trust_db.keys[fingerprint]:
102 if domain not in domains:
103 domains[domain] = set()
104 domains[domain].add(keys[fingerprint])
105 for domain in sorted(domains):
106 iter = self.trusted_keys.append(None, [domain, None])
107 for key in domains[domain]:
108 self.trusted_keys.append(iter, [key.name, key])
110 def may_expand(model, path, iter):
111 if len(path) == 1:
112 if model[iter][0] in expanded_elements:
113 tv.expand_row(path, False)
114 self.trusted_keys.foreach(may_expand)
116 trust.trust_db.watchers.append(update_keys)
117 tv.connect('destroy', lambda w: trust.trust_db.watchers.remove(update_keys))
119 update_keys()
121 def remove_key(fingerprint, domain):
122 trust.trust_db.untrust_key(fingerprint, domain)
123 trust.trust_db.notify()
125 def trusted_keys_button_press(tv, bev):
126 if bev.type == gtk.gdk.BUTTON_PRESS and bev.button == 3:
127 pos = tv.get_path_at_pos(int(bev.x), int(bev.y))
128 if not pos:
129 return False
130 path, col, x, y = pos
131 if len(path) != 2:
132 return False
134 domain = self.trusted_keys[path[:-1]][0]
135 key = self.trusted_keys[path][1]
137 menu = gtk.Menu()
139 item = gtk.MenuItem(_('Remove key for "%s"') % key.get_short_name())
140 item.connect('activate',
141 lambda item, fp = key.fingerprint, d = domain: remove_key(fp, d))
142 item.show()
143 menu.append(item)
145 menu.popup(None, None, None, bev.button, bev.time)
146 return True
147 return False
148 tv.connect('button-press-event', trusted_keys_button_press)
150 preferences_box = None
151 def show_preferences(config, notify_cb = None):
152 global preferences_box
153 if preferences_box:
154 preferences_box.destroy()
155 preferences_box = Preferences(config, notify_cb)
156 preferences_box.window.show()
157 return preferences_box.window
159 gui_help = help_box.HelpBox(_("Zero Install Preferences Help"),
160 (_('Overview'), '\n\n' +
161 _("""There are three ways to control which implementations are chosen. You can adjust the \
162 network policy and the overall stability policy, which affect all interfaces, or you \
163 can edit the policy of individual interfaces.""")),
165 (_('Network use'), '\n' +
166 _("""The 'Network use' option controls how the injector uses the network. If off-line, \
167 the network is not used at all. If 'Minimal' is selected then the injector will use \
168 the network if needed, but only if it has no choice. It will run an out-of-date \
169 version rather than download a newer one. If 'Full' is selected, the injector won't \
170 worry about how much it downloads, but will always pick the version it thinks is best.""")),
172 (_('Freshness'), '\n' +
173 _("""The feed files, which provide the information about which versions are \
174 available, are also cached. To update them, click on 'Refresh all now'. You can also \
175 get the injector to check for new versions automatically from time to time using \
176 the Freshness setting.""")),
178 (_('Help test new versions'), '\n' +
179 _("""The overall stability policy can either be to prefer stable versions, or to help test \
180 new versions. Choose whichever suits you. Since different programmers have different \
181 ideas of what 'stable' means, you may wish to override this on a per-interface basis.
183 To set the policy for an interface individually, select it in the main window and \
184 click on 'Interface Properties'. See that dialog's help text for more information.""")),
186 (_('Security'), '\n' +
187 _("""This section lists all keys which you currently trust. When fetching a new program or \
188 updates for an existing one, the feed must be signed by one of these keys. If not, \
189 you will be prompted to confirm that you trust the new key, and it will then be added \
190 to this list. To remove a key, right-click on it and choose 'Remove' from the menu.""")),