Release 1.4
[zeroinstall.git] / zeroinstall / 0launch-gui / impl_list.py
blob5f8817f5fbe9b3d2ceb98e02ee8c3d3e2ad096d0
1 # Copyright (C) 2009, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
4 import gtk, gobject, os, pango
5 from zeroinstall import _
6 from zeroinstall.injector import model, writer
7 from zeroinstall import support
8 import utils
10 def _build_stability_menu(policy, impl):
11 menu = gtk.Menu()
13 upstream = impl.upstream_stability or model.testing
14 choices = model.stability_levels.values()
15 choices.sort()
16 choices.reverse()
18 def set(new):
19 if isinstance(new, model.Stability):
20 impl.user_stability = new
21 else:
22 impl.user_stability = None
23 writer.save_feed(impl.feed)
24 import main
25 main.recalculate()
27 item = gtk.MenuItem(_('Unset (%s)') % _(str(upstream).capitalize()).lower())
28 item.connect('activate', lambda item: set(None))
29 item.show()
30 menu.append(item)
32 item = gtk.SeparatorMenuItem()
33 item.show()
34 menu.append(item)
36 for value in choices:
37 item = gtk.MenuItem(_(str(value)).capitalize())
38 item.connect('activate', lambda item, v = value: set(v))
39 item.show()
40 menu.append(item)
42 return menu
44 rox_filer = 'http://rox.sourceforge.net/2005/interfaces/ROX-Filer'
46 # Columns
47 ITEM = 0
48 ARCH = 1
49 STABILITY = 2
50 VERSION = 3
51 FETCH = 4
52 UNUSABLE = 5
53 RELEASED = 6
54 NOTES = 7
55 WEIGHT = 8 # Selected item is bold
56 LANGS = 9
58 def get_tooltip_text(policy, interface, impl):
59 if impl.local_path:
60 return _("Local: %s") % impl.local_path
61 if impl.id.startswith('package:'):
62 return _("Native package: %s") % impl.id.split(':', 1)[1]
63 if policy.get_cached(impl):
64 return _("Cached: %s") % policy.get_implementation_path(impl)
66 src = policy.fetcher.get_best_source(impl)
67 if src:
68 size = support.pretty_size(src.size)
69 return _("Not yet downloaded (%s)") % size
70 else:
71 return _("No downloads available!")
73 class ImplementationList:
74 tree_view = None
75 model = None
76 interface = None
77 policy = None
79 def __init__(self, policy, interface, widgets):
80 self.interface = interface
81 self.policy = policy
83 self.model = gtk.ListStore(object, str, str, str, # Item, arch, stability, version,
84 str, gobject.TYPE_BOOLEAN, str, str, # fetch, unusable, released, notes,
85 int, str) # weight, langs
87 self.tree_view = widgets.get_widget('versions_list')
88 self.tree_view.set_model(self.model)
90 text = gtk.CellRendererText()
91 text_strike = gtk.CellRendererText()
93 stability = gtk.TreeViewColumn(_('Stability'), text, text = STABILITY)
95 for column in (gtk.TreeViewColumn(_('Version'), text_strike, text = VERSION, strikethrough = UNUSABLE, weight = WEIGHT),
96 gtk.TreeViewColumn(_('Released'), text, text = RELEASED, weight = WEIGHT),
97 stability,
98 gtk.TreeViewColumn(_('Fetch'), text, text = FETCH, weight = WEIGHT),
99 gtk.TreeViewColumn(_('Arch'), text_strike, text = ARCH, strikethrough = UNUSABLE, weight = WEIGHT),
100 gtk.TreeViewColumn(_('Lang'), text_strike, text = LANGS, strikethrough = UNUSABLE, weight = WEIGHT),
101 gtk.TreeViewColumn(_('Notes'), text, text = NOTES, weight = WEIGHT)):
102 self.tree_view.append_column(column)
104 self.tree_view.set_property('has-tooltip', True)
105 def tooltip_callback(widget, x, y, keyboard_mode, tooltip):
106 x, y = self.tree_view.convert_widget_to_bin_window_coords(x, y)
107 pos = self.tree_view.get_path_at_pos(x, y)
108 if pos:
109 self.tree_view.set_tooltip_cell(tooltip, pos[0], None, None)
110 path = pos[0]
111 row = self.model[path]
112 if row[ITEM]:
113 tooltip.set_text(get_tooltip_text(policy, interface, row[ITEM]))
114 return True
115 return False
116 self.tree_view.connect('query-tooltip', tooltip_callback)
118 def button_press(tree_view, bev):
119 if bev.button not in (1, 3):
120 return False
121 pos = tree_view.get_path_at_pos(int(bev.x), int(bev.y))
122 if not pos:
123 return False
124 path, col, x, y = pos
125 impl = self.model[path][ITEM]
127 menu = gtk.Menu()
129 stability_menu = gtk.MenuItem(_('Rating'))
130 stability_menu.set_submenu(_build_stability_menu(self.policy, impl))
131 stability_menu.show()
132 menu.append(stability_menu)
134 if not impl.id.startswith('package:') and self.policy.get_cached(impl):
135 def open():
136 os.spawnlp(os.P_WAIT, '0launch',
137 '0launch', rox_filer, '-d',
138 self.policy.get_implementation_path(impl))
139 item = gtk.MenuItem(_('Open cached copy'))
140 item.connect('activate', lambda item: open())
141 item.show()
142 menu.append(item)
144 menu.popup(None, None, None, bev.button, bev.time)
146 self.tree_view.connect('button-press-event', button_press)
148 def get_selection(self):
149 return self.tree_view.get_selection()
151 def set_items(self, items):
152 self.model.clear()
153 selected = self.policy.solver.selections.get(self.interface, None)
154 for item, unusable in items:
155 new = self.model.append()
156 self.model[new][ITEM] = item
157 self.model[new][VERSION] = item.get_version()
158 self.model[new][RELEASED] = item.released or "-"
159 self.model[new][FETCH] = utils.get_fetch_info(self.policy, item)
160 if item.user_stability:
161 if item.user_stability == model.insecure:
162 self.model[new][STABILITY] = _('INSECURE')
163 elif item.user_stability == model.buggy:
164 self.model[new][STABILITY] = _('BUGGY')
165 elif item.user_stability == model.developer:
166 self.model[new][STABILITY] = _('DEVELOPER')
167 elif item.user_stability == model.testing:
168 self.model[new][STABILITY] = _('TESTING')
169 elif item.user_stability == model.stable:
170 self.model[new][STABILITY] = _('STABLE')
171 elif item.user_stability == model.packaged:
172 self.model[new][STABILITY] = _('PACKAGED')
173 elif item.user_stability == model.preferred:
174 self.model[new][STABILITY] = _('PREFERRED')
175 else:
176 self.model[new][STABILITY] = _(str(item.upstream_stability) or str(model.testing))
177 self.model[new][ARCH] = item.arch or _('any')
178 if selected is item:
179 self.model[new][WEIGHT] = pango.WEIGHT_BOLD
180 else:
181 self.model[new][WEIGHT] = pango.WEIGHT_NORMAL
182 self.model[new][UNUSABLE] = bool(unusable)
183 self.model[new][LANGS] = item.langs or '-'
184 self.model[new][NOTES] = unusable and _(unusable) or _('None')
186 def clear(self):
187 self.model.clear()