Moving files to new locations
authorEd Page <eopage@byu.net>
Wed, 29 Dec 2010 13:45:26 +0000 (07:45 -0600)
committerEd Page <eopage@byu.net>
Wed, 29 Dec 2010 13:45:26 +0000 (07:45 -0600)
42 files changed:
Makefile
src/Audiobook.py [new file with mode: 0644]
src/Browser.py [new file with mode: 0644]
src/CallMonitor.py [new file with mode: 0644]
src/FileStorage.py [new file with mode: 0644]
src/Gui.py [new file with mode: 0644]
src/Player.py [new file with mode: 0644]
src/SimpleGStreamer.py [new file with mode: 0644]
src/SimpleOSSOPlayer.py [new file with mode: 0644]
src/__init__.py [new file with mode: 0644]
src/constants.py [new file with mode: 0644]
src/gtk_toolbox.py [new file with mode: 0644]
src/hildonize.py [new file with mode: 0644]
src/nqaap.py [new file with mode: 0755]
src/nqaap_gtk.py [new file with mode: 0755]
src/opt/Nqa-Audiobook-player/Audiobook.py [deleted file]
src/opt/Nqa-Audiobook-player/Browser.py [deleted file]
src/opt/Nqa-Audiobook-player/CallMonitor.py [deleted file]
src/opt/Nqa-Audiobook-player/FileStorage.py [deleted file]
src/opt/Nqa-Audiobook-player/Gui.py [deleted file]
src/opt/Nqa-Audiobook-player/NoCover.png [deleted file]
src/opt/Nqa-Audiobook-player/Player.py [deleted file]
src/opt/Nqa-Audiobook-player/SimpleGStreamer.py [deleted file]
src/opt/Nqa-Audiobook-player/SimpleOSSOPlayer.py [deleted file]
src/opt/Nqa-Audiobook-player/__init__.py [deleted file]
src/opt/Nqa-Audiobook-player/constants.py [deleted file]
src/opt/Nqa-Audiobook-player/gtk_toolbox.py [deleted file]
src/opt/Nqa-Audiobook-player/hildonize.py [deleted file]
src/opt/Nqa-Audiobook-player/nqaap.py [deleted file]
src/opt/Nqa-Audiobook-player/nqaap_gtk.py [deleted file]
src/opt/Nqa-Audiobook-player/settings.py [deleted file]
src/settings.py [new file with mode: 0644]
src/usr/share/applications/hildon/nqaap.desktop [deleted file]
src/usr/share/icons/hicolor/26x26/hildon/nqaap.png [deleted file]
src/usr/share/icons/hicolor/48x48/hildon/nqaap.png [deleted file]
src/usr/share/icons/hicolor/64x64/hildon/nqaap.png [deleted file]
src/usr/share/icons/hicolor/scalable/hildon/nqaap.png [deleted file]
support/icons/hicolor/26x26/hildon/nqaap.png [new file with mode: 0644]
support/icons/hicolor/48x48/hildon/nqaap.png [new file with mode: 0644]
support/icons/hicolor/64x64/hildon/nqaap.png [new file with mode: 0644]
support/icons/hicolor/scalable/hildon/nqaap.png [new file with mode: 0644]
support/nqaap.desktop [new file with mode: 0644]

index ef92803..2ae5c24 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 PROJECT_NAME=nqaap
 SOURCE_PATH=src
 SOURCE=$(shell find $(SOURCE_PATH) -iname "*.py")
-PROGRAM=$(SOURCE_PATH)/opt/Nqa-Audiobook-player/$(PROJECT_NAME)_gtk.py
+PROGRAM=$(SOURCE_PATH)/$(PROJECT_NAME)_gtk.py
 OBJ=$(SOURCE:.py=.pyc)
 BUILD_PATH=./build
 TAG_FILE=~/.ctags/$(PROJECT_NAME).tags
