Use Glade for the interface properties box.
[zeroinstall.git] / zeroinstall / 0launch-gui / preferences.py
blob604661514d41589329b57aff0881d55513e95ba6
1 import gtk
2 from logging import warn
3 import os, sys
4 import help_box
5 from gui import policy, Template
6 from dialog import Dialog, MixedButton, frame
7 from zeroinstall.injector.model import network_levels
8 from zeroinstall.injector import trust, gpg
9 from freshness import freshness_levels, Freshness
10 from sets import Set
12 tips = gtk.Tooltips()
14 SHOW_CACHE = 0
16 class Preferences:
17 def __init__(self):
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 for level in network_levels:
25 network.append_text(level.capitalize())
26 network.set_active(list(network_levels).index(policy.network_use))
28 def set_network_use(combo):
29 policy.network_use = network_levels[network.get_active()]
30 policy.save_config()
31 policy.recalculate()
32 network.connect('changed', set_network_use)
34 # Freshness
35 times = [x.time for x in freshness_levels]
36 if policy.freshness not in times:
37 freshness_levels.append(Freshness(policy.freshness,
38 '%d seconds' % policy.freshness))
39 times.append(policy.freshness)
40 eb = gtk.EventBox() # For the tooltip
41 freshness = widgets.get_widget('freshness')
42 for level in freshness_levels:
43 freshness.append_text(str(level))
44 freshness.set_active(times.index(policy.freshness))
45 def set_freshness(combo):
46 policy.freshness = freshness_levels[freshness.get_active()].time
47 policy.save_config()
48 policy.recalculate()
49 freshness.connect('changed', set_freshness)
51 stable_toggle = widgets.get_widget('help_test')
52 stable_toggle.set_active(policy.help_with_testing)
53 def toggle_stability(toggle):
54 policy.help_with_testing = toggle.get_active()
55 policy.save_config()
56 policy.recalculate()
57 stable_toggle.connect('toggled', toggle_stability)
59 # Keys
60 keys_view = widgets.get_widget('trusted_keys')
61 KeyList(keys_view)
63 # Responses
64 self.window.set_default_response(gtk.RESPONSE_CLOSE)
65 self.window.default_widget.grab_focus()
67 def response(dialog, resp):
68 import download_box
69 if resp in (gtk.RESPONSE_CLOSE, gtk.RESPONSE_DELETE_EVENT):
70 self.window.destroy()
71 elif resp == gtk.RESPONSE_HELP:
72 gui_help.display()
73 self.window.connect('response', response)
75 self.window.set_default_size(-1, gtk.gdk.screen_height() / 3)
77 def destroyed(self):
78 global preferences_box
79 preferences_box = None
81 class KeyList:
82 def __init__(self, tv):
83 self.trusted_keys = gtk.TreeStore(str, object)
84 tv.set_model(self.trusted_keys)
85 tc = gtk.TreeViewColumn('Trusted keys', gtk.CellRendererText(), text = 0)
86 tv.append_column(tc)
87 trust.trust_db.ensure_uptodate()
89 def update_keys():
90 # Remember which ones are open
91 expanded_elements = set()
92 def add_row(tv, path):
93 if len(path) == 1:
94 domain = self.trusted_keys[path][0]
95 expanded_elements.add(domain)
96 tv.map_expanded_rows(add_row)
98 self.trusted_keys.clear()
99 domains = {}
101 keys = gpg.load_keys(trust.trust_db.keys.keys())
103 for fingerprint in keys:
104 for domain in trust.trust_db.keys[fingerprint]:
105 if domain not in domains:
106 domains[domain] = Set()
107 domains[domain].add(keys[fingerprint])
108 for domain in domains:
109 iter = self.trusted_keys.append(None, [domain, None])
110 for key in domains[domain]:
111 self.trusted_keys.append(iter, [key.name, key])
113 def may_expand(model, path, iter):
114 if len(path) == 1:
115 if model[iter][0] in expanded_elements:
116 tv.expand_row(path, False)
117 self.trusted_keys.foreach(may_expand)
119 trust.trust_db.watchers.append(update_keys)
120 tv.connect('destroy', lambda w: trust.trust_db.watchers.remove(update_keys))
122 update_keys()
124 def remove_key(fingerprint, domain):
125 trust.trust_db.untrust_key(fingerprint, domain)
126 trust.trust_db.notify()
128 def trusted_keys_button_press(tv, bev):
129 if bev.type == gtk.gdk.BUTTON_PRESS and bev.button == 3:
130 pos = tv.get_path_at_pos(int(bev.x), int(bev.y))
131 if not pos:
132 return False
133 path, col, x, y = pos
134 if len(path) != 2:
135 return False
137 domain = self.trusted_keys[path[:-1]][0]
138 key = self.trusted_keys[path][1]
140 menu = gtk.Menu()
142 item = gtk.MenuItem('Remove key for "%s"' % key.get_short_name())
143 item.connect('activate',
144 lambda item, fp = key.fingerprint, d = domain: remove_key(fp, d))
145 item.show()
146 menu.append(item)
148 menu.popup(None, None, None, bev.button, bev.time)
149 return True
150 return False
151 tv.connect('button-press-event', trusted_keys_button_press)
153 preferences_box = None
154 def show_preferences():
155 global preferences_box
156 if preferences_box is not None:
157 preferences_box.window.present()
158 else:
159 preferences_box = Preferences()
160 preferences_box.window.show()
162 gui_help = help_box.HelpBox("Zero Install Preferences Help",
163 ('Overview', """
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', """
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', """
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', """
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', """
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. To remove a key, right-click on it and choose 'Remove' from the menu."""),