Changing whitespace and fixing a bug with reconfiguring
authorEd Page <eopage@byu.net>
Tue, 28 Dec 2010 00:40:52 +0000 (18:40 -0600)
committerEd Page <eopage@byu.net>
Tue, 28 Dec 2010 00:40:52 +0000 (18:40 -0600)
src/opt/Nqa-Audiobook-player/Audiobook.py
src/opt/Nqa-Audiobook-player/Browser.py
src/opt/Nqa-Audiobook-player/FileStorage.py
src/opt/Nqa-Audiobook-player/Gui.py
src/opt/Nqa-Audiobook-player/Player.py
src/opt/Nqa-Audiobook-player/SimpleGStreamer.py
src/opt/Nqa-Audiobook-player/SimpleOSSOPlayer.py
src/opt/Nqa-Audiobook-player/nqaap_gtk.py
support/builddeb.py

index 179340f..cd28e1b 100644 (file)
@@ -10,167 +10,167 @@ _moduleLogger = logging.getLogger(__name__)
 
 class Audiobook(object):
 
-    def __init__(self, path, current_chapter = 0):
-        self.title = ""
-        self._coverPath = ""
-        self._chapterPaths = []
-        self.current_chapter = current_chapter
-
-        if is_playlist_book(path):
-            self._scan_index(path)
-        elif is_dir_book(path):
-            self._scan_dir(path)
-        elif is_single_chapter(path):
-            self._scan_chapter(path)
-        else:
-            _moduleLogger.info("Audiobook not found in path: " + path)
-            raise IOError("Audiobook directory not found")
-
-        if len(self._chapterPaths) <= self.current_chapter:
-            _moduleLogger.warning(
-                "Audiobook chapter out of range (%s/%s)" % (
-                    self.current_chapter, len(self._chapterPaths)
-                )
-            )
-            self.current_chapter = 0
-
-    @property
-    def chapters(self):
-        return self._chapterPaths
-
-    def get_current_chapter(self):
-        return self._chapterPaths[self.current_chapter]
-
-    def set_chapter(self, chapter):
-        if chapter in self.chapters:
-            self.current_chapter = self.chapters.index(chapter)
-        else:
-            raise Exception("Unknown chapter set")
-
-    def get_previous_chapter(self):
-        """
-        @returns the file name for the next chapter, without path
-        """
-        if 0 == self.current_chapter:
-            return False
-        else:
-            self.current_chapter -= 1
-            return self._chapterPaths[self.current_chapter]
-
-    def get_next_chapter(self):
-        """
-        @returns the file name for the next chapter, without path
-        """
-        if len(self._chapterPaths) == self.current_chapter:
-            return False
-        else:
-            self.current_chapter += 1
-            return self._chapterPaths[self.current_chapter]
-
-    def get_cover_img(self):
-        if self._coverPath:
-            return self._coverPath
-        else:
-            return "%s/NoCover.png" % os.path.dirname(__file__)
-
-    def _scan_dir(self, root):
-        self.title = os.path.split(root)[-1]
-        dirContent = (
-            os.path.join(root, f)
-            for f in os.listdir(root)
-            if not f.startswith(".")
-        )
-
-        files = [
-            path
-            for path in dirContent
-            if os.path.isfile(os.path.join(root, path))
-        ]
-
-        images = [
-            path
-            for path in files
-            if path.rsplit(".", 1)[-1] in ["png", "gif", "jpg", "jpeg"]
-        ]
-        if 0 < len(images):
-            self._coverPath = images[0]
-
-        self._chapterPaths = [
-            path
-            for path in files
-            if is_single_chapter(path)
-        ]
-        self._chapterPaths.sort()
-
-    def _scan_chapter(self, file):
-        self._chapterPaths = [file]
-
-    def _scan_playlist(self, file):
-        root = os.path.dirname(file)
-        self.title = os.path.basename(file).rsplit(".")[0]
-
-        with open(file, 'r') as f:
-            for line in f:
-                if line.startswith("#"):
-                    continue
-                path = line
-                if not os.path.isabs(path):
-                    path = os.path.normpath(os.path.join(root, path))
-                self._chapterPaths.append(path)
-        # Not sorting, assuming the file is in the desired order
-
-    def _scan_index(self, file):
-        import unicodedata
-
-        # Reading file
-        looking_for_title = False
-        looking_for_cover = False
-        looking_for_chapters = False
-
-        with open(file, 'r') as f:
-            for line in f:
-                # title
-                ascii = unicodedata.normalize('NFKD', unicode(line, "latin-1")).encode('ascii', 'ignore')
-                print line[:-1], "PIC\n" in line, line in "#PIC"
-                if "#BOOK" in line:
-                    looking_for_title = True
-                    continue
-                if looking_for_title:
-                    self.title = line[:-1]
-                    looking_for_title = False
-                if "#PIC" in line:
-                    looking_for_cover = True
-                    continue
-                if looking_for_cover:
-                    self.cover = line[:-1]
-                    looking_for_cover = False
-                if "#TRACKS" in line:
-                    looking_for_chapters = True
-                    continue
-                if looking_for_chapters:
-                    if "#CHAPTERS" in line:
-                        break           # no further information needed
-                    self.chapters.append(line.split(':')[0])
+       def __init__(self, path, current_chapter = 0):
+               self.title = ""
+               self._coverPath = ""
+               self._chapterPaths = []
+               self.current_chapter = current_chapter
+
+               if is_playlist_book(path):
+                       self._scan_index(path)
+               elif is_dir_book(path):
+                       self._scan_dir(path)
+               elif is_single_chapter(path):
+                       self._scan_chapter(path)
+               else:
+                       _moduleLogger.info("Audiobook not found in path: " + path)
+                       raise IOError("Audiobook directory not found")
+
+               if len(self._chapterPaths) <= self.current_chapter:
+                       _moduleLogger.warning(
+                               "Audiobook chapter out of range (%s/%s)" % (
+                                       self.current_chapter, len(self._chapterPaths)
+                               )
+                       )
+                       self.current_chapter = 0
+
+       @property
+       def chapters(self):
+               return self._chapterPaths
+
+       def get_current_chapter(self):
+               return self._chapterPaths[self.current_chapter]
+
+       def set_chapter(self, chapter):
+               if chapter in self.chapters:
+                       self.current_chapter = self.chapters.index(chapter)
+               else:
+                       raise Exception("Unknown chapter set")
+
+       def get_previous_chapter(self):
+               """
+               @returns the file name for the next chapter, without path
+               """
+               if 0 == self.current_chapter:
+                       return False
+               else:
+                       self.current_chapter -= 1
+                       return self._chapterPaths[self.current_chapter]
+
+       def get_next_chapter(self):
+               """
+               @returns the file name for the next chapter, without path
+               """
+               if len(self._chapterPaths) == self.current_chapter:
+                       return False
+               else:
+                       self.current_chapter += 1
+                       return self._chapterPaths[self.current_chapter]
+
+       def get_cover_img(self):
+               if self._coverPath:
+                       return self._coverPath
+               else:
+                       return "%s/NoCover.png" % os.path.dirname(__file__)
+
+       def _scan_dir(self, root):
+               self.title = os.path.split(root)[-1]
+               dirContent = (
+                       os.path.join(root, f)
+                       for f in os.listdir(root)
+                       if not f.startswith(".")
+               )
+
+               files = [
+                       path
+                       for path in dirContent
+                       if os.path.isfile(os.path.join(root, path))
+               ]
+
+               images = [
+                       path
+                       for path in files
+                       if path.rsplit(".", 1)[-1] in ["png", "gif", "jpg", "jpeg"]
+               ]
+               if 0 < len(images):
+                       self._coverPath = images[0]
+
+               self._chapterPaths = [
+                       path
+                       for path in files
+                       if is_single_chapter(path)
+               ]
+               self._chapterPaths.sort()
+
+       def _scan_chapter(self, file):
+               self._chapterPaths = [file]
+
+       def _scan_playlist(self, file):
+               root = os.path.dirname(file)
+               self.title = os.path.basename(file).rsplit(".")[0]
+
+               with open(file, 'r') as f:
+                       for line in f:
+                               if line.startswith("#"):
+                                       continue
+                               path = line
+                               if not os.path.isabs(path):
+                                       path = os.path.normpath(os.path.join(root, path))
+                               self._chapterPaths.append(path)
+               # Not sorting, assuming the file is in the desired order
+
+       def _scan_index(self, file):
+               import unicodedata
+
+               # Reading file
+               looking_for_title = False
+               looking_for_cover = False
+               looking_for_chapters = False
+
+               with open(file, 'r') as f:
+                       for line in f:
+                               # title
+                               ascii = unicodedata.normalize('NFKD', unicode(line, "latin-1")).encode('ascii', 'ignore')
+                               print line[:-1], "PIC\n" in line, line in "#PIC"
+                               if "#BOOK" in line:
+                                       looking_for_title = True
+                                       continue
+                               if looking_for_title:
+                                       self.title = line[:-1]
+                                       looking_for_title = False
+                               if "#PIC" in line:
+                                       looking_for_cover = True
+                                       continue
+                               if looking_for_cover:
+                                       self.cover = line[:-1]
+                                       looking_for_cover = False
+                               if "#TRACKS" in line:
+                                       looking_for_chapters = True
+                                       continue
+                               if looking_for_chapters:
+                                       if "#CHAPTERS" in line:
+                                               break              # no further information needed
+                                       self.chapters.append(line.split(':')[0])
 
 
 def is_dir_book(path):
-    return os.path.isdir(path)
+       return os.path.isdir(path)
 
 
 def is_playlist_book(path):
-    return path.rsplit(".", 1)[-1] in ["m3u"]
+       return path.rsplit(".", 1)[-1] in ["m3u"]
 
 
 def is_single_chapter(path):
-    return path.rsplit(".", 1)[-1] in ["awb", "mp3", "spx", "ogg", "ac3", "wav"]
+       return path.rsplit(".", 1)[-1] in ["awb", "mp3", "spx", "ogg", "ac3", "wav"]
 
 
 def is_book(path):
-    if is_dir_book(path):
-        return True
-    elif is_playlist_book(path):
-        return True
-    elif is_single_chapter(path):
-        return True
-    else:
-        return False
+       if is_dir_book(path):
+               return True
+       elif is_playlist_book(path):
+               return True
+       elif is_single_chapter(path):
+               return True
+       else:
+               return False
index 36d4e34..31ce7d6 100644 (file)
@@ -2,4 +2,4 @@ import os
 \r
 \r
 def open(url):\r
-    os.system('dbus-send --system --type=method_call --dest="com.nokia.osso_browser" /com/nokia/osso_browser/request com.nokia.osso_browser.load_url string:"%s"' % url)\r
+       os.system('dbus-send --system --type=method_call --dest="com.nokia.osso_browser" /com/nokia/osso_browser/request com.nokia.osso_browser.load_url string:"%s"' % url)\r
index 8536f8a..af19c9d 100644 (file)
@@ -13,94 +13,94 @@ _moduleLogger = logging.getLogger(__name__)
 
 class FileStorage(object):
 
