Fixing and documenting various bugs
[gc-dialer] / src / hildonize.py
1 #!/usr/bin/env python
2
3
4 import gobject
5 import gtk
6 import dbus
7
8
9 class _NullHildonModule(object):
10         pass
11
12
13 try:
14         import hildon as _hildon
15         hildon  = _hildon # Dumb but gets around pyflakiness
16 except (ImportError, OSError):
17         hildon = _NullHildonModule
18
19
20 IS_HILDON_SUPPORTED = hildon is not _NullHildonModule
21
22
23 class _NullHildonProgram(object):
24
25         def add_window(self, window):
26                 pass
27
28
29 def _hildon_get_app_class():
30         return hildon.Program
31
32
33 def _null_get_app_class():
34         return _NullHildonProgram
35
36
37 try:
38         hildon.Program
39         get_app_class = _hildon_get_app_class
40 except AttributeError:
41         get_app_class = _null_get_app_class
42
43
44 def _hildon_set_application_title(window, title):
45         pass
46
47
48 def _null_set_application_title(window, title):
49         window.set_title(title)
50
51
52 if IS_HILDON_SUPPORTED:
53         set_application_title = _hildon_set_application_title
54 else:
55         set_application_title = _null_set_application_title
56
57
58 def _fremantle_hildonize_window(app, window):
59         oldWindow = window
60         newWindow = hildon.StackableWindow()
61         oldWindow.get_child().reparent(newWindow)
62         app.add_window(newWindow)
63         return newWindow
64
65
66 def _hildon_hildonize_window(app, window):
67         oldWindow = window
68         newWindow = hildon.Window()
69         oldWindow.get_child().reparent(newWindow)
70         app.add_window(newWindow)
71         return newWindow
72
73
74 def _null_hildonize_window(app, window):
75         return window
76
77
78 try:
79         hildon.StackableWindow
80         hildonize_window = _fremantle_hildonize_window
81 except AttributeError:
82         try:
83                 hildon.Window
84                 hildonize_window = _hildon_hildonize_window
85         except AttributeError:
86                 hildonize_window = _null_hildonize_window
87
88
89 def _fremantle_hildonize_menu(window, gtkMenu, buttons):
90         appMenu = hildon.AppMenu()
91         for button in buttons:
92                 appMenu.append(button)
93         window.set_app_menu(appMenu)
94         gtkMenu.get_parent().remove(gtkMenu)
95         return appMenu
96
97
98 def _hildon_hildonize_menu(window, gtkMenu, ignoredButtons):
99         hildonMenu = gtk.Menu()
100         for child in gtkMenu.get_children():
101                 child.reparent(hildonMenu)
102         window.set_menu(hildonMenu)
103         gtkMenu.destroy()
104         return hildonMenu
105
106
107 def _null_hildonize_menu(window, gtkMenu, ignoredButtons):
108         return gtkMenu
109
110
111 try:
112         hildon.AppMenu
113         GTK_MENU_USED = False
114         hildonize_menu = _fremantle_hildonize_menu
115 except AttributeError:
116         GTK_MENU_USED = True
117         if IS_HILDON_SUPPORTED:
118                 hildonize_menu = _hildon_hildonize_menu
119         else:
120                 hildonize_menu = _null_hildonize_menu
121
122
123 def _hildon_set_cell_thumb_selectable(renderer):
124         renderer.set_property("scale", 1.5)
125
126
127 def _null_set_cell_thumb_selectable(renderer):
128         pass
129
130
131 if IS_HILDON_SUPPORTED:
132         set_cell_thumb_selectable = _hildon_set_cell_thumb_selectable
133 else:
134         set_cell_thumb_selectable = _null_set_cell_thumb_selectable
135
136
137 def _hildon_show_information_banner(parent, message):
138         hildon.hildon_banner_show_information(parent, "", message)
139
140
141 def _null_show_information_banner(parent, message):
142         pass
143
144
145 try:
146         hildon.hildon_banner_show_information
147         show_information_banner = _hildon_show_information_banner
148 except AttributeError:
149         show_information_banner = _null_show_information_banner
150
151
152 def _fremantle_show_busy_banner_start(parent, message):
153         hildon.hildon_gtk_window_set_progress_indicator(parent, True)
154         return parent
155
156
157 def _fremantle_show_busy_banner_end(parent):
158         hildon.hildon_gtk_window_set_progress_indicator(parent, False)
159
160
161 def _hildon_show_busy_banner_start(parent, message):
162         return hildon.hildon_banner_show_animation(parent, "", message)
163
164
165 def _hildon_show_busy_banner_end(banner):
166         banner.destroy()
167
168
169 def _null_show_busy_banner_start(parent, message):
170         return None
171
172
173 def _null_show_busy_banner_end(banner):
174         return None
175
176
177 try:
178         hildon.hildon_gtk_window_set_progress_indicator
179         show_busy_banner_start = _fremantle_show_busy_banner_start
180         show_busy_banner_end = _fremantle_show_busy_banner_end
181 except AttributeError:
182         try:
183                 hildon.hildon_banner_show_animation
184                 show_busy_banner_start = _hildon_show_busy_banner_start
185                 show_busy_banner_end = _hildon_show_busy_banner_end
186         except AttributeError:
187                 show_busy_banner_start = _null_show_busy_banner_start
188                 show_busy_banner_end = _null_show_busy_banner_end
189
190
191 def _hildon_hildonize_text_entry(textEntry):
192         textEntry.set_property('hildon-input-mode', 7)
193
194
195 def _null_hildonize_text_entry(textEntry):
196         pass
197
198
199 if IS_HILDON_SUPPORTED:
200         hildonize_text_entry = _hildon_hildonize_text_entry
201 else:
202         hildonize_text_entry = _null_hildonize_text_entry
203
204
205 def _hildon_mark_window_rotatable(window):
206         # gtk documentation is unclear whether this does a "=" or a "|="
207         window.set_flags(hildon.HILDON_PORTRAIT_MODE_SUPPORT)
208
209
210 def _null_mark_window_rotatable(window):
211         pass
212
213
214 try:
215         hildon.HILDON_PORTRAIT_MODE_SUPPORT
216         mark_window_rotatable = _hildon_mark_window_rotatable
217 except AttributeError:
218         mark_window_rotatable = _null_mark_window_rotatable
219
220
221 def _hildon_window_to_portrait(window):
222         # gtk documentation is unclear whether this does a "=" or a "|="
223         window.set_flags(hildon.HILDON_PORTRAIT_MODE_SUPPORT)
224
225
226 def _hildon_window_to_landscape(window):
227         # gtk documentation is unclear whether this does a "=" or a "&= ~"
228         window.unset_flags(hildon.HILDON_PORTRAIT_MODE_REQUEST)
229
230
231 def _null_window_to_portrait(window):
232         pass
233
234
235 def _null_window_to_landscape(window):
236         pass
237
238
239 try:
240         hildon.HILDON_PORTRAIT_MODE_SUPPORT
241         hildon.HILDON_PORTRAIT_MODE_REQUEST
242
243         window_to_portrait = _hildon_window_to_portrait
244         window_to_landscape = _hildon_window_to_landscape
245 except AttributeError:
246         window_to_portrait = _null_window_to_portrait
247         window_to_landscape = _null_window_to_landscape
248
249
250 def get_device_orientation():
251         bus = dbus.SystemBus()
252         try:
253                 rawMceRequest = bus.get_object("com.nokia.mce", "/com/nokia/mce/request")
254                 mceRequest = dbus.Interface(rawMceRequest, dbus_interface="com.nokia.mce.request")
255                 orientation, standState, faceState, xAxis, yAxis, zAxis = mceRequest.get_device_orientation()
256         except dbus.exception.DBusException:
257                 # catching for documentation purposes that when a system doesn't
258                 # support this, this is what to expect
259                 raise
260
261         if orientation == "":
262                 return gtk.ORIENTATION_HORIZONTAL
263         elif orientation == "":
264                 return gtk.ORIENTATION_VERTICAL
265         else:
266                 raise RuntimeError("Unknown orientation: %s" % orientation)
267
268
269 def _hildon_hildonize_password_entry(textEntry):
270         textEntry.set_property('hildon-input-mode', 7 | (1 << 29))
271
272
273 def _null_hildonize_password_entry(textEntry):
274         pass
275
276
277 if IS_HILDON_SUPPORTED:
278         hildonize_password_entry = _hildon_hildonize_password_entry
279 else:
280         hildonize_password_entry = _null_hildonize_password_entry
281
282
283 def _hildon_hildonize_combo_entry(comboEntry):
284         comboEntry.set_property('hildon-input-mode', 1 << 4)
285
286
287 def _null_hildonize_combo_entry(textEntry):
288         pass
289
290
291 if IS_HILDON_SUPPORTED:
292         hildonize_combo_entry = _hildon_hildonize_combo_entry
293 else:
294         hildonize_combo_entry = _null_hildonize_combo_entry
295
296
297 def _fremantle_hildonize_scrollwindow(scrolledWindow):
298         pannableWindow = hildon.PannableArea()
299
300         child = scrolledWindow.get_child()
301         scrolledWindow.remove(child)
302         pannableWindow.add(child)
303
304         parent = scrolledWindow.get_parent()
305         parent.remove(scrolledWindow)
306         parent.add(pannableWindow)
307
308         return pannableWindow
309
310
311 def _hildon_hildonize_scrollwindow(scrolledWindow):
312         hildon.hildon_helper_set_thumb_scrollbar(scrolledWindow, True)
313         return scrolledWindow
314
315
316 def _null_hildonize_scrollwindow(scrolledWindow):
317         return scrolledWindow
318
319
320 try:
321         hildon.PannableArea
322         hildonize_scrollwindow = _fremantle_hildonize_scrollwindow
323         hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
324 except AttributeError:
325         try:
326                 hildon.hildon_helper_set_thumb_scrollbar
327                 hildonize_scrollwindow = _hildon_hildonize_scrollwindow
328                 hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
329         except AttributeError:
330                 hildonize_scrollwindow = _null_hildonize_scrollwindow
331                 hildonize_scrollwindow_with_viewport = _null_hildonize_scrollwindow
332
333
334 def _hildon_request_number(parent, title, range, default):
335         spinner = hildon.NumberEditor(*range)
336         spinner.set_value(default)
337
338         dialog = gtk.Dialog(
339                 title,
340                 parent,
341                 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
342                 (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
343         )
344         dialog.set_default_response(gtk.RESPONSE_CANCEL)
345         dialog.get_child().add(spinner)
346
347         try:
348                 dialog.show_all()
349                 response = dialog.run()
350         finally:
351                 dialog.hide()
352
353         if response == gtk.RESPONSE_OK:
354                 return spinner.get_value()
355         elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
356                 raise RuntimeError("User cancelled request")
357         else:
358                 raise RuntimeError("Unrecognized response %r", response)
359
360
361 def _null_request_number(parent, title, range, default):
362         adjustment = gtk.Adjustment(default, range[0], range[1], 1, 5, 0)
363         spinner = gtk.SpinButton(adjustment, 0, 0)
364         spinner.set_wrap(False)
365
366         dialog = gtk.Dialog(
367                 title,
368                 parent,
369                 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
370                 (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
371         )
372         dialog.set_default_response(gtk.RESPONSE_CANCEL)
373         dialog.get_child().add(spinner)
374
375         try:
376                 dialog.show_all()
377                 response = dialog.run()
378         finally:
379                 dialog.hide()
380
381         if response == gtk.RESPONSE_OK:
382                 return spinner.get_value_as_int()
383         elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
384                 raise RuntimeError("User cancelled request")
385         else:
386                 raise RuntimeError("Unrecognized response %r", response)
387
388
389 try:
390         hildon.NumberEditor # TODO deprecated in fremantle
391         request_number = _hildon_request_number
392 except AttributeError:
393         request_number = _null_request_number
394
395
396 def _hildon_touch_selector(parent, title, items, defaultIndex):
397         model = gtk.ListStore(gobject.TYPE_STRING)
398         for item in items:
399                 model.append((item, ))
400
401         selector = hildon.TouchSelector()
402         selector.append_text_column(model, True)
403         selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
404         selector.set_active(0, defaultIndex)
405
406         dialog = hildon.PickerDialog(parent)
407         dialog.set_selector(selector)
408
409         try:
410                 dialog.show_all()
411                 response = dialog.run()
412         finally:
413                 dialog.hide()
414
415         if response == gtk.RESPONSE_OK:
416                 return selector.get_active(0)
417         elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
418                 raise RuntimeError("User cancelled request")
419         else:
420                 raise RuntimeError("Unrecognized response %r", response)
421
422
423 def _on_null_touch_selector_activated(treeView, path, column, dialog):
424         dialog.response(gtk.RESPONSE_OK)
425
426
427 def _null_touch_selector(parent, title, items, defaultIndex = -1):
428         model = gtk.ListStore(gobject.TYPE_STRING)
429         for item in items:
430                 model.append((item, ))
431
432         cell = gtk.CellRendererText()
433         set_cell_thumb_selectable(cell)
434         column = gtk.TreeViewColumn(title)
435         column .pack_start(cell, expand=True)
436         column.add_attribute(cell, "text", 0)
437
438         treeView = gtk.TreeView()
439         treeView.set_model(model)
440         treeView.append_column(column)
441         selection = treeView.get_selection()
442         selection.set_mode(gtk.SELECTION_SINGLE)
443         if 0 < defaultIndex:
444                 selection.select_path((defaultIndex, ))
445
446         scrolledWin = gtk.ScrolledWindow()
447         scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
448         scrolledWin.add(treeView)
449         hildonize_scrollwindow(scrolledWin)
450
451         dialog = gtk.Dialog(
452                 title,
453                 parent,
454                 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
455                 (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
456         )
457         dialog.set_default_response(gtk.RESPONSE_CANCEL)
458         dialog.get_child().add(scrolledWin)
459         parentSize = parent.get_size()
460         dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
461         treeView.connect("row-activated", _on_null_touch_selector_activated, dialog)
462
463         try:
464                 dialog.show_all()
465                 response = dialog.run()
466         finally:
467                 dialog.hide()
468
469         if response == gtk.RESPONSE_OK:
470                 model, itr = selection.get_selected()
471                 if itr is None:
472                         raise RuntimeError("No selection made")
473                 return model.get_path(itr)[0]
474         elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
475                 raise RuntimeError("User cancelled request")
476         else:
477                 raise RuntimeError("Unrecognized response %r", response)
478
479
480 try:
481         hildon.PickerDialog
482         hildon.TouchSelector
483         touch_selector = _hildon_touch_selector
484 except AttributeError:
485         touch_selector = _null_touch_selector
486
487
488 if __name__ == "__main__":
489         app = get_app_class()()
490         win = gtk.Window()
491         win = hildonize_window(app, win)
492         if True:
493                 print touch_selector(win, "Test", ["A", "B", "C", "D"], 2)