Added accelerator for Download button.
[zeroinstall.git] / iface_browser.py
blob0a955a900203bcc9276b4cdbe93cbd10c82ed333
1 import gtk
3 from zeroinstall.injector.model import Interface
4 import properties
5 from treetips import TreeTips
6 from gui import policy, pretty_size
8 def _stability(impl):
9 assert impl
10 if impl.user_stability is None:
11 return impl.upstream_stability
12 return _("%s (was %s)") % (impl.user_stability, impl.upstream_stability)
14 class InterfaceTips(TreeTips):
15 def get_tooltip_text(self, item):
16 interface, model_column = item
17 assert interface
18 if model_column == InterfaceBrowser.INTERFACE_NAME:
19 return _("Full name: %s") % interface.uri
20 elif model_column == InterfaceBrowser.SUMMARY:
21 if not interface.description:
22 return None
23 first_para = interface.description.split('\n\n', 1)[0]
24 return first_para.replace('\n', ' ')
26 impl = policy.implementation.get(interface, None)
27 if not impl:
28 return _("No suitable implementation was found. Check the "
29 "interface properties to find out why.")
31 if model_column == InterfaceBrowser.VERSION:
32 text = _("Currently preferred version: %s (%s)") % \
33 (impl.get_version(), _stability(impl))
34 old_impl = policy.original_implementation.get(interface, None)
35 if old_impl is not None and old_impl is not impl:
36 text += _('\nPreviously preferred version: %s (%s)') % \
37 (old_impl.get_version(), _stability(old_impl))
38 return text
40 assert model_column == InterfaceBrowser.DOWNLOAD_SIZE
42 if policy.get_cached(impl):
43 return _("This version is already stored on your computer.")
44 else:
45 src = policy.get_best_source(impl)
46 if not src:
47 return _("No downloads available!")
48 return _("Need to download %s (%s bytes)") % \
49 (pretty_size(src.size), src.size)
51 tips = InterfaceTips()
53 class InterfaceBrowser(gtk.ScrolledWindow):
54 model = None
55 root = None
56 edit_properties = None
58 INTERFACE = 0
59 INTERFACE_NAME = 1
60 VERSION = 2
61 SUMMARY = 3
62 DOWNLOAD_SIZE = 4
64 columns = [(_('Interface'), INTERFACE_NAME),
65 (_('Version'), VERSION),
66 (_('Fetch'), DOWNLOAD_SIZE),
67 (_('Description'), SUMMARY)]
69 def __init__(self):
70 self.edit_properties = gtk.Action('edit_properties',
71 'Interface Properties...',
72 'Set which implementation of this interface to use.',
73 gtk.STOCK_PROPERTIES)
74 self.edit_properties.set_property('sensitive', False)
76 gtk.ScrolledWindow.__init__(self)
77 self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
78 self.set_shadow_type(gtk.SHADOW_IN)
80 self.model = gtk.TreeStore(object, str, str, str, str)
81 self.tree_view = tree_view = gtk.TreeView(self.model)
83 text = gtk.CellRendererText()
85 column_objects = []
86 for name, model_column in self.columns:
87 column = gtk.TreeViewColumn(name, text, text = model_column)
88 tree_view.append_column(column)
89 column_objects.append(column)
91 self.add(tree_view)
92 tree_view.show()
94 tree_view.set_enable_search(True)
96 selection = tree_view.get_selection()
98 def motion(tree_view, ev):
99 if ev.window is not tree_view.get_bin_window():
100 return False
101 pos = tree_view.get_path_at_pos(int(ev.x), int(ev.y))
102 if pos:
103 path = pos[0]
104 col = self.columns[column_objects.index(pos[1])][1]
105 row = self.model[path]
106 item = (row[InterfaceBrowser.INTERFACE], col)
107 if item != tips.item:
108 tips.prime(tree_view, item)
109 else:
110 tips.hide()
112 tree_view.connect('motion-notify-event', motion)
113 tree_view.connect('leave-notify-event', lambda tv, ev: tips.hide())
115 def sel_changed(sel):
116 store, iter = sel.get_selected()
117 self.edit_properties.set_property('sensitive', iter != None)
118 selection.connect('changed', sel_changed)
120 def button_press(tree_view, bev):
121 if bev.button != 1 or bev.type != gtk.gdk._2BUTTON_PRESS:
122 return False
123 pos = tree_view.get_path_at_pos(int(bev.x), int(bev.y))
124 if not pos:
125 return False
126 path, col, x, y = pos
127 properties.edit(self.model[path][InterfaceBrowser.INTERFACE])
128 tree_view.connect('button-press-event', button_press)
130 def edit_selected(action):
131 store, iter = selection.get_selected()
132 assert iter
133 properties.edit(self.model[iter][InterfaceBrowser.INTERFACE])
134 self.edit_properties.connect('activate', edit_selected)
136 self.connect('destroy', lambda s: policy.watchers.remove(self.build_tree))
137 policy.watchers.append(self.build_tree)
139 def set_root(self, root):
140 assert isinstance(root, Interface)
141 self.root = root
142 policy.recalculate() # Calls build_tree
144 def build_tree(self):
145 if policy.original_implementation is None:
146 policy.set_original_implementations()
148 done = {} # Detect cycles
150 self.model.clear()
151 parent = None
152 def add_node(parent, iface):
153 if iface in done:
154 return
155 done[iface] = True
157 iter = self.model.append(parent)
158 self.model[iter][InterfaceBrowser.INTERFACE] = iface
159 self.model[iter][InterfaceBrowser.INTERFACE_NAME] = iface.get_name()
160 self.model[iter][InterfaceBrowser.SUMMARY] = iface.summary
162 impl = policy.implementation.get(iface, None)
163 if impl:
164 old_impl = policy.original_implementation.get(iface, None)
165 version_str = impl.get_version()
166 if old_impl is not None and old_impl is not impl:
167 version_str += " (was " + old_impl.get_version() + ")"
168 self.model[iter][InterfaceBrowser.VERSION] = version_str
170 if policy.get_cached(impl):
171 fetch = '(cached)'
172 else:
173 src = policy.get_best_source(impl)
174 if src:
175 fetch = pretty_size(src.size)
176 else:
177 fetch = '(unavailable)'
178 self.model[iter][InterfaceBrowser.DOWNLOAD_SIZE] = fetch
179 for child in impl.dependencies.values():
180 add_node(iter, policy.get_interface(child.interface))
181 else:
182 self.model[iter][InterfaceBrowser.VERSION] = '(choose)'
183 add_node(None, self.root)
184 self.tree_view.expand_all()