Only show two decimal places for download progress percentages.
[zeroinstall.git] / zeroinstall / 0launch-gui / impl_list.py
blob2602660d9fbe5ecab3ef085366fa96497aac6000
1 import gtk, gobject, os
2 from zeroinstall.injector import model, writer
3 from zeroinstall import support
4 from treetips import TreeTips
6 def popup_menu(bev, values, fn):
7 menu = gtk.Menu()
8 for value in values:
9 if value is None:
10 item = gtk.SeparatorMenuItem()
11 else:
12 item = gtk.MenuItem(str(value).capitalize())
13 item.connect('activate', lambda item, v=value: fn(v))
14 item.show()
15 menu.append(item)
16 menu.popup(None, None, None, bev.button, bev.time)
18 rox_filer = 'http://rox.sourceforge.net/2005/interfaces/ROX-Filer'
20 # Columns
21 ITEM = 0
22 ARCH = 1
23 STABILITY = 2
24 VERSION = 3
25 CACHED = 4
26 UNUSABLE = 5
27 RELEASED = 6
28 NOTES = 7
30 class ImplTips(TreeTips):
31 def __init__(self, policy, interface):
32 self.policy = policy
33 self.interface = interface
35 def get_tooltip_text(self, impl):
36 if impl.id.startswith('/'):
37 return _("Local: %s") % impl.id
38 if impl.id.startswith('package:'):
39 return _("Native package: %s") % impl.id.split(':', 1)[1]
40 if self.policy.get_cached(impl):
41 return _("Cached: %s") % self.policy.get_implementation_path(impl)
43 src = self.policy.fetcher.get_best_source(impl)
44 if src:
45 size = support.pretty_size(src.size)
46 return _("Not yet downloaded (%s)") % size
47 else:
48 return _("No downloads available!")
50 class ImplementationList:
51 tree_view = None
52 model = None
53 interface = None
54 policy = None
56 def __init__(self, policy, interface, widgets):
57 self.interface = interface
58 self.policy = policy
60 self.model = gtk.ListStore(object, str, str, str,
61 gobject.TYPE_BOOLEAN, gobject.TYPE_BOOLEAN,
62 str, str)
64 self.tree_view = widgets.get_widget('versions_list')
65 self.tree_view.set_model(self.model)
67 text = gtk.CellRendererText()
68 text_strike = gtk.CellRendererText()
69 toggle = gtk.CellRendererToggle()
71 stability = gtk.TreeViewColumn('Stability', text, text = STABILITY)
73 for column in (gtk.TreeViewColumn('Version', text, text = VERSION, strikethrough = UNUSABLE),
74 gtk.TreeViewColumn('Released', text, text = RELEASED, strikethrough = UNUSABLE),
75 stability,
76 gtk.TreeViewColumn('C', toggle, active = CACHED),
77 gtk.TreeViewColumn('Arch', text, text = ARCH),
78 gtk.TreeViewColumn('Notes', text, text = NOTES)):
79 self.tree_view.append_column(column)
81 tips = ImplTips(policy, interface)
83 def motion(tree_view, ev):
84 if ev.window is not tree_view.get_bin_window():
85 return False
86 pos = tree_view.get_path_at_pos(int(ev.x), int(ev.y))
87 if pos:
88 path = pos[0]
89 row = self.model[path]
90 if row[ITEM] is not tips.item:
91 tips.prime(tree_view, row[ITEM])
92 else:
93 tips.hide()
95 self.tree_view.connect('motion-notify-event', motion)
96 self.tree_view.connect('leave-notify-event', lambda tv, ev: tips.hide())
97 self.tree_view.connect('destroy', lambda tv: tips.hide())
99 def button_press(tree_view, bev):
100 if bev.button not in (1, 3):
101 return False
102 pos = tree_view.get_path_at_pos(int(bev.x), int(bev.y))
103 if not pos:
104 return False
105 path, col, x, y = pos
106 impl = self.model[path][ITEM]
107 if col == stability:
108 upstream = impl.upstream_stability or model.testing
109 choices = model.stability_levels.values()
110 choices.sort()
111 choices.reverse()
112 def set(new):
113 if isinstance(new, model.Stability):
114 impl.user_stability = new
115 else:
116 impl.user_stability = None
117 writer.save_interface(interface)
118 self.policy.recalculate()
119 popup_menu(bev, ['Unset (%s)' % upstream, None] + choices,
120 set)
121 elif bev.button == 3 and self.policy.get_cached(impl):
122 def open(item):
123 os.spawnlp(os.P_WAIT, '0launch',
124 '0launch', rox_filer, '-d',
125 self.policy.get_implementation_path(impl))
126 popup_menu(bev, ['Open cached copy'], open)
127 self.tree_view.connect('button-press-event', button_press)
129 def get_selection(self):
130 return self.tree_view.get_selection()
132 def set_items(self, items):
133 self.model.clear()
134 for item, unusable in items:
135 new = self.model.append()
136 self.model[new][ITEM] = item
137 self.model[new][VERSION] = item.get_version()
138 self.model[new][RELEASED] = item.released or "-"
139 self.model[new][CACHED] = self.policy.get_cached(item)
140 if item.user_stability:
141 self.model[new][STABILITY] = str(item.user_stability).upper()
142 else:
143 self.model[new][STABILITY] = item.upstream_stability or \
144 model.testing
145 self.model[new][ARCH] = item.arch or 'any'
146 self.model[new][UNUSABLE] = bool(unusable)
147 self.model[new][NOTES] = unusable
149 def clear(self):
150 self.model.clear()