More unicode work
[nqaap] / src / Gui.py
1 from __future__ import with_statement
2
3 import os
4 import ConfigParser
5 import codecs
6 import logging
7
8 import gobject
9 import gtk
10
11 import constants
12 import hildonize
13 import gtk_toolbox
14 import Browser
15 import CallMonitor
16 import settings
17
18 if hildonize.IS_FREMANTLE_SUPPORTED:
19         # I don't normally do this but I want to error as loudly as possibly when an issue arises
20         import hildon
21
22
23 _moduleLogger = logging.getLogger(__name__)
24
25
26 class Gui(object):
27
28         # @todo Jump straight to book selection on first launch?
29         # @todo Absolute increments (+/-5 seconds)
30         # @todo Show elapsed time / time lef
31         # @todo Volume control when screen is off
32         # @todo Variable speed
33         #  http://scaletempo.sourceforge.net/0/task-list.html
34         #  http://www.gstreamer.net/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-scaletempo.html
35
36         def __init__(self):
37                 _moduleLogger.info("Starting GUI")
38                 self._clipboard = gtk.clipboard_get()
39                 self._callMonitor = CallMonitor.CallMonitor()
40                 self.__settingsWindow = None
41                 self.__settingsManager = None
42                 self._bookSelection = []
43                 self._bookSelectionIndex = -1
44                 self._chapterSelection = []
45                 self._chapterSelectionIndex = -1
46                 self._sleepSelection = ["0", "1", "10", "20", "30", "60"]
47                 self._sleepSelectionIndex = 0
48
49                 self.__window_in_fullscreen = False #The window isn't in full screen mode initially.
50                 self.__isPortrait = False
51
52                 self.controller = None
53                 self.sleep_timer = None
54
55                 # set up gui
56                 self.setup()
57                 self._callMonitor.connect("call_start", self.__on_call_started)
58                 self._callMonitor.start()
59
60         def setup(self):
61                 self._app = hildonize.get_app_class()()
62                 self.win = gtk.Window()
63                 self.win = hildonize.hildonize_window(self._app, self.win)
64                 self.win.set_title(constants.__pretty_app_name__)
65
66                 # Cover image
67                 self.cover = gtk.Image()
68
69                 # Controls:
70
71                 # Label that hold the title of the book,and maybe the chapter
72                 self.title = gtk.Label()
73                 self.title.set_justify(gtk.JUSTIFY_CENTER)
74                 self._set_display_title("Select a book to start listening")
75
76                 self.chapter = gtk.Label()
77                 self.chapter.set_justify(gtk.JUSTIFY_CENTER)
78
79                 # Seekbar 
80                 if hildonize.IS_FREMANTLE_SUPPORTED:
81                         self.seek = hildon.Seekbar()
82                         self.seek.set_range(0.0, 100)
83                         self.seek.set_draw_value(False)
84                         self.seek.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
85                         self.seek.connect('change-value', self.seek_changed) # event
86                         # self.seek.connect('value-changed',self.seek_changed) # event
87                 else:
88                         adjustment = gtk.Adjustment(0, 0, 101, 1, 5, 1)
89                         self.seek = gtk.HScale(adjustment)
90                         self.seek.set_draw_value(False)
91                         self.seek.connect('change-value', self.seek_changed) # event
92
93                 # Pause button
94                 if hildonize.IS_FREMANTLE_SUPPORTED:
95                         self.backButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
96                         image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PREVIOUS, gtk.HILDON_SIZE_FINGER_HEIGHT)
97                         self.backButton.set_image(image)
98
99                         self.button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
100
101                         self.forwardButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
102                         image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_NEXT, gtk.HILDON_SIZE_FINGER_HEIGHT)
103                         self.forwardButton.set_image(image)
104                 else:
105                         self.backButton = gtk.Button(stock=gtk.STOCK_MEDIA_PREVIOUS)
106                         self.button = gtk.Button()
107                         self.forwardButton = gtk.Button(stock=gtk.STOCK_MEDIA_NEXT)
108                 self.set_button_text("Play", "Start playing the audiobook")
109                 self.backButton.connect('clicked', self._on_previous_chapter)
110                 self.button.connect('clicked', self.play_pressed) # event
111                 self.forwardButton.connect('clicked', self._on_next_chapter)
112
113                 self._toolbar = gtk.HBox()
114                 self._toolbar.pack_start(self.backButton, False, False, 0)
115                 self._toolbar.pack_start(self.button, True, True, 0)
116                 self._toolbar.pack_start(self.forwardButton, False, False, 0)
117
118                 # Box to hold the controls:
119                 self._controlLayout = gtk.VBox()
120                 self._controlLayout.pack_start(gtk.Label(), True, True, 0)
121                 self._controlLayout.pack_start(self.title, False, True, 0)
122                 self._controlLayout.pack_start(self.chapter, False, True, 0)
123                 self._controlLayout.pack_start(gtk.Label(), True, True, 0)
124                 self._controlLayout.pack_start(self.seek, False, True, 0)
125                 self._controlLayout.pack_start(self._toolbar, False, True, 0)
126
127                 #Box that divides the layout in two: cover on the lefta
128                 #and controls on the right
129                 self._viewLayout = gtk.HBox()
130                 self._viewLayout.pack_start(self.cover, True, True, 0)
131                 self._viewLayout.add(self._controlLayout)
132
133                 self._menuBar = gtk.MenuBar()
134                 self._menuBar.show()
135
136                 self._mainLayout = gtk.VBox()
137                 self._mainLayout.pack_start(self._menuBar, False, False, 0)
138                 self._mainLayout.pack_start(self._viewLayout)
139
140                 # Add hbox to the window
141                 self.win.add(self._mainLayout)
142
143                 #Menu:
144                 # Create menu
145                 self._populate_menu()
146
147                 self.win.connect("delete_event", self.quit) # Add shutdown event
148                 self.win.connect("key-press-event", self.on_key_press)
149                 self.win.connect("window-state-event", self._on_window_state_change)
150
151                 self.win.show_all()
152
153                 # Run update timer
154                 self.setup_timers()
155
156         def _populate_menu(self):
157                 self._menuBar = hildonize.hildonize_menu(
158                         self.win,
159                         self._menuBar,
160                 )
161                 if hildonize.IS_FREMANTLE_SUPPORTED:
162                         # Create a picker button 
163                         self.book_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
164                                                                                           hildon.BUTTON_ARRANGEMENT_VERTICAL)
165                         self.book_button.set_title("Audiobook") # Set a title to the button 
166                         self.book_button.connect("clicked", self._on_select_audiobook)
167
168                         # Create a picker button 
169                         self.chapter_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
170                                                                                           hildon.BUTTON_ARRANGEMENT_VERTICAL)
171                         self.chapter_button.set_title("Chapter") # Set a title to the button 
172                         self.chapter_button.connect("clicked", self._on_select_chapter)
173
174                         # Create a picker button 
175                         self.sleeptime_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
176                                                                                           hildon.BUTTON_ARRANGEMENT_VERTICAL)
177                         self.sleeptime_button.set_title("Sleeptimer") # Set a title to the button 
178                         self.sleeptime_button.connect("clicked", self._on_select_sleep)
179
180                         settings_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
181                         settings_button.set_label("Settings")
182                         settings_button.connect("clicked", self._on_settings)
183
184                         about_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
185                         about_button.set_label("About")
186                         about_button.connect("clicked", self._on_about_activate)
187
188                         help_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
189                         help_button.set_label("Help")
190                         help_button.connect("clicked", self.get_help)
191
192                         self._menuBar.append(self.book_button)          # Add the button to menu
193                         self._menuBar.append(self.chapter_button)               # Add the button to menu
194                         self._menuBar.append(self.sleeptime_button)             # Add the button to menu
195                         self._menuBar.append(settings_button)
196                         self._menuBar.append(help_button)
197                         self._menuBar.append(about_button)
198                         self._menuBar.show_all()
199                 else:
200                         self._audiobookMenuItem = gtk.MenuItem("Audiobook: ")
201                         self._audiobookMenuItem.connect("activate", self._on_select_audiobook)
202
203                         self._chapterMenuItem = gtk.MenuItem("Chapter: ")
204                         self._chapterMenuItem.connect("activate", self._on_select_chapter)
205
206                         self._sleepMenuItem = gtk.MenuItem("Sleeptimer: 0")
207                         self._sleepMenuItem.connect("activate", self._on_select_sleep)
208
209                         settingsMenuItem = gtk.MenuItem("Settings")
210                         settingsMenuItem.connect("activate", self._on_settings)
211
212                         aboutMenuItem = gtk.MenuItem("About")
213                         aboutMenuItem.connect("activate", self._on_about_activate)
214
215                         helpMenuItem = gtk.MenuItem("Help")
216                         helpMenuItem.connect("activate", self.get_help)
217
218                         booksMenu = gtk.Menu()
219                         booksMenu.append(self._audiobookMenuItem)
220                         booksMenu.append(self._chapterMenuItem)
221                         booksMenu.append(self._sleepMenuItem)
222                         booksMenu.append(settingsMenuItem)
223                         booksMenu.append(helpMenuItem)
224                         booksMenu.append(aboutMenuItem)
225
226                         booksMenuItem = gtk.MenuItem("Books")
227                         booksMenuItem.show()
228                         booksMenuItem.set_submenu(booksMenu)
229                         self._menuBar.append(booksMenuItem)
230                         self._menuBar.show_all()
231
232         def setup_timers(self):
233                 self.seek_timer = timeout_add_seconds(3, self.update_seek)
234
235         def save_settings(self):
236                 config = ConfigParser.SafeConfigParser()
237                 self._save_settings(config)
238                 with open(constants._user_settings_, "wb") as configFile:
239                         config.write(configFile)
240                 self.controller.save()
241
242         def _save_settings(self, config):
243                 config.add_section(constants.__pretty_app_name__)
244                 config.set(constants.__pretty_app_name__, "portrait", str(self.__isPortrait))
245                 config.set(constants.__pretty_app_name__, "fullscreen", str(self.__window_in_fullscreen))
246                 config.set(constants.__pretty_app_name__, "audiopath", self.controller.get_books_path())
247
248         def load_settings(self):
249                 config = ConfigParser.SafeConfigParser()
250                 config.read(constants._user_settings_)
251                 self._load_settings(config)
252
253         def _load_settings(self, config):
254                 isPortrait = False
255                 window_in_fullscreen = False
256                 booksPath = constants._default_book_path_
257                 try:
258                         isPortrait = config.getboolean(constants.__pretty_app_name__, "portrait")
259                         window_in_fullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen")
260                         booksPath = config.get(constants.__pretty_app_name__, "audiopath")
261                 except ConfigParser.NoSectionError, e:
262                         _moduleLogger.info(
263                                 "Settings file %s is missing section %s" % (
264                                         constants._user_settings_,
265                                         e.section,
266                                 )
267                         )
268
269                 if isPortrait ^ self.__isPortrait:
270                         if isPortrait:
271                                 orientation = gtk.ORIENTATION_VERTICAL
272                         else:
273                                 orientation = gtk.ORIENTATION_HORIZONTAL
274                         self.set_orientation(orientation)
275
276                 self.__window_in_fullscreen = window_in_fullscreen
277                 if self.__window_in_fullscreen:
278                         self.win.fullscreen()
279                 else:
280                         self.win.unfullscreen()
281
282                 self.controller.load(booksPath)
283
284         @staticmethod
285         def __format_name(path):
286                 if os.path.isfile(path):
287                         return os.path.basename(path).rsplit(".", 1)[0]
288                 else:
289                         return os.path.basename(path)
290
291         @gtk_toolbox.log_exception(_moduleLogger)
292         def _on_select_audiobook(self, *args):
293                 if not self._bookSelection:
294                         return
295                 index = hildonize.touch_selector(
296                         self.win,
297                         "Audiobook",
298                         (self.__format_name(bookPath) for bookPath in self._bookSelection),
299                         self._bookSelectionIndex if 0 <= self._bookSelectionIndex else 0,
300                 )
301                 self._bookSelectionIndex = index
302                 bookName = self._bookSelection[index]
303                 self.controller.set_book(bookName)
304                 self.set_button_text("Play", "Start playing the audiobook") # reset button
305
306         @gtk_toolbox.log_exception(_moduleLogger)
307         def _on_select_chapter(self, *args):
308                 if not self._chapterSelection:
309                         return
310                 index = hildonize.touch_selector(
311                         self.win,
312                         "Chapter",
313                         (self.__format_name(chapterPath) for chapterPath in self._chapterSelection),
314                         self._chapterSelectionIndex if 0 <= self._chapterSelectionIndex else 0,
315                 )
316                 self._chapterSelectionIndex = index
317                 chapterName = self._chapterSelection[index]
318                 self.controller.set_chapter(chapterName)
319                 self.set_button_text("Play", "Start playing the audiobook") # reset button
320
321         @gtk_toolbox.log_exception(_moduleLogger)
322         def _on_select_sleep(self, *args):
323                 if self.sleep_timer is not None:
324                         gobject.source_remove(self.sleep_timer)
325
326                 try:
327                         index = hildonize.touch_selector(
328                                 self.win,
329                                 "Sleeptimer",
330                                 self._sleepSelection,
331                                 self._sleepSelectionIndex if 0 <= self._sleepSelectionIndex else 0,
332                         )
333                 except RuntimeError:
334                         _moduleLogger.exception("Handling as if user cancelled")
335                         hildonize.show_information_banner(self.win, "Sleep timer canceled")
336                         index = 0
337
338                 self._sleepSelectionIndex = index
339                 sleepName = self._sleepSelection[index]
340
341                 time_out = int(sleepName)
342                 if 0 < time_out:
343                         timeout_add_seconds(time_out * 60, self.sleep)
344
345                 if hildonize.IS_FREMANTLE_SUPPORTED:
346                         self.sleeptime_button.set_text("Sleeptimer", sleepName)
347                 else:
348                         self._sleepMenuItem.get_child().set_text("Sleeptimer: %s" % (sleepName, ))
349
350         @gtk_toolbox.log_exception(_moduleLogger)
351         def __on_call_started(self, callMonitor):
352                 self.pause()
353
354         @gtk_toolbox.log_exception(_moduleLogger)
355         def _on_settings(self, *args):
356                 if self.__settingsWindow is None:
357                         vbox = gtk.VBox()
358                         self.__settingsManager = settings.SettingsDialog(vbox)
359
360                         self.__settingsWindow = gtk.Window()
361                         self.__settingsWindow.add(vbox)
362                         self.__settingsWindow = hildonize.hildonize_window(self._app, self.__settingsWindow)
363                         self.__settingsManager.window = self.__settingsWindow
364
365                         self.__settingsWindow.set_title("Settings")
366                         self.__settingsWindow.set_transient_for(self.win)
367                         self.__settingsWindow.set_default_size(*self.win.get_size())
368                         self.__settingsWindow.connect("delete-event", self._on_settings_delete)
369                 self.__settingsManager.set_portrait_state(self.__isPortrait)
370                 self.__settingsManager.set_audiobook_path(self.controller.get_books_path())
371                 self.__settingsWindow.set_modal(True)
372                 self.__settingsWindow.show_all()
373
374         @gtk_toolbox.log_exception(_moduleLogger)
375         def _on_settings_delete(self, *args):
376                 self.__settingsWindow.emit_stop_by_name("delete-event")
377                 self.__settingsWindow.hide()
378                 self.__settingsWindow.set_modal(False)
379
380                 isPortrait = self.__settingsManager.is_portrait()
381                 if isPortrait ^ self.__isPortrait:
382                         if isPortrait:
383                                 orientation = gtk.ORIENTATION_VERTICAL
384                         else:
385                                 orientation = gtk.ORIENTATION_HORIZONTAL
386                         self.set_orientation(orientation)
387                 if self.__settingsManager.get_audiobook_path() != self.controller.get_books_path():
388                         self.controller.reload(self.__settingsManager.get_audiobook_path())
389
390                 return True
391
392         @gtk_toolbox.log_exception(_moduleLogger)
393         def update_seek(self):
394                 if self.controller.is_playing():
395                         gtk.gdk.threads_enter()
396                         self.seek.set_value(self.controller.get_percentage() * 100)
397                         gtk.gdk.threads_leave()
398                 #self.controller.get_percentage() 
399                 return True                                      # run again
400
401         @gtk_toolbox.log_exception(_moduleLogger)
402         def sleep(self):
403                 _moduleLogger.info("sleep time timeout")
404                 hildonize.show_information_banner(self.win, "Sleep timer")
405                 self.controller.stop()
406                 self.set_button_text("Resume", "Resume playing the audiobook")
407                 return False                                    # do not repeat
408
409         @gtk_toolbox.log_exception(_moduleLogger)
410         def get_help(self, button):
411                 Browser.open("file:///opt/Nqa-Audiobook-player/Help/nqaap.html")
412
413         @gtk_toolbox.log_exception(_moduleLogger)
414         def seek_changed(self, seek, scroll , value):
415                 self.controller.seek_percent(seek.get_value() / 100.0)
416
417         @gtk_toolbox.log_exception(_moduleLogger)
418         def _on_next_chapter(self, *args):
419                 self.controller.next_chapter()
420
421         @gtk_toolbox.log_exception(_moduleLogger)
422         def _on_previous_chapter(self, *args):
423                 self.controller.previous_chapter()
424
425         @gtk_toolbox.log_exception(_moduleLogger)
426         def play_pressed(self, button):
427                 if self.controller.is_playing():
428                         self.pause()
429                 else:
430                         self.play()
431
432         @gtk_toolbox.log_exception(_moduleLogger)
433         def on_key_press(self, widget, event, *args):
434                 RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
435                 isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
436                 if (
437                         event.keyval == gtk.keysyms.F6 or
438                         event.keyval in RETURN_TYPES and isCtrl
439                 ):
440                         # The "Full screen" hardware key has been pressed 
441                         if self.__window_in_fullscreen:
442                                 self.win.unfullscreen ()
443                         else:
444                                 self.win.fullscreen ()
445                         return True
446                 elif event.keyval == gtk.keysyms.o and isCtrl:
447                         self._toggle_rotate()
448                         return True
449                 elif (
450                         event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
451                         event.get_state() & gtk.gdk.CONTROL_MASK
452                 ):
453                         self.quit()
454                 elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
455                         with codecs.open(constants._user_logpath_, "r", "utf-8") as f:
456                                 logLines = f.xreadlines()
457                                 log = u"".join(logLines)
458                                 self._clipboard.set_text(log)
459                         return True
460                 elif event.keyval in RETURN_TYPES:
461                         if self.controller.is_playing():
462                                 self.pause()
463                         else:
464                                 self.play()
465                         return True
466                 elif event.keyval == gtk.keysyms.Left:
467                         self.controller.previous_chapter()
468                         return True
469                 elif event.keyval == gtk.keysyms.Right:
470                         self.controller.next_chapter()
471                         return True
472
473         @gtk_toolbox.log_exception(_moduleLogger)
474         def _on_window_state_change(self, widget, event, *args):
475                 if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
476                         self.__window_in_fullscreen = True
477                 else:
478                         self.__window_in_fullscreen = False
479
480         @gtk_toolbox.log_exception(_moduleLogger)
481         def quit(self, *args):                   # what are the arguments?
482                 _moduleLogger.info("Shutting down")
483                 try:
484                         self.save_settings()
485                         self.controller.stop()            # to save the state
486                 finally:
487                         gtk.main_quit()
488
489         @gtk_toolbox.log_exception(_moduleLogger)
490         def _on_about_activate(self, *args):
491                 dlg = gtk.AboutDialog()
492                 dlg.set_name(constants.__pretty_app_name__)
493                 dlg.set_version("%s-%d" % (constants.__version__, constants.__build__))
494                 dlg.set_copyright("Copyright 2010")
495                 dlg.set_comments("")
496                 dlg.set_website("http://nqaap.garage.maemo.org/")
497                 dlg.set_authors(["Pengman <pengmeister@gmail.com>", "Ed Page <eopage@byu.net>"])
498                 dlg.run()
499                 dlg.destroy()
500
501         # Actions:  
502
503         def play(self):
504                 self.set_button_text("Stop", "Stop playing the audiobook")
505                 self.controller.play()
506
507         def pause(self):
508                 self.set_button_text("Resume", "Resume playing the audiobook")
509                 self.controller.stop()
510
511         def set_orientation(self, orientation):
512                 if orientation == gtk.ORIENTATION_VERTICAL:
513                         if self.__isPortrait:
514                                 return
515                         hildonize.window_to_portrait(self.win)
516                         self.__isPortrait = True
517
518                         self._viewLayout.remove(self._controlLayout)
519                         self._mainLayout.add(self._controlLayout)
520                 elif orientation == gtk.ORIENTATION_HORIZONTAL:
521                         if not self.__isPortrait:
522                                 return
523                         hildonize.window_to_landscape(self.win)
524                         self.__isPortrait = False
525
526                         self._mainLayout.remove(self._controlLayout)
527                         self._viewLayout.add(self._controlLayout)
528                 else:
529                         raise NotImplementedError(orientation)
530
531         def get_orientation(self):
532                 return gtk.ORIENTATION_VERTICAL if self.__isPortrait else gtk.ORIENTATION_HORIZONTAL
533
534         def _toggle_rotate(self):
535                 if self.__isPortrait:
536                         self.set_orientation(gtk.ORIENTATION_HORIZONTAL)
537                 else:
538                         self.set_orientation(gtk.ORIENTATION_VERTICAL)
539
540         def change_chapter(self, chapterName):
541                 if chapterName is None:
542                         _moduleLogger.debug("chapter selection canceled.")
543                         return True                                # this should end the function and indicate it has been handled
544
545                 _moduleLogger.debug("chapter changed (by controller) to: %s" % chapterName)
546
547         def set_button_text(self, title, text):
548                 if hildonize.IS_FREMANTLE_SUPPORTED:
549                         self.button.set_text(title, text)
550                 else:
551                         self.button.set_label("%s" % (title, ))
552
553         def set_books(self, books):
554                 _moduleLogger.debug("new books")
555                 del self._bookSelection[:]
556                 self._bookSelection.extend(books)
557                 if len(books) == 0 and self.controller is not None:
558                         hildonize.show_information_banner(self.win, "No audiobooks found. \nPlease place your audiobooks in the directory %s" % self.controller.get_books_path())
559
560         def set_book(self, bookPath, cover):
561                 bookName = self.__format_name(bookPath)
562
563                 self.set_button_text("Play", "Start playing the audiobook") # reset button
564                 self._set_display_title(bookName)
565                 if hildonize.IS_FREMANTLE_SUPPORTED:
566                         self.book_button.set_text("Audiobook", bookName)
567                 else:
568                         self._audiobookMenuItem.get_child().set_text("Audiobook: %s" % (bookName, ))
569                 if cover != "":
570                         self.cover.set_from_file(cover)
571
572         def set_chapter(self, chapterIndex):
573                 '''
574                 Called from controller whenever a new chapter is started
575
576                 chapter parameter is supposed to be the index for the chapter, not the name
577                 '''
578                 self.auto_chapter_selected = True
579                 self._set_display_chapter(str(chapterIndex + 1))
580                 if hildonize.IS_FREMANTLE_SUPPORTED:
581                         self.chapter_button.set_text("Chapter", str(chapterIndex))
582                 else:
583                         self._chapterMenuItem.get_child().set_text("Chapter: %s" % (chapterIndex+1, ))
584
585         def set_chapters(self, chapters):
586                 _moduleLogger.debug("setting chapters" )
587                 del self._chapterSelection[:]
588                 self._chapterSelection.extend(chapters)
589
590         def set_sleep_timer(self, mins):
591                 pass
592
593         # Utils
594         def set_selected_value(self, button, value):
595                 i = button.get_selector().get_model(0).index[value] # get index of value from list
596                 button.set_active(i)                                                            # set active index to that index
597
598         def _set_display_title(self, title):
599                 self.title.set_markup("<b><big>%s</big></b>" % title)
600
601         def _set_display_chapter(self, chapter):
602                 self.chapter.set_markup("<b><big>Chapter %s</big></b>" % chapter)
603
604
605 def _old_timeout_add_seconds(timeout, callback):
606         return gobject.timeout_add(timeout * 1000, callback)
607
608
609 def _timeout_add_seconds(timeout, callback):
610         return gobject.timeout_add_seconds(timeout, callback)
611
612
613 try:
614         gobject.timeout_add_seconds
615         timeout_add_seconds = _timeout_add_seconds
616 except AttributeError:
617         timeout_add_seconds = _old_timeout_add_seconds
618
619
620 if __name__ == "__main__":
621         g = Gui(None)