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