import gtk
from logging import warn
import os, sys
import help_box
from gui import policy
from dialog import Dialog, MixedButton, frame
from zeroinstall.injector.model import network_levels
from zeroinstall.injector import trust, gpg
from freshness import freshness_levels, Freshness
from sets import Set
tips = gtk.Tooltips()
SHOW_CACHE = 0
class Preferences(Dialog):
def __init__(self):
Dialog.__init__(self)
self.set_title('Zero Install Preferences')
self.connect('destroy', lambda w: self.destroyed())
content = gtk.VBox(False, 2)
content.set_border_width(8)
self.vbox.pack_start(content, True, True, 0)
vbox = gtk.VBox(False, 0)
frame(content, 'Policy settings', vbox)
# Network use
hbox = gtk.HBox(False, 2)
vbox.pack_start(hbox, False, True, 0)
hbox.set_border_width(4)
eb = gtk.EventBox() # For the tooltip
network = gtk.combo_box_new_text()
eb.add(network)
for level in network_levels:
network.append_text(level.capitalize())
network.set_active(list(network_levels).index(policy.network_use))
hbox.pack_start(gtk.Label('Network use:'), False, True, 0)
hbox.pack_start(eb, True, True, 2)
def set_network_use(combo):
policy.network_use = network_levels[network.get_active()]
policy.save_config()
policy.recalculate()
network.connect('changed', set_network_use)
tips.set_tip(eb, _('This controls whether the injector will always try to '
'run the best version, downloading it if needed, or whether it will prefer '
'to run an older version that is already on your machine.'))
hbox.show_all()
# Freshness
hbox = gtk.HBox(False, 2)
vbox.pack_start(hbox, False, True, 0)
hbox.set_border_width(4)
times = [x.time for x in freshness_levels]
if policy.freshness not in times:
freshness_levels.append(Freshness(policy.freshness,
'%d seconds' % policy.freshness))
times.append(policy.freshness)
eb = gtk.EventBox() # For the tooltip
freshness = gtk.combo_box_new_text()
eb.add(freshness)
for level in freshness_levels:
freshness.append_text(str(level))
freshness.set_active(times.index(policy.freshness))
hbox.pack_start(gtk.Label('Freshness:'), False, True, 0)
hbox.pack_start(eb, True, True, 2)
def set_freshness(combo):
policy.freshness = freshness_levels[freshness.get_active()].time
policy.save_config()
policy.recalculate()
freshness.connect('changed', set_freshness)
tips.set_tip(eb, _('Sets how often the injector will check for new versions.'))
stable_toggle = gtk.CheckButton('Help test new versions')
vbox.pack_start(stable_toggle, False, True, 0)
tips.set_tip(stable_toggle,
"Try out new versions as soon as they are available, instead of "
"waiting for them to be marked as 'stable'. "
"This sets the default policy. Click on 'Interface Properties...' "
"to set the policy for an individual interface.")
stable_toggle.set_active(policy.help_with_testing)
def toggle_stability(toggle):
policy.help_with_testing = toggle.get_active()
policy.save_config()
policy.recalculate()
stable_toggle.connect('toggled', toggle_stability)
# Keys
frame(content, 'Security', KeyList(), expand = True)
# Responses
self.add_button(gtk.STOCK_HELP, gtk.RESPONSE_HELP)
self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
self.set_default_response(gtk.RESPONSE_CLOSE)
self.default_widget.grab_focus()
def response(dialog, resp):
import download_box
if resp in (gtk.RESPONSE_CLOSE, gtk.RESPONSE_DELETE_EVENT):
self.destroy()
elif resp == gtk.RESPONSE_HELP:
gui_help.display()
self.connect('response', response)
self.set_default_size(-1, gtk.gdk.screen_height() / 3)
self.vbox.show_all()
def destroyed(self):
global preferences_box
preferences_box = None
class KeyList(gtk.VBox):
def __init__(self):
gtk.VBox.__init__(self, False, 0)
label = gtk.Label('')
label.set_markup('<i>You have said that you trust these keys to sign software updates.</i>')
label.set_padding(4, 4)
label.set_alignment(0, 0.5)
self.pack_start(label, False, True, 0)
self.trusted_keys = gtk.TreeStore(str, object)
tv = gtk.TreeView(self.trusted_keys)
tc = gtk.TreeViewColumn('Trusted keys', gtk.CellRendererText(), text = 0)
tv.append_column(tc)
swin = gtk.ScrolledWindow(None, None)
swin.set_shadow_type(gtk.SHADOW_IN)
swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
swin.add(tv)
trust.trust_db.ensure_uptodate()
def update_keys():
# Remember which ones are open
expanded_elements = set()
def add_row(tv, path):
if len(path) == 1:
domain = self.trusted_keys[path][0]
expanded_elements.add(domain)
tv.map_expanded_rows(add_row)
self.trusted_keys.clear()
domains = {}
keys = gpg.load_keys(trust.trust_db.keys.keys())
for fingerprint in keys:
for domain in trust.trust_db.keys[fingerprint]:
if domain not in domains:
domains[domain] = Set()
domains[domain].add(keys[fingerprint])
for domain in domains:
iter = self.trusted_keys.append(None, [domain, None])
for key in domains[domain]:
self.trusted_keys.append(iter, [key.name, key])
def may_expand(model, path, iter):
if len(path) == 1:
if model[iter][0] in expanded_elements:
tv.expand_row(path, False)
self.trusted_keys.foreach(may_expand)
trust.trust_db.watchers.append(update_keys)
self.connect('destroy', lambda w: trust.trust_db.watchers.remove(update_keys))
self.pack_start(swin, True, True, 0)
update_keys()
def remove_key(fingerprint, domain):
trust.trust_db.untrust_key(fingerprint, domain)
trust.trust_db.notify()
def trusted_keys_button_press(tv, bev):
if bev.type == gtk.gdk.BUTTON_PRESS and bev.button == 3:
pos = tv.get_path_at_pos(int(bev.x), int(bev.y))
if not pos:
return False
path, col, x, y = pos
if len(path) != 2:
return False
domain = self.trusted_keys[path[:-1]][0]
key = self.trusted_keys[path][1]
menu = gtk.Menu()
item = gtk.MenuItem('Remove key for "%s"' % key.get_short_name())
item.connect('activate',
lambda item, fp = key.fingerprint, d = domain: remove_key(fp, d))
item.show()
menu.append(item)
menu.popup(None, None, None, bev.button, bev.time)
return True
return False
tv.connect('button-press-event', trusted_keys_button_press)
preferences_box = None
def show_preferences():
global preferences_box
if preferences_box is not None:
preferences_box.present()
else:
preferences_box = Preferences()
preferences_box.show()
gui_help = help_box.HelpBox("Zero Install Preferences Help",
('Overview', """
There are three ways to control which implementations are chosen. You can adjust the \
network policy and the overall stability policy, which affect all interfaces, or you \
can edit the policy of individual interfaces."""),
('Network use', """
The 'Network use' option controls how the injector uses the network. If off-line, \
the network is not used at all. If 'Minimal' is selected then the injector will use \
the network if needed, but only if it has no choice. It will run an out-of-date \
version rather than download a newer one. If 'Full' is selected, the injector won't \
worry about how much it downloads, but will always pick the version it thinks is best."""),
('Freshness', """
The feed files, which provide the information about which versions are \
available, are also cached. To update them, click on 'Refresh all now'. You can also \
get the injector to check for new versions automatically from time to time using \
the Freshness setting."""),
('Help test new versions', """
The overall stability policy can either be to prefer stable versions, or to help test \
new versions. Choose whichever suits you. Since different programmers have different \
ideas of what 'stable' means, you may wish to override this on a per-interface basis.
To set the policy for an interface individually, select it in the main window and \
click on 'Interface Properties'. See that dialog's help text for more information."""),
('Security', """
This section lists all keys which you currently trust. When fetching a new program or \
updates for an existing one, the feed must be signed by one of these keys. If not, \
you will be prompted to confirm that you trust the new key, and it will then be added \
to this list. To remove a key, right-click on it and choose 'Remove' from the menu."""),
)
syntax highlighted by Code2HTML, v. 0.9.1