-    def __init__(self, path="~/.SornPlayer/"):
-        # Setup dir
-        _moduleLogger.info("init filestorage")
-        self.path = path
-        self.books_path = os.path.join(self.path, "books.json")
-        self.selected = None
-        self._books = {}
-
-    def load(self):
-        if not os.path.isdir(self.path):
-            os.makedirs(self.path)
-
-        try:
-            with open(self.books_path, "r") as settingsFile:
-                settings = simplejson.load(settingsFile)
-        except IOError, e:
-            _moduleLogger.info("No settings")
-            settings = {}
-        except ValueError:
-            _moduleLogger.info("Settings were corrupt")
-            settings = {}
-
-        if settings:
-            self._books = settings["books"]
-            self.selected = settings["selected"]
-        else:
-            _moduleLogger.info("Falling back to old settings format")
-            self._load_old_settings()
-
-    def save(self):
-        settings = {
-            "selected": self.selected,
-            "books": self._books,
-        }
-        with open(self.books_path, "w") as settingsFile:
-            simplejson.dump(settings, settingsFile)
-
-    def get_selected(self):
-        """returns the currently selected book"""
-        return self.selected
-
-    def select_book(self, bookName):
-        """ Sets the book as the currently playing, and adds it to the
-        database if it is not already there"""
-        book_file = os.path.join(self.books_path, bookName)
-        if bookName not in self._books:
-            self._books[bookName] = {
-                "chapter": 0,
-                "position": 0,
-            }
-
-        self.selected = bookName
-
-    def set_time(self, chapter, position):
-        """ Sets the current time for the book that is currently selected"""
-        bookInfo = self._books[self.selected]
-        bookInfo["chapter"] = chapter
-        bookInfo["position"] = position
-
-    def get_time(self):
-        """Returns the current saved time for the current selected book"""
-        bookInfo = self._books[self.selected]
-        return bookInfo["chapter"], bookInfo["position"]
-
-    def _load_old_settings(self):
-        conf = os.path.join(self.path, "current")
-
-        try:
-            with open(conf) as f:
-                self.selected = f.readline()
-
-            books_path = os.path.join(self.path, "books/")
-            for book in os.listdir(books_path):
-                book_file = os.path.join(books_path, book)
-                with open(book_file, 'r') as f:
-                    chapter = int(f.readline())
-                    position = int(f.readline())
-                self._books[book] = {
-                    "chapter": chapter,
-                    "position": position,
-                }
-        except IOError, e:
-            if e.errno == 2:
-                pass
-            else:
-                raise
-        except OSError, e:
-            if e.errno == 2:
-                pass
-            else:
-                raise
+       def __init__(self, path="~/.SornPlayer/"):
+               # Setup dir
+               _moduleLogger.info("init filestorage")
+               self.path = path
+               self.books_path = os.path.join(self.path, "books.json")
+               self.selected = None
+               self._books = {}
+
+       def load(self):
+               if not os.path.isdir(self.path):
+                       os.makedirs(self.path)
+
+               try:
+                       with open(self.books_path, "r") as settingsFile:
+                               settings = simplejson.load(settingsFile)
+               except IOError, e:
+                       _moduleLogger.info("No settings")
+                       settings = {}
+               except ValueError:
+                       _moduleLogger.info("Settings were corrupt")
+                       settings = {}
+
+               if settings:
+                       self._books = settings["books"]
+                       self.selected = settings["selected"]
+               else:
+                       _moduleLogger.info("Falling back to old settings format")
+                       self._load_old_settings()
+
+       def save(self):
+               settings = {
+                       "selected": self.selected,
+                       "books": self._books,
+               }
+               with open(self.books_path, "w") as settingsFile:
+                       simplejson.dump(settings, settingsFile)
+
+       def get_selected(self):
+               """returns the currently selected book"""
+               return self.selected
+
+       def select_book(self, bookName):
+               """ Sets the book as the currently playing, and adds it to the
+               database if it is not already there"""
+               book_file = os.path.join(self.books_path, bookName)
+               if bookName not in self._books:
+                       self._books[bookName] = {
+                               "chapter": 0,
+                               "position": 0,
+                       }
+
+               self.selected = bookName
+
+       def set_time(self, chapter, position):
+               """ Sets the current time for the book that is currently selected"""
+               bookInfo = self._books[self.selected]
+               bookInfo["chapter"] = chapter
+               bookInfo["position"] = position
+
+       def get_time(self):
+               """Returns the current saved time for the current selected book"""
+               bookInfo = self._books[self.selected]
+               return bookInfo["chapter"], bookInfo["position"]
+
+       def _load_old_settings(self):
+               conf = os.path.join(self.path, "current")
+
+               try:
+                       with open(conf) as f:
+                               self.selected = f.readline()
+
+                       books_path = os.path.join(self.path, "books/")
+                       for book in os.listdir(books_path):
+                               book_file = os.path.join(books_path, book)
+                               with open(book_file, 'r') as f:
+                                       chapter = int(f.readline())
+                                       position = int(f.readline())
+                               self._books[book] = {
+                                       "chapter": chapter,
+                                       "position": position,
+                               }
+               except IOError, e:
+                       if e.errno == 2:
+                               pass
+                       else:
+                               raise
+               except OSError, e:
+                       if e.errno == 2:
+                               pass
+                       else:
+                               raise
index 9eecb2c..5b0ff29 100644 (file)
@@ -15,8 +15,8 @@ import CallMonitor
 import settings
 
 if hildonize.IS_FREMANTLE_SUPPORTED:
-    # I don't normally do this but I want to error as loudly as possibly when an issue arises
-    import hildon
+       # I don't normally do this but I want to error as loudly as possibly when an issue arises
+       import hildon
 
 
 _moduleLogger = logging.getLogger(__name__)
@@ -24,599 +24,599 @@ _moduleLogger = logging.getLogger(__name__)
 
 class Gui(object):
 