diff --git a/src/Audiobook.py b/src/Audiobook.py
new file mode 100644 (file)
index 0000000..cd28e1b
--- /dev/null
@@ -0,0 +1,176 @@
+from __future__ import with_statement
+
+import os
+
+import logging
+
+
+_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 is_dir_book(path):
+       return os.path.isdir(path)
+
+
+def is_playlist_book(path):
+       return path.rsplit(".", 1)[-1] in ["m3u"]
+
+
+def is_single_chapter(path):
+       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
diff --git a/src/Browser.py b/src/Browser.py
new file mode 100644 (file)
index 0000000..31ce7d6
--- /dev/null
@@ -0,0 +1,5 @@
+import os\r
+\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
diff --git a/src/CallMonitor.py b/src/CallMonitor.py
new file mode 100644 (file)
index 0000000..97be5a7
--- /dev/null
@@ -0,0 +1,145 @@
+import logging
+
+import gobject
+import dbus
+import telepathy
+
+import gtk_toolbox
+
+
+_moduleLogger = logging.getLogger(__name__)
+DBUS_PROPERTIES = 'org.freedesktop.DBus.Properties'
+
+
+class NewChannelSignaller(object):
+
+       def __init__(self, on_new_channel):
+               self._sessionBus = dbus.SessionBus()
+               self._on_user_new_channel = on_new_channel
+
+       def start(self):
+               self._sessionBus.add_signal_receiver(
+                       self._on_new_channel,
+                       "NewChannel",
+                       "org.freedesktop.Telepathy.Connection",
+                       None,
+                       None
+               )
+
+       def stop(self):
+               self._sessionBus.remove_signal_receiver(
+                       self._on_new_channel,
+                       "NewChannel",
+                       "org.freedesktop.Telepathy.Connection",
+                       None,
+                       None
+               )
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_new_channel(
+               self, channelObjectPath, channelType, handleType, handle, supressHandler
+       ):
+               connObjectPath = channel_path_to_conn_path(channelObjectPath)
+               serviceName = path_to_service_name(channelObjectPath)
+               try:
+                       self._on_user_new_channel(
+                               self._sessionBus, serviceName, connObjectPath, channelObjectPath, channelType
+                       )
+               except Exception:
+                       _moduleLogger.exception("Blocking exception from being passed up")
+
+
+class ChannelClosed(object):
+
+       def __init__(self, bus, conn, chan, on_closed):
+               self.__on_closed = on_closed
+
+               chan[telepathy.interfaces.CHANNEL].connect_to_signal(
+                       "Closed",
+                       self._on_closed,
+               )
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_closed(self):
+               self.__on_closed(self)
+
+
+class CallMonitor(gobject.GObject):
+
+       __gsignals__ = {
+               'call_start' : (
+                       gobject.SIGNAL_RUN_LAST,
+                       gobject.TYPE_NONE,
+                       (),
+               ),
+               'call_end' : (
+                       gobject.SIGNAL_RUN_LAST,
+                       gobject.TYPE_NONE,
+                       (),
+               ),
+       }
+
+       def __init__(self):
+               gobject.GObject.__init__(self)
+               self._isActive = False
+               self._newChannelMonitor = NewChannelSignaller(self._on_new_channel)
+               self._channelClosedMonitors = []
+
+       def start(self):
+               self._isActive = True
+               self._newChannelMonitor.start()
+
+       def stop(self):
+               self._isActive = False
+               self._newChannelMonitor.stop()
+
+       def _on_new_channel(self, sessionBus, serviceName, connObjectPath, channelObjectPath, channelType):
+               if not self._isActive:
+                       return
+
+               if channelType != telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA:
+                       return
+
+               cmName = cm_from_path(connObjectPath)
+               conn = telepathy.client.Connection(serviceName, connObjectPath)
+               try:
+                       chan = telepathy.client.Channel(serviceName, channelObjectPath)
+               except dbus.exceptions.UnknownMethodException:
+                       _moduleLogger.exception("Client might not have implemented a deprecated method")
+                       return
+
+               missDetection = ChannelClosed(
+                       sessionBus, conn, chan, self._on_close
+               )
+               self._outstandingRequests.append(missDetection)
+               if len(self._outstandingRequests) == 1:
+                       self.emit("call_start")
+
+       def _on_close(self, channelCloseMonitor):
+               self._outstandingRequests.remove(channelCloseMonitor)
+               if not self._outstandingRequests:
+                       self.emit("call_stop")
+
+
+def channel_path_to_conn_path(channelObjectPath):
+       """
+       >>> channel_path_to_conn_path("/org/freedesktop/Telepathy/ConnectionManager/theonering/gv/USERNAME/Channel1")
+       '/org/freedesktop/Telepathy/ConnectionManager/theonering/gv/USERNAME'
+       """
+       return channelObjectPath.rsplit("/", 1)[0]
+
+
+def path_to_service_name(path):
+       """
+       >>> path_to_service_name("/org/freedesktop/Telepathy/ConnectionManager/theonering/gv/USERNAME/Channel1")
+       'org.freedesktop.Telepathy.ConnectionManager.theonering.gv.USERNAME'
+       """
+       return ".".join(path[1:].split("/")[0:7])
+
+
+def cm_from_path(path):
+       """
+       >>> cm_from_path("/org/freedesktop/Telepathy/ConnectionManager/theonering/gv/USERNAME/Channel1")
+       'theonering'
+       """
+       return path[1:].split("/")[4]
diff --git a/src/FileStorage.py b/src/FileStorage.py
new file mode 100644 (file)
index 0000000..af19c9d
--- /dev/null
@@ -0,0 +1,106 @@
+from __future__ import with_statement   # enable with
+
+import os
+import simplejson
+import logging
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+# @todo Add bookmarks
+
+
+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
diff --git a/src/Gui.py b/src/Gui.py
new file mode 100644 (file)
index 0000000..5b0ff29
--- /dev/null
@@ -0,0 +1,622 @@
+from __future__ import with_statement
+
+import os
+import ConfigParser
+import logging
+
+import gobject
+import gtk
+
+import constants
+import hildonize
+import gtk_toolbox
+import Browser
+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
+
+
+_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)
+
+
+def _old_timeout_add_seconds(timeout, callback):
+       return gobject.timeout_add(timeout * 1000, callback)
+
+
+def _timeout_add_seconds(timeout, callback):
+       return gobject.timeout_add_seconds(timeout, callback)
+
+
+try:
+       gobject.timeout_add_seconds
+       timeout_add_seconds = _timeout_add_seconds
+except AttributeError:
+       timeout_add_seconds = _old_timeout_add_seconds
+
+
+if __name__ == "__main__":
+       g = Gui(None)
diff --git a/src/Player.py b/src/Player.py
new file mode 100644 (file)
index 0000000..6293ce5
--- /dev/null
@@ -0,0 +1,199 @@
+import os
+import threading
+import time
+import logging
+
+import constants
+import hildonize
+import Audiobook
+import FileStorage
+
+
+_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()
+               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 ()
diff --git a/src/SimpleGStreamer.py b/src/SimpleGStreamer.py
new file mode 100644 (file)
index 0000000..5d91edd
--- /dev/null
@@ -0,0 +1,108 @@
+import os
+import logging
+
+import gst
+
+import gtk_toolbox
+
+
+_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)
diff --git a/src/SimpleOSSOPlayer.py b/src/SimpleOSSOPlayer.py
new file mode 100644 (file)
index 0000000..698e0db
--- /dev/null
@@ -0,0 +1,115 @@
+import os
+import logging
+
+import dbus
+
+import gtk_toolbox
+
+
+_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) )
diff --git a/src/__init__.py b/src/__init__.py
new file mode 100644 (file)
index 0000000..4265cc3
--- /dev/null
@@ -0,0 +1 @@
+#!/usr/bin/env python
diff --git a/src/constants.py b/src/constants.py
new file mode 100644 (file)
index 0000000..3fdc0c3
--- /dev/null
@@ -0,0 +1,11 @@
+import os
+
+__pretty_app_name__ = "nQaap"
+__app_name__ = "nqaap"
+__version__ = "0.8.6"
+__build__ = 0
+__app_magic__ = 0xdeadbeef
+_data_path_ = os.path.join(os.path.expanduser("~"), ".%s" % __app_name__)
+_user_settings_ = "%s/settings.ini" % _data_path_
+_user_logpath_ = "%s/%s.log" % (_data_path_, __app_name__)
+_default_book_path_ = os.path.join(os.path.expanduser("~"), "MyDocs/Audiobooks/")
diff --git a/src/gtk_toolbox.py b/src/gtk_toolbox.py
new file mode 100644 (file)
index 0000000..784c871
--- /dev/null
@@ -0,0 +1,577 @@
+#!/usr/bin/python
+
+from __future__ import with_statement
+
+import os
+import errno
+import sys
+import time
+import itertools
+import functools
+import contextlib
+import logging
+import threading
+import Queue
+
+import gobject
+import gtk
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+def get_screen_orientation():
+       width, height = gtk.gdk.get_default_root_window().get_size()
+       if width < height:
+               return gtk.ORIENTATION_VERTICAL
+       else:
+               return gtk.ORIENTATION_HORIZONTAL
+
+
+def orientation_change_connect(handler, *args):
+       """
+       @param handler(orientation, *args) -> None(?)
+       """
+       initialScreenOrientation = get_screen_orientation()
+       orientationAndArgs = list(itertools.chain((initialScreenOrientation, ), args))
+
+       def _on_screen_size_changed(screen):
+               newScreenOrientation = get_screen_orientation()
+               if newScreenOrientation != orientationAndArgs[0]:
+                       orientationAndArgs[0] = newScreenOrientation
+                       handler(*orientationAndArgs)
+
+       rootScreen = gtk.gdk.get_default_root_window()
+       return gtk.connect(rootScreen, "size-changed", _on_screen_size_changed)
+
+
+@contextlib.contextmanager
+def flock(path, timeout=-1):
+       WAIT_FOREVER = -1
+       DELAY = 0.1
+       timeSpent = 0
+
+       acquired = False
+
+       while timeSpent <= timeout or timeout == WAIT_FOREVER:
+               try:
+                       fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR)
+                       acquired = True
+                       break
+               except OSError, e:
+                       if e.errno != errno.EEXIST:
+                               raise
+               time.sleep(DELAY)
+               timeSpent += DELAY
+
+       assert acquired, "Failed to grab file-lock %s within timeout %d" % (path, timeout)
+
+       try:
+               yield fd
+       finally:
+               os.unlink(path)
+
+
+@contextlib.contextmanager
+def gtk_lock():
+       gtk.gdk.threads_enter()
+       try:
+               yield
+       finally:
+               gtk.gdk.threads_leave()
+
+
+def find_parent_window(widget):
+       while True:
+               parent = widget.get_parent()
+               if isinstance(parent, gtk.Window):
+                       return parent
+               widget = parent
+
+
+def make_idler(func):
+       """
+       Decorator that makes a generator-function into a function that will continue execution on next call
+       """
+       a = []
+
+       @functools.wraps(func)
+       def decorated_func(*args, **kwds):
+               if not a:
+                       a.append(func(*args, **kwds))
+               try:
+                       a[0].next()
+                       return True
+               except StopIteration:
+                       del a[:]
+                       return False
+
+       return decorated_func
+
+
+def asynchronous_gtk_message(original_func):
+       """
+       @note Idea came from http://www.aclevername.com/articles/python-webgui/
+       """
+
+       def execute(allArgs):
+               args, kwargs = allArgs
+               with gtk_lock():
+                       original_func(*args, **kwargs)
+               return False
+
+       @functools.wraps(original_func)
+       def delayed_func(*args, **kwargs):
+               gobject.idle_add(execute, (args, kwargs))
+
+       return delayed_func
+
+
+def synchronous_gtk_message(original_func):
+       """
+       @note Idea came from http://www.aclevername.com/articles/python-webgui/
+       """
+
+       @functools.wraps(original_func)
+       def immediate_func(*args, **kwargs):
+               with gtk_lock():
+                       return original_func(*args, **kwargs)
+
+       return immediate_func
+
+
+def autostart(func):
+       """
+       >>> @autostart
+       ... def grep_sink(pattern):
+       ...     print "Looking for %s" % pattern
+       ...     while True:
+       ...             line = yield
+       ...             if pattern in line:
+       ...                     print line,
+       >>> g = grep_sink("python")
+       Looking for python
+       >>> g.send("Yeah but no but yeah but no")
+       >>> g.send("A series of tubes")
+       >>> g.send("python generators rock!")
+       python generators rock!
+       >>> g.close()
+       """
+
+       @functools.wraps(func)
+       def start(*args, **kwargs):
+               cr = func(*args, **kwargs)
+               cr.next()
+               return cr
+
+       return start
+
+
+@autostart
+def printer_sink(format = "%s"):
+       """
+       >>> pr = printer_sink("%r")
+       >>> pr.send("Hello")
+       'Hello'
+       >>> pr.send("5")
+       '5'
+       >>> pr.send(5)
+       5
+       >>> p = printer_sink()
+       >>> p.send("Hello")
+       Hello
+       >>> p.send("World")
+       World
+       >>> # p.throw(RuntimeError, "Goodbye")
+       >>> # p.send("Meh")
+       >>> # p.close()
+       """
+       while True:
+               item = yield
+               print format % (item, )
+
+
+@autostart
+def null_sink():
+       """
+       Good for uses like with cochain to pick up any slack
+       """
+       while True:
+               item = yield
+
+
+@autostart
+def comap(function, target):
+       """
+       >>> p = printer_sink()
+       >>> cm = comap(lambda x: x+1, p)
+       >>> cm.send((0, ))
+       1
+       >>> cm.send((1.0, ))
+       2.0
+       >>> cm.send((-2, ))
+       -1
+       """
+       while True:
+               try:
+                       item = yield
+                       mappedItem = function(*item)
+                       target.send(mappedItem)
+               except Exception, e:
+                       _moduleLogger.exception("Forwarding exception!")
+                       target.throw(e.__class__, str(e))
+
+
+def _flush_queue(queue):
+       while not queue.empty():
+               yield queue.get()
+
+
+@autostart
+def queue_sink(queue):
+       """
+       >>> q = Queue.Queue()
+       >>> qs = queue_sink(q)
+       >>> qs.send("Hello")
+       >>> qs.send("World")
+       >>> qs.throw(RuntimeError, "Goodbye")
+       >>> qs.send("Meh")
+       >>> qs.close()
+       >>> print [i for i in _flush_queue(q)]
+       [(None, 'Hello'), (None, 'World'), (<type 'exceptions.RuntimeError'>, 'Goodbye'), (None, 'Meh'), (<type 'exceptions.GeneratorExit'>, None)]
+       """
+       while True:
+               try:
+                       item = yield
+                       queue.put((None, item))
+               except Exception, e:
+                       queue.put((e.__class__, str(e)))
+               except GeneratorExit:
+                       queue.put((GeneratorExit, None))
+                       raise
+
+
+def decode_item(item, target):
+       if item[0] is None:
+               target.send(item[1])
+               return False
+       elif item[0] is GeneratorExit:
+               target.close()
+               return True
+       else:
+               target.throw(item[0], item[1])
+               return False
+
+
+def nonqueue_source(queue, target):
+       isDone = False
+       while not isDone:
+               item = queue.get()
+               isDone = decode_item(item, target)
+               while not queue.empty():
+                       queue.get_nowait()
+
+
+def threaded_stage(target, thread_factory = threading.Thread):
+       messages = Queue.Queue()
+
+       run_source = functools.partial(nonqueue_source, messages, target)
+       thread = thread_factory(target=run_source)
+       thread.setDaemon(True)
+       thread.start()
+
+       # Sink running in current thread
+       return queue_sink(messages)
+
+
+def log_exception(logger):
+
+       def log_exception_decorator(func):
+
+               @functools.wraps(func)
+               def wrapper(*args, **kwds):
+                       try:
+                               return func(*args, **kwds)
+                       except Exception:
+                               logger.exception(func.__name__)
+
+               return wrapper
+
+       return log_exception_decorator
+
+
+class LoginWindow(object):
+
+       def __init__(self, widgetTree):
+               """
+               @note Thread agnostic
+               """
+               self._dialog = widgetTree.get_widget("loginDialog")
+               self._parentWindow = widgetTree.get_widget("mainWindow")
+               self._serviceCombo = widgetTree.get_widget("serviceCombo")
+               self._usernameEntry = widgetTree.get_widget("usernameentry")
+               self._passwordEntry = widgetTree.get_widget("passwordentry")
+
+               self._serviceList = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
+               self._serviceCombo.set_model(self._serviceList)
+               cell = gtk.CellRendererText()
+               self._serviceCombo.pack_start(cell, True)
+               self._serviceCombo.add_attribute(cell, 'text', 1)
+               self._serviceCombo.set_active(0)
+
+               widgetTree.get_widget("loginbutton").connect("clicked", self._on_loginbutton_clicked)
+               widgetTree.get_widget("logins_close_button").connect("clicked", self._on_loginclose_clicked)
+
+       def request_credentials(self,
+               parentWindow = None,
+               defaultCredentials = ("", "")
+       ):
+               """
+               @note UI Thread
+               """
+               if parentWindow is None:
+                       parentWindow = self._parentWindow
+
+               self._serviceCombo.hide()
+               self._serviceList.clear()
+
+               self._usernameEntry.set_text(defaultCredentials[0])
+               self._passwordEntry.set_text(defaultCredentials[1])
+
+               try:
+                       self._dialog.set_transient_for(parentWindow)
+                       self._dialog.set_default_response(gtk.RESPONSE_OK)
+                       response = self._dialog.run()
+                       if response != gtk.RESPONSE_OK:
+                               raise RuntimeError("Login Cancelled")
+
+                       username = self._usernameEntry.get_text()
+                       password = self._passwordEntry.get_text()
+                       self._passwordEntry.set_text("")
+               finally:
+                       self._dialog.hide()
+
+               return username, password
+
+       def request_credentials_from(self,
+               services,
+               parentWindow = None,
+               defaultCredentials = ("", "")
+       ):
+               """
+               @note UI Thread
+               """
+               if parentWindow is None:
+                       parentWindow = self._parentWindow
+
+               self._serviceList.clear()
+               for serviceIdserviceName in services:
+                       self._serviceList.append(serviceIdserviceName)
+               self._serviceCombo.set_active(0)
+               self._serviceCombo.show()
+
+               self._usernameEntry.set_text(defaultCredentials[0])
+               self._passwordEntry.set_text(defaultCredentials[1])
+
+               try:
+                       self._dialog.set_transient_for(parentWindow)
+                       self._dialog.set_default_response(gtk.RESPONSE_OK)
+                       response = self._dialog.run()
+                       if response != gtk.RESPONSE_OK:
+                               raise RuntimeError("Login Cancelled")
+
+                       username = self._usernameEntry.get_text()
+                       password = self._passwordEntry.get_text()
+               finally:
+                       self._dialog.hide()
+
+               itr = self._serviceCombo.get_active_iter()
+               serviceId = int(self._serviceList.get_value(itr, 0))
+               self._serviceList.clear()
+               return serviceId, username, password
+
+       def _on_loginbutton_clicked(self, *args):
+               self._dialog.response(gtk.RESPONSE_OK)
+
+       def _on_loginclose_clicked(self, *args):
+               self._dialog.response(gtk.RESPONSE_CANCEL)
+
+
+def safecall(f, errorDisplay=None, default=None, exception=Exception):
+       '''
+       Returns modified f. When the modified f is called and throws an
+       exception, the default value is returned
+       '''
+       def _safecall(*args, **argv):
+               try:
+                       return f(*args,**argv)
+               except exception, e:
+                       if errorDisplay is not None:
+                               errorDisplay.push_exception(e)
+                       return default
+       return _safecall
+
+
+class ErrorDisplay(object):
+
+       def __init__(self, widgetTree):
+               super(ErrorDisplay, self).__init__()
+               self.__errorBox = widgetTree.get_widget("errorEventBox")
+               self.__errorDescription = widgetTree.get_widget("errorDescription")
+               self.__errorClose = widgetTree.get_widget("errorClose")
+               self.__parentBox = self.__errorBox.get_parent()
+
+               self.__errorBox.connect("button_release_event", self._on_close)
+
+               self.__messages = []
+               self.__parentBox.remove(self.__errorBox)
+
+       def push_message_with_lock(self, message):
+               with gtk_lock():
+                       self.push_message(message)
+
+       def push_message(self, message):
+               self.__messages.append(message)
+               if 1 == len(self.__messages):
+                       self.__show_message(message)
+
+       def push_exception_with_lock(self):
+               with gtk_lock():
+                       self.push_exception()
+
+       def push_exception(self):
+               userMessage = str(sys.exc_info()[1])
+               self.push_message(userMessage)
+               _moduleLogger.exception(userMessage)
+
+       def pop_message(self):
+               del self.__messages[0]
+               if 0 == len(self.__messages):
+                       self.__hide_message()
+               else:
+                       self.__errorDescription.set_text(self.__messages[0])
+
+       def _on_close(self, *args):
+               self.pop_message()
+
+       def __show_message(self, message):
+               self.__errorDescription.set_text(message)
+               self.__parentBox.pack_start(self.__errorBox, False, False)
+               self.__parentBox.reorder_child(self.__errorBox, 1)
+
+       def __hide_message(self):
+               self.__errorDescription.set_text("")
+               self.__parentBox.remove(self.__errorBox)
+
+
+class DummyErrorDisplay(object):
+
+       def __init__(self):
+               super(DummyErrorDisplay, self).__init__()
+
+               self.__messages = []
+
+       def push_message_with_lock(self, message):
+               self.push_message(message)
+
+       def push_message(self, message):
+               if 0 < len(self.__messages):
+                       self.__messages.append(message)
+               else:
+                       self.__show_message(message)
+
+       def push_exception(self, exception = None):
+               userMessage = str(sys.exc_value)
+               _moduleLogger.exception(userMessage)
+
+       def pop_message(self):
+               if 0 < len(self.__messages):
+                       self.__show_message(self.__messages[0])
+                       del self.__messages[0]
+
+       def __show_message(self, message):
+               _moduleLogger.debug(message)
+
+
+class MessageBox(gtk.MessageDialog):
+
+       def __init__(self, message):
+               parent = None
+               gtk.MessageDialog.__init__(
+                       self,
+                       parent,
+                       gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+                       gtk.MESSAGE_ERROR,
+                       gtk.BUTTONS_OK,
+                       message,
+               )
+               self.set_default_response(gtk.RESPONSE_OK)
+               self.connect('response', self._handle_clicked)
+
+       def _handle_clicked(self, *args):
+               self.destroy()
+
+
+class MessageBox2(gtk.MessageDialog):
+
+       def __init__(self, message):
+               parent = None
+               gtk.MessageDialog.__init__(
+                       self,
+                       parent,
+                       gtk.DIALOG_DESTROY_WITH_PARENT,
+                       gtk.MESSAGE_ERROR,
+                       gtk.BUTTONS_OK,
+                       message,
+               )
+               self.set_default_response(gtk.RESPONSE_OK)
+               self.connect('response', self._handle_clicked)
+
+       def _handle_clicked(self, *args):
+               self.destroy()
+
+
+class PopupCalendar(object):
+
+       def __init__(self, parent, displayDate, title = ""):
+               self._displayDate = displayDate
+
+               self._calendar = gtk.Calendar()
+               self._calendar.select_month(self._displayDate.month, self._displayDate.year)
+               self._calendar.select_day(self._displayDate.day)
+               self._calendar.set_display_options(
+                       gtk.CALENDAR_SHOW_HEADING |
+                       gtk.CALENDAR_SHOW_DAY_NAMES |
+                       gtk.CALENDAR_NO_MONTH_CHANGE |
+                       0
+               )
+               self._calendar.connect("day-selected", self._on_day_selected)
+
+               self._popupWindow = gtk.Window()
+               self._popupWindow.set_title(title)
+               self._popupWindow.add(self._calendar)
+               self._popupWindow.set_transient_for(parent)
+               self._popupWindow.set_modal(True)
+               self._popupWindow.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
+               self._popupWindow.set_skip_pager_hint(True)
+               self._popupWindow.set_skip_taskbar_hint(True)
+
+       def run(self):
+               self._popupWindow.show_all()
+
+       def _on_day_selected(self, *args):
+               try:
+                       self._calendar.select_month(self._displayDate.month, self._displayDate.year)
+                       self._calendar.select_day(self._displayDate.day)
+               except Exception, e:
+                       _moduleLogger.exception(e)
+
+
+if __name__ == "__main__":
+       if False:
+               import datetime
+               cal = PopupCalendar(None, datetime.datetime.now())
+               cal._popupWindow.connect("destroy", lambda w: gtk.main_quit())
+               cal.run()
+
+       gtk.main()
diff --git a/src/hildonize.py b/src/hildonize.py
new file mode 100644 (file)
index 0000000..48ca31a
--- /dev/null
@@ -0,0 +1,744 @@
+#!/usr/bin/env python
+
+"""
+Open Issues
+       @bug not all of a message is shown
+       @bug Buttons are too small
+"""
+
+
+import gobject
+import gtk
+import dbus
+
+
+class _NullHildonModule(object):
+       pass
+
+
+try:
+       import hildon as _hildon
+       hildon  = _hildon # Dumb but gets around pyflakiness
+except (ImportError, OSError):
+       hildon = _NullHildonModule
+
+
+IS_HILDON_SUPPORTED = hildon is not _NullHildonModule
+
+
+class _NullHildonProgram(object):
+
+       def add_window(self, window):
+               pass
+
+
+def _hildon_get_app_class():
+       return hildon.Program
+
+
+def _null_get_app_class():
+       return _NullHildonProgram
+
+
+try:
+       hildon.Program
+       get_app_class = _hildon_get_app_class
+except AttributeError:
+       get_app_class = _null_get_app_class
+
+
+def _hildon_set_application_name(name):
+       gtk.set_application_name(name)
+
+
+def _null_set_application_name(name):
+       pass
+
+
+try:
+       gtk.set_application_name
+       set_application_name = _hildon_set_application_name
+except AttributeError:
+       set_application_name = _null_set_application_name
+
+
+def _fremantle_hildonize_window(app, window):
+       oldWindow = window
+       newWindow = hildon.StackableWindow()
+       if oldWindow.get_child() is not None:
+               oldWindow.get_child().reparent(newWindow)
+       app.add_window(newWindow)
+       return newWindow
+
+
+def _hildon_hildonize_window(app, window):
+       oldWindow = window
+       newWindow = hildon.Window()
+       if oldWindow.get_child() is not None:
+               oldWindow.get_child().reparent(newWindow)
+       app.add_window(newWindow)
+       return newWindow
+
+
+def _null_hildonize_window(app, window):
+       return window
+
+
+try:
+       hildon.StackableWindow
+       hildonize_window = _fremantle_hildonize_window
+except AttributeError:
+       try:
+               hildon.Window
+               hildonize_window = _hildon_hildonize_window
+       except AttributeError:
+               hildonize_window = _null_hildonize_window
+
+
+def _fremantle_hildonize_menu(window, gtkMenu):
+       appMenu = hildon.AppMenu()
+       window.set_app_menu(appMenu)
+       gtkMenu.get_parent().remove(gtkMenu)
+       return appMenu
+
+
+def _hildon_hildonize_menu(window, gtkMenu):
+       hildonMenu = gtk.Menu()
+       for child in gtkMenu.get_children():
+               child.reparent(hildonMenu)
+       window.set_menu(hildonMenu)
+       gtkMenu.destroy()
+       return hildonMenu
+
+
+def _null_hildonize_menu(window, gtkMenu):
+       return gtkMenu
+
+
+try:
+       hildon.AppMenu
+       GTK_MENU_USED = False
+       IS_FREMANTLE_SUPPORTED = True
+       hildonize_menu = _fremantle_hildonize_menu
+except AttributeError:
+       GTK_MENU_USED = True
+       IS_FREMANTLE_SUPPORTED = False
+       if IS_HILDON_SUPPORTED:
+               hildonize_menu = _hildon_hildonize_menu
+       else:
+               hildonize_menu = _null_hildonize_menu
+
+
+def _hildon_set_button_auto_selectable(button):
+       button.set_theme_size(hildon.HILDON_SIZE_AUTO_HEIGHT)
+
+
+def _null_set_button_auto_selectable(button):
+       pass
+
+
+try:
+       hildon.HILDON_SIZE_AUTO_HEIGHT
+       gtk.Button.set_theme_size
+       set_button_auto_selectable = _hildon_set_button_auto_selectable
+except AttributeError:
+       set_button_auto_selectable = _null_set_button_auto_selectable
+
+
+def _hildon_set_button_finger_selectable(button):
+       button.set_theme_size(hildon.HILDON_SIZE_FINGER_HEIGHT)
+
+
+def _null_set_button_finger_selectable(button):
+       pass
+
+
+try:
+       hildon.HILDON_SIZE_FINGER_HEIGHT
+       gtk.Button.set_theme_size
+       set_button_finger_selectable = _hildon_set_button_finger_selectable
+except AttributeError:
+       set_button_finger_selectable = _null_set_button_finger_selectable
+
+
+def _hildon_set_button_thumb_selectable(button):
+       button.set_theme_size(hildon.HILDON_SIZE_THUMB_HEIGHT)
+
+
+def _null_set_button_thumb_selectable(button):
+       pass
+
+
+try:
+       hildon.HILDON_SIZE_THUMB_HEIGHT
+       gtk.Button.set_theme_size
+       set_button_thumb_selectable = _hildon_set_button_thumb_selectable
+except AttributeError:
+       set_button_thumb_selectable = _null_set_button_thumb_selectable
+
+
+def _hildon_set_cell_thumb_selectable(renderer):
+       renderer.set_property("scale", 1.5)
+
+
+def _null_set_cell_thumb_selectable(renderer):
+       pass
+
+
+if IS_HILDON_SUPPORTED:
+       set_cell_thumb_selectable = _hildon_set_cell_thumb_selectable
+else:
+       set_cell_thumb_selectable = _null_set_cell_thumb_selectable
+
+
+def _hildon_set_pix_cell_thumb_selectable(renderer):
+       renderer.set_property("stock-size", 48)
+
+
+def _null_set_pix_cell_thumb_selectable(renderer):
+       pass
+
+
+if IS_HILDON_SUPPORTED:
+       set_pix_cell_thumb_selectable = _hildon_set_pix_cell_thumb_selectable
+else:
+       set_pix_cell_thumb_selectable = _null_set_pix_cell_thumb_selectable
+
+
+def _fremantle_show_information_banner(parent, message):
+       hildon.hildon_banner_show_information(parent, "", message)
+
+
+def _hildon_show_information_banner(parent, message):
+       hildon.hildon_banner_show_information(parent, None, message)
+
+
+def _null_show_information_banner(parent, message):
+       pass
+
+
+if IS_FREMANTLE_SUPPORTED:
+       show_information_banner = _fremantle_show_information_banner
+else:
+       try:
+               hildon.hildon_banner_show_information
+               show_information_banner = _hildon_show_information_banner
+       except AttributeError:
+               show_information_banner = _null_show_information_banner
+
+
+def _fremantle_show_busy_banner_start(parent, message):
+       hildon.hildon_gtk_window_set_progress_indicator(parent, True)
+       return parent
+
+
+def _fremantle_show_busy_banner_end(banner):
+       hildon.hildon_gtk_window_set_progress_indicator(banner, False)
+
+
+def _hildon_show_busy_banner_start(parent, message):
+       return hildon.hildon_banner_show_animation(parent, None, message)
+
+
+def _hildon_show_busy_banner_end(banner):
+       banner.destroy()
+
+
+def _null_show_busy_banner_start(parent, message):
+       return None
+
+
+def _null_show_busy_banner_end(banner):
+       assert banner is None
+
+
+try:
+       hildon.hildon_gtk_window_set_progress_indicator
+       show_busy_banner_start = _fremantle_show_busy_banner_start
+       show_busy_banner_end = _fremantle_show_busy_banner_end
+except AttributeError:
+       try:
+               hildon.hildon_banner_show_animation
+               show_busy_banner_start = _hildon_show_busy_banner_start
+               show_busy_banner_end = _hildon_show_busy_banner_end
+       except AttributeError:
+               show_busy_banner_start = _null_show_busy_banner_start
+               show_busy_banner_end = _null_show_busy_banner_end
+
+
+def _hildon_hildonize_text_entry(textEntry):
+       textEntry.set_property('hildon-input-mode', 7)
+
+
+def _null_hildonize_text_entry(textEntry):
+       pass
+
+
+if IS_HILDON_SUPPORTED:
+       hildonize_text_entry = _hildon_hildonize_text_entry
+else:
+       hildonize_text_entry = _null_hildonize_text_entry
+
+
+def _hildon_window_to_portrait(window):
+       # gtk documentation is unclear whether this does a "=" or a "|="
+       flags = hildon.PORTRAIT_MODE_SUPPORT | hildon.PORTRAIT_MODE_REQUEST
+       hildon.hildon_gtk_window_set_portrait_flags(window, flags)
+
+
+def _hildon_window_to_landscape(window):
+       # gtk documentation is unclear whether this does a "=" or a "&= ~"
+       flags = hildon.PORTRAIT_MODE_SUPPORT
+       hildon.hildon_gtk_window_set_portrait_flags(window, flags)
+
+
+def _null_window_to_portrait(window):
+       pass
+
+
+def _null_window_to_landscape(window):
+       pass
+
+
+try:
+       hildon.PORTRAIT_MODE_SUPPORT
+       hildon.PORTRAIT_MODE_REQUEST
+       hildon.hildon_gtk_window_set_portrait_flags
+
+       window_to_portrait = _hildon_window_to_portrait
+       window_to_landscape = _hildon_window_to_landscape
+except AttributeError:
+       window_to_portrait = _null_window_to_portrait
+       window_to_landscape = _null_window_to_landscape
+
+
+def get_device_orientation():
+       bus = dbus.SystemBus()
+       try:
+               rawMceRequest = bus.get_object("com.nokia.mce", "/com/nokia/mce/request")
+               mceRequest = dbus.Interface(rawMceRequest, dbus_interface="com.nokia.mce.request")
+               orientation, standState, faceState, xAxis, yAxis, zAxis = mceRequest.get_device_orientation()
+       except dbus.exception.DBusException:
+               # catching for documentation purposes that when a system doesn't
+               # support this, this is what to expect
+               raise
+
+       if orientation == "":
+               return gtk.ORIENTATION_HORIZONTAL
+       elif orientation == "":
+               return gtk.ORIENTATION_VERTICAL
+       else:
+               raise RuntimeError("Unknown orientation: %s" % orientation)
+
+
+def _hildon_hildonize_password_entry(textEntry):
+       textEntry.set_property('hildon-input-mode', 7 | (1 << 29))
+
+
+def _null_hildonize_password_entry(textEntry):
+       pass
+
+
+if IS_HILDON_SUPPORTED:
+       hildonize_password_entry = _hildon_hildonize_password_entry
+else:
+       hildonize_password_entry = _null_hildonize_password_entry
+
+
+def _hildon_hildonize_combo_entry(comboEntry):
+       comboEntry.set_property('hildon-input-mode', 1 << 4)
+
+
+def _null_hildonize_combo_entry(textEntry):
+       pass
+
+
+if IS_HILDON_SUPPORTED:
+       hildonize_combo_entry = _hildon_hildonize_combo_entry
+else:
+       hildonize_combo_entry = _null_hildonize_combo_entry
+
+
+def _fremantle_hildonize_scrollwindow(scrolledWindow):
+       pannableWindow = hildon.PannableArea()
+
+       child = scrolledWindow.get_child()
+       scrolledWindow.remove(child)
+       pannableWindow.add(child)
+
+       parent = scrolledWindow.get_parent()
+       if parent is not None:
+               parent.remove(scrolledWindow)
+               parent.add(pannableWindow)
+
+       return pannableWindow
+
+
+def _hildon_hildonize_scrollwindow(scrolledWindow):
+       hildon.hildon_helper_set_thumb_scrollbar(scrolledWindow, True)
+       return scrolledWindow
+
+
+def _null_hildonize_scrollwindow(scrolledWindow):
+       return scrolledWindow
+
+
+try:
+       hildon.PannableArea
+       hildonize_scrollwindow = _fremantle_hildonize_scrollwindow
+       hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
+except AttributeError:
+       try:
+               hildon.hildon_helper_set_thumb_scrollbar
+               hildonize_scrollwindow = _hildon_hildonize_scrollwindow
+               hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
+       except AttributeError:
+               hildonize_scrollwindow = _null_hildonize_scrollwindow
+               hildonize_scrollwindow_with_viewport = _null_hildonize_scrollwindow
+
+
+def _hildon_request_number(parent, title, range, default):
+       spinner = hildon.NumberEditor(*range)
+       spinner.set_value(default)
+
+       dialog = gtk.Dialog(
+               title,
+               parent,
+               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+               (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+       )
+       dialog.set_default_response(gtk.RESPONSE_CANCEL)
+       dialog.get_child().add(spinner)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+
+               if response == gtk.RESPONSE_OK:
+                       return spinner.get_value()
+               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+                       raise RuntimeError("User cancelled request")
+               else:
+                       raise RuntimeError("Unrecognized response %r", response)
+       finally:
+               dialog.hide()
+               dialog.destroy()
+
+
+def _null_request_number(parent, title, range, default):
+       adjustment = gtk.Adjustment(default, range[0], range[1], 1, 5, 0)
+       spinner = gtk.SpinButton(adjustment, 0, 0)
+       spinner.set_wrap(False)
+
+       dialog = gtk.Dialog(
+               title,
+               parent,
+               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+               (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+       )
+       dialog.set_default_response(gtk.RESPONSE_CANCEL)
+       dialog.get_child().add(spinner)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+
+               if response == gtk.RESPONSE_OK:
+                       return spinner.get_value_as_int()
+               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+                       raise RuntimeError("User cancelled request")
+               else:
+                       raise RuntimeError("Unrecognized response %r", response)
+       finally:
+               dialog.hide()
+               dialog.destroy()
+
+
+try:
+       hildon.NumberEditor # TODO deprecated in fremantle
+       request_number = _hildon_request_number
+except AttributeError:
+       request_number = _null_request_number
+
+
+def _hildon_touch_selector(parent, title, items, defaultIndex):
+       model = gtk.ListStore(gobject.TYPE_STRING)
+       for item in items:
+               model.append((item, ))
+
+       selector = hildon.TouchSelector()
+       selector.append_text_column(model, True)
+       selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
+       selector.set_active(0, defaultIndex)
+
+       dialog = hildon.PickerDialog(parent)
+       dialog.set_selector(selector)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+
+               if response == gtk.RESPONSE_OK:
+                       return selector.get_active(0)
+               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+                       raise RuntimeError("User cancelled request")
+               else:
+                       raise RuntimeError("Unrecognized response %r", response)
+       finally:
+               dialog.hide()
+               dialog.destroy()
+
+
+def _on_null_touch_selector_activated(treeView, path, column, dialog, pathData):
+       dialog.response(gtk.RESPONSE_OK)
+       pathData[0] = path
+
+
+def _null_touch_selector(parent, title, items, defaultIndex = -1):
+       parentSize = parent.get_size()
+
+       model = gtk.ListStore(gobject.TYPE_STRING)
+       for item in items:
+               model.append((item, ))
+
+       cell = gtk.CellRendererText()
+       set_cell_thumb_selectable(cell)
+       column = gtk.TreeViewColumn(title)
+       column.pack_start(cell, expand=True)
+       column.add_attribute(cell, "text", 0)
+
+       treeView = gtk.TreeView()
+       treeView.set_model(model)
+       treeView.append_column(column)
+       selection = treeView.get_selection()
+       selection.set_mode(gtk.SELECTION_SINGLE)
+       if 0 < defaultIndex:
+               selection.select_path((defaultIndex, ))
+
+       scrolledWin = gtk.ScrolledWindow()
+       scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+       scrolledWin.add(treeView)
+
+       dialog = gtk.Dialog(
+               title,
+               parent,
+               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+               (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+       )
+       dialog.set_default_response(gtk.RESPONSE_CANCEL)
+       dialog.get_child().add(scrolledWin)
+       dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
+
+       scrolledWin = hildonize_scrollwindow(scrolledWin)
+       pathData = [None]
+       treeView.connect("row-activated", _on_null_touch_selector_activated, dialog, pathData)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+
+               if response == gtk.RESPONSE_OK:
+                       if pathData[0] is None:
+                               raise RuntimeError("No selection made")
+                       return pathData[0][0]
+               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+                       raise RuntimeError("User cancelled request")
+               else:
+                       raise RuntimeError("Unrecognized response %r", response)
+       finally:
+               dialog.hide()
+               dialog.destroy()
+
+
+try:
+       hildon.PickerDialog
+       hildon.TouchSelector
+       touch_selector = _hildon_touch_selector
+except AttributeError:
+       touch_selector = _null_touch_selector
+
+
+def _hildon_touch_selector_entry(parent, title, items, defaultItem):
+       # Got a segfault when using append_text_column with TouchSelectorEntry, so using this way
+       try:
+               selector = hildon.TouchSelectorEntry(text=True)
+       except TypeError:
+               selector = hildon.hildon_touch_selector_entry_new_text()
+       defaultIndex = -1
+       for i, item in enumerate(items):
+               selector.append_text(item)
+               if item == defaultItem:
+                       defaultIndex = i
+
+       dialog = hildon.PickerDialog(parent)
+       dialog.set_selector(selector)
+
+       if 0 < defaultIndex:
+               selector.set_active(0, defaultIndex)
+       else:
+               selector.get_entry().set_text(defaultItem)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+       finally:
+               dialog.hide()
+
+       if response == gtk.RESPONSE_OK:
+               return selector.get_entry().get_text()
+       elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+               raise RuntimeError("User cancelled request")
+       else:
+               raise RuntimeError("Unrecognized response %r", response)
+
+
+def _on_null_touch_selector_entry_entry_changed(entry, result, selection, defaultIndex):
+       custom = entry.get_text().strip()
+       if custom:
+               result[0] = custom
+               selection.unselect_all()
+       else:
+               result[0] = None
+               selection.select_path((defaultIndex, ))
+
+
+def _on_null_touch_selector_entry_entry_activated(customEntry, dialog, result):
+       dialog.response(gtk.RESPONSE_OK)
+       result[0] = customEntry.get_text()
+
+
+def _on_null_touch_selector_entry_tree_activated(treeView, path, column, dialog, result):
+       dialog.response(gtk.RESPONSE_OK)
+       model = treeView.get_model()
+       itr = model.get_iter(path)
+       if itr is not None:
+               result[0] = model.get_value(itr, 0)
+
+
+def _null_touch_selector_entry(parent, title, items, defaultItem):
+       parentSize = parent.get_size()
+
+       model = gtk.ListStore(gobject.TYPE_STRING)
+       defaultIndex = -1
+       for i, item in enumerate(items):
+               model.append((item, ))
+               if item == defaultItem:
+                       defaultIndex = i
+
+       cell = gtk.CellRendererText()
+       set_cell_thumb_selectable(cell)
+       column = gtk.TreeViewColumn(title)
+       column.pack_start(cell, expand=True)
+       column.add_attribute(cell, "text", 0)
+
+       treeView = gtk.TreeView()
+       treeView.set_model(model)
+       treeView.append_column(column)
+       selection = treeView.get_selection()
+       selection.set_mode(gtk.SELECTION_SINGLE)
+
+       scrolledWin = gtk.ScrolledWindow()
+       scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+       scrolledWin.add(treeView)
+
+       customEntry = gtk.Entry()
+
+       layout = gtk.VBox()
+       layout.pack_start(customEntry, expand=False)
+       layout.pack_start(scrolledWin)
+
+       dialog = gtk.Dialog(
+               title,
+               parent,
+               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
+               (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+       )
+       dialog.set_default_response(gtk.RESPONSE_CANCEL)
+       dialog.get_child().add(layout)
+       dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
+
+       scrolledWin = hildonize_scrollwindow(scrolledWin)
+
+       result = [None]
+       if 0 < defaultIndex:
+               selection.select_path((defaultIndex, ))
+               result[0] = defaultItem
+       else:
+               customEntry.set_text(defaultItem)
+
+       customEntry.connect("activate", _on_null_touch_selector_entry_entry_activated, dialog, result)
+       customEntry.connect("changed", _on_null_touch_selector_entry_entry_changed, result, selection, defaultIndex)
+       treeView.connect("row-activated", _on_null_touch_selector_entry_tree_activated, dialog, result)
+
+       try:
+               dialog.show_all()
+               response = dialog.run()
+
+               if response == gtk.RESPONSE_OK:
+                       _, itr = selection.get_selected()
+                       if itr is not None:
+                               return model.get_value(itr, 0)
+                       else:
+                               enteredText = customEntry.get_text().strip()
+                               if enteredText:
+                                       return enteredText
+                               elif result[0] is not None:
+                                       return result[0]
+                               else:
+                                       raise RuntimeError("No selection made")
+               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
+                       raise RuntimeError("User cancelled request")
+               else:
+                       raise RuntimeError("Unrecognized response %r", response)
+       finally:
+               dialog.hide()
+               dialog.destroy()
+
+
+try:
+       hildon.PickerDialog
+       hildon.TouchSelectorEntry
+       touch_selector_entry = _hildon_touch_selector_entry
+except AttributeError:
+       touch_selector_entry = _null_touch_selector_entry
+
+
+if __name__ == "__main__":
+       app = get_app_class()()
+
+       label = gtk.Label("Hello World from a Label!")
+
+       win = gtk.Window()
+       win.add(label)
+       win = hildonize_window(app, win)
+       if False and IS_FREMANTLE_SUPPORTED:
+               appMenu = hildon.AppMenu()
+               for i in xrange(5):
+                       b = gtk.Button(str(i))
+                       appMenu.append(b)
+               win.set_app_menu(appMenu)
+               win.show_all()
+               appMenu.show_all()
+               gtk.main()
+       elif False:
+               print touch_selector(win, "Test", ["A", "B", "C", "D"], 2)
+       elif False:
+               print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "C")
+               print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "Blah")
+       elif False:
+               import pprint
+               name, value = "", ""
+               goodLocals = [
+                       (name, value) for (name, value) in locals().iteritems()
+                       if not name.startswith("_")
+               ]
+               pprint.pprint(goodLocals)
+       elif False:
+               import time
+               show_information_banner(win, "Hello World")
+               time.sleep(5)
+       elif False:
+               import time
+               banner = show_busy_banner_start(win, "Hello World")
+               time.sleep(5)
+               show_busy_banner_end(banner)
diff --git a/src/nqaap.py b/src/nqaap.py
new file mode 100755 (executable)
index 0000000..ab32ba2
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+import os
+import logging
+
+import constants
+import nqaap_gtk
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+try:
+       os.makedirs(constants._data_path_)
+except OSError, e:
+       if e.errno != 17:
+               raise
+
+logging.basicConfig(level=logging.DEBUG, filename=constants._user_logpath_)
+_moduleLogger.info("%s %s-%s" % (constants.__pretty_app_name__, constants.__version__, constants.__build__))
+_moduleLogger.info("OS: %s" % (os.uname()[0], ))
+_moduleLogger.info("Kernel: %s (%s) for %s" % os.uname()[2:])
+_moduleLogger.info("Hostname: %s" % os.uname()[1])
+
+try:
+       nqaap_gtk.run()
+finally:
+       logging.shutdown()
diff --git a/src/nqaap_gtk.py b/src/nqaap_gtk.py
new file mode 100755 (executable)
index 0000000..90e812f
--- /dev/null
@@ -0,0 +1,38 @@
+#! /usr/bin/env python  
+
+import logging
+
+import dbus
+import dbus.mainloop.glib
+import gobject
+import gtk
+
+import constants
+import hildonize
+from Player import Player
+from Gui import Gui
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+def run():
+       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()
+
+       gtk.main()
+
+
+if __name__ == "__main__":
+       logging.basicConfig(level=logging.DEBUG)
+       run()
diff --git a/src/opt/Nqa-Audiobook-player/Audiobook.py b/src/opt/Nqa-Audiobook-player/Audiobook.py
deleted file mode 100644 (file)
index cd28e1b..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-from __future__ import with_statement
-
-import os
-
-import logging
-
-
-_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 is_dir_book(path):
-       return os.path.isdir(path)
-
-
-def is_playlist_book(path):
-       return path.rsplit(".", 1)[-1] in ["m3u"]
-
-
-def is_single_chapter(path):
-       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
diff --git a/src/opt/Nqa-Audiobook-player/Browser.py b/src/opt/Nqa-Audiobook-player/Browser.py
deleted file mode 100644 (file)
index 31ce7d6..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-import os\r
-\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
diff --git a/src/opt/Nqa-Audiobook-player/CallMonitor.py b/src/opt/Nqa-Audiobook-player/CallMonitor.py
deleted file mode 100644 (file)
index 97be5a7..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-import logging
-
-import gobject
-import dbus
-import telepathy
-
-import gtk_toolbox
-
-
-_moduleLogger = logging.getLogger(__name__)
-DBUS_PROPERTIES = 'org.freedesktop.DBus.Properties'
-
-
-class NewChannelSignaller(object):
-
-       def __init__(self, on_new_channel):
-               self._sessionBus = dbus.SessionBus()
-               self._on_user_new_channel = on_new_channel
-
-       def start(self):
-               self._sessionBus.add_signal_receiver(
-                       self._on_new_channel,
-                       "NewChannel",
-                       "org.freedesktop.Telepathy.Connection",
-                       None,
-                       None
-               )
-
-       def stop(self):
-               self._sessionBus.remove_signal_receiver(
-                       self._on_new_channel,
-                       "NewChannel",
-                       "org.freedesktop.Telepathy.Connection",
-                       None,
-                       None
-               )
-
-       @gtk_toolbox.log_exception(_moduleLogger)
-       def _on_new_channel(
-               self, channelObjectPath, channelType, handleType, handle, supressHandler
-       ):
-               connObjectPath = channel_path_to_conn_path(channelObjectPath)
-               serviceName = path_to_service_name(channelObjectPath)
-               try:
-                       self._on_user_new_channel(
-                               self._sessionBus, serviceName, connObjectPath, channelObjectPath, channelType
-                       )
-               except Exception:
-                       _moduleLogger.exception("Blocking exception from being passed up")
-
-
-class ChannelClosed(object):
-
-       def __init__(self, bus, conn, chan, on_closed):
-               self.__on_closed = on_closed
-
-               chan[telepathy.interfaces.CHANNEL].connect_to_signal(
-                       "Closed",
-                       self._on_closed,
-               )
-
-       @gtk_toolbox.log_exception(_moduleLogger)
-       def _on_closed(self):
-               self.__on_closed(self)
-
-
-class CallMonitor(gobject.GObject):
-
-       __gsignals__ = {
-               'call_start' : (
-                       gobject.SIGNAL_RUN_LAST,
-                       gobject.TYPE_NONE,
-                       (),
-               ),
-               'call_end' : (
-                       gobject.SIGNAL_RUN_LAST,
-                       gobject.TYPE_NONE,
-                       (),
-               ),
-       }
-
-       def __init__(self):
-               gobject.GObject.__init__(self)
-               self._isActive = False
-               self._newChannelMonitor = NewChannelSignaller(self._on_new_channel)
-               self._channelClosedMonitors = []
-
-       def start(self):
-               self._isActive = True
-               self._newChannelMonitor.start()
-
-       def stop(self):
-               self._isActive = False
-               self._newChannelMonitor.stop()
-
-       def _on_new_channel(self, sessionBus, serviceName, connObjectPath, channelObjectPath, channelType):
-               if not self._isActive:
-                       return
-
-               if channelType != telepathy.interfaces.CHANNEL_TYPE_STREAMED_MEDIA:
-                       return
-
-               cmName = cm_from_path(connObjectPath)
-               conn = telepathy.client.Connection(serviceName, connObjectPath)
-               try:
-                       chan = telepathy.client.Channel(serviceName, channelObjectPath)
-               except dbus.exceptions.UnknownMethodException:
-                       _moduleLogger.exception("Client might not have implemented a deprecated method")
-                       return
-
-               missDetection = ChannelClosed(
-                       sessionBus, conn, chan, self._on_close
-               )
-               self._outstandingRequests.append(missDetection)
-               if len(self._outstandingRequests) == 1:
-                       self.emit("call_start")
-
-       def _on_close(self, channelCloseMonitor):
-               self._outstandingRequests.remove(channelCloseMonitor)
-               if not self._outstandingRequests:
-                       self.emit("call_stop")
-
-
-def channel_path_to_conn_path(channelObjectPath):
-       """
-       >>> channel_path_to_conn_path("/org/freedesktop/Telepathy/ConnectionManager/theonering/gv/USERNAME/Channel1")
-       '/org/freedesktop/Telepathy/ConnectionManager/theonering/gv/USERNAME'
-       """
-       return channelObjectPath.rsplit("/", 1)[0]
-
-
-def path_to_service_name(path):
-       """
-       >>> path_to_service_name("/org/freedesktop/Telepathy/ConnectionManager/theonering/gv/USERNAME/Channel1")
-       'org.freedesktop.Telepathy.ConnectionManager.theonering.gv.USERNAME'
-       """
-       return ".".join(path[1:].split("/")[0:7])
-
-
-def cm_from_path(path):
-       """
-       >>> cm_from_path("/org/freedesktop/Telepathy/ConnectionManager/theonering/gv/USERNAME/Channel1")
-       'theonering'
-       """
-       return path[1:].split("/")[4]
diff --git a/src/opt/Nqa-Audiobook-player/FileStorage.py b/src/opt/Nqa-Audiobook-player/FileStorage.py
deleted file mode 100644 (file)
index af19c9d..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-from __future__ import with_statement   # enable with
-
-import os
-import simplejson
-import logging
-
-
-_moduleLogger = logging.getLogger(__name__)
-
-
-# @todo Add bookmarks
-
-
-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
diff --git a/src/opt/Nqa-Audiobook-player/Gui.py b/src/opt/Nqa-Audiobook-player/Gui.py
deleted file mode 100644 (file)
index 5b0ff29..0000000
+++ /dev/null
@@ -1,622 +0,0 @@
-from __future__ import with_statement
-
-import os
-import ConfigParser
-import logging
-
-import gobject
-import gtk
-
-import constants
-import hildonize
-import gtk_toolbox
-import Browser
-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
-
-
-_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)
-
-
-def _old_timeout_add_seconds(timeout, callback):
-       return gobject.timeout_add(timeout * 1000, callback)
-
-
-def _timeout_add_seconds(timeout, callback):
-       return gobject.timeout_add_seconds(timeout, callback)
-
-
-try:
-       gobject.timeout_add_seconds
-       timeout_add_seconds = _timeout_add_seconds
-except AttributeError:
-       timeout_add_seconds = _old_timeout_add_seconds
-
-
-if __name__ == "__main__":
-       g = Gui(None)
diff --git a/src/opt/Nqa-Audiobook-player/NoCover.png b/src/opt/Nqa-Audiobook-player/NoCover.png
deleted file mode 100644 (file)
index 80e142b..0000000
Binary files a/src/opt/Nqa-Audiobook-player/NoCover.png and /dev/null differ
diff --git a/src/opt/Nqa-Audiobook-player/Player.py b/src/opt/Nqa-Audiobook-player/Player.py
deleted file mode 100644 (file)
index 6293ce5..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-import os
-import threading
-import time
-import logging
-
-import constants
-import hildonize
-import Audiobook
-import FileStorage
-
-
-_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()
-               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 ()
diff --git a/src/opt/Nqa-Audiobook-player/SimpleGStreamer.py b/src/opt/Nqa-Audiobook-player/SimpleGStreamer.py
deleted file mode 100644 (file)
index 5d91edd..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-import os
-import logging
-
-import gst
-
-import gtk_toolbox
-
-
-_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)
diff --git a/src/opt/Nqa-Audiobook-player/SimpleOSSOPlayer.py b/src/opt/Nqa-Audiobook-player/SimpleOSSOPlayer.py
deleted file mode 100644 (file)
index 698e0db..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-import os
-import logging
-
-import dbus
-
-import gtk_toolbox
-
-
-_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) )
diff --git a/src/opt/Nqa-Audiobook-player/__init__.py b/src/opt/Nqa-Audiobook-player/__init__.py
deleted file mode 100644 (file)
index 4265cc3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#!/usr/bin/env python
diff --git a/src/opt/Nqa-Audiobook-player/constants.py b/src/opt/Nqa-Audiobook-player/constants.py
deleted file mode 100644 (file)
index 3fdc0c3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-import os
-
-__pretty_app_name__ = "nQaap"
-__app_name__ = "nqaap"
-__version__ = "0.8.6"
-__build__ = 0
-__app_magic__ = 0xdeadbeef
-_data_path_ = os.path.join(os.path.expanduser("~"), ".%s" % __app_name__)
-_user_settings_ = "%s/settings.ini" % _data_path_
-_user_logpath_ = "%s/%s.log" % (_data_path_, __app_name__)
-_default_book_path_ = os.path.join(os.path.expanduser("~"), "MyDocs/Audiobooks/")
diff --git a/src/opt/Nqa-Audiobook-player/gtk_toolbox.py b/src/opt/Nqa-Audiobook-player/gtk_toolbox.py
deleted file mode 100644 (file)
index 784c871..0000000
+++ /dev/null
@@ -1,577 +0,0 @@
-#!/usr/bin/python
-
-from __future__ import with_statement
-
-import os
-import errno
-import sys
-import time
-import itertools
-import functools
-import contextlib
-import logging
-import threading
-import Queue
-
-import gobject
-import gtk
-
-
-_moduleLogger = logging.getLogger(__name__)
-
-
-def get_screen_orientation():
-       width, height = gtk.gdk.get_default_root_window().get_size()
-       if width < height:
-               return gtk.ORIENTATION_VERTICAL
-       else:
-               return gtk.ORIENTATION_HORIZONTAL
-
-
-def orientation_change_connect(handler, *args):
-       """
-       @param handler(orientation, *args) -> None(?)
-       """
-       initialScreenOrientation = get_screen_orientation()
-       orientationAndArgs = list(itertools.chain((initialScreenOrientation, ), args))
-
-       def _on_screen_size_changed(screen):
-               newScreenOrientation = get_screen_orientation()
-               if newScreenOrientation != orientationAndArgs[0]:
-                       orientationAndArgs[0] = newScreenOrientation
-                       handler(*orientationAndArgs)
-
-       rootScreen = gtk.gdk.get_default_root_window()
-       return gtk.connect(rootScreen, "size-changed", _on_screen_size_changed)
-
-
-@contextlib.contextmanager
-def flock(path, timeout=-1):
-       WAIT_FOREVER = -1
-       DELAY = 0.1
-       timeSpent = 0
-
-       acquired = False
-
-       while timeSpent <= timeout or timeout == WAIT_FOREVER:
-               try:
-                       fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR)
-                       acquired = True
-                       break
-               except OSError, e:
-                       if e.errno != errno.EEXIST:
-                               raise
-               time.sleep(DELAY)
-               timeSpent += DELAY
-
-       assert acquired, "Failed to grab file-lock %s within timeout %d" % (path, timeout)
-
-       try:
-               yield fd
-       finally:
-               os.unlink(path)
-
-
-@contextlib.contextmanager
-def gtk_lock():
-       gtk.gdk.threads_enter()
-       try:
-               yield
-       finally:
-               gtk.gdk.threads_leave()
-
-
-def find_parent_window(widget):
-       while True:
-               parent = widget.get_parent()
-               if isinstance(parent, gtk.Window):
-                       return parent
-               widget = parent
-
-
-def make_idler(func):
-       """
-       Decorator that makes a generator-function into a function that will continue execution on next call
-       """
-       a = []
-
-       @functools.wraps(func)
-       def decorated_func(*args, **kwds):
-               if not a:
-                       a.append(func(*args, **kwds))
-               try:
-                       a[0].next()
-                       return True
-               except StopIteration:
-                       del a[:]
-                       return False
-
-       return decorated_func
-
-
-def asynchronous_gtk_message(original_func):
-       """
-       @note Idea came from http://www.aclevername.com/articles/python-webgui/
-       """
-
-       def execute(allArgs):
-               args, kwargs = allArgs
-               with gtk_lock():
-                       original_func(*args, **kwargs)
-               return False
-
-       @functools.wraps(original_func)
-       def delayed_func(*args, **kwargs):
-               gobject.idle_add(execute, (args, kwargs))
-
-       return delayed_func
-
-
-def synchronous_gtk_message(original_func):
-       """
-       @note Idea came from http://www.aclevername.com/articles/python-webgui/
-       """
-
-       @functools.wraps(original_func)
-       def immediate_func(*args, **kwargs):
-               with gtk_lock():
-                       return original_func(*args, **kwargs)
-
-       return immediate_func
-
-
-def autostart(func):
-       """
-       >>> @autostart
-       ... def grep_sink(pattern):
-       ...     print "Looking for %s" % pattern
-       ...     while True:
-       ...             line = yield
-       ...             if pattern in line:
-       ...                     print line,
-       >>> g = grep_sink("python")
-       Looking for python
-       >>> g.send("Yeah but no but yeah but no")
-       >>> g.send("A series of tubes")
-       >>> g.send("python generators rock!")
-       python generators rock!
-       >>> g.close()
-       """
-
-       @functools.wraps(func)
-       def start(*args, **kwargs):
-               cr = func(*args, **kwargs)
-               cr.next()
-               return cr
-
-       return start
-
-
-@autostart
-def printer_sink(format = "%s"):
-       """
-       >>> pr = printer_sink("%r")
-       >>> pr.send("Hello")
-       'Hello'
-       >>> pr.send("5")
-       '5'
-       >>> pr.send(5)
-       5
-       >>> p = printer_sink()
-       >>> p.send("Hello")
-       Hello
-       >>> p.send("World")
-       World
-       >>> # p.throw(RuntimeError, "Goodbye")
-       >>> # p.send("Meh")
-       >>> # p.close()
-       """
-       while True:
-               item = yield
-               print format % (item, )
-
-
-@autostart
-def null_sink():
-       """
-       Good for uses like with cochain to pick up any slack
-       """
-       while True:
-               item = yield
-
-
-@autostart
-def comap(function, target):
-       """
-       >>> p = printer_sink()
-       >>> cm = comap(lambda x: x+1, p)
-       >>> cm.send((0, ))
-       1
-       >>> cm.send((1.0, ))
-       2.0
-       >>> cm.send((-2, ))
-       -1
-       """
-       while True:
-               try:
-                       item = yield
-                       mappedItem = function(*item)
-                       target.send(mappedItem)
-               except Exception, e:
-                       _moduleLogger.exception("Forwarding exception!")
-                       target.throw(e.__class__, str(e))
-
-
-def _flush_queue(queue):
-       while not queue.empty():
-               yield queue.get()
-
-
-@autostart
-def queue_sink(queue):
-       """
-       >>> q = Queue.Queue()
-       >>> qs = queue_sink(q)
-       >>> qs.send("Hello")
-       >>> qs.send("World")
-       >>> qs.throw(RuntimeError, "Goodbye")
-       >>> qs.send("Meh")
-       >>> qs.close()
-       >>> print [i for i in _flush_queue(q)]
-       [(None, 'Hello'), (None, 'World'), (<type 'exceptions.RuntimeError'>, 'Goodbye'), (None, 'Meh'), (<type 'exceptions.GeneratorExit'>, None)]
-       """
-       while True:
-               try:
-                       item = yield
-                       queue.put((None, item))
-               except Exception, e:
-                       queue.put((e.__class__, str(e)))
-               except GeneratorExit:
-                       queue.put((GeneratorExit, None))
-                       raise
-
-
-def decode_item(item, target):
-       if item[0] is None:
-               target.send(item[1])
-               return False
-       elif item[0] is GeneratorExit:
-               target.close()
-               return True
-       else:
-               target.throw(item[0], item[1])
-               return False
-
-
-def nonqueue_source(queue, target):
-       isDone = False
-       while not isDone:
-               item = queue.get()
-               isDone = decode_item(item, target)
-               while not queue.empty():
-                       queue.get_nowait()
-
-
-def threaded_stage(target, thread_factory = threading.Thread):
-       messages = Queue.Queue()
-
-       run_source = functools.partial(nonqueue_source, messages, target)
-       thread = thread_factory(target=run_source)
-       thread.setDaemon(True)
-       thread.start()
-
-       # Sink running in current thread
-       return queue_sink(messages)
-
-
-def log_exception(logger):
-
-       def log_exception_decorator(func):
-
-               @functools.wraps(func)
-               def wrapper(*args, **kwds):
-                       try:
-                               return func(*args, **kwds)
-                       except Exception:
-                               logger.exception(func.__name__)
-
-               return wrapper
-
-       return log_exception_decorator
-
-
-class LoginWindow(object):
-
-       def __init__(self, widgetTree):
-               """
-               @note Thread agnostic
-               """
-               self._dialog = widgetTree.get_widget("loginDialog")
-               self._parentWindow = widgetTree.get_widget("mainWindow")
-               self._serviceCombo = widgetTree.get_widget("serviceCombo")
-               self._usernameEntry = widgetTree.get_widget("usernameentry")
-               self._passwordEntry = widgetTree.get_widget("passwordentry")
-
-               self._serviceList = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
-               self._serviceCombo.set_model(self._serviceList)
-               cell = gtk.CellRendererText()
-               self._serviceCombo.pack_start(cell, True)
-               self._serviceCombo.add_attribute(cell, 'text', 1)
-               self._serviceCombo.set_active(0)
-
-               widgetTree.get_widget("loginbutton").connect("clicked", self._on_loginbutton_clicked)
-               widgetTree.get_widget("logins_close_button").connect("clicked", self._on_loginclose_clicked)
-
-       def request_credentials(self,
-               parentWindow = None,
-               defaultCredentials = ("", "")
-       ):
-               """
-               @note UI Thread
-               """
-               if parentWindow is None:
-                       parentWindow = self._parentWindow
-
-               self._serviceCombo.hide()
-               self._serviceList.clear()
-
-               self._usernameEntry.set_text(defaultCredentials[0])
-               self._passwordEntry.set_text(defaultCredentials[1])
-
-               try:
-                       self._dialog.set_transient_for(parentWindow)
-                       self._dialog.set_default_response(gtk.RESPONSE_OK)
-                       response = self._dialog.run()
-                       if response != gtk.RESPONSE_OK:
-                               raise RuntimeError("Login Cancelled")
-
-                       username = self._usernameEntry.get_text()
-                       password = self._passwordEntry.get_text()
-                       self._passwordEntry.set_text("")
-               finally:
-                       self._dialog.hide()
-
-               return username, password
-
-       def request_credentials_from(self,
-               services,
-               parentWindow = None,
-               defaultCredentials = ("", "")
-       ):
-               """
-               @note UI Thread
-               """
-               if parentWindow is None:
-                       parentWindow = self._parentWindow
-
-               self._serviceList.clear()
-               for serviceIdserviceName in services:
-                       self._serviceList.append(serviceIdserviceName)
-               self._serviceCombo.set_active(0)
-               self._serviceCombo.show()
-
-               self._usernameEntry.set_text(defaultCredentials[0])
-               self._passwordEntry.set_text(defaultCredentials[1])
-
-               try:
-                       self._dialog.set_transient_for(parentWindow)
-                       self._dialog.set_default_response(gtk.RESPONSE_OK)
-                       response = self._dialog.run()
-                       if response != gtk.RESPONSE_OK:
-                               raise RuntimeError("Login Cancelled")
-
-                       username = self._usernameEntry.get_text()
-                       password = self._passwordEntry.get_text()
-               finally:
-                       self._dialog.hide()
-
-               itr = self._serviceCombo.get_active_iter()
-               serviceId = int(self._serviceList.get_value(itr, 0))
-               self._serviceList.clear()
-               return serviceId, username, password
-
-       def _on_loginbutton_clicked(self, *args):
-               self._dialog.response(gtk.RESPONSE_OK)
-
-       def _on_loginclose_clicked(self, *args):
-               self._dialog.response(gtk.RESPONSE_CANCEL)
-
-
-def safecall(f, errorDisplay=None, default=None, exception=Exception):
-       '''
-       Returns modified f. When the modified f is called and throws an
-       exception, the default value is returned
-       '''
-       def _safecall(*args, **argv):
-               try:
-                       return f(*args,**argv)
-               except exception, e:
-                       if errorDisplay is not None:
-                               errorDisplay.push_exception(e)
-                       return default
-       return _safecall
-
-
-class ErrorDisplay(object):
-
-       def __init__(self, widgetTree):
-               super(ErrorDisplay, self).__init__()
-               self.__errorBox = widgetTree.get_widget("errorEventBox")
-               self.__errorDescription = widgetTree.get_widget("errorDescription")
-               self.__errorClose = widgetTree.get_widget("errorClose")
-               self.__parentBox = self.__errorBox.get_parent()
-
-               self.__errorBox.connect("button_release_event", self._on_close)
-
-               self.__messages = []
-               self.__parentBox.remove(self.__errorBox)
-
-       def push_message_with_lock(self, message):
-               with gtk_lock():
-                       self.push_message(message)
-
-       def push_message(self, message):
-               self.__messages.append(message)
-               if 1 == len(self.__messages):
-                       self.__show_message(message)
-
-       def push_exception_with_lock(self):
-               with gtk_lock():
-                       self.push_exception()
-
-       def push_exception(self):
-               userMessage = str(sys.exc_info()[1])
-               self.push_message(userMessage)
-               _moduleLogger.exception(userMessage)
-
-       def pop_message(self):
-               del self.__messages[0]
-               if 0 == len(self.__messages):
-                       self.__hide_message()
-               else:
-                       self.__errorDescription.set_text(self.__messages[0])
-
-       def _on_close(self, *args):
-               self.pop_message()
-
-       def __show_message(self, message):
-               self.__errorDescription.set_text(message)
-               self.__parentBox.pack_start(self.__errorBox, False, False)
-               self.__parentBox.reorder_child(self.__errorBox, 1)
-
-       def __hide_message(self):
-               self.__errorDescription.set_text("")
-               self.__parentBox.remove(self.__errorBox)
-
-
-class DummyErrorDisplay(object):
-
-       def __init__(self):
-               super(DummyErrorDisplay, self).__init__()
-
-               self.__messages = []
-
-       def push_message_with_lock(self, message):
-               self.push_message(message)
-
-       def push_message(self, message):
-               if 0 < len(self.__messages):
-                       self.__messages.append(message)
-               else:
-                       self.__show_message(message)
-
-       def push_exception(self, exception = None):
-               userMessage = str(sys.exc_value)
-               _moduleLogger.exception(userMessage)
-
-       def pop_message(self):
-               if 0 < len(self.__messages):
-                       self.__show_message(self.__messages[0])
-                       del self.__messages[0]
-
-       def __show_message(self, message):
-               _moduleLogger.debug(message)
-
-
-class MessageBox(gtk.MessageDialog):
-
-       def __init__(self, message):
-               parent = None
-               gtk.MessageDialog.__init__(
-                       self,
-                       parent,
-                       gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
-                       gtk.MESSAGE_ERROR,
-                       gtk.BUTTONS_OK,
-                       message,
-               )
-               self.set_default_response(gtk.RESPONSE_OK)
-               self.connect('response', self._handle_clicked)
-
-       def _handle_clicked(self, *args):
-               self.destroy()
-
-
-class MessageBox2(gtk.MessageDialog):
-
-       def __init__(self, message):
-               parent = None
-               gtk.MessageDialog.__init__(
-                       self,
-                       parent,
-                       gtk.DIALOG_DESTROY_WITH_PARENT,
-                       gtk.MESSAGE_ERROR,
-                       gtk.BUTTONS_OK,
-                       message,
-               )
-               self.set_default_response(gtk.RESPONSE_OK)
-               self.connect('response', self._handle_clicked)
-
-       def _handle_clicked(self, *args):
-               self.destroy()
-
-
-class PopupCalendar(object):
-
-       def __init__(self, parent, displayDate, title = ""):
-               self._displayDate = displayDate
-
-               self._calendar = gtk.Calendar()
-               self._calendar.select_month(self._displayDate.month, self._displayDate.year)
-               self._calendar.select_day(self._displayDate.day)
-               self._calendar.set_display_options(
-                       gtk.CALENDAR_SHOW_HEADING |
-                       gtk.CALENDAR_SHOW_DAY_NAMES |
-                       gtk.CALENDAR_NO_MONTH_CHANGE |
-                       0
-               )
-               self._calendar.connect("day-selected", self._on_day_selected)
-
-               self._popupWindow = gtk.Window()
-               self._popupWindow.set_title(title)
-               self._popupWindow.add(self._calendar)
-               self._popupWindow.set_transient_for(parent)
-               self._popupWindow.set_modal(True)
-               self._popupWindow.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
-               self._popupWindow.set_skip_pager_hint(True)
-               self._popupWindow.set_skip_taskbar_hint(True)
-
-       def run(self):
-               self._popupWindow.show_all()
-
-       def _on_day_selected(self, *args):
-               try:
-                       self._calendar.select_month(self._displayDate.month, self._displayDate.year)
-                       self._calendar.select_day(self._displayDate.day)
-               except Exception, e:
-                       _moduleLogger.exception(e)
-
-
-if __name__ == "__main__":
-       if False:
-               import datetime
-               cal = PopupCalendar(None, datetime.datetime.now())
-               cal._popupWindow.connect("destroy", lambda w: gtk.main_quit())
-               cal.run()
-
-       gtk.main()
diff --git a/src/opt/Nqa-Audiobook-player/hildonize.py b/src/opt/Nqa-Audiobook-player/hildonize.py
deleted file mode 100644 (file)
index 48ca31a..0000000
+++ /dev/null
@@ -1,744 +0,0 @@
-#!/usr/bin/env python
-
-"""
-Open Issues
-       @bug not all of a message is shown
-       @bug Buttons are too small
-"""
-
-
-import gobject
-import gtk
-import dbus
-
-
-class _NullHildonModule(object):
-       pass
-
-
-try:
-       import hildon as _hildon
-       hildon  = _hildon # Dumb but gets around pyflakiness
-except (ImportError, OSError):
-       hildon = _NullHildonModule
-
-
-IS_HILDON_SUPPORTED = hildon is not _NullHildonModule
-
-
-class _NullHildonProgram(object):
-
-       def add_window(self, window):
-               pass
-
-
-def _hildon_get_app_class():
-       return hildon.Program
-
-
-def _null_get_app_class():
-       return _NullHildonProgram
-
-
-try:
-       hildon.Program
-       get_app_class = _hildon_get_app_class
-except AttributeError:
-       get_app_class = _null_get_app_class
-
-
-def _hildon_set_application_name(name):
-       gtk.set_application_name(name)
-
-
-def _null_set_application_name(name):
-       pass
-
-
-try:
-       gtk.set_application_name
-       set_application_name = _hildon_set_application_name
-except AttributeError:
-       set_application_name = _null_set_application_name
-
-
-def _fremantle_hildonize_window(app, window):
-       oldWindow = window
-       newWindow = hildon.StackableWindow()
-       if oldWindow.get_child() is not None:
-               oldWindow.get_child().reparent(newWindow)
-       app.add_window(newWindow)
-       return newWindow
-
-
-def _hildon_hildonize_window(app, window):
-       oldWindow = window
-       newWindow = hildon.Window()
-       if oldWindow.get_child() is not None:
-               oldWindow.get_child().reparent(newWindow)
-       app.add_window(newWindow)
-       return newWindow
-
-
-def _null_hildonize_window(app, window):
-       return window
-
-
-try:
-       hildon.StackableWindow
-       hildonize_window = _fremantle_hildonize_window
-except AttributeError:
-       try:
-               hildon.Window
-               hildonize_window = _hildon_hildonize_window
-       except AttributeError:
-               hildonize_window = _null_hildonize_window
-
-
-def _fremantle_hildonize_menu(window, gtkMenu):
-       appMenu = hildon.AppMenu()
-       window.set_app_menu(appMenu)
-       gtkMenu.get_parent().remove(gtkMenu)
-       return appMenu
-
-
-def _hildon_hildonize_menu(window, gtkMenu):
-       hildonMenu = gtk.Menu()
-       for child in gtkMenu.get_children():
-               child.reparent(hildonMenu)
-       window.set_menu(hildonMenu)
-       gtkMenu.destroy()
-       return hildonMenu
-
-
-def _null_hildonize_menu(window, gtkMenu):
-       return gtkMenu
-
-
-try:
-       hildon.AppMenu
-       GTK_MENU_USED = False
-       IS_FREMANTLE_SUPPORTED = True
-       hildonize_menu = _fremantle_hildonize_menu
-except AttributeError:
-       GTK_MENU_USED = True
-       IS_FREMANTLE_SUPPORTED = False
-       if IS_HILDON_SUPPORTED:
-               hildonize_menu = _hildon_hildonize_menu
-       else:
-               hildonize_menu = _null_hildonize_menu
-
-
-def _hildon_set_button_auto_selectable(button):
-       button.set_theme_size(hildon.HILDON_SIZE_AUTO_HEIGHT)
-
-
-def _null_set_button_auto_selectable(button):
-       pass
-
-
-try:
-       hildon.HILDON_SIZE_AUTO_HEIGHT
-       gtk.Button.set_theme_size
-       set_button_auto_selectable = _hildon_set_button_auto_selectable
-except AttributeError:
-       set_button_auto_selectable = _null_set_button_auto_selectable
-
-
-def _hildon_set_button_finger_selectable(button):
-       button.set_theme_size(hildon.HILDON_SIZE_FINGER_HEIGHT)
-
-
-def _null_set_button_finger_selectable(button):
-       pass
-
-
-try:
-       hildon.HILDON_SIZE_FINGER_HEIGHT
-       gtk.Button.set_theme_size
-       set_button_finger_selectable = _hildon_set_button_finger_selectable
-except AttributeError:
-       set_button_finger_selectable = _null_set_button_finger_selectable
-
-
-def _hildon_set_button_thumb_selectable(button):
-       button.set_theme_size(hildon.HILDON_SIZE_THUMB_HEIGHT)
-
-
-def _null_set_button_thumb_selectable(button):
-       pass
-
-
-try:
-       hildon.HILDON_SIZE_THUMB_HEIGHT
-       gtk.Button.set_theme_size
-       set_button_thumb_selectable = _hildon_set_button_thumb_selectable
-except AttributeError:
-       set_button_thumb_selectable = _null_set_button_thumb_selectable
-
-
-def _hildon_set_cell_thumb_selectable(renderer):
-       renderer.set_property("scale", 1.5)
-
-
-def _null_set_cell_thumb_selectable(renderer):
-       pass
-
-
-if IS_HILDON_SUPPORTED:
-       set_cell_thumb_selectable = _hildon_set_cell_thumb_selectable
-else:
-       set_cell_thumb_selectable = _null_set_cell_thumb_selectable
-
-
-def _hildon_set_pix_cell_thumb_selectable(renderer):
-       renderer.set_property("stock-size", 48)
-
-
-def _null_set_pix_cell_thumb_selectable(renderer):
-       pass
-
-
-if IS_HILDON_SUPPORTED:
-       set_pix_cell_thumb_selectable = _hildon_set_pix_cell_thumb_selectable
-else:
-       set_pix_cell_thumb_selectable = _null_set_pix_cell_thumb_selectable
-
-
-def _fremantle_show_information_banner(parent, message):
-       hildon.hildon_banner_show_information(parent, "", message)
-
-
-def _hildon_show_information_banner(parent, message):
-       hildon.hildon_banner_show_information(parent, None, message)
-
-
-def _null_show_information_banner(parent, message):
-       pass
-
-
-if IS_FREMANTLE_SUPPORTED:
-       show_information_banner = _fremantle_show_information_banner
-else:
-       try:
-               hildon.hildon_banner_show_information
-               show_information_banner = _hildon_show_information_banner
-       except AttributeError:
-               show_information_banner = _null_show_information_banner
-
-
-def _fremantle_show_busy_banner_start(parent, message):
-       hildon.hildon_gtk_window_set_progress_indicator(parent, True)
-       return parent
-
-
-def _fremantle_show_busy_banner_end(banner):
-       hildon.hildon_gtk_window_set_progress_indicator(banner, False)
-
-
-def _hildon_show_busy_banner_start(parent, message):
-       return hildon.hildon_banner_show_animation(parent, None, message)
-
-
-def _hildon_show_busy_banner_end(banner):
-       banner.destroy()
-
-
-def _null_show_busy_banner_start(parent, message):
-       return None
-
-
-def _null_show_busy_banner_end(banner):
-       assert banner is None
-
-
-try:
-       hildon.hildon_gtk_window_set_progress_indicator
-       show_busy_banner_start = _fremantle_show_busy_banner_start
-       show_busy_banner_end = _fremantle_show_busy_banner_end
-except AttributeError:
-       try:
-               hildon.hildon_banner_show_animation
-               show_busy_banner_start = _hildon_show_busy_banner_start
-               show_busy_banner_end = _hildon_show_busy_banner_end
-       except AttributeError:
-               show_busy_banner_start = _null_show_busy_banner_start
-               show_busy_banner_end = _null_show_busy_banner_end
-
-
-def _hildon_hildonize_text_entry(textEntry):
-       textEntry.set_property('hildon-input-mode', 7)
-
-
-def _null_hildonize_text_entry(textEntry):
-       pass
-
-
-if IS_HILDON_SUPPORTED:
-       hildonize_text_entry = _hildon_hildonize_text_entry
-else:
-       hildonize_text_entry = _null_hildonize_text_entry
-
-
-def _hildon_window_to_portrait(window):
-       # gtk documentation is unclear whether this does a "=" or a "|="
-       flags = hildon.PORTRAIT_MODE_SUPPORT | hildon.PORTRAIT_MODE_REQUEST
-       hildon.hildon_gtk_window_set_portrait_flags(window, flags)
-
-
-def _hildon_window_to_landscape(window):
-       # gtk documentation is unclear whether this does a "=" or a "&= ~"
-       flags = hildon.PORTRAIT_MODE_SUPPORT
-       hildon.hildon_gtk_window_set_portrait_flags(window, flags)
-
-
-def _null_window_to_portrait(window):
-       pass
-
-
-def _null_window_to_landscape(window):
-       pass
-
-
-try:
-       hildon.PORTRAIT_MODE_SUPPORT
-       hildon.PORTRAIT_MODE_REQUEST
-       hildon.hildon_gtk_window_set_portrait_flags
-
-       window_to_portrait = _hildon_window_to_portrait
-       window_to_landscape = _hildon_window_to_landscape
-except AttributeError:
-       window_to_portrait = _null_window_to_portrait
-       window_to_landscape = _null_window_to_landscape
-
-
-def get_device_orientation():
-       bus = dbus.SystemBus()
-       try:
-               rawMceRequest = bus.get_object("com.nokia.mce", "/com/nokia/mce/request")
-               mceRequest = dbus.Interface(rawMceRequest, dbus_interface="com.nokia.mce.request")
-               orientation, standState, faceState, xAxis, yAxis, zAxis = mceRequest.get_device_orientation()
-       except dbus.exception.DBusException:
-               # catching for documentation purposes that when a system doesn't
-               # support this, this is what to expect
-               raise
-
-       if orientation == "":
-               return gtk.ORIENTATION_HORIZONTAL
-       elif orientation == "":
-               return gtk.ORIENTATION_VERTICAL
-       else:
-               raise RuntimeError("Unknown orientation: %s" % orientation)
-
-
-def _hildon_hildonize_password_entry(textEntry):
-       textEntry.set_property('hildon-input-mode', 7 | (1 << 29))
-
-
-def _null_hildonize_password_entry(textEntry):
-       pass
-
-
-if IS_HILDON_SUPPORTED:
-       hildonize_password_entry = _hildon_hildonize_password_entry
-else:
-       hildonize_password_entry = _null_hildonize_password_entry
-
-
-def _hildon_hildonize_combo_entry(comboEntry):
-       comboEntry.set_property('hildon-input-mode', 1 << 4)
-
-
-def _null_hildonize_combo_entry(textEntry):
-       pass
-
-
-if IS_HILDON_SUPPORTED:
-       hildonize_combo_entry = _hildon_hildonize_combo_entry
-else:
-       hildonize_combo_entry = _null_hildonize_combo_entry
-
-
-def _fremantle_hildonize_scrollwindow(scrolledWindow):
-       pannableWindow = hildon.PannableArea()
-
-       child = scrolledWindow.get_child()
-       scrolledWindow.remove(child)
-       pannableWindow.add(child)
-
-       parent = scrolledWindow.get_parent()
-       if parent is not None:
-               parent.remove(scrolledWindow)
-               parent.add(pannableWindow)
-
-       return pannableWindow
-
-
-def _hildon_hildonize_scrollwindow(scrolledWindow):
-       hildon.hildon_helper_set_thumb_scrollbar(scrolledWindow, True)
-       return scrolledWindow
-
-
-def _null_hildonize_scrollwindow(scrolledWindow):
-       return scrolledWindow
-
-
-try:
-       hildon.PannableArea
-       hildonize_scrollwindow = _fremantle_hildonize_scrollwindow
-       hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
-except AttributeError:
-       try:
-               hildon.hildon_helper_set_thumb_scrollbar
-               hildonize_scrollwindow = _hildon_hildonize_scrollwindow
-               hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
-       except AttributeError:
-               hildonize_scrollwindow = _null_hildonize_scrollwindow
-               hildonize_scrollwindow_with_viewport = _null_hildonize_scrollwindow
-
-
-def _hildon_request_number(parent, title, range, default):
-       spinner = hildon.NumberEditor(*range)
-       spinner.set_value(default)
-
-       dialog = gtk.Dialog(
-               title,
-               parent,
-               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
-               (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
-       )
-       dialog.set_default_response(gtk.RESPONSE_CANCEL)
-       dialog.get_child().add(spinner)
-
-       try:
-               dialog.show_all()
-               response = dialog.run()
-
-               if response == gtk.RESPONSE_OK:
-                       return spinner.get_value()
-               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
-                       raise RuntimeError("User cancelled request")
-               else:
-                       raise RuntimeError("Unrecognized response %r", response)
-       finally:
-               dialog.hide()
-               dialog.destroy()
-
-
-def _null_request_number(parent, title, range, default):
-       adjustment = gtk.Adjustment(default, range[0], range[1], 1, 5, 0)
-       spinner = gtk.SpinButton(adjustment, 0, 0)
-       spinner.set_wrap(False)
-
-       dialog = gtk.Dialog(
-               title,
-               parent,
-               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
-               (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
-       )
-       dialog.set_default_response(gtk.RESPONSE_CANCEL)
-       dialog.get_child().add(spinner)
-
-       try:
-               dialog.show_all()
-               response = dialog.run()
-
-               if response == gtk.RESPONSE_OK:
-                       return spinner.get_value_as_int()
-               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
-                       raise RuntimeError("User cancelled request")
-               else:
-                       raise RuntimeError("Unrecognized response %r", response)
-       finally:
-               dialog.hide()
-               dialog.destroy()
-
-
-try:
-       hildon.NumberEditor # TODO deprecated in fremantle
-       request_number = _hildon_request_number
-except AttributeError:
-       request_number = _null_request_number
-
-
-def _hildon_touch_selector(parent, title, items, defaultIndex):
-       model = gtk.ListStore(gobject.TYPE_STRING)
-       for item in items:
-               model.append((item, ))
-
-       selector = hildon.TouchSelector()
-       selector.append_text_column(model, True)
-       selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
-       selector.set_active(0, defaultIndex)
-
-       dialog = hildon.PickerDialog(parent)
-       dialog.set_selector(selector)
-
-       try:
-               dialog.show_all()
-               response = dialog.run()
-
-               if response == gtk.RESPONSE_OK:
-                       return selector.get_active(0)
-               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
-                       raise RuntimeError("User cancelled request")
-               else:
-                       raise RuntimeError("Unrecognized response %r", response)
-       finally:
-               dialog.hide()
-               dialog.destroy()
-
-
-def _on_null_touch_selector_activated(treeView, path, column, dialog, pathData):
-       dialog.response(gtk.RESPONSE_OK)
-       pathData[0] = path
-
-
-def _null_touch_selector(parent, title, items, defaultIndex = -1):
-       parentSize = parent.get_size()
-
-       model = gtk.ListStore(gobject.TYPE_STRING)
-       for item in items:
-               model.append((item, ))
-
-       cell = gtk.CellRendererText()
-       set_cell_thumb_selectable(cell)
-       column = gtk.TreeViewColumn(title)
-       column.pack_start(cell, expand=True)
-       column.add_attribute(cell, "text", 0)
-
-       treeView = gtk.TreeView()
-       treeView.set_model(model)
-       treeView.append_column(column)
-       selection = treeView.get_selection()
-       selection.set_mode(gtk.SELECTION_SINGLE)
-       if 0 < defaultIndex:
-               selection.select_path((defaultIndex, ))
-
-       scrolledWin = gtk.ScrolledWindow()
-       scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-       scrolledWin.add(treeView)
-
-       dialog = gtk.Dialog(
-               title,
-               parent,
-               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
-               (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
-       )
-       dialog.set_default_response(gtk.RESPONSE_CANCEL)
-       dialog.get_child().add(scrolledWin)
-       dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
-
-       scrolledWin = hildonize_scrollwindow(scrolledWin)
-       pathData = [None]
-       treeView.connect("row-activated", _on_null_touch_selector_activated, dialog, pathData)
-
-       try:
-               dialog.show_all()
-               response = dialog.run()
-
-               if response == gtk.RESPONSE_OK:
-                       if pathData[0] is None:
-                               raise RuntimeError("No selection made")
-                       return pathData[0][0]
-               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
-                       raise RuntimeError("User cancelled request")
-               else:
-                       raise RuntimeError("Unrecognized response %r", response)
-       finally:
-               dialog.hide()
-               dialog.destroy()
-
-
-try:
-       hildon.PickerDialog
-       hildon.TouchSelector
-       touch_selector = _hildon_touch_selector
-except AttributeError:
-       touch_selector = _null_touch_selector
-
-
-def _hildon_touch_selector_entry(parent, title, items, defaultItem):
-       # Got a segfault when using append_text_column with TouchSelectorEntry, so using this way
-       try:
-               selector = hildon.TouchSelectorEntry(text=True)
-       except TypeError:
-               selector = hildon.hildon_touch_selector_entry_new_text()
-       defaultIndex = -1
-       for i, item in enumerate(items):
-               selector.append_text(item)
-               if item == defaultItem:
-                       defaultIndex = i
-
-       dialog = hildon.PickerDialog(parent)
-       dialog.set_selector(selector)
-
-       if 0 < defaultIndex:
-               selector.set_active(0, defaultIndex)
-       else:
-               selector.get_entry().set_text(defaultItem)
-
-       try:
-               dialog.show_all()
-               response = dialog.run()
-       finally:
-               dialog.hide()
-
-       if response == gtk.RESPONSE_OK:
-               return selector.get_entry().get_text()
-       elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
-               raise RuntimeError("User cancelled request")
-       else:
-               raise RuntimeError("Unrecognized response %r", response)
-
-
-def _on_null_touch_selector_entry_entry_changed(entry, result, selection, defaultIndex):
-       custom = entry.get_text().strip()
-       if custom:
-               result[0] = custom
-               selection.unselect_all()
-       else:
-               result[0] = None
-               selection.select_path((defaultIndex, ))
-
-
-def _on_null_touch_selector_entry_entry_activated(customEntry, dialog, result):
-       dialog.response(gtk.RESPONSE_OK)
-       result[0] = customEntry.get_text()
-
-
-def _on_null_touch_selector_entry_tree_activated(treeView, path, column, dialog, result):
-       dialog.response(gtk.RESPONSE_OK)
-       model = treeView.get_model()
-       itr = model.get_iter(path)
-       if itr is not None:
-               result[0] = model.get_value(itr, 0)
-
-
-def _null_touch_selector_entry(parent, title, items, defaultItem):
-       parentSize = parent.get_size()
-
-       model = gtk.ListStore(gobject.TYPE_STRING)
-       defaultIndex = -1
-       for i, item in enumerate(items):
-               model.append((item, ))
-               if item == defaultItem:
-                       defaultIndex = i
-
-       cell = gtk.CellRendererText()
-       set_cell_thumb_selectable(cell)
-       column = gtk.TreeViewColumn(title)
-       column.pack_start(cell, expand=True)
-       column.add_attribute(cell, "text", 0)
-
-       treeView = gtk.TreeView()
-       treeView.set_model(model)
-       treeView.append_column(column)
-       selection = treeView.get_selection()
-       selection.set_mode(gtk.SELECTION_SINGLE)
-
-       scrolledWin = gtk.ScrolledWindow()
-       scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-       scrolledWin.add(treeView)
-
-       customEntry = gtk.Entry()
-
-       layout = gtk.VBox()
-       layout.pack_start(customEntry, expand=False)
-       layout.pack_start(scrolledWin)
-
-       dialog = gtk.Dialog(
-               title,
-               parent,
-               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
-               (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
-       )
-       dialog.set_default_response(gtk.RESPONSE_CANCEL)
-       dialog.get_child().add(layout)
-       dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
-
-       scrolledWin = hildonize_scrollwindow(scrolledWin)
-
-       result = [None]
-       if 0 < defaultIndex:
-               selection.select_path((defaultIndex, ))
-               result[0] = defaultItem
-       else:
-               customEntry.set_text(defaultItem)
-
-       customEntry.connect("activate", _on_null_touch_selector_entry_entry_activated, dialog, result)
-       customEntry.connect("changed", _on_null_touch_selector_entry_entry_changed, result, selection, defaultIndex)
-       treeView.connect("row-activated", _on_null_touch_selector_entry_tree_activated, dialog, result)
-
-       try:
-               dialog.show_all()
-               response = dialog.run()
-
-               if response == gtk.RESPONSE_OK:
-                       _, itr = selection.get_selected()
-                       if itr is not None:
-                               return model.get_value(itr, 0)
-                       else:
-                               enteredText = customEntry.get_text().strip()
-                               if enteredText:
-                                       return enteredText
-                               elif result[0] is not None:
-                                       return result[0]
-                               else:
-                                       raise RuntimeError("No selection made")
-               elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
-                       raise RuntimeError("User cancelled request")
-               else:
-                       raise RuntimeError("Unrecognized response %r", response)
-       finally:
-               dialog.hide()
-               dialog.destroy()
-
-
-try:
-       hildon.PickerDialog
-       hildon.TouchSelectorEntry
-       touch_selector_entry = _hildon_touch_selector_entry
-except AttributeError:
-       touch_selector_entry = _null_touch_selector_entry
-
-
-if __name__ == "__main__":
-       app = get_app_class()()
-
-       label = gtk.Label("Hello World from a Label!")
-
-       win = gtk.Window()
-       win.add(label)
-       win = hildonize_window(app, win)
-       if False and IS_FREMANTLE_SUPPORTED:
-               appMenu = hildon.AppMenu()
-               for i in xrange(5):
-                       b = gtk.Button(str(i))
-                       appMenu.append(b)
-               win.set_app_menu(appMenu)
-               win.show_all()
-               appMenu.show_all()
-               gtk.main()
-       elif False:
-               print touch_selector(win, "Test", ["A", "B", "C", "D"], 2)
-       elif False:
-               print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "C")
-               print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "Blah")
-       elif False:
-               import pprint
-               name, value = "", ""
-               goodLocals = [
-                       (name, value) for (name, value) in locals().iteritems()
-                       if not name.startswith("_")
-               ]
-               pprint.pprint(goodLocals)
-       elif False:
-               import time
-               show_information_banner(win, "Hello World")
-               time.sleep(5)
-       elif False:
-               import time
-               banner = show_busy_banner_start(win, "Hello World")
-               time.sleep(5)
-               show_busy_banner_end(banner)
diff --git a/src/opt/Nqa-Audiobook-player/nqaap.py b/src/opt/Nqa-Audiobook-player/nqaap.py
deleted file mode 100755 (executable)
index ab32ba2..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env python
-
-import os
-import logging
-
-import constants
-import nqaap_gtk
-
-
-_moduleLogger = logging.getLogger(__name__)
-
-
-try:
-       os.makedirs(constants._data_path_)
-except OSError, e:
-       if e.errno != 17:
-               raise
-
-logging.basicConfig(level=logging.DEBUG, filename=constants._user_logpath_)
-_moduleLogger.info("%s %s-%s" % (constants.__pretty_app_name__, constants.__version__, constants.__build__))
-_moduleLogger.info("OS: %s" % (os.uname()[0], ))
-_moduleLogger.info("Kernel: %s (%s) for %s" % os.uname()[2:])
-_moduleLogger.info("Hostname: %s" % os.uname()[1])
-
-try:
-       nqaap_gtk.run()
-finally:
-       logging.shutdown()
diff --git a/src/opt/Nqa-Audiobook-player/nqaap_gtk.py b/src/opt/Nqa-Audiobook-player/nqaap_gtk.py
deleted file mode 100755 (executable)
index 90e812f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#! /usr/bin/env python  
-
-import logging
-
-import dbus
-import dbus.mainloop.glib
-import gobject
-import gtk
-
-import constants
-import hildonize
-from Player import Player
-from Gui import Gui
-
-
-_moduleLogger = logging.getLogger(__name__)
-
-
-def run():
-       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()
-
-       gtk.main()
-
-
-if __name__ == "__main__":
-       logging.basicConfig(level=logging.DEBUG)
-       run()
diff --git a/src/opt/Nqa-Audiobook-player/settings.py b/src/opt/Nqa-Audiobook-player/settings.py
deleted file mode 100644 (file)
index afb50a9..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-"""
-This file is part of Multilist.
-
-Multilist is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Multilist is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
-
-Copyright (C) 2008 Christoph Würstle
-"""
-
-import logging
-
-import gtk
-
-import hildonize
-import gtk_toolbox
-
-try:
-       _
-except NameError:
-       _ = lambda x: x
-
-
-_moduleLogger = logging.getLogger(__name__)
-
-
-class SettingsDialog(object):
-
-       def __init__(self, parent):
-               self.window = None
-
-               self.__isPortraitCheckbutton = gtk.CheckButton("Portrait Mode")
-
-               self.__rotationSection = gtk.VBox()
-               self.__rotationSection.pack_start(self.__isPortraitCheckbutton, False, True)
-
-               rotationFrame = gtk.Frame("Rotation")
-               rotationFrame.add(self.__rotationSection)
-
-               self.__audioBooksPath = gtk.Entry()
-               self.__audioBooksPathButton = gtk.Button("Choose")
-               self.__audioBooksPathButton.connect("clicked", self._on_path_choose)
-
-               self.__audiobookPathSection = gtk.HBox()
-               self.__audiobookPathSection.pack_start(self.__audioBooksPath, True, True)
-               self.__audiobookPathSection.pack_start(self.__audioBooksPathButton, False, True)
-
-               self.__audiobookSection = gtk.VBox()
-               self.__audiobookSection.pack_start(self.__audiobookPathSection)
-
-               audiobookFrame = gtk.Frame("Audiobooks")
-               audiobookFrame.add(self.__audiobookSection)
-
-               settingsBox = gtk.VBox()
-               settingsBox.pack_start(rotationFrame, False, True)
-               settingsBox.pack_start(audiobookFrame, False, True)
-               settingsView = gtk.Viewport()
-               settingsView.add(settingsBox)
-               settingsScrollView = gtk.ScrolledWindow()
-               settingsScrollView.add(settingsView)
-               settingsScrollView.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-               parent.pack_start(settingsScrollView, True, True)
-
-               settingsScrollView = hildonize.hildonize_scrollwindow(settingsScrollView)
-
-       def set_portrait_state(self, isPortrait):
-               self.__isPortraitCheckbutton.set_active(isPortrait)
-
-       def is_portrait(self):
-               return self.__isPortraitCheckbutton.get_active()
-
-       def set_audiobook_path(self, path):
-               self.__audioBooksPath.set_text(path)
-
-       def get_audiobook_path(self):
-               return self.__audioBooksPath.get_text()
-
-       @gtk_toolbox.log_exception(_moduleLogger)
-       def _on_path_choose(self, *args):
-               fileChooser = gtk.FileChooserDialog(
-                       title="Audiobooks",
-                       action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
-                       parent=self.window,
-               )
-               fileChooser.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
-               fileChooser.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
-               fileChooser.set_filename(self.__audioBooksPath.get_text())
-               userResponse = fileChooser.run()
-               fileChooser.hide()
-               if userResponse == gtk.RESPONSE_OK:
-                       filename = fileChooser.get_filename()
-                       self.__audioBooksPath.set_text(filename)
diff --git a/src/settings.py b/src/settings.py
new file mode 100644 (file)
index 0000000..afb50a9
--- /dev/null
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+This file is part of Multilist.
+
+Multilist is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Multilist is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
+
+Copyright (C) 2008 Christoph Würstle
+"""
+
+import logging
+
+import gtk
+
+import hildonize
+import gtk_toolbox
+
+try:
+       _
+except NameError:
+       _ = lambda x: x
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+class SettingsDialog(object):
+
+       def __init__(self, parent):
+               self.window = None
+
+               self.__isPortraitCheckbutton = gtk.CheckButton("Portrait Mode")
+
+               self.__rotationSection = gtk.VBox()
+               self.__rotationSection.pack_start(self.__isPortraitCheckbutton, False, True)
+
+               rotationFrame = gtk.Frame("Rotation")
+               rotationFrame.add(self.__rotationSection)
+
+               self.__audioBooksPath = gtk.Entry()
+               self.__audioBooksPathButton = gtk.Button("Choose")
+               self.__audioBooksPathButton.connect("clicked", self._on_path_choose)
+
+               self.__audiobookPathSection = gtk.HBox()
+               self.__audiobookPathSection.pack_start(self.__audioBooksPath, True, True)
+               self.__audiobookPathSection.pack_start(self.__audioBooksPathButton, False, True)
+
+               self.__audiobookSection = gtk.VBox()
+               self.__audiobookSection.pack_start(self.__audiobookPathSection)
+
+               audiobookFrame = gtk.Frame("Audiobooks")
+               audiobookFrame.add(self.__audiobookSection)
+
+               settingsBox = gtk.VBox()
+               settingsBox.pack_start(rotationFrame, False, True)
+               settingsBox.pack_start(audiobookFrame, False, True)
+               settingsView = gtk.Viewport()
+               settingsView.add(settingsBox)
+               settingsScrollView = gtk.ScrolledWindow()
+               settingsScrollView.add(settingsView)
+               settingsScrollView.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+               parent.pack_start(settingsScrollView, True, True)
+
+               settingsScrollView = hildonize.hildonize_scrollwindow(settingsScrollView)
+
+       def set_portrait_state(self, isPortrait):
+               self.__isPortraitCheckbutton.set_active(isPortrait)
+
+       def is_portrait(self):
+               return self.__isPortraitCheckbutton.get_active()
+
+       def set_audiobook_path(self, path):
+               self.__audioBooksPath.set_text(path)
+
+       def get_audiobook_path(self):
+               return self.__audioBooksPath.get_text()
+
+       @gtk_toolbox.log_exception(_moduleLogger)
+       def _on_path_choose(self, *args):
+               fileChooser = gtk.FileChooserDialog(
+                       title="Audiobooks",
+                       action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
+                       parent=self.window,
+               )
+               fileChooser.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
+               fileChooser.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
+               fileChooser.set_filename(self.__audioBooksPath.get_text())
+               userResponse = fileChooser.run()
+               fileChooser.hide()
+               if userResponse == gtk.RESPONSE_OK:
+                       filename = fileChooser.get_filename()
+                       self.__audioBooksPath.set_text(filename)
diff --git a/src/usr/share/applications/hildon/nqaap.desktop b/src/usr/share/applications/hildon/nqaap.desktop
deleted file mode 100644 (file)
index db906b7..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[Desktop Entry]
-Version=1.0.0
-Encoding=UTF-8
-Name=nQaap
-Exec=/usr/bin/run-standalone.sh python /opt/Nqa-Audiobook-player/nqaap.py
-Icon=nqaap
-X-Icon-path=/usr/share/icons
-X-Window-Icon=nqaap
-Type=Application
-X-Osso-Type=application/x-executable
diff --git a/src/usr/share/icons/hicolor/26x26/hildon/nqaap.png b/src/usr/share/icons/hicolor/26x26/hildon/nqaap.png
deleted file mode 100644 (file)
index a804ecf..0000000
Binary files a/src/usr/share/icons/hicolor/26x26/hildon/nqaap.png and /dev/null differ
diff --git a/src/usr/share/icons/hicolor/48x48/hildon/nqaap.png b/src/usr/share/icons/hicolor/48x48/hildon/nqaap.png
deleted file mode 100644 (file)
index eeedbaf..0000000
Binary files a/src/usr/share/icons/hicolor/48x48/hildon/nqaap.png and /dev/null differ
diff --git a/src/usr/share/icons/hicolor/64x64/hildon/nqaap.png b/src/usr/share/icons/hicolor/64x64/hildon/nqaap.png
deleted file mode 100644 (file)
index fb75ea2..0000000
Binary files a/src/usr/share/icons/hicolor/64x64/hildon/nqaap.png and /dev/null differ
diff --git a/src/usr/share/icons/hicolor/scalable/hildon/nqaap.png b/src/usr/share/icons/hicolor/scalable/hildon/nqaap.png
deleted file mode 100644 (file)
index c497199..0000000
Binary files a/src/usr/share/icons/hicolor/scalable/hildon/nqaap.png and /dev/null differ
diff --git a/support/icons/hicolor/26x26/hildon/nqaap.png b/support/icons/hicolor/26x26/hildon/nqaap.png
new file mode 100644 (file)
index 0000000..a804ecf
Binary files /dev/null and b/support/icons/hicolor/26x26/hildon/nqaap.png differ
diff --git a/support/icons/hicolor/48x48/hildon/nqaap.png b/support/icons/hicolor/48x48/hildon/nqaap.png
new file mode 100644 (file)
index 0000000..eeedbaf
Binary files /dev/null and b/support/icons/hicolor/48x48/hildon/nqaap.png differ
diff --git a/support/icons/hicolor/64x64/hildon/nqaap.png b/support/icons/hicolor/64x64/hildon/nqaap.png
new file mode 100644 (file)
index 0000000..fb75ea2
Binary files /dev/null and b/support/icons/hicolor/64x64/hildon/nqaap.png differ
diff --git a/support/icons/hicolor/scalable/hildon/nqaap.png b/support/icons/hicolor/scalable/hildon/nqaap.png
new file mode 100644 (file)
index 0000000..c497199
Binary files /dev/null and b/support/icons/hicolor/scalable/hildon/nqaap.png differ
diff --git a/support/nqaap.desktop b/support/nqaap.desktop
new file mode 100644 (file)
index 0000000..db906b7
--- /dev/null
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Version=1.0.0
+Encoding=UTF-8
+Name=nQaap
+Exec=/usr/bin/run-standalone.sh python /opt/Nqa-Audiobook-player/nqaap.py
+Icon=nqaap
+X-Icon-path=/usr/share/icons
+X-Window-Icon=nqaap
+Type=Application
+X-Osso-Type=application/x-executable