Holding the pointer over an interface in the main window shows a tooltip
[zeroinstall.git] / properties.py
blob2243dac8646458bef1887510e772c0b70ed88001
1 from zeroinstall.injector.model import *
2 from zeroinstall.injector import writer
3 import gtk
5 import help_box
6 from dialog import Dialog
7 from gui import policy
8 from impl_list import ImplementationList
9 import time
11 _dialogs = {} # Interface -> Properties
13 def enumerate(items):
14 x = 0
15 for i in items:
16 yield x, i
17 x += 1
19 class Description(gtk.ScrolledWindow):
20 def __init__(self):
21 gtk.ScrolledWindow.__init__(self, None, None)
22 self.set_shadow_type(gtk.SHADOW_IN)
23 self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
24 description = gtk.TextView()
25 description.set_left_margin(4)
26 description.set_right_margin(4)
27 description.set_wrap_mode(gtk.WRAP_WORD)
28 description.set_editable(False)
29 description.set_cursor_visible(False)
30 self.add(description)
32 self.buffer = description.get_buffer()
33 self.heading_style = self.buffer.create_tag(underline = True, scale = 1.2)
34 description.set_size_request(-1, 100)
36 def set_details(self, interface):
37 buffer = self.buffer
38 heading_style = self.heading_style
40 buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
42 iter = buffer.get_start_iter()
44 buffer.insert_with_tags(iter,
45 '%s (%s)' % (interface.get_name(), interface.summary), heading_style)
47 buffer.insert(iter, '\nFull name: %s' % interface.uri)
49 # (converts to local time)
50 if interface.last_modified:
51 buffer.insert(iter, '\nLast upstream change: %s' % time.ctime(interface.last_modified))
53 if interface.last_checked:
54 buffer.insert(iter, '\nLast checked: %s' % time.ctime(interface.last_checked))
56 if interface.last_local_update:
57 buffer.insert(iter, '\nLast local update: %s' % time.ctime(interface.last_local_update))
59 buffer.insert_with_tags(iter, '\n\nDescription\n', heading_style)
61 buffer.insert(iter, interface.description or "-")
64 class Properties(Dialog):
65 interface = None
66 use_list = None
68 def __init__(self, interface):
69 Dialog.__init__(self)
70 self.interface = interface
71 self.set_title('Interface ' + interface.get_name())
72 self.set_default_size(gtk.gdk.screen_width() / 2,
73 gtk.gdk.screen_height() / 3)
75 vbox = gtk.VBox(False, 4)
76 vbox.set_border_width(4)
77 self.vbox.pack_start(vbox, True, True, 0)
79 self.add_button(gtk.STOCK_HELP, gtk.RESPONSE_HELP)
80 #self.add_button(gtk.STOCK_REFRESH, 1)
81 self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CANCEL)
82 self.set_default_response(gtk.RESPONSE_CANCEL)
84 def response(dialog, resp):
85 if resp == gtk.RESPONSE_CANCEL:
86 self.destroy()
87 #elif resp == 1:
88 # policy.begin_iface_download(interface, True)
89 elif resp == gtk.RESPONSE_HELP:
90 properties_help.display()
91 self.connect('response', response)
93 vpaned = gtk.VPaned()
94 vbox.pack_start(vpaned, True, True, 0)
96 description = Description()
97 description.set_details(interface)
98 vpaned.add1(description)
100 self.use_list = ImplementationList(interface)
101 vpaned.add2(self.use_list)
102 self.use_list.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
104 hbox = gtk.HBox(False, 2)
105 vbox.pack_start(hbox, False, True, 0)
107 stability = gtk.combo_box_new_text()
108 stability.append_text('Use default setting')
109 stability.set_active(0)
110 for i, x in enumerate((stable, testing, developer)):
111 stability.append_text(str(x).capitalize())
112 if x is interface.stability_policy:
113 stability.set_active(i + 1)
114 hbox.pack_start(gtk.Label('Preferred stability:'), False, True, 0)
115 hbox.pack_start(stability, False, True, 0)
116 def set_stability_policy(combo):
117 i = stability.get_active()
118 if i == 0:
119 new_stability = None
120 else:
121 name = stability.get_model()[i][0].lower()
122 new_stability = stability_levels[name]
123 interface.set_stability_policy(new_stability)
124 writer.save_interface(interface)
125 policy.recalculate()
126 stability.connect('changed', set_stability_policy)
128 self.update_list()
129 vbox.show_all()
131 def updated():
132 self.update_list()
133 description.set_details(interface)
134 self.connect('destroy', lambda s: policy.watchers.remove(updated))
135 policy.watchers.append(updated)
137 def update_list(self):
138 impls = policy.get_ranked_implementations(self.interface)
139 self.use_list.set_items(impls)
141 def edit(interface):
142 assert isinstance(interface, Interface)
143 if interface in _dialogs:
144 _dialogs[interface].destroy()
145 _dialogs[interface] = Properties(interface)
146 _dialogs[interface].show()
148 properties_help = help_box.HelpBox("Injector Properties Help",
149 ('Interface properties', """
150 This window displays information about an interface. At the top is the interface's \
151 short name, unique ID, summary and long description. The unique ID is also the \
152 location which is used to update the information."""),
154 ('Dates and times', """
155 Up to three times may be displayed:
156 - 'Last upstream change' shows the version of the cached copy of the interface file.
157 - 'Last checked' is the last time a fresh copy of the upstream interface file was \
158 downloaded.
159 - 'Last local update' is the modification time of your local additions to the interface. \
160 You'll only have this displayed if you have made your own custom versions of a program."""),
162 ('Implementations', """
163 The main part of the window is a list of all known implementations of the interface. \
164 The columns have the following meanings:
166 Version gives the version number. High-numbered versions are considered to be \
167 better than low-numbered ones.
169 Stability is 'stable' if the implementation is believed to be stable, 'buggy' if \
170 it is known to contain serious bugs, and 'testing' if its stability is not yet \
171 known. This information is normally supplied and updated by the author of the \
172 software, but you can override their rating (overridden values are shown in upper-case). \
173 You can also use the special level 'preferred'.
175 C(ached) indicates whether the implementation is already stored on your computer. \
176 In off-line mode, only cached implementations are considered for use.
178 Arch indicates what kind of computer system the implementation is for, or 'any' \
179 if it works with all types of system.
181 ID is the unique identifier for the implementation. Normally, this is a cryptographic \
182 digest of it's contents, but it can also be a simple path name.
183 """),
184 ('Sort order', """
185 The implementations are listed in the injector's currently preferred order (the one \
186 at the top will actually be used). Usable implementations all come before unusable \
187 ones.
189 Unusable ones are those for incompatible \
190 architectures, those marked as 'buggy', versions explicitly marked as incompatible with \
191 another interface you are using and, in off-line mode, uncached implementations. Unusable \
192 implementations are shown crossed out.
194 For the usable implementations, the order is as follows:
196 - Preferred implementations come first.
198 - Then, if network use is set to 'Minimal', cached implementations come before \
199 non-cached.
201 - Then, implementations at or above the selected stability level come before all others.
203 - Then, higher-numbered versions come before low-numbered ones.
205 - Then cached come before non-cached (for 'Full' network use mode).
206 """))