1 from zeroinstall
.injector
.model
import *
2 from zeroinstall
.injector
import writer
6 from dialog
import Dialog
8 from impl_list
import ImplementationList
12 _dialogs
= {} # Interface -> Properties
25 def format_para(para
):
26 lines
= [l
.strip() for l
in para
.split('\n')]
27 return ' '.join(lines
)
29 class Description(gtk
.ScrolledWindow
):
31 gtk
.ScrolledWindow
.__init
__(self
, None, None)
32 self
.set_shadow_type(gtk
.SHADOW_IN
)
33 self
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_ALWAYS
)
34 description
= gtk
.TextView()
35 description
.set_left_margin(4)
36 description
.set_right_margin(4)
37 description
.set_wrap_mode(gtk
.WRAP_WORD
)
38 description
.set_editable(False)
39 description
.set_cursor_visible(False)
42 self
.buffer = description
.get_buffer()
43 self
.heading_style
= self
.buffer.create_tag(underline
= True, scale
= 1.2)
44 description
.set_size_request(-1, 100)
46 def set_details(self
, interface
):
48 heading_style
= self
.heading_style
50 buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
52 iter = buffer.get_start_iter()
54 buffer.insert_with_tags(iter,
55 '%s (%s)' % (interface
.get_name(), interface
.summary
), heading_style
)
57 buffer.insert(iter, '\n%s\n' % interface
.uri
)
59 # (converts to local time)
60 if interface
.last_modified
:
61 buffer.insert(iter, '\nLast upstream change: %s' % time
.ctime(interface
.last_modified
))
63 if interface
.last_checked
:
64 buffer.insert(iter, '\nLast checked: %s' % time
.ctime(interface
.last_checked
))
66 if hasattr(interface
, 'feeds') and interface
.feeds
:
67 for feed
in interface
.feeds
:
68 if hasattr(feed
, 'uri'):
70 buffer.insert(iter, '\nFeed: %s' % feed
)
72 buffer.insert_with_tags(iter, '\n\nDescription\n', heading_style
)
74 paragraphs
= [format_para(p
) for p
in (interface
.description
or "-").split('\n\n')]
76 buffer.insert(iter, '\n\n'.join(paragraphs
))
79 class Properties(Dialog
):
83 def __init__(self
, interface
):
85 self
.interface
= interface
86 self
.set_title('Interface ' + interface
.get_name())
87 self
.set_default_size(gtk
.gdk
.screen_width() / 2,
88 gtk
.gdk
.screen_height() / 3)
90 vbox
= gtk
.VBox(False, 4)
91 vbox
.set_border_width(4)
92 self
.vbox
.pack_start(vbox
, True, True, 0)
94 self
.add_button(gtk
.STOCK_HELP
, gtk
.RESPONSE_HELP
)
95 add_feed_button
= self
.add_mixed_button(_('Add Local Feed...'),
96 gtk
.STOCK_ADD
, ADD_FEED
)
97 self
.add_button(gtk
.STOCK_CLOSE
, gtk
.RESPONSE_CANCEL
)
98 self
.set_default_response(gtk
.RESPONSE_CANCEL
)
100 tips
.set_tip(add_feed_button
,
101 _('If you have another implementation of this interface (e.g., a '
102 'CVS checkout), you can add it to the list by registering the XML '
103 'feed file that came with it.'))
105 def response(dialog
, resp
):
106 if resp
== gtk
.RESPONSE_CANCEL
:
109 # policy.begin_iface_download(interface, True)
110 elif resp
== gtk
.RESPONSE_HELP
:
111 properties_help
.display()
112 elif resp
== ADD_FEED
:
114 self
.connect('response', response
)
116 main_hbox
= gtk
.HBox(False, 5)
117 vbox
.pack_start(main_hbox
, True, True, 0)
119 description
= Description()
120 description
.set_details(interface
)
121 main_hbox
.pack_start(description
, True, True, 0)
123 main_hbox
.pack_start(self
.build_versions_column(interface
), False, True, 0)
130 description
.set_details(interface
)
131 self
.connect('destroy', lambda s
: policy
.watchers
.remove(updated
))
132 policy
.watchers
.append(updated
)
134 def update_list(self
):
135 impls
= policy
.get_ranked_implementations(self
.interface
)
136 self
.use_list
.set_items(impls
)
138 def build_versions_column(self
, interface
):
139 assert self
.use_list
is None
141 vbox
= gtk
.VBox(False, 2)
143 hbox
= gtk
.HBox(False, 2)
144 vbox
.pack_start(hbox
, False, True, 2)
147 stability
= gtk
.combo_box_new_text()
149 stability
.append_text('Use default setting')
150 stability
.set_active(0)
151 for i
, x
in enumerate((stable
, testing
, developer
)):
152 stability
.append_text(str(x
).capitalize())
153 if x
is interface
.stability_policy
:
154 stability
.set_active(i
+ 1)
155 hbox
.pack_start(gtk
.Label('Preferred stability:'), False, True, 2)
156 hbox
.pack_start(eb
, True, True, 0)
157 def set_stability_policy(combo
):
158 i
= stability
.get_active()
162 name
= stability
.get_model()[i
][0].lower()
163 new_stability
= stability_levels
[name
]
164 interface
.set_stability_policy(new_stability
)
165 writer
.save_interface(interface
)
167 stability
.connect('changed', set_stability_policy
)
168 tips
.set_tip(eb
, _('Implementations at this stability level or higher '
169 'will be used in preference to others. You can use this '
170 'to override the global "Help test new versions" setting '
171 'just for this interface.'))
173 self
.use_list
= ImplementationList(interface
)
174 self
.use_list
.set_policy(gtk
.POLICY_NEVER
, gtk
.POLICY_AUTOMATIC
)
175 vbox
.pack_start(self
.use_list
, True, True, 2)
179 def add_feed(interface
):
180 sel
= gtk
.FileSelection(_('Select XML feed file'))
182 from xml
.dom
import minidom
183 from zeroinstall
.injector
import reader
184 feed
= sel
.get_filename()
186 if hasattr(policy
, 'get_feed_targets'):
187 feed_targets
= policy
.get_feed_targets(feed
)
188 if interface
not in feed_targets
:
189 raise Exception("Not a valid feed for '%s'; this is a feed for:\n%s" %
191 '\n'.join([f
.uri
for f
in feed_targets
])))
192 if interface
.get_feed(feed
):
193 dialog
.alert(None, 'This feed is already registered.')
195 interface
.feeds
.append(Feed(feed
, user_override
= True, arch
= None))
197 doc
= minidom
.parse(feed
)
198 uri
= doc
.documentElement
.getAttribute('uri')
200 raise Exception("Missing uri attribute in interface file '%s'" % feed
)
201 if uri
!= interface
.uri
:
202 raise Exception("Feed is for interface '%s', not '%s'" %
203 (uri
, interface
.uri
))
204 if feed
in interface
.feeds
:
205 raise Exception("Feed is already registered")
206 interface
.feeds
.append(feed
)
207 writer
.save_interface(interface
)
209 reader
.update_from_cache(interface
)
211 except Exception, ex
:
212 dialog
.alert(None, "Error in feed file '%s':\n\n%s" % (feed
, str(ex
)))
214 sel
.ok_button
.connect('clicked', ok
)
215 sel
.cancel_button
.connect('clicked', lambda b
: sel
.destroy())
219 assert isinstance(interface
, Interface
)
220 if interface
in _dialogs
:
221 _dialogs
[interface
].destroy()
222 _dialogs
[interface
] = Properties(interface
)
223 _dialogs
[interface
].show()
225 properties_help
= help_box
.HelpBox("Injector Properties Help",
226 ('Interface properties', """
227 This window displays information about an interface. On the left is some information \
230 - At the top is its short name.
231 - Below that is the full name; this is also location which is used to update \
233 - 'Last upstream change' shows the version of the cached copy of the interface file.
234 - 'Last checked' is the last time a fresh copy of the upstream interface file was \
236 - 'Local feed' is shown if you have other sources of versions of this program (for \
237 example, a CVS checkout).
238 - Then there is a longer description of the interface."""),
240 ('Implementations', """
241 The right side of the window is a list of all known implementations of the interface. \
242 The columns have the following meanings:
244 Version gives the version number. High-numbered versions are considered to be \
245 better than low-numbered ones.
247 Stability is 'stable' if the implementation is believed to be stable, 'buggy' if \
248 it is known to contain serious bugs, and 'testing' if its stability is not yet \
249 known. This information is normally supplied and updated by the author of the \
250 software, but you can override their rating (overridden values are shown in upper-case). \
251 You can also use the special level 'preferred'.
253 C(ached) indicates whether the implementation is already stored on your computer. \
254 In off-line mode, only cached implementations are considered for use.
256 Arch indicates what kind of computer system the implementation is for, or 'any' \
257 if it works with all types of system.
260 The implementations are listed in the injector's currently preferred order (the one \
261 at the top will actually be used). Usable implementations all come before unusable \
264 Unusable ones are those for incompatible \
265 architectures, those marked as 'buggy', versions explicitly marked as incompatible with \
266 another interface you are using and, in off-line mode, uncached implementations. Unusable \
267 implementations are shown crossed out.
269 For the usable implementations, the order is as follows:
271 - Preferred implementations come first.
273 - Then, if network use is set to 'Minimal', cached implementations come before \
276 - Then, implementations at or above the selected stability level come before all others.
278 - Then, higher-numbered versions come before low-numbered ones.
280 - Then cached come before non-cached (for 'Full' network use mode).