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