Tell the user when a background update completes, not when it starts
[zeroinstall/solver.git] / zeroinstall / 0launch-gui / impl_list.py
blob9226f5bf2de6bd0a2a79429dbed5403fdd2c901a
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 from zeroinstall.gtkui import gtkutils
9 import utils
11 def _build_stability_menu(impl):
12 menu = gtk.Menu()
14 upstream = impl.upstream_stability or model.testing
15 choices = model.stability_levels.values()
16 choices.sort()
17 choices.reverse()
19 def set(new):
20 if isinstance(new, model.Stability):
21 impl.user_stability = new
22 else:
23 impl.user_stability = None
24 writer.save_feed(impl.feed)
25 import main
26 main.recalculate()
28 item = gtk.MenuItem(_('Unset (%s)') % _(str(upstream).capitalize()).lower())
29 item.connect('activate', lambda item: set(None))
30 item.show()
31 menu.append(item)
33 item = gtk.SeparatorMenuItem()
34 item.show()
35 menu.append(item)
37 for value in choices:
38 item = gtk.MenuItem(_(str(value)).capitalize())
39 item.connect('activate', lambda item, v = value: set(v))
40 item.show()
41 menu.append(item)
43 return menu
45 rox_filer = 'http://rox.sourceforge.net/2005/interfaces/ROX-Filer'
47 # Columns
48 ITEM = 0
49 ARCH = 1
50 STABILITY = 2
51 VERSION = 3
52 FETCH = 4
53 UNUSABLE = 5
54 RELEASED = 6
55 NOTES = 7
56 WEIGHT = 8 # Selected item is bold
57 LANGS = 9
59 def get_tooltip_text(config, interface, impl):
60 if impl.local_path:
61 return _("Local: %s") % impl.local_path
62 if impl.id.startswith('package:'):
63 return _("Native package: %s") % impl.id.split(':', 1)[1]
64 if impl.is_available(config.stores):
65 return _("Cached: %s") % config.stores.lookup_any(impl.digests)
67 src = config.fetcher.get_best_source(impl)
68 if src:
69 size = support.pretty_size(src.size)
70 return _("Not yet downloaded (%s)") % size
71 else:
72 return _("No downloads available!")
74 class ImplementationList:
75 tree_view = None
76 model = None
77 interface = None
78 driver = None
80 def __init__(self, driver, interface, widgets):
81 self.interface = interface
82 self.driver = driver
84 self.model = gtk.ListStore(object, str, str, str, # Item, arch, stability, version,
85 str, gobject.TYPE_BOOLEAN, str, str, # fetch, unusable, released, notes,
86 int, str) # weight, langs
88 self.tree_view = widgets.get_widget('versions_list')
89 self.tree_view.set_model(self.model)
91 text = gtk.CellRendererText()
92 text_strike = gtk.CellRendererText()
94 stability = gtk.TreeViewColumn(_('Stability'), text, text = STABILITY)
96 for column in (gtk.TreeViewColumn(_('Version'), text_strike, text = VERSION, strikethrough = UNUSABLE, weight = WEIGHT),
97 gtk.TreeViewColumn(_('Released'), text, text = RELEASED, weight = WEIGHT),
98 stability,
99 gtk.TreeViewColumn(_('Fetch'), text, text = FETCH, weight = WEIGHT),
100 gtk.TreeViewColumn(_('Arch'), text_strike, text = ARCH, strikethrough = UNUSABLE, weight = WEIGHT),
101 gtk.TreeViewColumn(_('Lang'), text_strike, text = LANGS, strikethrough = UNUSABLE, weight = WEIGHT),
102 gtk.TreeViewColumn(_('Notes'), text, text = NOTES, weight = WEIGHT)):
103 self.tree_view.append_column(column)
105 self.tree_view.set_property('has-tooltip', True)
106 def tooltip_callback(widget, x, y, keyboard_mode, tooltip):
107 x, y = self.tree_view.convert_widget_to_bin_window_coords(x, y)
108 pos = self.tree_view.get_path_at_pos(x, y)
109 if pos:
110 self.tree_view.set_tooltip_cell(tooltip, pos[0], None, None)
111 path = pos[0]
112 row = self.model[path]
113 if row[ITEM]:
114 tooltip.set_text(get_tooltip_text(driver.config, interface, row[ITEM]))
115 return True
116 return False
117 self.tree_view.connect('query-tooltip', tooltip_callback)
119 def button_press(tree_view, bev):
120 if bev.button not in (1, 3):
121 return False
122 pos = tree_view.get_path_at_pos(int(bev.x), int(bev.y))
123 if not pos:
124 return False
125 path, col, x, y = pos
126 impl = self.model[path][ITEM]
128 menu = gtk.Menu()
130 stability_menu = gtk.MenuItem(_('Rating'))
131 stability_menu.set_submenu(_build_stability_menu(impl))
132 stability_menu.show()
133 menu.append(stability_menu)
135 if not impl.id.startswith('package:') and impl.is_available(self.driver.config.stores):
136 def open():
137 os.spawnlp(os.P_WAIT, '0launch',
138 '0launch', rox_filer, '-d',
139 impl.local_path or self.driver.config.stores.lookup_any(impl.digests))
140 item = gtk.MenuItem(_('Open cached copy'))
141 item.connect('activate', lambda item: open())
142 item.show()
143 menu.append(item)
145 item = gtk.MenuItem(_('Explain this decision'))
146 item.connect('activate', lambda item: self.show_explaination(impl))
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 show_explaination(self, impl):
155 reason = self.driver.solver.justify_decision(self.driver.requirements, self.interface, impl)
156 gtkutils.show_message_box(self.tree_view.get_toplevel(), reason, gtk.MESSAGE_INFO)
158 def get_selection(self):
159 return self.tree_view.get_selection()
161 def set_items(self, items):
162 self.model.clear()
163 selected = self.driver.solver.selections.get(self.interface, None)
164 for item, unusable in items:
165 new = self.model.append()
166 self.model[new][ITEM] = item
167 self.model[new][VERSION] = item.get_version()
168 self.model[new][RELEASED] = item.released or "-"
169 self.model[new][FETCH] = utils.get_fetch_info(self.driver.config, item)
170 if item.user_stability:
171 if item.user_stability == model.insecure:
172 self.model[new][STABILITY] = _('INSECURE')
173 elif item.user_stability == model.buggy:
174 self.model[new][STABILITY] = _('BUGGY')
175 elif item.user_stability == model.developer:
176 self.model[new][STABILITY] = _('DEVELOPER')
177 elif item.user_stability == model.testing:
178 self.model[new][STABILITY] = _('TESTING')
179 elif item.user_stability == model.stable:
180 self.model[new][STABILITY] = _('STABLE')
181 elif item.user_stability == model.packaged:
182 self.model[new][STABILITY] = _('PACKAGED')
183 elif item.user_stability == model.preferred:
184 self.model[new][STABILITY] = _('PREFERRED')
185 else:
186 self.model[new][STABILITY] = _(str(item.upstream_stability) or str(model.testing))
187 self.model[new][ARCH] = item.arch or _('any')
188 if selected is item:
189 self.model[new][WEIGHT] = pango.WEIGHT_BOLD
190 else:
191 self.model[new][WEIGHT] = pango.WEIGHT_NORMAL
192 self.model[new][UNUSABLE] = bool(unusable)
193 self.model[new][LANGS] = item.langs or '-'
194 self.model[new][NOTES] = unusable and _(unusable) or _('None')
196 def clear(self):
197 self.model.clear()