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
116 self.lock = Ao_lock()
117 self.exit_flag = False
118 super(View, self).__init__()
120 def set_title(self, title):
123 def set_view(self, view):
125 Sets the main view to be displayed (e.g., an appuifw.Listbox
131 self.adjustment = None
133 appuifw.app.screen=COMMON_CONFIG['screen'].encode('utf-8')
134 appuifw.app.title=self.title
135 appuifw.app.body=self.view
136 appuifw.app.exit_key_handler=self.exit
139 while not self.exit_flag:
147 self.exit_flag = True
150 def update(self,subject=None):
152 Update the current view (e.g., make sure refresh is called). We
153 can't call it directly, since we're in another thread.
160 Called when the current view must be updated. Never call
161 directly. Subclasses should extend this method, not update.
163 appuifw.app.menu=self.get_menu_entries()
165 def get_menu_entries(self):
166 """ Returns a list of menu entries to display. Will be
167 automatically updated on each refresh.
169 Each menu entry is a tuple of a title for the entry and a
170 function to call when the entry is selected.
174 class ListView(View):
176 super(ListView, self).__init__()
177 self.set_view(appuifw.Listbox(self.items(),self.entry_selected))
178 self.view.bind(EKeyUpArrow,lambda: self.arrow_key_pressed(-1))
179 self.view.bind(EKeyDownArrow,lambda: self.arrow_key_pressed(1))
181 def arrow_key_pressed(self, dir):
183 This function is called when an arrow key is pressed. Since we
184 don't get any "current list index has changed" events, we'll
185 have to create these ourselves this way.
187 Since the current index is only updated after the key event,
188 we'll have to adjust the index with the direction of the
189 keypress (-1 for up, +1 for down).
191 new_index = (self.selected_index() + dir) % len(self.items())
192 self.index_changed(new_index)
194 def entry_selected(self):
196 This function is called when the user selects an an entry (e.g.,
197 navigates to it and push the ok button).
201 def index_changed(self,new_index):
203 This function is called when the index changes. The given index
204 is the new index (don't use self.selected_index() here, since it
205 won't be correct yet!).
210 """ This function should return the list of items to display.
211 See appuifw.ListBox for valid elements for this list. """
214 def set_index(self,index):
215 """ Changes the currently selected item to index. """
216 self.view.set_list(self.items(),index % len(self.items()))
218 def selected_index(self):
219 """ Returns the currently selected index. """
220 return self.view.current()
222 class WidgetBasedListView(ListView):
224 self.widgets = self.generate_widgets()
225 super(WidgetBasedListView,self).__init__()
229 self.set_bindings_for_selection(0)
232 def index_changed(self,new_index):
233 self.set_bindings_for_selection(new_index)
234 super(WidgeteBasedListView, self).index_changed(new_index)
236 def notify(self,object,attribute,new=None,old=None):
239 self.widgets = self.generate_widgets()
240 self.redisplay_widgets()
241 super(WidgetBasedListView,self).refresh()
242 def redisplay_widgets(self):
243 self.set_index(self.selected_index())
245 return self.all_widget_texts()
246 def all_widget_texts(self):
247 return [entry.list_repr() for entry in self.widgets]
251 def current_widget(self):
252 return self.widgets[self.selected_index()]
255 class KeyBindingView(View):
258 self.binding_map = {}
259 super(KeyBindingView,self).__init__()
261 def set_keybindings(self, binding_map):
263 Set a new map of key bindings. This map maps method names to a
264 tuple of keyname and description.
266 The method name refers to a method on the selected item, or the
269 Example: { 'search_item' : ('0', 'Search item') }
272 self.binding_map = binding_map
274 def get_menu_entries(self):
276 for key,key_name,description,function in self.key_and_menu_bindings(self.selected_index()):
277 if description != '':
279 if key_name == 'Backspace': key_name='C'
280 description='[%s] '%key_name +description
282 description=' '+description
283 menu_entries.append((description,function))
284 menu_entries.append((u'Exit', self.exit))
285 return menu_entries + super(KeyBindingView, self).get_menu_entries()
287 def set_bindings_for_selection(self,selected_index):
288 self.remove_all_key_bindings()
290 for key,key_name,description,function in self.key_and_menu_bindings(selected_index):
292 self.view.bind(key,function)
294 def remove_all_key_bindings(self):
295 for key in all_key_values():
296 self.view.bind(key,no_action)
298 class SearchableListView(WidgetBasedListView):
300 self.current_entry_filter_index = -1
301 self.entry_filters = []
302 self.filtered_list = lambda:[]
304 super(SearchableListView,self).__init__()
306 def set_filters(self, entry_filters):
308 Set the filters that could be applied to this list. Each filter
309 can be applied in turn by calling switch_entry_filter (for
310 example from a key binding).
312 The entry_filters argument should be a list of filters. The
313 active filter is stored into self.filtered_list and should be
314 processed by generate_widgets in the subclass.
316 self.current_entry_filter_index = 0
317 self.entry_filters = entry_filters
318 self.filtered_list = self.entry_filters[0]
320 def search_item(self):
321 selected_item = appuifw.selection_list(self.all_widget_texts(),search_field=1)
322 if selected_item == None or selected_item == -1:
323 selected_item = self.selected_index()
324 self.view.set_list(self.items(),selected_item)
325 self.set_bindings_for_selection(selected_item)
327 def switch_entry_filter(self):
328 self.current_entry_filter_index += 1
329 self.filtered_list = self.entry_filters[self.current_entry_filter_index % len(self.entry_filters)]
333 class EditableListView(SearchableListView,KeyBindingView):
335 super(EditableListView, self).__init__()
337 def key_and_menu_bindings(self,selected_index):
338 key_and_menu_bindings=[]
339 for function in applicable_functions(self.widgets[selected_index],self.binding_map)+\
340 applicable_functions(self,self.binding_map):
341 execute_and_update_function = self.execute_and_update(function)
342 (key,description) = self.binding_map[function.__name__]
343 key_and_menu_bindings.append((get_key(key),key,description,execute_and_update_function))
344 return key_and_menu_bindings
346 def entry_selected(self):
347 self.current_widget().change()
349 def execute_and_update(self,function):
350 return lambda: (function(),self.refresh(),self.index_changed())
352 def notify(self,item,attribute,new=None,old=None):
355 #class DisplayableFunction:
356 # def __init__(self,display_name,function):
357 # self.display_name = display_name
358 # self.function = function
359 # def list_repr(self):
360 # return self.display_name
365 __all__= ('EditableListView','show_config')