Improved UI for versions menu
[zeroinstall/zeroinstall-rsl.git] / zeroinstall / 0launch-gui / impl_list.py
blobdabb4313d10856d7b5087a5d899a3287f8431601
1 # Copyright (C) 2009, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
4 import gtk, gobject, os
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
55 class ImplTips(TreeTips):
56 def __init__(self, policy, interface):
57 self.policy = policy
58 self.interface = interface
60 def get_tooltip_text(self):
61 impl = self.item
62 if impl.id.startswith('/'):
63 return _("Local: %s") % impl.id
64 if impl.id.startswith('package:'):
65 return _("Native package: %s") % impl.id.split(':', 1)[1]
66 if self.policy.get_cached(impl):
67 return _("Cached: %s") % self.policy.get_implementation_path(impl)
69 src = self.policy.fetcher.get_best_source(impl)
70 if src:
71 size = support.pretty_size(src.size)
72 return _("Not yet downloaded (%s)") % size
73 else:
74 return _("No downloads available!")
76 class ImplementationList:
77 tree_view = None
78 model = None
79 interface = None
80 policy = None
82 def __init__(self, policy, interface, widgets):
83 self.interface = interface
84 self.policy = policy
86 self.model = gtk.ListStore(object, str, str, str, # Item, arch, stability, version,
87 str, gobject.TYPE_BOOLEAN, str, str) # fetch, unusable, released, notes
89 self.tree_view = widgets.get_widget('versions_list')
90 self.tree_view.set_model(self.model)
92 text = gtk.CellRendererText()
93 text_strike = gtk.CellRendererText()
95 stability = gtk.TreeViewColumn(_('Stability'), text, text = STABILITY)
97 for column in (gtk.TreeViewColumn(_('Version'), text_strike, text = VERSION, strikethrough = UNUSABLE),
98 gtk.TreeViewColumn(_('Released'), text, text = RELEASED),
99 stability,
100 gtk.TreeViewColumn(_('Fetch'), text, text = FETCH),
101 gtk.TreeViewColumn(_('Arch'), text_strike, text = ARCH, strikethrough = UNUSABLE),
102 gtk.TreeViewColumn(_('Notes'), text, text = NOTES)):
103 self.tree_view.append_column(column)
105 tips = ImplTips(policy, interface)
107 def motion(tree_view, ev):
108 if ev.window is not tree_view.get_bin_window():
109 return False
110 pos = tree_view.get_path_at_pos(int(ev.x), int(ev.y))
111 if pos:
112 path = pos[0]
113 row = self.model[path]
114 if row[ITEM] is not tips.item:
115 tips.prime(tree_view, row[ITEM])
116 else:
117 tips.hide()
119 self.tree_view.connect('motion-notify-event', motion)
120 self.tree_view.connect('leave-notify-event', lambda tv, ev: tips.hide())
121 self.tree_view.connect('destroy', lambda tv: tips.hide())
123 def button_press(tree_view, bev):
124 if bev.button not in (1, 3):
125 return False
126 pos = tree_view.get_path_at_pos(int(bev.x), int(bev.y))
127 if not pos:
128 return False
129 path, col, x, y = pos
130 impl = self.model[path][ITEM]
132 menu = gtk.Menu()
134 stability_menu = gtk.MenuItem('Rating')
135 stability_menu.set_submenu(_build_stability_menu(self.policy, impl))
136 stability_menu.show()
137 menu.append(stability_menu)
139 if self.policy.get_cached(impl):
140 def open():
141 os.spawnlp(os.P_WAIT, '0launch',
142 '0launch', rox_filer, '-d',
143 self.policy.get_implementation_path(impl))
144 item = gtk.MenuItem('Open cached copy')
145 item.connect('activate', lambda item: open())
146 item.show()
147 menu.append(item)
149 menu.popup(None, None, None, bev.button, bev.time)
151 self.tree_view.connect('button-press-event', button_press)
153 def get_selection(self):
154 return self.tree_view.get_selection()
156 def set_items(self, items):
157 self.model.clear()
158 for item, unusable in items:
159 new = self.model.append()
160 self.model[new][ITEM] = item
161 self.model[new][VERSION] = item.get_version()
162 self.model[new][RELEASED] = item.released or "-"
163 self.model[new][FETCH] = utils.get_fetch_info(self.policy, item)
164 if item.user_stability:
165 self.model[new][STABILITY] = str(item.user_stability).upper()
166 else:
167 self.model[new][STABILITY] = item.upstream_stability or \
168 model.testing
169 self.model[new][ARCH] = item.arch or 'any'
170 self.model[new][UNUSABLE] = bool(unusable)
171 self.model[new][NOTES] = unusable
173 def clear(self):
174 self.model.clear()