-    # @todo Jump straight to book selection on first launch?
-    # @todo Absolute increments (+/-5 seconds)
-    # @todo Show elapsed time / time lef
-    # @todo Volume control when screen is off
-    # @todo Variable speed
-    #  http://scaletempo.sourceforge.net/0/task-list.html
-    #  http://www.gstreamer.net/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-scaletempo.html
-
-    def __init__(self):
-        _moduleLogger.info("Starting GUI")
-        self._clipboard = gtk.clipboard_get()
-        self._callMonitor = CallMonitor.CallMonitor()
-        self.__settingsWindow = None
-        self.__settingsManager = None
-        self._bookSelection = []
-        self._bookSelectionIndex = -1
-        self._chapterSelection = []
-        self._chapterSelectionIndex = -1
-        self._sleepSelection = ["0", "1", "10", "20", "30", "60"]
-        self._sleepSelectionIndex = 0
-
-        self.__window_in_fullscreen = False #The window isn't in full screen mode initially.
-        self.__isPortrait = False
-
-        self.controller = None
-        self.sleep_timer = None
-
-        # set up gui
-        self.setup()
-        self._callMonitor.connect("call_start", self.__on_call_started)
-        self._callMonitor.start()
-
-    def setup(self):
-        self._app = hildonize.get_app_class()()
-        self.win = gtk.Window()
-        self.win = hildonize.hildonize_window(self._app, self.win)
-        self.win.set_title(constants.__pretty_app_name__)
-
-        # Cover image
-        self.cover = gtk.Image()
-
-        # Controls:
-
-        # Label that hold the title of the book,and maybe the chapter
-        self.title = gtk.Label()
-        self.title.set_justify(gtk.JUSTIFY_CENTER)
-        self._set_display_title("Select a book to start listening")
-
-        self.chapter = gtk.Label()
-        self.chapter.set_justify(gtk.JUSTIFY_CENTER)
-
-        # Seekbar 
-        if hildonize.IS_FREMANTLE_SUPPORTED:
-            self.seek = hildon.Seekbar()
-            self.seek.set_range(0.0, 100)
-            self.seek.set_draw_value(False)
-            self.seek.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
-            self.seek.connect('change-value', self.seek_changed) # event
-            # self.seek.connect('value-changed',self.seek_changed) # event
-        else:
-            adjustment = gtk.Adjustment(0, 0, 101, 1, 5, 1)
-            self.seek = gtk.HScale(adjustment)
-            self.seek.set_draw_value(False)
-            self.seek.connect('change-value', self.seek_changed) # event
-
-        # Pause button
-        if hildonize.IS_FREMANTLE_SUPPORTED:
-            self.backButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
-            image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PREVIOUS, gtk.HILDON_SIZE_FINGER_HEIGHT)
-            self.backButton.set_image(image)
-
-            self.button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
-
-            self.forwardButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
-            image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_NEXT, gtk.HILDON_SIZE_FINGER_HEIGHT)
-            self.forwardButton.set_image(image)
-        else:
-            self.backButton = gtk.Button(stock=gtk.STOCK_MEDIA_PREVIOUS)
-            self.button = gtk.Button()
-            self.forwardButton = gtk.Button(stock=gtk.STOCK_MEDIA_NEXT)
-        self.set_button_text("Play", "Start playing the audiobook")
-        self.backButton.connect('clicked', self._on_previous_chapter)
-        self.button.connect('clicked', self.play_pressed) # event
-        self.forwardButton.connect('clicked', self._on_next_chapter)
-
-        self._toolbar = gtk.HBox()
-        self._toolbar.pack_start(self.backButton, False, False, 0)
-        self._toolbar.pack_start(self.button, True, True, 0)
-        self._toolbar.pack_start(self.forwardButton, False, False, 0)
-
-        # Box to hold the controls:
-        self._controlLayout = gtk.VBox()
-        self._controlLayout.pack_start(gtk.Label(), True, True, 0)
-        self._controlLayout.pack_start(self.title, False, True, 0)
-        self._controlLayout.pack_start(self.chapter, False, True, 0)
-        self._controlLayout.pack_start(gtk.Label(), True, True, 0)
-        self._controlLayout.pack_start(self.seek, False, True, 0)
-        self._controlLayout.pack_start(self._toolbar, False, True, 0)
-
-        #Box that divides the layout in two: cover on the lefta
-        #and controls on the right
-        self._viewLayout = gtk.HBox()
-        self._viewLayout.pack_start(self.cover, True, True, 0)
-        self._viewLayout.add(self._controlLayout)
-
-        self._menuBar = gtk.MenuBar()
-        self._menuBar.show()
-
-        self._mainLayout = gtk.VBox()
-        self._mainLayout.pack_start(self._menuBar, False, False, 0)
-        self._mainLayout.pack_start(self._viewLayout)
-
-        # Add hbox to the window
-        self.win.add(self._mainLayout)
-
-        #Menu:
-        # Create menu
-        self._populate_menu()
-
-        self.win.connect("delete_event", self.quit) # Add shutdown event
-        self.win.connect("key-press-event", self.on_key_press)
-        self.win.connect("window-state-event", self._on_window_state_change)
-
-        self.win.show_all()
-
-        # Run update timer
-        self.setup_timers()
-
-    def _populate_menu(self):
-        self._menuBar = hildonize.hildonize_menu(
-            self.win,
-            self._menuBar,
-        )
-        if hildonize.IS_FREMANTLE_SUPPORTED:
-            # Create a picker button 
-            self.book_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
-                                              hildon.BUTTON_ARRANGEMENT_VERTICAL)
-            self.book_button.set_title("Audiobook") # Set a title to the button 
-            self.book_button.connect("clicked", self._on_select_audiobook)
-
-            # Create a picker button 
-            self.chapter_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
-                                              hildon.BUTTON_ARRANGEMENT_VERTICAL)
-            self.chapter_button.set_title("Chapter") # Set a title to the button 
-            self.chapter_button.connect("clicked", self._on_select_chapter)
-
-            # Create a picker button 
-            self.sleeptime_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
-                                              hildon.BUTTON_ARRANGEMENT_VERTICAL)
-            self.sleeptime_button.set_title("Sleeptimer") # Set a title to the button 
-            self.sleeptime_button.connect("clicked", self._on_select_sleep)
-
-            settings_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
-            settings_button.set_label("Settings")
-            settings_button.connect("clicked", self._on_settings)
-
-            about_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
-            about_button.set_label("About")
-            about_button.connect("clicked", self._on_about_activate)
-
-            help_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
-            help_button.set_label("Help")
-            help_button.connect("clicked", self.get_help)
-
-            self._menuBar.append(self.book_button)        # Add the button to menu
-            self._menuBar.append(self.chapter_button)        # Add the button to menu
-            self._menuBar.append(self.sleeptime_button)        # Add the button to menu
-            self._menuBar.append(settings_button)
-            self._menuBar.append(help_button)
-            self._menuBar.append(about_button)
-            self._menuBar.show_all()
-        else:
-            self._audiobookMenuItem = gtk.MenuItem("Audiobook: ")
-            self._audiobookMenuItem.connect("activate", self._on_select_audiobook)
-
-            self._chapterMenuItem = gtk.MenuItem("Chapter: ")
-            self._chapterMenuItem.connect("activate", self._on_select_chapter)
-
-            self._sleepMenuItem = gtk.MenuItem("Sleeptimer: 0")
-            self._sleepMenuItem.connect("activate", self._on_select_sleep)
-
-            settingsMenuItem = gtk.MenuItem("Settings")
-            settingsMenuItem.connect("activate", self._on_settings)
-
-            aboutMenuItem = gtk.MenuItem("About")
-            aboutMenuItem.connect("activate", self._on_about_activate)
-
-            helpMenuItem = gtk.MenuItem("Help")
-            helpMenuItem.connect("activate", self.get_help)
-
-            booksMenu = gtk.Menu()
-            booksMenu.append(self._audiobookMenuItem)
-            booksMenu.append(self._chapterMenuItem)
-            booksMenu.append(self._sleepMenuItem)
-            booksMenu.append(settingsMenuItem)
-            booksMenu.append(helpMenuItem)
-            booksMenu.append(aboutMenuItem)
-
-            booksMenuItem = gtk.MenuItem("Books")
-            booksMenuItem.show()
-            booksMenuItem.set_submenu(booksMenu)
-            self._menuBar.append(booksMenuItem)
-            self._menuBar.show_all()
-
-    def setup_timers(self):
-        self.seek_timer = timeout_add_seconds(3, self.update_seek)
-
-    def save_settings(self):
-        config = ConfigParser.SafeConfigParser()
-        self._save_settings(config)
-        with open(constants._user_settings_, "wb") as configFile:
-            config.write(configFile)
-        self.controller.save()
-
-    def _save_settings(self, config):
-        config.add_section(constants.__pretty_app_name__)
-        config.set(constants.__pretty_app_name__, "portrait", str(self.__isPortrait))
-        config.set(constants.__pretty_app_name__, "fullscreen", str(self.__window_in_fullscreen))
-        config.set(constants.__pretty_app_name__, "audiopath", self.controller.get_books_path())
-
-    def load_settings(self):
-        config = ConfigParser.SafeConfigParser()
-        config.read(constants._user_settings_)
-        self._load_settings(config)
-
-    def _load_settings(self, config):
-        isPortrait = False
-        window_in_fullscreen = False
-        booksPath = constants._default_book_path_
-        try:
-            isPortrait = config.getboolean(constants.__pretty_app_name__, "portrait")
-            window_in_fullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen")
-            booksPath = config.get(constants.__pretty_app_name__, "audiopath")
-        except ConfigParser.NoSectionError, e:
-            _moduleLogger.info(
-                "Settings file %s is missing section %s" % (
-                    constants._user_settings_,
-                    e.section,
-                )
-            )
-
-        if isPortrait ^ self.__isPortrait:
-            if isPortrait:
-                orientation = gtk.ORIENTATION_VERTICAL
-            else:
-                orientation = gtk.ORIENTATION_HORIZONTAL
-            self.set_orientation(orientation)
-
-        self.__window_in_fullscreen = window_in_fullscreen
-        if self.__window_in_fullscreen:
-            self.win.fullscreen()
-        else:
-            self.win.unfullscreen()
-
-        self.controller.load(booksPath)
-
-    @staticmethod
-    def __format_name(path):
-        if os.path.isfile(path):
-            return os.path.basename(path).rsplit(".", 1)[0]
-        else:
-            return os.path.basename(path)
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_select_audiobook(self, *args):
-        if not self._bookSelection:
-            return
-        index = hildonize.touch_selector(
-            self.win,
-            "Audiobook",
-            (self.__format_name(bookPath) for bookPath in self._bookSelection),
-            self._bookSelectionIndex if 0 <= self._bookSelectionIndex else 0,
-        )
-        self._bookSelectionIndex = index
-        bookName = self._bookSelection[index]
-        self.controller.set_book(bookName)
-        self.set_button_text("Play", "Start playing the audiobook") # reset button
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_select_chapter(self, *args):
-        if not self._chapterSelection:
-            return
-        index = hildonize.touch_selector(
-            self.win,
-            "Chapter",
-            (self.__format_name(chapterPath) for chapterPath in self._chapterSelection),
-            self._chapterSelectionIndex if 0 <= self._chapterSelectionIndex else 0,
-        )
-        self._chapterSelectionIndex = index
-        chapterName = self._chapterSelection[index]
-        self.controller.set_chapter(chapterName)
-        self.set_button_text("Play", "Start playing the audiobook") # reset button
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_select_sleep(self, *args):
-        if self.sleep_timer is not None:
-            gobject.source_remove(self.sleep_timer)
-
-        try:
-            index = hildonize.touch_selector(
-                self.win,
-                "Sleeptimer",
-                self._sleepSelection,
-                self._sleepSelectionIndex if 0 <= self._sleepSelectionIndex else 0,
-            )
-        except RuntimeError:
-            _moduleLogger.exception("Handling as if user cancelled")
-            hildonize.show_information_banner(self.win, "Sleep timer canceled")
-            index = 0
-
-        self._sleepSelectionIndex = index
-        sleepName = self._sleepSelection[index]
-
-        time_out = int(sleepName)
-        if 0 < time_out:
-            timeout_add_seconds(time_out * 60, self.sleep)
-
-        if hildonize.IS_FREMANTLE_SUPPORTED:
-            self.sleeptime_button.set_text("Sleeptimer", sleepName)
-        else:
-            self._sleepMenuItem.get_child().set_text("Sleeptimer: %s" % (sleepName, ))
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def __on_call_started(self, callMonitor):
-        self.pause()
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_settings(self, *args):
-        if self.__settingsWindow is None:
-            vbox = gtk.VBox()
-            self.__settingsManager = settings.SettingsDialog(vbox)
-
-            self.__settingsWindow = gtk.Window()
-            self.__settingsWindow.add(vbox)
-            self.__settingsWindow = hildonize.hildonize_window(self._app, self.__settingsWindow)
-            self.__settingsManager.window = self.__settingsWindow
-
-            self.__settingsWindow.set_title("Settings")
-            self.__settingsWindow.set_transient_for(self.win)
-            self.__settingsWindow.set_default_size(*self.win.get_size())
-            self.__settingsWindow.connect("delete-event", self._on_settings_delete)
-        self.__settingsManager.set_portrait_state(self.__isPortrait)
-        self.__settingsManager.set_audiobook_path(self.controller.get_books_path())
-        self.__settingsWindow.set_modal(True)
-        self.__settingsWindow.show_all()
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_settings_delete(self, *args):
-        self.__settingsWindow.emit_stop_by_name("delete-event")
-        self.__settingsWindow.hide()
-        self.__settingsWindow.set_modal(False)
-
-        isPortrait = self.__settingsManager.is_portrait()
-        if isPortrait ^ self.__isPortrait:
-            if isPortrait:
-                orientation = gtk.ORIENTATION_VERTICAL
-            else:
-                orientation = gtk.ORIENTATION_HORIZONTAL
-            self.set_orientation(orientation)
-        if self.__settingsManager.get_audiobook_path() != self.controller.get_books_path():
-            self.controller.reload(self.__settingsManager.get_audiobook_path())
-
-        return True
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def update_seek(self):
-        #print self.controller.get_percentage()
-        if self.controller.is_playing():
-            gtk.gdk.threads_enter()
-            self.seek.set_value(self.controller.get_percentage() * 100)
-            gtk.gdk.threads_leave()
-        #self.controller.get_percentage() 
-        return True                     # run again
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def sleep(self):
-        _moduleLogger.info("sleep time timeout")
-        hildonize.show_information_banner(self.win, "Sleep timer")
-        self.controller.stop()
-        self.set_button_text("Resume", "Resume playing the audiobook")
-        return False                    # do not repeat
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def get_help(self, button):
-        Browser.open("file:///opt/Nqa-Audiobook-player/Help/nqaap.html")
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def seek_changed(self, seek, scroll , value):
-        # print "sok", scroll
-        self.controller.seek_percent(seek.get_value() / 100.0)
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_next_chapter(self, *args):
-        self.controller.next_chapter()
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_previous_chapter(self, *args):
-        self.controller.previous_chapter()
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def play_pressed(self, button):
-        if self.controller.is_playing():
-            self.pause()
-        else:
-            self.play()
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def on_key_press(self, widget, event, *args):
-        RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
-        isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
-        if (
-            event.keyval == gtk.keysyms.F6 or
-            event.keyval in RETURN_TYPES and isCtrl
-        ):
-            # The "Full screen" hardware key has been pressed 
-            if self.__window_in_fullscreen:
-                self.win.unfullscreen ()
-            else:
-                self.win.fullscreen ()
-            return True
-        elif event.keyval == gtk.keysyms.o and isCtrl:
-            self._toggle_rotate()
-            return True
-        elif (
-            event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
-            event.get_state() & gtk.gdk.CONTROL_MASK
-        ):
-            self.quit()
-        elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
-            with open(constants._user_logpath_, "r") as f:
-                logLines = f.xreadlines()
-                log = "".join(logLines)
-                self._clipboard.set_text(str(log))
-            return True
-        elif event.keyval in RETURN_TYPES:
-            if self.controller.is_playing():
-                self.pause()
-            else:
-                self.play()
-            return True
-        elif event.keyval == gtk.keysyms.Left:
-            self.controller.previous_chapter()
-            return True
-        elif event.keyval == gtk.keysyms.Right:
-            self.controller.next_chapter()
-            return True
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_window_state_change(self, widget, event, *args):
-        if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
-            self.__window_in_fullscreen = True
-        else:
-            self.__window_in_fullscreen = False
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def quit(self, *args):             # what are the arguments?
-        _moduleLogger.info("Shutting down")
-        try:
-            self.save_settings()
-            self.controller.stop()          # to save the state
-        finally:
-            gtk.main_quit()
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_about_activate(self, *args):
-        dlg = gtk.AboutDialog()
-        dlg.set_name(constants.__pretty_app_name__)
-        dlg.set_version("%s-%d" % (constants.__version__, constants.__build__))
-        dlg.set_copyright("Copyright 2010")
-        dlg.set_comments("")
-        dlg.set_website("http://nqaap.garage.maemo.org/")
-        dlg.set_authors(["Pengman <pengmeister@gmail.com>", "Ed Page <eopage@byu.net>"])
-        dlg.run()
-        dlg.destroy()
-
-    # Actions:  
-
-    def play(self):
-        self.set_button_text("Stop", "Stop playing the audiobook")
-        self.controller.play()
-
-    def pause(self):
-        self.set_button_text("Resume", "Resume playing the audiobook")
-        self.controller.stop()
-
-    def set_orientation(self, orientation):
-        if orientation == gtk.ORIENTATION_VERTICAL:
-            if self.__isPortrait:
-                return
-            hildonize.window_to_portrait(self.win)
-            self.__isPortrait = True
-
-            self._viewLayout.remove(self._controlLayout)
-            self._mainLayout.add(self._controlLayout)
-        elif orientation == gtk.ORIENTATION_HORIZONTAL:
-            if not self.__isPortrait:
-                return
-            hildonize.window_to_landscape(self.win)
-            self.__isPortrait = False
-
-            self._mainLayout.remove(self._controlLayout)
-            self._viewLayout.add(self._controlLayout)
-        else:
-            raise NotImplementedError(orientation)
-
-    def get_orientation(self):
-        return gtk.ORIENTATION_VERTICAL if self.__isPortrait else gtk.ORIENTATION_HORIZONTAL
-
-    def _toggle_rotate(self):
-        if self.__isPortrait:
-            self.set_orientation(gtk.ORIENTATION_HORIZONTAL)
-        else:
-            self.set_orientation(gtk.ORIENTATION_VERTICAL)
-
-    def change_chapter(self, chapterName):
-        if chapterName is None:
-            _moduleLogger.debug("chapter selection canceled.")
-            return True                   # this should end the function and indicate it has been handled
-
-        _moduleLogger.debug("chapter changed (by controller) to: %s" % chapterName)
-
-    def set_button_text(self, title, text):
-        if hildonize.IS_FREMANTLE_SUPPORTED:
-            self.button.set_text(title, text)
-        else:
-            self.button.set_label("%s" % (title, ))
-
-    def set_books(self, books):
-        _moduleLogger.debug("new books")
-        del self._bookSelection[:]
-        self._bookSelection.extend(books)
-        if len(books) == 0 and self.controller is not None:
-            hildonize.show_information_banner(self.win, "No audiobooks found. \nPlease place your audiobooks in the directory %s" % self.controller.get_books_path())
-
-    def set_book(self, bookPath, cover):
-        bookName = self.__format_name(bookPath)
-
-        self.set_button_text("Play", "Start playing the audiobook") # reset button
-        self._set_display_title(bookName)
-        if hildonize.IS_FREMANTLE_SUPPORTED:
-            self.book_button.set_text("Audiobook", bookName)
-        else:
-            self._audiobookMenuItem.get_child().set_text("Audiobook: %s" % (bookName, ))
-        if cover != "":
-            self.cover.set_from_file(cover)
-
-    def set_chapter(self, chapterIndex):
-        '''
-        Called from controller whenever a new chapter is started
-
-        chapter parameter is supposed to be the index for the chapter, not the name
-        '''
-        self.auto_chapter_selected = True
-        self._set_display_chapter(str(chapterIndex + 1))
-        if hildonize.IS_FREMANTLE_SUPPORTED:
-            self.chapter_button.set_text("Chapter", str(chapterIndex))
-        else:
-            self._chapterMenuItem.get_child().set_text("Chapter: %s" % (chapterIndex+1, ))
-
-    def set_chapters(self, chapters):
-        _moduleLogger.debug("setting chapters" )
-        del self._chapterSelection[:]
-        self._chapterSelection.extend(chapters)
-
-    def set_sleep_timer(self, mins):
-        pass
-
-    # Utils
-    def set_selected_value(self, button, value):
-        i = button.get_selector().get_model(0).index[value] # get index of value from list
-        button.set_active(i)                                # set active index to that index
-
-    def _set_display_title(self, title):
-        self.title.set_markup("<b><big>%s</big></b>" % title)
-
-    def _set_display_chapter(self, chapter):
-        self.chapter.set_markup("<b><big>Chapter %s</big></b>" % chapter)
+       # @todo Jump straight to book selection on first launch?
+       # @todo Absolute increments (+/-5 seconds)
+       # @todo Show elapsed time / time lef
+       # @todo Volume control when screen is off
+       # @todo Variable speed
+       #  http://scaletempo.sourceforge.net/0/task-list.html
+       #  http://www.gstreamer.net/data/doc/gstreamer/head/gst-plugins-bad-plugins/html/gst-plugins-bad-plugins-scaletempo.html
+
+       def __init__(self):
+               _moduleLogger.info("Starting GUI")
+               self._clipboard = gtk.clipboard_get()
+               self._callMonitor = CallMonitor.CallMonitor()
+               self.__settingsWindow = None
+               self.__settingsManager = None
+               self._bookSelection = []
+               self._bookSelectionIndex = -1
+               self._chapterSelection = []
+               self._chapterSelectionIndex = -1
+               self._sleepSelection = ["0", "1", "10", "20", "30", "60"]
+               self._sleepSelectionIndex = 0
+
+               self.__window_in_fullscreen = False #The window isn't in full screen mode initially.
+               self.__isPortrait = False
+
+               self.controller = None
+               self.sleep_timer = None
+
+               # set up gui
+               self.setup()
+               self._callMonitor.connect("call_start", self.__on_call_started)
+               self._callMonitor.start()
+
+       def setup(self):
+               self._app = hildonize.get_app_class()()
+               self.win = gtk.Window()
+               self.win = hildonize.hildonize_window(self._app, self.win)
+               self.win.set_title(constants.__pretty_app_name__)
+
+               # Cover image
+               self.cover = gtk.Image()
+
+               # Controls:
+
+               # Label that hold the title of the book,and maybe the chapter
+               self.title = gtk.Label()
+               self.title.set_justify(gtk.JUSTIFY_CENTER)
+               self._set_display_title("Select a book to start listening")
+
+               self.chapter = gtk.Label()
+               self.chapter.set_justify(gtk.JUSTIFY_CENTER)
+
+               # Seekbar 
+               if hildonize.IS_FREMANTLE_SUPPORTED:
+                       self.seek = hildon.Seekbar()
+                       self.seek.set_range(0.0, 100)
+                       self.seek.set_draw_value(False)
+                       self.seek.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
+                       self.seek.connect('change-value', self.seek_changed) # event
+                       # self.seek.connect('value-changed',self.seek_changed) # event
+               else:
+                       adjustment = gtk.Adjustment(0, 0, 101, 1, 5, 1)
+                       self.seek = gtk.HScale(adjustment)
+                       self.seek.set_draw_value(False)
+                       self.seek.connect('change-value', self.seek_changed) # event
+
+               # Pause button
+               if hildonize.IS_FREMANTLE_SUPPORTED:
+                       self.backButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+                       image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_PREVIOUS, gtk.HILDON_SIZE_FINGER_HEIGHT)
+                       self.backButton.set_image(image)
+
+                       self.button = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+
+                       self.forwardButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+                       image = gtk.image_new_from_stock(gtk.STOCK_MEDIA_NEXT, gtk.HILDON_SIZE_FINGER_HEIGHT)
+                       self.forwardButton.set_image(image)
+               else:
+                       self.backButton = gtk.Button(stock=gtk.STOCK_MEDIA_PREVIOUS)
+                       self.button = gtk.Button()
+                       self.forwardButton = gtk.Button(stock=gtk.STOCK_MEDIA_NEXT)
+               self.set_button_text("Play", "Start playing the audiobook")
+               self.backButton.connect('clicked', self._on_previous_chapter)
+               self.button.connect('clicked', self.play_pressed) # event
+               self.forwardButton.connect('clicked', self._on_next_chapter)
+
+               self._toolbar = gtk.HBox()
+               self._toolbar.pack_start(self.backButton, False, False, 0)
+               self._toolbar.pack_start(self.button, True, True, 0)
+               self._toolbar.pack_start(self.forwardButton, False, False, 0)
+
+               # Box to hold the controls:
+               self._controlLayout = gtk.VBox()
+               self._controlLayout.pack_start(gtk.Label(), True, True, 0)
+               self._controlLayout.pack_start(self.title, False, True, 0)
+               self._controlLayout.pack_start(self.chapter, False, True, 0)
+               self._controlLayout.pack_start(gtk.Label(), True, True, 0)
+               self._controlLayout.pack_start(self.seek, False, True, 0)
+               self._controlLayout.pack_start(self._toolbar, False, True, 0)
+
+               #Box that divides the layout in two: cover on the lefta
+               #and controls on the right
+               self._viewLayout = gtk.HBox()
+               self._viewLayout.pack_start(self.cover, True, True, 0)
+               self._viewLayout.add(self._controlLayout)
+
+               self._menuBar = gtk.MenuBar()
+               self._menuBar.show()
+
+               self._mainLayout = gtk.VBox()
+               self._mainLayout.pack_start(self._menuBar, False, False, 0)
+               self._mainLayout.pack_start(self._viewLayout)
+
+               # Add hbox to the window
+               self.win.add(self._mainLayout)
+
+               #Menu:
+               # Create menu
+               self._populate_menu()
+
+               self.win.connect("delete_event", self.quit) # Add shutdown event
+               self.win.connect("key-press-event", self.on_key_press)
+               self.win.connect("window-state-event", self._on_window_state_change)
+
+               self.win.show_all()
+
+               # Run update timer
+               self.setup_timers()
+
+       def _populate_menu(self):
+               self._menuBar = hildonize.hildonize_menu(
+                       self.win,
+                       self._menuBar,
+               )
+               if hildonize.IS_FREMANTLE_SUPPORTED:
+                       # Create a picker button 
+                       self.book_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
+                                                                                         hildon.BUTTON_ARRANGEMENT_VERTICAL)
+                       self.book_button.set_title("Audiobook") # Set a title to the button 
+                       self.book_button.connect("clicked", self._on_select_audiobook)
+
+                       # Create a picker button 
+                       self.chapter_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
+                                                                                         hildon.BUTTON_ARRANGEMENT_VERTICAL)
+                       self.chapter_button.set_title("Chapter") # Set a title to the button 
+                       self.chapter_button.connect("clicked", self._on_select_chapter)
+
+                       # Create a picker button 
+                       self.sleeptime_button = hildon.Button(gtk.HILDON_SIZE_AUTO,
+                                                                                         hildon.BUTTON_ARRANGEMENT_VERTICAL)
+                       self.sleeptime_button.set_title("Sleeptimer") # Set a title to the button 
+                       self.sleeptime_button.connect("clicked", self._on_select_sleep)
+
+                       settings_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+                       settings_button.set_label("Settings")
+                       settings_button.connect("clicked", self._on_settings)
+
+                       about_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+                       about_button.set_label("About")
+                       about_button.connect("clicked", self._on_about_activate)
+
+                       help_button = hildon.Button(gtk.HILDON_SIZE_AUTO, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+                       help_button.set_label("Help")
+                       help_button.connect("clicked", self.get_help)
+
+                       self._menuBar.append(self.book_button)          # Add the button to menu
+                       self._menuBar.append(self.chapter_button)               # Add the button to menu
+                       self._menuBar.append(self.sleeptime_button)             # Add the button to menu
+                       self._menuBar.append(settings_button)
+                       self._menuBar.append(help_button)
+                       self._menuBar.append(about_button)
+                       self._menuBar.show_all()
+               else:
+                       self._audiobookMenuItem = gtk.MenuItem("Audiobook: ")
+                       self._audiobookMenuItem.connect("activate", self._on_select_audiobook)
+
+                       self._chapterMenuItem = gtk.MenuItem("Chapter: ")
+                       self._chapterMenuItem.connect("activate", self._on_select_chapter)
+
+                       self._sleepMenuItem = gtk.MenuItem("Sleeptimer: 0")
+                       self._sleepMenuItem.connect("activate", self._on_select_sleep)
+
+                       settingsMenuItem = gtk.MenuItem("Settings")
+                       settingsMenuItem.connect("activate", self._on_settings)
+
+                       aboutMenuItem = gtk.MenuItem("About")
+                       aboutMenuItem.connect("activate", self._on_about_activate)
+
+                       helpMenuItem = gtk.MenuItem("Help")
+                       helpMenuItem.connect("activate", self.get_help)
+
+                       booksMenu = gtk.Menu()
+                       booksMenu.append(self._audiobookMenuItem)
+                       booksMenu.append(self._chapterMenuItem)
+                       booksMenu.append(self._sleepMenuItem)
+                       booksMenu.append(settingsMenuItem)
+                       booksMenu.append(helpMenuItem)
+                       booksMenu.append(aboutMenuItem)
+
+                       booksMenuItem = gtk.MenuItem("Books")
+                       booksMenuItem.show()
+                       booksMenuItem.set_submenu(booksMenu)
+                       self._menuBar.append(booksMenuItem)
+                       self._menuBar.show_all()
+
+       def setup_timers(self):
+               self.seek_timer = timeout_add_seconds(3, self.update_seek)
+
+       def save_settings(self):
+               config = ConfigParser.SafeConfigParser()
+               self._save_settings(config)
+               with open(constants._user_settings_, "wb") as configFile:
+                       config.write(configFile)
+               self.controller.save()
+
+       def _save_settings(self, config):
+               config.add_section(constants.__pretty_app_name__)
+               config.set(constants.__pretty_app_name__, "portrait", str(self.__isPortrait))
+               config.set(constants.__pretty_app_name__, "fullscreen", str(self.__window_in_fullscreen))
+               config.set(constants.__pretty_app_name__, "audiopath", self.controller.get_books_path())
+
+       def load_settings(self):
+               config = ConfigParser.SafeConfigParser()
+               config.read(constants._user_settings_)
+               self._load_settings(config)
+
+       def _load_settings(self, config):
+               isPortrait = False
+               window_in_fullscreen = False
+               booksPath = constants._default_book_path_
+               try:
+                       isPortrait = config.getboolean(constants.__pretty_app_name__, "portrait")
+                       window_in_fullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen")
+                       booksPath = config.get(constants.__pretty_app_name__, "audiopath")
+               except ConfigParser.NoSectionError, e:
+                       _moduleLogger.info(
+                               "Settings file %s is missing section %s" % (
+                                       constants._user_settings_,
+                                       e.section,
+                               )
+                       )
+
+               if isPortrait ^ self.__isPortrait:
+                       if isPortrait:
+                               orientation = gtk.ORIENTATION_VERTICAL
+                       else:
+                               orientation = gtk.ORIENTATION_HORIZONTAL
+                       self.set_orientation(orientation)
+
+               self.__window_in_fullscreen = window_in_fullscreen
+               if self.__window_in_fullscreen:
+                       self.win.fullscreen()
+               else:
+                       self.win.unfullscreen()
+
+               self.controller.load(booksPath)
+
+       @staticmethod
+       def __format_name(path):
+               if os.path.isfile(path):
+                       return os.path.basename(path).rsplit(".", 1)[0]
+               else:
+                       return os.path.basename(path)
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_select_audiobook(self, *args):
+               if not self._bookSelection:
+                       return
+               index = hildonize.touch_selector(
+                       self.win,
+                       "Audiobook",
+                       (self.__format_name(bookPath) for bookPath in self._bookSelection),
+                       self._bookSelectionIndex if 0 <= self._bookSelectionIndex else 0,
+               )
+               self._bookSelectionIndex = index
+               bookName = self._bookSelection[index]
+               self.controller.set_book(bookName)
+               self.set_button_text("Play", "Start playing the audiobook") # reset button
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_select_chapter(self, *args):
+               if not self._chapterSelection:
+                       return
+               index = hildonize.touch_selector(
+                       self.win,
+                       "Chapter",
+                       (self.__format_name(chapterPath) for chapterPath in self._chapterSelection),
+                       self._chapterSelectionIndex if 0 <= self._chapterSelectionIndex else 0,
+               )
+               self._chapterSelectionIndex = index
+               chapterName = self._chapterSelection[index]
+               self.controller.set_chapter(chapterName)
+               self.set_button_text("Play", "Start playing the audiobook") # reset button
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_select_sleep(self, *args):
+               if self.sleep_timer is not None:
+                       gobject.source_remove(self.sleep_timer)
+
+               try:
+                       index = hildonize.touch_selector(
+                               self.win,
+                               "Sleeptimer",
+                               self._sleepSelection,
+                               self._sleepSelectionIndex if 0 <= self._sleepSelectionIndex else 0,
+                       )
+               except RuntimeError:
+                       _moduleLogger.exception("Handling as if user cancelled")
+                       hildonize.show_information_banner(self.win, "Sleep timer canceled")
+                       index = 0
+
+               self._sleepSelectionIndex = index
+               sleepName = self._sleepSelection[index]
+
+               time_out = int(sleepName)
+               if 0 < time_out:
+                       timeout_add_seconds(time_out * 60, self.sleep)
+
+               if hildonize.IS_FREMANTLE_SUPPORTED:
+                       self.sleeptime_button.set_text("Sleeptimer", sleepName)
+               else:
+                       self._sleepMenuItem.get_child().set_text("Sleeptimer: %s" % (sleepName, ))
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def __on_call_started(self, callMonitor):
+               self.pause()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_settings(self, *args):
+               if self.__settingsWindow is None:
+                       vbox = gtk.VBox()
+                       self.__settingsManager = settings.SettingsDialog(vbox)
+
+                       self.__settingsWindow = gtk.Window()
+                       self.__settingsWindow.add(vbox)
+                       self.__settingsWindow = hildonize.hildonize_window(self._app, self.__settingsWindow)
+                       self.__settingsManager.window = self.__settingsWindow
+
+                       self.__settingsWindow.set_title("Settings")
+                       self.__settingsWindow.set_transient_for(self.win)
+                       self.__settingsWindow.set_default_size(*self.win.get_size())
+                       self.__settingsWindow.connect("delete-event", self._on_settings_delete)
+               self.__settingsManager.set_portrait_state(self.__isPortrait)
+               self.__settingsManager.set_audiobook_path(self.controller.get_books_path())
+               self.__settingsWindow.set_modal(True)
+               self.__settingsWindow.show_all()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_settings_delete(self, *args):
+               self.__settingsWindow.emit_stop_by_name("delete-event")
+               self.__settingsWindow.hide()
+               self.__settingsWindow.set_modal(False)
+
+               isPortrait = self.__settingsManager.is_portrait()
+               if isPortrait ^ self.__isPortrait:
+                       if isPortrait:
+                               orientation = gtk.ORIENTATION_VERTICAL
+                       else:
+                               orientation = gtk.ORIENTATION_HORIZONTAL
+                       self.set_orientation(orientation)
+               if self.__settingsManager.get_audiobook_path() != self.controller.get_books_path():
+                       self.controller.reload(self.__settingsManager.get_audiobook_path())
+
+               return True
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def update_seek(self):
+               #print self.controller.get_percentage()
+               if self.controller.is_playing():
+                       gtk.gdk.threads_enter()
+                       self.seek.set_value(self.controller.get_percentage() * 100)
+                       gtk.gdk.threads_leave()
+               #self.controller.get_percentage() 
+               return True                                      # run again
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def sleep(self):
+               _moduleLogger.info("sleep time timeout")
+               hildonize.show_information_banner(self.win, "Sleep timer")
+               self.controller.stop()
+               self.set_button_text("Resume", "Resume playing the audiobook")
+               return False                                    # do not repeat
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def get_help(self, button):
+               Browser.open("file:///opt/Nqa-Audiobook-player/Help/nqaap.html")
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def seek_changed(self, seek, scroll , value):
+               # print "sok", scroll
+               self.controller.seek_percent(seek.get_value() / 100.0)
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_next_chapter(self, *args):
+               self.controller.next_chapter()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_previous_chapter(self, *args):
+               self.controller.previous_chapter()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def play_pressed(self, button):
+               if self.controller.is_playing():
+                       self.pause()
+               else:
+                       self.play()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def on_key_press(self, widget, event, *args):
+               RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
+               isCtrl = bool(event.get_state() & gtk.gdk.CONTROL_MASK)
+               if (
+                       event.keyval == gtk.keysyms.F6 or
+                       event.keyval in RETURN_TYPES and isCtrl
+               ):
+                       # The "Full screen" hardware key has been pressed 
+                       if self.__window_in_fullscreen:
+                               self.win.unfullscreen ()
+                       else:
+                               self.win.fullscreen ()
+                       return True
+               elif event.keyval == gtk.keysyms.o and isCtrl:
+                       self._toggle_rotate()
+                       return True
+               elif (
+                       event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
+                       event.get_state() & gtk.gdk.CONTROL_MASK
+               ):
+                       self.quit()
+               elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
+                       with open(constants._user_logpath_, "r") as f:
+                               logLines = f.xreadlines()
+                               log = "".join(logLines)
+                               self._clipboard.set_text(str(log))
+                       return True
+               elif event.keyval in RETURN_TYPES:
+                       if self.controller.is_playing():
+                               self.pause()
+                       else:
+                               self.play()
+                       return True
+               elif event.keyval == gtk.keysyms.Left:
+                       self.controller.previous_chapter()
+                       return True
+               elif event.keyval == gtk.keysyms.Right:
+                       self.controller.next_chapter()
+                       return True
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_window_state_change(self, widget, event, *args):
+               if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
+                       self.__window_in_fullscreen = True
+               else:
+                       self.__window_in_fullscreen = False
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def quit(self, *args):                   # what are the arguments?
+               _moduleLogger.info("Shutting down")
+               try:
+                       self.save_settings()
+                       self.controller.stop()            # to save the state
+               finally:
+                       gtk.main_quit()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_about_activate(self, *args):
+               dlg = gtk.AboutDialog()
+               dlg.set_name(constants.__pretty_app_name__)
+               dlg.set_version("%s-%d" % (constants.__version__, constants.__build__))
+               dlg.set_copyright("Copyright 2010")
+               dlg.set_comments("")
+               dlg.set_website("http://nqaap.garage.maemo.org/")
+               dlg.set_authors(["Pengman <pengmeister@gmail.com>", "Ed Page <eopage@byu.net>"])
+               dlg.run()
+               dlg.destroy()
+
+       # Actions:  
+
+       def play(self):
+               self.set_button_text("Stop", "Stop playing the audiobook")
+               self.controller.play()
+
+       def pause(self):
+               self.set_button_text("Resume", "Resume playing the audiobook")
+               self.controller.stop()
+
+       def set_orientation(self, orientation):
+               if orientation == gtk.ORIENTATION_VERTICAL:
+                       if self.__isPortrait:
+                               return
+                       hildonize.window_to_portrait(self.win)
+                       self.__isPortrait = True
+
+                       self._viewLayout.remove(self._controlLayout)
+                       self._mainLayout.add(self._controlLayout)
+               elif orientation == gtk.ORIENTATION_HORIZONTAL:
+                       if not self.__isPortrait:
+                               return
+                       hildonize.window_to_landscape(self.win)
+                       self.__isPortrait = False
+
+                       self._mainLayout.remove(self._controlLayout)
+                       self._viewLayout.add(self._controlLayout)
+               else:
+                       raise NotImplementedError(orientation)
+
+       def get_orientation(self):
+               return gtk.ORIENTATION_VERTICAL if self.__isPortrait else gtk.ORIENTATION_HORIZONTAL
+
+       def _toggle_rotate(self):
+               if self.__isPortrait:
+                       self.set_orientation(gtk.ORIENTATION_HORIZONTAL)
+               else:
+                       self.set_orientation(gtk.ORIENTATION_VERTICAL)
+
+       def change_chapter(self, chapterName):
+               if chapterName is None:
+                       _moduleLogger.debug("chapter selection canceled.")
+                       return True                                # this should end the function and indicate it has been handled
+
+               _moduleLogger.debug("chapter changed (by controller) to: %s" % chapterName)
+
+       def set_button_text(self, title, text):
+               if hildonize.IS_FREMANTLE_SUPPORTED:
+                       self.button.set_text(title, text)
+               else:
+                       self.button.set_label("%s" % (title, ))
+
+       def set_books(self, books):
+               _moduleLogger.debug("new books")
+               del self._bookSelection[:]
+               self._bookSelection.extend(books)
+               if len(books) == 0 and self.controller is not None:
+                       hildonize.show_information_banner(self.win, "No audiobooks found. \nPlease place your audiobooks in the directory %s" % self.controller.get_books_path())
+
+       def set_book(self, bookPath, cover):
+               bookName = self.__format_name(bookPath)
+
+               self.set_button_text("Play", "Start playing the audiobook") # reset button
+               self._set_display_title(bookName)
+               if hildonize.IS_FREMANTLE_SUPPORTED:
+                       self.book_button.set_text("Audiobook", bookName)
+               else:
+                       self._audiobookMenuItem.get_child().set_text("Audiobook: %s" % (bookName, ))
+               if cover != "":
+                       self.cover.set_from_file(cover)
+
+       def set_chapter(self, chapterIndex):
+               '''
+               Called from controller whenever a new chapter is started
+
+               chapter parameter is supposed to be the index for the chapter, not the name
+               '''
+               self.auto_chapter_selected = True
+               self._set_display_chapter(str(chapterIndex + 1))
+               if hildonize.IS_FREMANTLE_SUPPORTED:
+                       self.chapter_button.set_text("Chapter", str(chapterIndex))
+               else:
+                       self._chapterMenuItem.get_child().set_text("Chapter: %s" % (chapterIndex+1, ))
+
+       def set_chapters(self, chapters):
+               _moduleLogger.debug("setting chapters" )
+               del self._chapterSelection[:]
+               self._chapterSelection.extend(chapters)
+
+       def set_sleep_timer(self, mins):
+               pass
+
+       # Utils
+       def set_selected_value(self, button, value):
+               i = button.get_selector().get_model(0).index[value] # get index of value from list
+               button.set_active(i)                                                            # set active index to that index
+
+       def _set_display_title(self, title):
+               self.title.set_markup("<b><big>%s</big></b>" % title)
+
+       def _set_display_chapter(self, chapter):
+               self.chapter.set_markup("<b><big>Chapter %s</big></b>" % chapter)
 
 
 def _old_timeout_add_seconds(timeout, callback):
-    return gobject.timeout_add(timeout * 1000, callback)
+       return gobject.timeout_add(timeout * 1000, callback)
 
 
 def _timeout_add_seconds(timeout, callback):
-    return gobject.timeout_add_seconds(timeout, callback)
+       return gobject.timeout_add_seconds(timeout, callback)
 
 
 try:
-    gobject.timeout_add_seconds
-    timeout_add_seconds = _timeout_add_seconds
+       gobject.timeout_add_seconds
+       timeout_add_seconds = _timeout_add_seconds
 except AttributeError:
-    timeout_add_seconds = _old_timeout_add_seconds
+       timeout_add_seconds = _old_timeout_add_seconds
 
 
 if __name__ == "__main__":
-    g = Gui(None)
+       g = Gui(None)
index 8535a43..6293ce5 100644 (file)
@@ -14,185 +14,186 @@ _moduleLogger = logging.getLogger(__name__)
 
 class Player(object):
 
-    def __init__(self, ui):
-        self.storage = FileStorage.FileStorage(path = constants._data_path_)
-        if hildonize.IS_HILDON_SUPPORTED and not hildonize.IS_FREMANTLE_SUPPORTED:
-            import SimpleOSSOPlayer as _SimplePlayer
-            SimplePlayer = _SimplePlayer # silence PyFlakes
-        else:
-            import SimpleGStreamer as SimplePlayer
-        self.player = SimplePlayer.SimplePlayer(self.next_chapter)
-        self.ui = ui
-        self.audiobook = None
-        self._bookDir = None
-        self._bookPaths = {}
-
-    def get_books_path(self):
-        return self._bookDir
-
-    def reload(self, booksPath):
-        if self.audiobook is not None:
-            position = self.player.elapsed()
-            self.storage.set_time(self.audiobook.current_chapter, position)
-        self.save()
-        self.load(booksPath)
-
-    def load(self, booksPath):
-        _moduleLogger.info("Loading books from %s" % booksPath)
-        self.storage.load()
-        self._bookDir = booksPath
-
-        self._bookPaths = dict(
-            (self.__format_name(bookPath), bookPath)
-            for bookPath in self._find_books()
-        )
-        if self.ui is not None:
-            bookPaths = self._bookPaths.values()
-            bookPaths.sort()
-            self.ui.set_books(bookPaths)
-
-        lastBookName = self.storage.get_selected()
-        if lastBookName is not None:
-            _moduleLogger.info("continuing book: %s" % lastBookName)
-            try:
-                bookPath = self._bookPaths[lastBookName]
-                self.set_book(bookPath)
-            except KeyError:
-                _moduleLogger.exception("Audiobook was not found")
-            except IndexError:
-                _moduleLogger.exception("Chapter was not found")
-            except IOError:
-                _moduleLogger.exception("Audiobook could not be loaded")
-            except Exception:
-                _moduleLogger.exception("Can you say 'confusion'?")
-
-    def save(self):
-        position = self.player.elapsed()
-        self.storage.set_time(self.audiobook.current_chapter, position)
-        self.storage.save()
-
-    @staticmethod
-    def __format_name(path):
-        if os.path.isfile(path):
-            return os.path.basename(path).rsplit(".", 1)[0]
-        else:
-            return os.path.basename(path)
-
-    def set_book(self, bookPath):
-        oldBookName = self.storage.get_selected()
-        try:
-            bookName = self.__format_name(bookPath)
-            self.storage.select_book(bookName)
-            chapter_num, _ = self.storage.get_time()
-            self.audiobook = Audiobook.Audiobook(
-                bookPath,
-                chapter_num
-            )
-        except:
-            self.storage.select_book(oldBookName)
-            raise
-
-        # self.player.set_file(self.audiobook.get_current_chapter())
-        # self.player.seek_time(time) 
-
-        if self.ui is not None:
-            self.ui.set_book(bookPath, self.audiobook.get_cover_img())
-            self.ui.set_chapters(self.audiobook.chapters)
-
-        chapter_title = self.audiobook.chapters[self.audiobook.current_chapter]
-        self.set_chapter(chapter_title, True)
-
-    def set_chapter(self, chapter, continuing = False):
-        _moduleLogger.info("set chapter:" + chapter + " : Continuing: " + str(continuing))
-        self.audiobook.set_chapter(chapter)
-        self.player.set_file(self.audiobook.get_current_chapter())
-        if not continuing:
-            self.storage.set_time(self.audiobook.current_chapter, 0)
-
-        if self.ui is not None:
-            self.ui.set_chapter(self.audiobook.current_chapter)
-
-    def previous_chapter(self, *args):
-        _moduleLogger.info("Going back a chapter")
-        self.player.stop()
-        next_file = self.audiobook.get_previous_chapter()
-        if next_file is not False:
-            self.set_chapter(next_file)
-            self.player.play()
-        else:                           # the book is over
-            self.storage.set_time(0, 0)
-
-    def next_chapter(self, *args):
-        _moduleLogger.info("Advancing a chapter")
-        self.player.stop()
-        next_file = self.audiobook.get_next_chapter()
-        if next_file is not False:
-            self.set_chapter(next_file)
-            self.player.play()
-        else:                           # the book is over
-            self.storage.set_time(0, 0)
-
-    def play(self):
-        if self.audiobook is not None:
-            self.player.play()
-            _, target_time = self.storage.get_time()
-            if 0 < target_time:
-                time.sleep(1)
-                self.player.seek_time(target_time)
-            #print self.player.elapsed()
-        else:
-            print "No book selected, find one in ", self._bookDir
-
-    def stop(self):
-        position = self.player.elapsed()
-        self.player.stop()
-
-        if self.audiobook is not None:
-            self.storage.set_time(self.audiobook.current_chapter, position)
-
-    def is_playing(self):
-        return self.player.playing
-
-    def sleeptimer(self, secs):
-        #print "sleeper", secs
-        time.sleep(secs)
-        #print "now its time to sleep"
-        self.stop()
-
-    def start_sleeptimer(self, secs):
-        #print "startin sleep"
-        sleep_thread = threading.Thread(target=self.sleeptimer, args=(secs, ))
-        sleep_thread.start()
-        #print "started sleep"
-
-    def get_percentage(self):
-        try:
-            return float(self.player.elapsed()) / float(self.player.duration())
-        except ZeroDivisionError:
-            return 0.0
-
-    def seek_percent(self, ratio):
-        try:
-            target = int(self.player.duration() * ratio) # Calculate where to seek
-            self.player.seek_time(target)      # seek
-
-            position = self.player.elapsed()
-            self.storage.set_time(self.audiobook.current_chapter, target) # save position
-            return True
-        except:
-            _moduleLogger.exception("Seek failed")
-            return False
-
-    def _find_books(self):
-        try:
-            paths = (
-                os.path.join(self._bookDir, f)
-                for f in os.listdir(self._bookDir)
-            )
-            return (
-                path
-                for path in paths
-                if Audiobook.is_book(path)
-            )
-        except OSError:
-            return ()
+       def __init__(self, ui):
+               self.storage = FileStorage.FileStorage(path = constants._data_path_)
+               if hildonize.IS_HILDON_SUPPORTED and not hildonize.IS_FREMANTLE_SUPPORTED:
+                       import SimpleOSSOPlayer as _SimplePlayer
+                       SimplePlayer = _SimplePlayer # silence PyFlakes
+               else:
+                       import SimpleGStreamer as SimplePlayer
+               self.player = SimplePlayer.SimplePlayer(self.next_chapter)
+               self.ui = ui
+               self.audiobook = None
+               self._bookDir = None
+               self._bookPaths = {}
+
+       def get_books_path(self):
+               return self._bookDir
+
+       def reload(self, booksPath):
+               if self.audiobook is not None:
+                       position = self.player.elapsed()
+                       self.storage.set_time(self.audiobook.current_chapter, position)
+               self.save()
+               self.load(booksPath)
+
+       def load(self, booksPath):
+               _moduleLogger.info("Loading books from %s" % booksPath)
+               self.storage.load()
+               self._bookDir = booksPath
+
+               self._bookPaths = dict(
+                       (self.__format_name(bookPath), bookPath)
+                       for bookPath in self._find_books()
+               )
+               if self.ui is not None:
+                       bookPaths = self._bookPaths.values()
+                       bookPaths.sort()
+                       self.ui.set_books(bookPaths)
+
+               lastBookName = self.storage.get_selected()
+               if lastBookName is not None:
+                       _moduleLogger.info("continuing book: %s" % lastBookName)
+                       try:
+                               bookPath = self._bookPaths[lastBookName]
+                               self.set_book(bookPath)
+                       except KeyError:
+                               _moduleLogger.exception("Audiobook was not found")
+                       except IndexError:
+                               _moduleLogger.exception("Chapter was not found")
+                       except IOError:
+                               _moduleLogger.exception("Audiobook could not be loaded")
+                       except Exception:
+                               _moduleLogger.exception("Can you say 'confusion'?")
+
+       def save(self):
+               position = self.player.elapsed()
+               if self.audiobook is not None:
+                       self.storage.set_time(self.audiobook.current_chapter, position)
+               self.storage.save()
+
+       @staticmethod
+       def __format_name(path):
+               if os.path.isfile(path):
+                       return os.path.basename(path).rsplit(".", 1)[0]
+               else:
+                       return os.path.basename(path)
+
+       def set_book(self, bookPath):
+               oldBookName = self.storage.get_selected()
+               try:
+                       bookName = self.__format_name(bookPath)
+                       self.storage.select_book(bookName)
+                       chapter_num, _ = self.storage.get_time()
+                       self.audiobook = Audiobook.Audiobook(
+                               bookPath,
+                               chapter_num
+                       )
+               except:
+                       self.storage.select_book(oldBookName)
+                       raise
+
+               # self.player.set_file(self.audiobook.get_current_chapter())
+               # self.player.seek_time(time) 
+
+               if self.ui is not None:
+                       self.ui.set_book(bookPath, self.audiobook.get_cover_img())
+                       self.ui.set_chapters(self.audiobook.chapters)
+
+               chapter_title = self.audiobook.chapters[self.audiobook.current_chapter]
+               self.set_chapter(chapter_title, True)
+
+       def set_chapter(self, chapter, continuing = False):
+               _moduleLogger.info("set chapter:" + chapter + " : Continuing: " + str(continuing))
+               self.audiobook.set_chapter(chapter)
+               self.player.set_file(self.audiobook.get_current_chapter())
+               if not continuing:
+                       self.storage.set_time(self.audiobook.current_chapter, 0)
+
+               if self.ui is not None:
+                       self.ui.set_chapter(self.audiobook.current_chapter)
+
+       def previous_chapter(self, *args):
+               _moduleLogger.info("Going back a chapter")
+               self.player.stop()
+               next_file = self.audiobook.get_previous_chapter()
+               if next_file is not False:
+                       self.set_chapter(next_file)
+                       self.player.play()
+               else:                                              # the book is over
+                       self.storage.set_time(0, 0)
+
+       def next_chapter(self, *args):
+               _moduleLogger.info("Advancing a chapter")
+               self.player.stop()
+               next_file = self.audiobook.get_next_chapter()
+               if next_file is not False:
+                       self.set_chapter(next_file)
+                       self.player.play()
+               else:                                              # the book is over
+                       self.storage.set_time(0, 0)
+
+       def play(self):
+               if self.audiobook is not None:
+                       self.player.play()
+                       _, target_time = self.storage.get_time()
+                       if 0 < target_time:
+                               time.sleep(1)
+                               self.player.seek_time(target_time)
+                       #print self.player.elapsed()
+               else:
+                       print "No book selected, find one in ", self._bookDir
+
+       def stop(self):
+               position = self.player.elapsed()
+               self.player.stop()
+
+               if self.audiobook is not None:
+                       self.storage.set_time(self.audiobook.current_chapter, position)
+
+       def is_playing(self):
+               return self.player.playing
+
+       def sleeptimer(self, secs):
+               #print "sleeper", secs
+               time.sleep(secs)
+               #print "now its time to sleep"
+               self.stop()
+
+       def start_sleeptimer(self, secs):
+               #print "startin sleep"
+               sleep_thread = threading.Thread(target=self.sleeptimer, args=(secs, ))
+               sleep_thread.start()
+               #print "started sleep"
+
+       def get_percentage(self):
+               try:
+                       return float(self.player.elapsed()) / float(self.player.duration())
+               except ZeroDivisionError:
+                       return 0.0
+
+       def seek_percent(self, ratio):
+               try:
+                       target = int(self.player.duration() * ratio) # Calculate where to seek
+                       self.player.seek_time(target)     # seek
+
+                       position = self.player.elapsed()
+                       self.storage.set_time(self.audiobook.current_chapter, target) # save position
+                       return True
+               except:
+                       _moduleLogger.exception("Seek failed")
+                       return False
+
+       def _find_books(self):
+               try:
+                       paths = (
+                               os.path.join(self._bookDir, f)
+                               for f in os.listdir(self._bookDir)
+                       )
+                       return (
+                               path
+                               for path in paths
+                               if Audiobook.is_book(path)
+                       )
+               except OSError:
+                       return ()
index d5f19a4..5d91edd 100644 (file)
@@ -11,98 +11,98 @@ _moduleLogger = logging.getLogger(__name__)
 
 class SimplePlayer(object):
 
-    # @todo Add pitch/speed control
-    # http://github.com/jwagner/playitslowly/blob/master/playitslowly/pipeline.py
-
-    def __init__(self, on_playing_done = None):
-        #Fields
-        self.playing = False
-        self.__filename = ""
-        self.__elapsed = 0
-        self.__duration = 0
-
-        #Event callbacks
-        self.on_playing_done = on_playing_done
-
-        #Set up GStreamer
-        self.player = gst.element_factory_make("playbin2", "player")
-        fakesink = gst.element_factory_make("fakesink", "fakesink")
-        self.player.set_property("video-sink", fakesink)
-        bus = self.player.get_bus()
-        bus.add_signal_watch()
-        bus.connect("message", self.on_message)
-
-        #Constants
-        self.time_format = gst.Format(gst.FORMAT_TIME)
-        self.seek_flag = gst.SEEK_FLAG_FLUSH
-
-    @property
-    def has_file(self):
-        return 0 < len(self.__filename)
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def on_message(self, bus, message):
-        t = message.type
-        if t == gst.MESSAGE_EOS:        # End-Of-Stream
-            self.player.set_state(gst.STATE_NULL)
-            self.playing = False
-            if self.on_playing_done is not None: # event callback
-                self.on_playing_done(self)
-        elif t == gst.MESSAGE_ERROR:
-            self.player.set_state(gst.STATE_NULL)
-            err, debug = message.parse_error()
-            #print "Error: %s" % err, debug
-            _moduleLogger.error("Error: %s, (%s)" % (err, debug))
-            self.playing = False
-
-    def set_file(self, file):
-        _moduleLogger.info("set file: %s", file)
-        if os.path.isfile(file):
-            if self.__filename != file:
-                self._invalidate_cache()
-            if self.playing:
-                self.stop()
-
-            file = os.path.abspath(file) # ensure absolute path
-            _moduleLogger.debug("set file (absolute path): %s "%file)
-            self.player.set_property("uri", "file://" + file)
-            self.__filename = file
-        else:
-            _moduleLogger.error("File: %s not found" % file)
-
-    def play(self):
-        _moduleLogger.info("Started playing")
-        self.player.set_state(gst.STATE_PLAYING)
-        self.playing = True
-
-    def stop(self):
-        self.player.set_state(gst.STATE_NULL)
-        self.playing = False
-        _moduleLogger.info("Stopped playing")
-
-    def elapsed(self):
-        try:
-            self.__elapsed = self.player.query_position(self.time_format, None)[0]
-        except:
-            pass
-        return self.__elapsed
-
-    def duration(self):
-        try:
-            self.__duration = self.player.query_duration(self.time_format, None)[0]
-        except:
-            _moduleLogger.exception("Query failed")
-            pass
-        return self.__duration
-
-    def seek_time(self, ns):
-        _moduleLogger.debug("Seeking to: %s", ns)
-        self.player.seek_simple(self.time_format, self.seek_flag, ns)
-
-    def _invalidate_cache(self):
-        self.__elapsed = 0
-        self.__duration = 0
-
-    def __seek_percent(self, percent):
-        format = gst.Format(gst.FORMAT_PERCENT)
-        self.player.seek_simple(format, self.seek_flag, percent)
+       # @todo Add pitch/speed control
+       # http://github.com/jwagner/playitslowly/blob/master/playitslowly/pipeline.py
+
+       def __init__(self, on_playing_done = None):
+               #Fields
+               self.playing = False
+               self.__filename = ""
+               self.__elapsed = 0
+               self.__duration = 0
+
+               #Event callbacks
+               self.on_playing_done = on_playing_done
+
+               #Set up GStreamer
+               self.player = gst.element_factory_make("playbin2", "player")
+               fakesink = gst.element_factory_make("fakesink", "fakesink")
+               self.player.set_property("video-sink", fakesink)
+               bus = self.player.get_bus()
+               bus.add_signal_watch()
+               bus.connect("message", self.on_message)
+
+               #Constants
+               self.time_format = gst.Format(gst.FORMAT_TIME)
+               self.seek_flag = gst.SEEK_FLAG_FLUSH
+
+       @property
+       def has_file(self):
+               return 0 < len(self.__filename)
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def on_message(self, bus, message):
+               t = message.type
+               if t == gst.MESSAGE_EOS:                # End-Of-Stream
+                       self.player.set_state(gst.STATE_NULL)
+                       self.playing = False
+                       if self.on_playing_done is not None: # event callback
+                               self.on_playing_done(self)
+               elif t == gst.MESSAGE_ERROR:
+                       self.player.set_state(gst.STATE_NULL)
+                       err, debug = message.parse_error()
+                       #print "Error: %s" % err, debug
+                       _moduleLogger.error("Error: %s, (%s)" % (err, debug))
+                       self.playing = False
+
+       def set_file(self, file):
+               _moduleLogger.info("set file: %s", file)
+               if os.path.isfile(file):
+                       if self.__filename != file:
+                               self._invalidate_cache()
+                       if self.playing:
+                               self.stop()
+
+                       file = os.path.abspath(file) # ensure absolute path
+                       _moduleLogger.debug("set file (absolute path): %s "%file)
+                       self.player.set_property("uri", "file://" + file)
+                       self.__filename = file
+               else:
+                       _moduleLogger.error("File: %s not found" % file)
+
+       def play(self):
+               _moduleLogger.info("Started playing")
+               self.player.set_state(gst.STATE_PLAYING)
+               self.playing = True
+
+       def stop(self):
+               self.player.set_state(gst.STATE_NULL)
+               self.playing = False
+               _moduleLogger.info("Stopped playing")
+
+       def elapsed(self):
+               try:
+                       self.__elapsed = self.player.query_position(self.time_format, None)[0]
+               except:
+                       pass
+               return self.__elapsed
+
+       def duration(self):
+               try:
+                       self.__duration = self.player.query_duration(self.time_format, None)[0]
+               except:
+                       _moduleLogger.exception("Query failed")
+                       pass
+               return self.__duration
+
+       def seek_time(self, ns):
+               _moduleLogger.debug("Seeking to: %s", ns)
+               self.player.seek_simple(self.time_format, self.seek_flag, ns)
+
+       def _invalidate_cache(self):
+               self.__elapsed = 0
+               self.__duration = 0
+
+       def __seek_percent(self, percent):
+               format = gst.Format(gst.FORMAT_PERCENT)
+               self.player.seek_simple(format, self.seek_flag, percent)
index 9129f1a..698e0db 100644 (file)
@@ -11,105 +11,105 @@ _moduleLogger = logging.getLogger(__name__)
 
 class SimplePlayer(object):
 
-    SERVICE_NAME         = "com.nokia.osso_media_server"
-    OBJECT_PATH          = "/com/nokia/osso_media_server"
-    AUDIO_INTERFACE_NAME = "com.nokia.osso_media_server.music"
-
-    def __init__(self, on_playing_done = None):
-        #Fields
-        self.has_file = False
-        self.playing = False
-        self.__elapsed = 0
-
-        #Event callbacks
-        self.on_playing_done = on_playing_done
-
-        session_bus = dbus.SessionBus()
-
-        # Get the osso-media-player proxy object
-        oms_object = session_bus.get_object(
-            self.SERVICE_NAME,
-            self.OBJECT_PATH,
-            introspect=False,
-            follow_name_owner_changes=True,
-        )
-        # Use the audio interface
-        oms_audio_interface = dbus.Interface(
-            oms_object,
-            self.AUDIO_INTERFACE_NAME,
-        )
-        self._audioProxy = oms_audio_interface
-
-        self._audioProxy.connect_to_signal("state_changed", self._on_state_changed)
-        self._audioProxy.connect_to_signal("end_of_stream", self._on_end_of_stream)
-
-        error_signals = [
-            "no_media_selected",
-            "file_not_found",
-            "type_not_found",
-            "unsupported_type",
-            "gstreamer",
-            "dsp",
-            "device_unavailable",
-            "corrupted_file",
-            "out_of_memory",
-            "audio_codec_not_supported",
-        ]
-        for error in error_signals:
-            self._audioProxy.connect_to_signal(error, self._on_error)
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_error(self, *args):
-        self.playing = False
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_end_of_stream(self, *args):
-        self.playing = False
-        if self.on_playing_done is not None: # event callback
-            self.on_playing_done(self)
-
-    @gtk_toolbox.log_exception(_moduleLogger)
-    def _on_state_changed(self, state):
-        _moduleLogger.info("State: %s", state)
-
-    def set_file(self, file):
-        _moduleLogger.info("set file: %s", file)
-        if os.path.isfile(file):
-            if self.playing:
-                self.stop()
-
-            uri = "file://" + file
-            self._audioProxy.set_media_location(uri)
-            self.has_file = True
-        else:
-            _moduleLogger.error("File: %s not found" % file)
-
-    def play(self):
-        _moduleLogger.info("Started playing")
-        self._audioProxy.play()
-        self.playing = True
-
-    def stop(self):
-        self._audioProxy.stop()
-        self.playing = False
-        _moduleLogger.info("Stopped playing")
-
-    def elapsed(self):
-        pos_info = self._audioProxy.get_position()
-        if isinstance(pos_info, tuple):
-            pos, _ = pos_info
-            return pos
-        else:
-            return 0
-
-    def duration(self):
-        pos_info = self._audioProxy.get_position()
-        if isinstance(pos_info, tuple):
-            _, dur = pos_info
-            return dur
-        else:
-            return 0
-
-    def seek_time(self, ns):
-        _moduleLogger.debug("Seeking to: %s", ns)
-        self._audioProxy.seek( dbus.Int32(1), dbus.Int32(ns) )
+       SERVICE_NAME             = "com.nokia.osso_media_server"
+       OBJECT_PATH               = "/com/nokia/osso_media_server"
+       AUDIO_INTERFACE_NAME = "com.nokia.osso_media_server.music"
+
+       def __init__(self, on_playing_done = None):
+               #Fields
+               self.has_file = False
+               self.playing = False
+               self.__elapsed = 0
+
+               #Event callbacks
+               self.on_playing_done = on_playing_done
+
+               session_bus = dbus.SessionBus()
+
+               # Get the osso-media-player proxy object
+               oms_object = session_bus.get_object(
+                       self.SERVICE_NAME,
+                       self.OBJECT_PATH,
+                       introspect=False,
+                       follow_name_owner_changes=True,
+               )
+               # Use the audio interface
+               oms_audio_interface = dbus.Interface(
+                       oms_object,
+                       self.AUDIO_INTERFACE_NAME,
+               )
+               self._audioProxy = oms_audio_interface
+
+               self._audioProxy.connect_to_signal("state_changed", self._on_state_changed)
+               self._audioProxy.connect_to_signal("end_of_stream", self._on_end_of_stream)
+
+               error_signals = [
+                       "no_media_selected",
+                       "file_not_found",
+                       "type_not_found",
+                       "unsupported_type",
+                       "gstreamer",
+                       "dsp",
+                       "device_unavailable",
+                       "corrupted_file",
+                       "out_of_memory",
+                       "audio_codec_not_supported",
+               ]
+               for error in error_signals:
+                       self._audioProxy.connect_to_signal(error, self._on_error)
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_error(self, *args):
+               self.playing = False
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_end_of_stream(self, *args):
+               self.playing = False
+               if self.on_playing_done is not None: # event callback
+                       self.on_playing_done(self)
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_state_changed(self, state):
+               _moduleLogger.info("State: %s", state)
+
+       def set_file(self, file):
+               _moduleLogger.info("set file: %s", file)
+               if os.path.isfile(file):
+                       if self.playing:
+                               self.stop()
+
+                       uri = "file://" + file
+                       self._audioProxy.set_media_location(uri)
+                       self.has_file = True
+               else:
+                       _moduleLogger.error("File: %s not found" % file)
+
+       def play(self):
+               _moduleLogger.info("Started playing")
+               self._audioProxy.play()
+               self.playing = True
+
+       def stop(self):
+               self._audioProxy.stop()
+               self.playing = False
+               _moduleLogger.info("Stopped playing")
+
+       def elapsed(self):
+               pos_info = self._audioProxy.get_position()
+               if isinstance(pos_info, tuple):
+                       pos, _ = pos_info
+                       return pos
+               else:
+                       return 0
+
+       def duration(self):
+               pos_info = self._audioProxy.get_position()
+               if isinstance(pos_info, tuple):
+                       _, dur = pos_info
+                       return dur
+               else:
+                       return 0
+
+       def seek_time(self, ns):
+               _moduleLogger.debug("Seeking to: %s", ns)
+               self._audioProxy.seek( dbus.Int32(1), dbus.Int32(ns) )
index 3dc6e4f..90e812f 100755 (executable)
@@ -17,22 +17,22 @@ _moduleLogger = logging.getLogger(__name__)
 
 
 def run():
-    l = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-    gobject.threads_init()
-    gtk.gdk.threads_init()
+       l = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+       gobject.threads_init()
+       gtk.gdk.threads_init()
 
-    if hildonize.IS_FREMANTLE_SUPPORTED:
-        hildonize.set_application_name("FMRadio")
-    else:
-        hildonize.set_application_name(constants.__pretty_app_name__)
-    gui = Gui()
-    controller = Player(ui = gui)
-    gui.controller = controller
-    gui.load_settings()
+       if hildonize.IS_FREMANTLE_SUPPORTED:
+               hildonize.set_application_name("FMRadio")
+       else:
+               hildonize.set_application_name(constants.__pretty_app_name__)
+       gui = Gui()
+       controller = Player(ui = gui)
+       gui.controller = controller
+       gui.load_settings()
 
-    gtk.main()
+       gtk.main()
 
 
 if __name__ == "__main__":
-    logging.basicConfig(level=logging.DEBUG)
-    run()
+       logging.basicConfig(level=logging.DEBUG)
+       run()
index 8c327bd..ab31cb5 100755 (executable)
@@ -19,115 +19,115 @@ import py2deb
 \r
 \r
 def build_package(distribution):\r
-    py2deb.Py2deb.SECTIONS = py2deb.SECTIONS_BY_POLICY[distribution]\r
-    try:\r
-        os.chdir(os.path.dirname(sys.argv[0]))\r
-    except:\r
-        pass\r
+       py2deb.Py2deb.SECTIONS = py2deb.SECTIONS_BY_POLICY[distribution]\r
+       try:\r
+               os.chdir(os.path.dirname(sys.argv[0]))\r
+       except:\r
+               pass\r
 \r
-    p=py2deb.Py2deb("nqaap") #This is the package name and MUST be in\r
-                               #lowercase! (using e.g. "mClock" fails\r
-                               #miserably...)\r
-    p.prettyName="NQA Audiobook Player"\r
-    p.description="""Very simple Audiobook player.\r
+       p=py2deb.Py2deb("nqaap") #This is the package name and MUST be in\r
+                                                          #lowercase! (using e.g. "mClock" fails\r
+                                                          #miserably...)\r
+       p.prettyName="NQA Audiobook Player"\r
+       p.description="""Very simple Audiobook player.\r
 Supports playing, pausing, seeking (sort of) and saving state when changing book/closing.\r
 Plays books arranged as dirs under myDocs/Audiobooks\r
 .\r
 Homepage: http://wiki.maemo.org/Nqaap"""\r
-    p.author="Soeren 'Pengman' Pedersen"\r
-    p.mail="pengmeister@gmail.com"\r
-    p.license = "lgpl"\r
-    p.depends = ", ".join([\r
-        "python2.6 | python2.5",\r
-        "python-gtk2 | python2.5-gtk2",\r
-        "python-dbus | python2.5-dbus",\r
-        "python-telepathy | python2.5-telepathy",\r
-        "python-gobject | python2.5-gobject",\r
-        "python-simplejson",\r
-    ])\r
-    maemoSpecificDepends = ", python-osso | python2.5-osso, python-hildon | python2.5-hildon"\r
-    p.depends += {\r
-        "debian": ", python-gst0.10",\r
-        "diablo": maemoSpecificDepends,\r
-        "fremantle": maemoSpecificDepends + ", python-gst0.10",\r
-    }[distribution]\r
-    p.section = {\r
-        "debian": "sound",\r
-        "diablo": "user/multimedia",\r
-        "fremantle": "user/multimedia",\r
-    }[distribution]\r
-    p.icon = "src/usr/share/icons/hicolor/48x48/hildon/nqaap.png"\r
-    p.arch="all"                #should be all for python, any for all arch\r
-    p.urgency="low"             #not used in maemo onl for deb os\r
-    p.distribution=distribution\r
-    p.repository="extras"\r
-    p.bugTracker="https://bugs.maemo.org/enter_bug.cgi?product=nQa%%20Audiobook%%20Player"\r
-    p.postinstall="""#!/bin/sh\r
+       p.author="Soeren 'Pengman' Pedersen"\r
+       p.mail="pengmeister@gmail.com"\r
+       p.license = "lgpl"\r
+       p.depends = ", ".join([\r
+               "python2.6 | python2.5",\r
+               "python-gtk2 | python2.5-gtk2",\r
+               "python-dbus | python2.5-dbus",\r
+               "python-telepathy | python2.5-telepathy",\r
+               "python-gobject | python2.5-gobject",\r
+               "python-simplejson",\r
+       ])\r
+       maemoSpecificDepends = ", python-osso | python2.5-osso, python-hildon | python2.5-hildon"\r
+       p.depends += {\r
+               "debian": ", python-gst0.10",\r
+               "diablo": maemoSpecificDepends,\r
+               "fremantle": maemoSpecificDepends + ", python-gst0.10",\r
+       }[distribution]\r
+       p.section = {\r
+               "debian": "sound",\r
+               "diablo": "user/multimedia",\r
+               "fremantle": "user/multimedia",\r
+       }[distribution]\r
+       p.icon = "src/usr/share/icons/hicolor/48x48/hildon/nqaap.png"\r
+       p.arch="all"                            #should be all for python, any for all arch\r
+       p.urgency="low"                  #not used in maemo onl for deb os\r
+       p.distribution=distribution\r
+       p.repository="extras"\r
+       p.bugTracker="https://bugs.maemo.org/enter_bug.cgi?product=nQa%%20Audiobook%%20Player"\r
+       p.postinstall="""#!/bin/sh\r
 rm -f ~/.nqaap/nqaap.log\r
 """\r
-    #  p.postremove="""#!/bin/sh\r
-    #  chmod +x /usr/bin/mclock.py""" #Set here your post remove script\r
-    #  p.preinstall="""#!/bin/sh\r
-    #  chmod +x /usr/bin/mclock.py""" #Set here your pre install script\r
-    #  p.preremove="""#!/bin/sh\r
-    #  chmod +x /usr/bin/mclock.py""" #Set here your pre remove script\r
-    version = "0.8.6"           #Version of your software, e.g. "1.2.0" or "0.8.2"\r
-    build = "0" #Build number, e.g. "1" for the first build of this\r
-                                #version of your software. Increment\r
-                                #for later re-builds of the same\r
-                                #version of your software.  Text with\r
-                                #changelog information to be displayed\r
-                                #in the package "Details" tab of the\r
-                                #Maemo Application Manager\r
-    changeloginformation = """\r
+       #  p.postremove="""#!/bin/sh\r
+       #  chmod +x /usr/bin/mclock.py""" #Set here your post remove script\r
+       #  p.preinstall="""#!/bin/sh\r
+       #  chmod +x /usr/bin/mclock.py""" #Set here your pre install script\r
+       #  p.preremove="""#!/bin/sh\r
+       #  chmod +x /usr/bin/mclock.py""" #Set here your pre remove script\r
+       version = "0.8.6"                  #Version of your software, e.g. "1.2.0" or "0.8.2"\r
+       build = "0" #Build number, e.g. "1" for the first build of this\r
+                                                               #version of your software. Increment\r
+                                                               #for later re-builds of the same\r
+                                                               #version of your software.  Text with\r
+                                                               #changelog information to be displayed\r
+                                                               #in the package "Details" tab of the\r
+                                                               #Maemo Application Manager\r
+       changeloginformation = """\r
 * About window as requested by magnuslu\r
 * Switched how storage of active book, chapter, and chapter position is stored\r
 """.strip()\r
-    dir_name = "src" #Name of the subfolder containing your package\r
-                                #source files\r
-                                #(e.g. usr\share\icons\hicolor\scalable\myappicon.svg,\r
-                                #usr\lib\myapp\somelib.py). We suggest\r
-                                #to leave it named src in all projects\r
-                                #and will refer to that in the wiki\r
-                                #article on maemo.org\r
-    #Thanks to DareTheHair from talk.maemo.org for this snippet that\r
-    #recursively builds the file list\r
-    for root, dirs, files in os.walk(dir_name):\r
-        if any(f.startswith(".") for f in root.split(os.sep)):\r
-            continue # avoid hidden folders, esp svn ones\r
+       dir_name = "src" #Name of the subfolder containing your package\r
+                                                               #source files\r
+                                                               #(e.g. usr\share\icons\hicolor\scalable\myappicon.svg,\r
+                                                               #usr\lib\myapp\somelib.py). We suggest\r
+                                                               #to leave it named src in all projects\r
+                                                               #and will refer to that in the wiki\r
+                                                               #article on maemo.org\r
+       #Thanks to DareTheHair from talk.maemo.org for this snippet that\r
+       #recursively builds the file list\r
+       for root, dirs, files in os.walk(dir_name):\r
+               if any(f.startswith(".") for f in root.split(os.sep)):\r
+                       continue # avoid hidden folders, esp svn ones\r
 \r
-        real_dir = root[len(dir_name):]\r
-        fake_file = []\r
-        for f in files:\r
-            fake_file.append(root + os.sep + f + "|" + f)\r
-        if len(fake_file) > 0:\r
-            p[real_dir] = fake_file\r
+               real_dir = root[len(dir_name):]\r
+               fake_file = []\r
+               for f in files:\r
+                       fake_file.append(root + os.sep + f + "|" + f)\r
+               if len(fake_file) > 0:\r
+                       p[real_dir] = fake_file\r
 \r
-    print p\r
-    if distribution == "debian":\r
-        print p.generate(\r
-            version="%s-%s" % (version, build),\r
-            changelog=changeloginformation,\r
-            build=True,\r
-            tar=False,\r
-            changes=False,\r
-            dsc=False,\r
-        )\r
-    else:\r
-        print p.generate(\r
-            version="%s-%s" % (version, build),\r
-            changelog=changeloginformation,\r
-            build=False,\r
-            tar=True,\r
-            changes=True,\r
-            dsc=True,\r
-        )\r
-    print "Building for %s finished" % distribution\r
+       print p\r
+       if distribution == "debian":\r
+               print p.generate(\r
+                       version="%s-%s" % (version, build),\r
+                       changelog=changeloginformation,\r
+                       build=True,\r
+                       tar=False,\r
+                       changes=False,\r
+                       dsc=False,\r
+               )\r
+       else:\r
+               print p.generate(\r
+                       version="%s-%s" % (version, build),\r
+                       changelog=changeloginformation,\r
+                       build=False,\r
+                       tar=True,\r
+                       changes=True,\r
+                       dsc=True,\r
+               )\r
+       print "Building for %s finished" % distribution\r
 \r
 \r
 if __name__ == "__main__":\r
-    if len(sys.argv) == 1:\r
-        distribution = "fremantle"\r
-    else:\r
-        distribution = sys.argv[1]\r
-    build_package(distribution)\r
+       if len(sys.argv) == 1:\r
+               distribution = "fremantle"\r
+       else:\r
+               distribution = sys.argv[1]\r
+       build_package(distribution)\r