Highlight selected version in bold
[zeroinstall/solver.git] / zeroinstall / 0launch-gui / impl_list.py
blob7161102e4cd1af23e592531cc042afdf45d41378
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.injector import model, writer
6 from zeroinstall import support
7 from zeroinstall.gtkui.treetips import TreeTips
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 policy.recalculate()
26 item = gtk.MenuItem(_('Unset (%s)') % upstream)
27 item.connect('activate', lambda item: set(None))
28 item.show()
29 menu.append(item)
31 item = gtk.SeparatorMenuItem()
32 item.show()
33 menu.append(item)
35 for value in choices:
36 item = gtk.MenuItem(_(str(value)).capitalize())
37 item.connect('activate', lambda item, v = value: set(v))
38 item.show()
39 menu.append(item)
41 return menu
43 rox_filer = 'http://rox.sourceforge.net/2005/interfaces/ROX-Filer'
45 # Columns
46 ITEM = 0
47 ARCH = 1
48 STABILITY = 2
49 VERSION = 3
50 FETCH = 4
51 UNUSABLE = 5
52 RELEASED = 6
53 NOTES = 7
54 WEIGHT = 8 # Selected item is bold
56 class ImplTips(TreeTips):
57 def __init__(self, policy, interface):
58 self.policy = policy
59 self.interface = interface
61 def get_tooltip_text(self):
62 impl = self.item
63 if impl.local_path:
64 return _("Local: %s") % impl.local_path
65 if impl.id.startswith('package:'):
66 return _("Native package: %s") % impl.id.split(':', 1)[1]
67 if self.policy.get_cached(impl):
68 return _("Cached: %s") % self.policy.get_implementation_path(impl)
70 src = self.policy.fetcher.get_best_source(impl)
71 if src:
72 size = support.pretty_size(src.size)
73 return _("Not yet downloaded (%s)") % size
74 else:
75 return _("No downloads available!")
77 class ImplementationList:
78 tree_view = None
79 model = None
80 interface = None
81 policy = None
83 def __init__(self, policy, interface, widgets):
84 self.interface = interface
85 self.policy = policy
87 self.model = gtk.ListStore(object, str, str, str, # Item, arch, stability, version,
88 str, gobject.TYPE_BOOLEAN, str, str, int) # fetch, unusable, released, notes, weight
90 self.tree_view = widgets.get_widget('versions_list')
91 self.tree_view.set_model(self.model)
93 text = gtk.CellRendererText()
94 text_strike = gtk.CellRendererText()
96 stability = gtk.TreeViewColumn(_('Stability'), text, text = STABILITY)
98 for column in (gtk.TreeViewColumn(_('Version'), text_strike, text = VERSION, strikethrough = UNUSABLE, weight = WEIGHT),
99 gtk.TreeViewColumn(_('Released'), text, text = RELEASED, weight = WEIGHT),
100 stability,
101 gtk.TreeViewColumn(_('Fetch'), text, text = FETCH, weight = WEIGHT),
102 gtk.TreeViewColumn(_('Arch'), text_strike, text = ARCH, strikethrough = UNUSABLE, weight = WEIGHT),
103 gtk.TreeViewColumn(_('Notes'), text, text = NOTES, weight = WEIGHT)):
104 self.tree_view.append_column(column)
106 tips = ImplTips(policy, interface)
108 def motion(tree_view, ev):
109 if ev.window is not tree_view.get_bin_window():
110 return False
111 pos = tree_view.get_path_at_pos(int(ev.x), int(ev.y))
112 if pos:
113 path = pos[0]
114 row = self.model[path]
115 if row[ITEM] is not tips.item:
116 tips.prime(tree_view, row[ITEM])
117 else:
118 tips.hide()
120 self.tree_view.connect('motion-notify-event', motion)
121 self.tree_view.connect('leave-notify-event', lambda tv, ev: tips.hide())
122 self.tree_view.connect('destroy', lambda tv: tips.hide())
124 def button_press(tree_view, bev):
125 if bev.button not in (1, 3):
126 return False
127 pos = tree_view.get_path_at_pos(int(bev.x), int(bev.y))
128 if not pos:
129 return False
130 path, col, x, y = pos
131 impl = self.model[path][ITEM]
133 menu = gtk.Menu()
135 stability_menu = gtk.MenuItem(_('Rating'))
136 stability_menu.set_submenu(_build_stability_menu(self.policy, impl))
137 stability_menu.show()
138 menu.append(stability_menu)
140 if self.policy.get_cached(impl):
141 def open():
142 os.spawnlp(os.P_WAIT, '0launch',
143 '0launch', rox_filer, '-d',
144 self.policy.get_implementation_path(impl))
145 item = gtk.MenuItem(_('Open cached copy'))
146 item.connect('activate', lambda item: open())
147 item.show()
148 menu.append(item)
150 menu.popup(None, None, None, bev.button, bev.time)
152 self.tree_view.connect('button-press-event', button_press)
154 def get_selection(self):
155 return self.tree_view.get_selection()
157 def set_items(self, items):
158 self.model.clear()
159 selected = self.policy.solver.selections.get(self.interface, None)
160 for item, unusable in items:
161 new = self.model.append()
162 self.model[new][ITEM] = item
163 self.model[new][VERSION] = item.get_version()
164 self.model[new][RELEASED] = item.released or "-"
165 self.model[new][FETCH] = utils.get_fetch_info(self.policy, item)
166 if item.user_stability:
167 if item.user_stability == model.insecure:
168 self.model[new][STABILITY] = _('INSECURE')
169 elif item.user_stability == model.buggy:
170 self.model[new][STABILITY] = _('BUGGY')
171 elif item.user_stability == model.developer:
172 self.model[new][STABILITY] = _('DEVELOPER')
173 elif item.user_stability == model.testing:
174 self.model[new][STABILITY] = _('TESTING')
175 elif item.user_stability == model.stable:
176 self.model[new][STABILITY] = _('STABLE')
177 elif item.user_stability == model.packaged:
178 self.model[new][STABILITY] = _('PACKAGED')
179 elif item.user_stability == model.preferred:
180 self.model[new][STABILITY] = _('PREFERRED')
181 else:
182 self.model[new][STABILITY] = _(str(item.upstream_stability) or str(model.testing))
183 self.model[new][ARCH] = item.arch or _('any')
184 if selected == item:
185 self.model[new][WEIGHT] = pango.WEIGHT_BOLD
186 else:
187 self.model[new][WEIGHT] = pango.WEIGHT_NORMAL
188 self.model[new][UNUSABLE] = bool(unusable)
189 self.model[new][NOTES] = _(unusable)
191 def clear(self):
192 self.model.clear()