1 '''
2 Defines reusable gtk widgets for ordering L{AEUserInterface}s and setting them to
3 load or not load at runtime.
4
5 @var RAISE: Raise priority of a L{AEUserInterface} for handling events or getting
6 loaded
7 @type RAISE: integer
8 @var LOWER: Lower priority of a L{AEUserInterface} for handling events or getting
9 loaded
10 @type LOWER: integer
11 @var TO_LOAD: Indicates a L{AEUserInterface} is now set to be loaded
12 @type TO_LOAD: integer
13 @var TO_UNLOAD: Indicates a L{AEUserInterface} is now set to be unloaded
14 @type TO_UNLOAD: integer
15
16 @author: Peter Parente
17 @organization: IBM Corporation
18 @copyright: Copyright (c) 2005, 2007 IBM Corporation
19 @license: The BSD License
20
21 All rights reserved. This program and the accompanying materials are made
22 available under the terms of the BSD license which accompanies
23 this distribution, and is available at
24 U{http://www.opensource.org/licenses/bsd-license.php}
25 '''
26 import pygtk
27 pygtk.require('2.0')
28 import gtk, gobject
29 import gtk.glade
30 import weakref
31 from Tools.i18n import _, DOMAIN
32
33
34 RAISE = 0
35 LOWER = 1
36 TO_LOAD = 2
37 TO_UNLOAD = 3
38
40 '''
41 Reusable viewer for L{AEUserInterface}s. Shows the name and description of all
42 elements. If constructed with the ordered flag set, allows reordering of
43 elements using raise and lower buttons. If constructed with the activatable
44 flag set, allows for selecting UIEs to load or not load.
45
46 @ivar chooser: Chooser that is showing this view
47 @type chooser: weakref.proxy for L{AccessEngine.AEChooser}
48 @ivar loaded: Class names, names, and descriptions of all loaded
49 L{AccessEngine.AEUserInterface}s
50 @type loaded: list of 3-tuple of string
51 @ivar unloaded: Class names, names, and descriptions of all L{AEUserInterface}s
52 @type unloaded: list of 3-tuple of string
53 @ivar uie_tv: List view of all L{AccessEngine.AEUserInterface}s
54 @type uie_tv: gtk.TreeView
55 @ivar lower_button: button to lower priority of L{AccessEngine.AEScript}s
56 @type lower_button: gtk.Button
57 @ivar raise_button: button to raise priority of L{AccessEngine.AEScript}s
58 @type raise_button: gtk.Button
59 @ivar changed: Has the view been maniuplated in any way?
60 @type changed: boolean
61 '''
62 - def __init__(self, chooser, ordered=True, activatable=True, wrap=450):
63 '''
64 Initializes the view by constructing the list view and populating it with
65 data.
66
67 @param chooser: Chooser that is showing this view
68 @type chooser: L{AccessEngine.AEChooser}
69 @param ordered: Can loaded items be reordered?
70 @type ordered: boolean
71 @param activatable: Can items be set to load/unload?
72 @type activatable: boolean
73 @param wrap: Width in pixels at which to wrap description text
74 @type wrap: integer
75 '''
76 self.changed = False
77
78 self.chooser = weakref.proxy(chooser)
79
80
81 if ordered:
82 name = 'ordered vbox'
83 else:
84 name = 'unordered scrollwindow'
85
86
87 source = gtk.glade.XML(chooser._getResource('uie_widget.glade'),
88 name, DOMAIN)
89
90
91 self.uie_tv = source.get_widget('uie treeview')
92 self.root = source.get_widget(name)
93
94
95 model = gtk.ListStore(str, str, str, bool)
96 self.uie_tv.set_model(model)
97
98
99 col = gtk.TreeViewColumn(_('Name'))
100 rend = gtk.CellRendererText()
101 if activatable:
102 rend2 = gtk.CellRendererToggle()
103 rend2.set_property('activatable', True)
104 col.pack_end(rend2, False)
105 col.set_attributes(rend2, active=3)
106
107 rend2.connect('toggled', self._onToggleLoad, model, 3)
108 col.pack_start(rend, True)
109 col.set_attributes(rend, text=1)
110 self.uie_tv.append_column(col)
111
112 rend = gtk.CellRendererText()
113 rend.set_property('wrap-width', wrap)
114 col = gtk.TreeViewColumn(_('Description'), rend, text=2)
115 self.uie_tv.append_column(col)
116
117
118 self.raise_button = source.get_widget('raise button')
119 self.lower_button = source.get_widget('lower button')
120
121
122 source.signal_autoconnect(self)
123
125 '''
126 Gets if the order or load/unload status has been changed by the user.
127
128 @return: Has the view been manipulated in any way?
129 @rtype: boolean
130 '''
131 return self.changed
132
133 - def setData(self, loaded, unloaded):
134 '''
135 Sets the L{AEUserInterface} data to be shown by the list view. Puts the
136 cursor on the first item if it exists.
137
138 @param loaded: Class names, names, and descriptions of all loaded
139 L{AEUserInterface}s
140 @type loaded: list of 3-tuple of string
141 @param unloaded: Class names, names, and descriptions of all
142 L{AEUserInterface}s
143 @type unloaded: list of 3-tuple of string
144 '''
145 model = self.uie_tv.get_model()
146
147 self.loaded = [metadata+(True,) for metadata in loaded]
148 self.unloaded = [metadata+(False,) for metadata in unloaded]
149
150
151 map(model.append, self.loaded)
152 map(model.append, self.unloaded)
153
154
155 first = model.get_iter_first()
156 if first is not None:
157 self.uie_tv.set_cursor_on_cell(model.get_path(first))
158
160 '''
161 @return: Count of the number of L{AccessEngine.AEScript}s set to load
162 @rtype: integer
163 '''
164 scripts = self.uie_tv.get_model()
165 return len([row[0] for row in scripts if row[3]])
166
176
178 '''
179 Returns the list of all L{AEUserInterface}s.
180
181 @return: All L{AEUserInterface} class names
182 @rtype: list of string
183 '''
184 return [row[0] for row in model]
185
187 '''
188 Returns the new loaded/unloaded L{AEUserInterface} configuration.
189
190 @return: 2-tuple of loaded, unloaded L{AEUserInterface} class names
191 @rtype: 2-tuple of list, list
192 '''
193 model = self.uie_tv.get_model()
194 loaded = [row[0] for row in model if row[3]]
195 unloaded = [row[0] for row in model if not row[3]]
196 return loaded, unloaded
197
199 '''
200 Sets a L{AEUserInterface} to load or unload. Moves the UIE to the top of the
201 load order if it is now set to load or to the bottom of the entire list if
202 it is set to unload.
203
204 @param cell: Cell toggled
205 @type cell: gtk.TreeViewCell
206 @param path: Path to the row toggled
207 @type path: tuple
208 @param model: Model for the gtk.TreeView
209 @type model: gtk.ListStore
210 @param column: Column in the model that the toggle should affect
211 @type column: integer
212 '''
213 self.changed = True
214 val = not model[path][column]
215
216 model[path][column] = val
217 if self.raise_button is None:
218
219 return
220 if val == True:
221
222 iter = model.get_iter(path)
223 model.move_after(iter, None)
224 self.uie_tv.scroll_to_cell((0,))
225 self.chooser._signal(TO_LOAD, name=model[0][1])
226 self.raise_button.set_sensitive(False)
227 self.lower_button.set_sensitive(True)
228 else:
229
230 iter = model.get_iter(path)
231 last = reduce(lambda x, s: s + int(x), [r[3] for r in model], 0)
232 new_path = (last,)
233 new_iter = model.get_iter(new_path)
234 model.move_after(iter, new_iter)
235 self.uie_tv.scroll_to_cell(new_path)
236 self.chooser._signal(TO_UNLOAD, name=model[last][1])
237 self.raise_button.set_sensitive(False)
238 self.lower_button.set_sensitive(False)
239
241 '''
242 Handles 'raise' button 'clicked' events. Determines the current selected
243 item in 'loaded' list, raises its index (loaded priority) so it displays at
244 a higher position.
245
246 @param widget: Source of GUI event
247 @type widget: gtk.Widget
248 '''
249 model = self.uie_tv.get_model()
250 path, col = self.uie_tv.get_cursor()
251 if path is not None:
252 self.changed = True
253 row = path[0]
254 new_path = (row-1,)
255
256 iter1 = model.get_iter(path)
257 iter2 = model.get_iter(new_path)
258 model.swap(iter1, iter2)
259
260 if row < self._getLoadedCount():
261 below = model[row][1]
262 else:
263 below = None
264 if row-2 >= 0:
265 above = model[row-2][1]
266 else:
267 above = None
268 self.chooser._signal(RAISE, above=above, below=below,
269 name=model[row-1][1])
270 self.uie_tv.scroll_to_cell(new_path)
271 self._onCursorChanged(self.uie_tv)
272
274 '''
275 Handles 'lower' button 'clicked' events. Determines the current selected
276 item in 'loaded' list, lower its index (loaded priority) so it displays at
277 a lower position.
278
279 @param widget: Source of GUI event
280 @type widget: gtk.Widget
281 '''
282 model = self.uie_tv.get_model()
283 path, col = self.uie_tv.get_cursor()
284 if path is not None:
285 self.changed = True
286 row = path[0]
287 new_path = (row+1,)
288
289 iter1 = model.get_iter(path)
290 iter2 = model.get_iter(new_path)
291 model.swap(iter1, iter2)
292
293 if row+2 < self._getLoadedCount():
294 below = model[row+2][1]
295 else:
296 below = None
297 if row >= 0:
298 above = model[row][1]
299 else:
300 above = None
301 self.chooser._signal(LOWER, above=above, below=below,
302 name=model[row+1][1])
303
304 self.uie_tv.scroll_to_cell(new_path)
305
306 self._onCursorChanged(self.uie_tv)
307
309 '''
310 Determines whether or not raise/lower button should be enabled (in Gtk
311 terms, whether or not the 'sensitive' flag is set to True). If current
312 selection is at top, disable 'raise' button; if selection is at bottom,
313 disable 'lower' button. This only affects usability, not functionality;
314 that is, gtk doesn't dim the buttons automatically, the onRaise/onLower
315 methods discard requests to move a table item beyond its proper scope.
316
317 Does nothing if the widget is not ordered.
318
319 @param tv: View of the loaded or unloaded L{AEUserInterface}s
320 @type tv: gtk.TreeView
321 '''
322 if self.lower_button is None:
323
324 return
325 model = tv.get_model()
326 path, col = tv.get_cursor()
327 can_up = can_down = True
328 n = self._getLoadedCount()
329 if path[0] == 0:
330
331 can_up = False
332 can_down = True
333 elif path[0] == n-1:
334
335 can_up = True
336 can_down = False
337 elif path is None or n == 0 or path[0] >= n:
338
339 can_up = can_down = False
340
341 self.lower_button.set_sensitive(can_down)
342 self.raise_button.set_sensitive(can_up)
343