1 from config.config import *
2 from model.projects import Projects
6 from log.logging import logger
7 from e32 import Ao_lock, in_emulator
8 from key_codes import *
14 for k, v in cfg.items():
15 v = cfg.format_value(v)
16 if isinstance(v, int) or isinstance(v, long):
19 elif isinstance(v, list) or isinstance(v, tuple):
21 if not isinstance(item, unicode):
22 raise Exception("list can contain only unicode objects, "\
23 "object %r is not supported" % item)
26 elif isinstance(v, unicode):
29 raise Exception("%s has non-supported value" % k)
31 fields.append((unicode(k), tname, v))
34 form = appuifw.Form(fields=fields, flags=appuifw.FFormEditModeOnly | \
35 appuifw.FFormDoubleSpaced)
40 form.save_hook = save_hook
44 # return true if user saved, false otherwise
48 for label, tname, value in form:
50 value = (value[0], int(value[1]))
52 cfg[str(label)] = cfg.parse_value(value)
60 def applicable_functions(obj,allowed_function_names):
61 function_names = [function_name for function_name in dir(obj) if function_name in allowed_function_names]
62 return [eval('obj.%s'%function_name) for function_name in function_names]
64 def get_key(key_name):
68 key=eval('EKey%s'%key_name)
71 def key_shortname(key_name):
72 """ Find the one-character name for a key """
75 elif key_name == 'Backspace':
81 return filter(lambda entry:entry[0:4]=='EKey',dir(key_codes))
100 def save_gui(object):
101 object.old_gui = appuifw.app.body
102 object.old_menu = appuifw.app.menu
103 object.old_exit_key_handler = appuifw.app.exit_key_handler
104 object.old_title=appuifw.app.title
106 def restore_gui(object):
107 appuifw.app.body = object.old_gui
108 appuifw.app.menu = object.old_menu
109 appuifw.app.exit_key_handler = object.old_exit_key_handler
110 appuifw.app.title = object.old_title
114 # Store a list of keys we bound, so we can unbind them
118 self.lock = Ao_lock()
119 self.exit_flag = False
120 super(View, self).__init__()
122 def set_title(self, title):
125 def set_view(self, view):
127 Sets the main view to be displayed (e.g., an appuifw.Listbox
133 self.adjustment = None
135 appuifw.app.screen=COMMON_CONFIG['screen'].encode('utf-8')
136 appuifw.app.title=self.title
137 appuifw.app.body=self.view
138 appuifw.app.exit_key_handler=self.exit
141 while not self.exit_flag:
149 self.exit_flag = True
152 def update(self,subject=None):
154 Update the current view (e.g., make sure refresh is called). We
155 can't call it directly, since we're in another thread.
162 Called when the current view must be updated. Never call
163 directly. Subclasses should extend this method, not update.
167 def refresh_menu(self):
169 Refresh the menu and its bindings. Calls self.menu_items() to
172 # Two helper functions
173 def shortcut_prefix(key_name):
174 short = key_shortname(key_name)
175 return '[%s]' % short if short else ' '
177 def do_entry((text, callback, key_name)):
178 key = get_key(key_name)
180 self.view.bind(key, callback)
181 self.menu_keys.append(key)
182 title = "%s %s" % (shortcut_prefix(key_name), text)
183 return(title, callback)
185 # Clear the bindings we previously added (we can't just clear
186 # all bindings, since other classes might have added other
188 for key in self.menu_keys:
189 self.view.bind(key, no_action)
192 # Set the menu, and let do_entry add binds at the same time.
193 appuifw.app.menu = [do_entry(item) for item in self.menu_items()]
195 def menu_items(self):
197 Should return a list of menu items. Each menu item is a tuple:
198 (text, callback, shortcut key name).
200 return [(u'Exit', self.exit, None)]
202 class ListView(View):
204 super(ListView, self).__init__()
205 self.current_index = None
206 self.set_view(appuifw.Listbox(self.items(),self.entry_selected))
207 self.view.bind(EKeyUpArrow,lambda: self.arrow_key_pressed(-1))
208 self.view.bind(EKeyDownArrow,lambda: self.arrow_key_pressed(1))
210 def arrow_key_pressed(self, dir):
212 This function is called when an arrow key is pressed. Since we
213 don't get any "current list index has changed" events, we'll
214 have to create these ourselves this way.
216 Since the current index is only updated after the key event,
217 we'll have to adjust the index with the direction of the
218 keypress (-1 for up, +1 for down).
220 self.current_index = (self.selected_index() + dir) % len(self.items())
222 self.current_index = None
226 super(ListView, self).run()
228 def entry_selected(self):
230 This function is called when the user selects an an entry (e.g.,
231 navigates to it and push the ok button).
235 def index_changed(self):
237 This function is called when the index changes. The given index
238 is the new index (don't use self.selected_index() here, since it
239 won't be correct yet!).
244 """ This function should return the list of items to display.
245 See appuifw.ListBox for valid elements for this list. """
248 def set_index(self,index):
249 """ Changes the currently selected item to index. """
250 self.view.set_list(self.items(),index % len(self.items()))
252 def selected_index(self):
253 """ Returns the currently selected index. """
254 if not self.current_index is None:
255 # We allow the current index to be overridden, so it can be
256 # valid during index_changed events. See arrow_key_pressed.
257 return self.current_index
259 return self.view.current()
261 class WidgetBasedListView(ListView):
263 self.binding_map = {}
264 self.widgets = self.generate_widgets()
265 super(WidgetBasedListView,self).__init__()
267 def index_changed(self):
269 super(WidgetBasedListView, self).index_changed()
271 def entry_selected(self):
272 self.current_widget().change()
275 def notify(self,object,attribute,new=None,old=None):
279 self.widgets = self.generate_widgets()
280 self.redisplay_widgets()
281 super(WidgetBasedListView,self).refresh()
283 def redisplay_widgets(self):
285 Redisplay the widgets. Should be called if the widgets
286 themselves have changed, does not call generate_widgets again.
288 self.set_index(self.selected_index())
291 # Let ListView show each widget's text.
292 return self.all_widget_texts()
294 def all_widget_texts(self):
296 Return the widget texts as they should be displayed in the
299 return [entry.list_repr() for entry in self.widgets]
301 def current_widget(self):
302 """ Returns the currently selected widget. """
303 return self.widgets[self.selected_index()]
305 def generate_widgets():
306 """ This function should return a list of widgets. """
309 def menu_items(self):
310 # Determine the current menu based on the methods available on
311 # the selected widget and on ourselves.
313 for function in applicable_functions(self.current_widget(),self.binding_map)+\
314 applicable_functions(self,self.binding_map):
315 (key,description) = self.binding_map[function.__name__]
319 menu_items.append((description, do_callback, key))
320 menu_items += super(WidgetBasedListView, self).menu_items()
323 def set_menu(self, binding_map):
325 Set a new map of menu entries with hotkeys. This map maps method names to a
326 tuple of keyname and description.
328 Keyname is a string containing the name of the key (the
329 part after EKey, e.g., "0", "Star", etc.). Keyname can be "", in
330 which case the item has no shortcut.
332 The method name refers to a method on the selected widget, or
335 Example: { 'search_item' : ('0', 'Search item') }
337 self.binding_map = binding_map
339 class SearchableListView(WidgetBasedListView):
341 self.current_entry_filter_index = -1
342 self.entry_filters = []
343 self.filtered_list = lambda:[]
345 super(SearchableListView,self).__init__()
347 def set_filters(self, entry_filters):
349 Set the filters that could be applied to this list. Each filter
350 can be applied in turn by calling switch_entry_filter (for
351 example from a key binding).
353 The entry_filters argument should be a list of filters. The
354 active filter is stored into self.filtered_list and should be
355 processed by generate_widgets in the subclass.
357 self.current_entry_filter_index = 0
358 self.entry_filters = entry_filters
359 self.filtered_list = self.entry_filters[0]
361 def search_item(self):
362 selected_item = appuifw.selection_list(self.all_widget_texts(),search_field=1)
363 if selected_item == None or selected_item == -1:
364 selected_item = self.selected_index()
365 self.view.set_list(self.items(),selected_item)
366 self.set_bindings_for_selection(selected_item)
368 def switch_entry_filter(self):
369 self.current_entry_filter_index += 1
370 self.filtered_list = self.entry_filters[self.current_entry_filter_index % len(self.entry_filters)]
373 #class DisplayableFunction:
374 # def __init__(self,display_name,function):
375 # self.display_name = display_name
376 # self.function = function
377 # def list_repr(self):
378 # return self.display_name
383 __all__= ('SearchableListView','show_config')