From: Ed Page Date: Fri, 25 Sep 2009 18:06:34 +0000 (-0500) Subject: Removing a lot of code that shouldn't be needed for telepathy X-Git-Url: http://git.maemo.org/git/?p=theonering;a=commitdiff_plain;h=7fc888508c2bd6a34e9cb0627142c95e321c3f9c;hp=869f01f31ca4fb49bac4c506953604dc65f04925 Removing a lot of code that shouldn't be needed for telepathy --- diff --git a/src/alarm_handler.py b/src/alarm_handler.py deleted file mode 100644 index d3a9bb9..0000000 --- a/src/alarm_handler.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env python - -import os -import time -import datetime -import ConfigParser - -import dbus -import osso.alarmd as alarmd - - -class AlarmHandler(object): - - _INVALID_COOKIE = -1 - _TITLE = "Dialcentral Notifications" - _LAUNCHER = os.path.abspath(os.path.join(os.path.dirname(__file__), "alarm_notify.py")) - _REPEAT_FOREVER = -1 - _DEFAULT_FLAGS = ( - alarmd.ALARM_EVENT_NO_DIALOG | - alarmd.ALARM_EVENT_NO_SNOOZE | - alarmd.ALARM_EVENT_CONNECTED - ) - - def __init__(self): - self._recurrence = 5 - - bus = dbus.SystemBus() - self._alarmdDBus = bus.get_object("com.nokia.alarmd", "/com/nokia/alarmd"); - self._alarmCookie = self._INVALID_COOKIE - self._launcher = self._LAUNCHER - - def load_settings(self, config, sectionName): - try: - self._recurrence = config.getint(sectionName, "recurrence") - self._alarmCookie = config.getint(sectionName, "alarmCookie") - launcher = config.get(sectionName, "notifier") - if launcher: - self._launcher = launcher - except ConfigParser.NoOptionError: - pass - - def save_settings(self, config, sectionName): - config.set(sectionName, "recurrence", str(self._recurrence)) - config.set(sectionName, "alarmCookie", str(self._alarmCookie)) - launcher = self._launcher if self._launcher != self._LAUNCHER else "" - config.set(sectionName, "notifier", launcher) - - def apply_settings(self, enabled, recurrence): - if recurrence != self._recurrence or enabled != self.isEnabled: - if self.isEnabled: - self._clear_alarm() - if enabled: - self._set_alarm(recurrence) - self._recurrence = int(recurrence) - - @property - def recurrence(self): - return self._recurrence - - @property - def isEnabled(self): - return self._alarmCookie != self._INVALID_COOKIE - - def _get_start_time(self, recurrence): - now = datetime.datetime.now() - startTimeMinute = now.minute + max(recurrence, 5) # being safe - startTimeHour = now.hour + int(startTimeMinute / 60) - startTimeMinute = startTimeMinute % 59 - now.replace(minute=startTimeMinute) - timestamp = int(time.mktime(now.timetuple())) - return timestamp - - def _set_alarm(self, recurrence): - assert 1 <= recurrence, "Notifications set to occur too frequently: %d" % recurrence - alarmTime = self._get_start_time(recurrence) - - #Setup the alarm arguments so that they can be passed to the D-Bus add_event method - action = [] - action.extend(['flags', self._DEFAULT_FLAGS]) - action.extend(['title', self._TITLE]) - action.extend(['path', self._launcher]) - action.extend([ - 'arguments', - dbus.Array( - [alarmTime, int(27)], - signature=dbus.Signature('v') - ) - ]) #int(27) used in place of alarm_index - - event = [] - event.extend([dbus.ObjectPath('/AlarmdEventRecurring'), dbus.UInt32(4)]) - event.extend(['action', dbus.ObjectPath('/AlarmdActionExec')]) #use AlarmdActionExec instead of AlarmdActionDbus - event.append(dbus.UInt32(len(action) / 2)) - event.extend(action) - event.extend(['time', dbus.Int64(alarmTime)]) - event.extend(['recurr_interval', dbus.UInt32(recurrence)]) - event.extend(['recurr_count', dbus.Int32(self._REPEAT_FOREVER)]) - - self._alarmCookie = self._alarmdDBus.add_event(*event); - - def _clear_alarm(self): - if self._alarmCookie == self._INVALID_COOKIE: - return - deleteResult = self._alarmdDBus.del_event(dbus.Int32(self._alarmCookie)) - self._alarmCookie = self._INVALID_COOKIE - assert deleteResult != -1, "Deleting of alarm event failed" - - -def main(): - import ConfigParser - import constants - try: - import optparse - except ImportError: - return - - parser = optparse.OptionParser() - parser.add_option("-x", "--display", action="store_true", dest="display", help="Display data") - parser.add_option("-e", "--enable", action="store_true", dest="enabled", help="Whether the alarm should be enabled or not", default=False) - parser.add_option("-d", "--disable", action="store_false", dest="enabled", help="Whether the alarm should be enabled or not", default=False) - parser.add_option("-r", "--recurrence", action="store", type="int", dest="recurrence", help="How often the alarm occurs", default=5) - (commandOptions, commandArgs) = parser.parse_args() - - alarmHandler = AlarmHandler() - config = ConfigParser.SafeConfigParser() - config.read(constants._user_settings_) - alarmHandler.load_settings(config, "alarm") - - if commandOptions.display: - print "Alarm (%s) is %s for every %d minutes" % ( - alarmHandler._alarmCookie, - "enabled" if alarmHandler.isEnabled else "disabled", - alarmHandler.recurrence, - ) - else: - isEnabled = commandOptions.enabled - recurrence = commandOptions.recurrence - alarmHandler.apply_settings(isEnabled, recurrence) - - alarmHandler.save_settings(config, "alarm") - configFile = open(constants._user_settings_, "wb") - try: - config.write(configFile) - finally: - configFile.close() - - -if __name__ == "__main__": - main() diff --git a/src/alarm_notify.py b/src/alarm_notify.py deleted file mode 100755 index 9cb42b8..0000000 --- a/src/alarm_notify.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env python - -import os -import filecmp -import ConfigParser -import pprint - -import constants -import gv_backend - - -def get_missed(backend): - missedPage = backend._browser.download(backend._missedCallsURL) - missedJson = backend._grab_json(missedPage) - return missedJson - - -def get_voicemail(backend): - voicemailPage = backend._browser.download(backend._voicemailURL) - voicemailJson = backend._grab_json(voicemailPage) - return voicemailJson - - -def get_sms(backend): - smsPage = backend._browser.download(backend._smsURL) - smsJson = backend._grab_json(smsPage) - return smsJson - - -def remove_reltime(data): - for messageData in data["messages"].itervalues(): - del messageData["relativeStartTime"] - - -def is_type_changed(backend, type, get_material): - jsonMaterial = get_material(backend) - unreadCount = jsonMaterial["unreadCounts"][type] - - previousSnapshotPath = os.path.join(constants._data_path_, "snapshot_%s.old.json" % type) - currentSnapshotPath = os.path.join(constants._data_path_, "snapshot_%s.json" % type) - - try: - os.remove(previousSnapshotPath) - except OSError, e: - # check if failed purely because the old file didn't exist, which is fine - if e.errno != 2: - raise - try: - os.rename(currentSnapshotPath, previousSnapshotPath) - previousExists = True - except OSError, e: - # check if failed purely because the new old file didn't exist, which is fine - if e.errno != 2: - raise - previousExists = False - - remove_reltime(jsonMaterial) - textMaterial = pprint.pformat(jsonMaterial) - currentSnapshot = file(currentSnapshotPath, "w") - try: - currentSnapshot.write(textMaterial) - finally: - currentSnapshot.close() - - if unreadCount == 0 or not previousExists: - return False - - seemEqual = filecmp.cmp(previousSnapshotPath, currentSnapshotPath) - return not seemEqual - - -def is_changed(): - gvCookiePath = os.path.join(constants._data_path_, "gv_cookies.txt") - backend = gv_backend.GVDialer(gvCookiePath) - - loggedIn = False - - if not loggedIn: - loggedIn = backend.is_authed() - - config = ConfigParser.SafeConfigParser() - config.read(constants._user_settings_) - if not loggedIn: - import base64 - try: - blobs = ( - config.get(constants.__pretty_app_name__, "bin_blob_%i" % i) - for i in xrange(2) - ) - creds = ( - base64.b64decode(blob) - for blob in blobs - ) - username, password = tuple(creds) - loggedIn = backend.login(username, password) - except ConfigParser.NoOptionError, e: - pass - except ConfigParser.NoSectionError, e: - pass - - try: - notifyOnMissed = config.getboolean("2 - Account Info", "notifyOnMissed") - notifyOnVoicemail = config.getboolean("2 - Account Info", "notifyOnVoicemail") - notifyOnSms = config.getboolean("2 - Account Info", "notifyOnSms") - except ConfigParser.NoOptionError, e: - notifyOnMissed = False - notifyOnVoicemail = False - notifyOnSms = False - except ConfigParser.NoSectionError, e: - notifyOnMissed = False - notifyOnVoicemail = False - notifyOnSms = False - - assert loggedIn - notifySources = [] - if notifyOnMissed: - notifySources.append(("missed", get_missed)) - if notifyOnVoicemail: - notifySources.append(("voicemail", get_voicemail)) - if notifyOnSms: - notifySources.append(("sms", get_sms)) - - notifyUser = False - for type, get_material in notifySources: - if is_type_changed(backend, type, get_material): - notifyUser = True - return notifyUser - - -def notify_on_change(): - notifyUser = is_changed() - - if notifyUser: - import led_handler - led = led_handler.LedHandler() - led.on() - - -if __name__ == "__main__": - notify_on_change() diff --git a/src/dc_glade.py b/src/dc_glade.py deleted file mode 100755 index b23521a..0000000 --- a/src/dc_glade.py +++ /dev/null @@ -1,868 +0,0 @@ -#!/usr/bin/python2.5 - -""" -DialCentral - Front end for Google's GoogleVoice service. -Copyright (C) 2008 Mark Bergman bergman AT merctech DOT com - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -@todo Add "login failed" and "attempting login" notifications -""" - - -from __future__ import with_statement - -import sys -import gc -import os -import threading -import base64 -import ConfigParser -import itertools -import logging - -import gtk -import gtk.glade - -import constants -import hildonize -import gtk_toolbox - - -def getmtime_nothrow(path): - try: - return os.path.getmtime(path) - except Exception: - return 0 - - -def display_error_message(msg): - error_dialog = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg) - - def close(dialog, response): - dialog.destroy() - error_dialog.connect("response", close) - error_dialog.run() - - -class Dialcentral(object): - - _glade_files = [ - os.path.join(os.path.dirname(__file__), "dialcentral.glade"), - os.path.join(os.path.dirname(__file__), "../lib/dialcentral.glade"), - '/usr/lib/dialcentral/dialcentral.glade', - ] - - KEYPAD_TAB = 0 - RECENT_TAB = 1 - MESSAGES_TAB = 2 - CONTACTS_TAB = 3 - ACCOUNT_TAB = 4 - - NULL_BACKEND = 0 - GV_BACKEND = 2 - BACKENDS = (NULL_BACKEND, GV_BACKEND) - - def __init__(self): - self._initDone = False - self._connection = None - self._osso = None - self._clipboard = gtk.clipboard_get() - - self._credentials = ("", "") - self._selectedBackendId = self.NULL_BACKEND - self._defaultBackendId = self.GV_BACKEND - self._phoneBackends = None - self._dialpads = None - self._accountViews = None - self._messagesViews = None - self._recentViews = None - self._contactsViews = None - self._alarmHandler = None - self._ledHandler = None - self._originalCurrentLabels = [] - - for path in self._glade_files: - if os.path.isfile(path): - self._widgetTree = gtk.glade.XML(path) - break - else: - display_error_message("Cannot find dialcentral.glade") - gtk.main_quit() - return - - self._window = self._widgetTree.get_widget("mainWindow") - self._notebook = self._widgetTree.get_widget("notebook") - self._errorDisplay = gtk_toolbox.ErrorDisplay(self._widgetTree) - self._credentialsDialog = gtk_toolbox.LoginWindow(self._widgetTree) - - self._isFullScreen = False - self._app = hildonize.get_app_class()() - self._window = hildonize.hildonize_window(self._app, self._window) - hildonize.hildonize_text_entry(self._widgetTree.get_widget("usernameentry")) - hildonize.hildonize_password_entry(self._widgetTree.get_widget("passwordentry")) - - for scrollingWidget in ( - 'recent_scrolledwindow', - 'message_scrolledwindow', - 'contacts_scrolledwindow', - "phoneSelectionMessages_scrolledwindow", - "smsMessages_scrolledwindow", - ): - hildonize.hildonize_scrollwindow(self._widgetTree.get_widget(scrollingWidget)) - for scrollingWidget in ( - "phonetypes_scrolledwindow", - "smsMessage_scrolledEntry", - ): - hildonize.hildonize_scrollwindow_with_viewport(self._widgetTree.get_widget(scrollingWidget)) - - replacementButtons = [gtk.Button("Test")] - menu = hildonize.hildonize_menu( - self._window, - self._widgetTree.get_widget("dialpad_menubar"), - replacementButtons - ) - - self._window.connect("key-press-event", self._on_key_press) - self._window.connect("window-state-event", self._on_window_state_change) - if not hildonize.IS_HILDON_SUPPORTED: - logging.warning("No hildonization support") - - hildonize.set_application_title(self._window, "%s" % constants.__pretty_app_name__) - - self._window.connect("destroy", self._on_close) - self._window.set_default_size(800, 300) - self._window.show_all() - - self._loginSink = gtk_toolbox.threaded_stage( - gtk_toolbox.comap( - self._attempt_login, - gtk_toolbox.null_sink(), - ) - ) - - backgroundSetup = threading.Thread(target=self._idle_setup) - backgroundSetup.setDaemon(True) - backgroundSetup.start() - - def _idle_setup(self): - """ - If something can be done after the UI loads, push it here so it's not blocking the UI - """ - # Barebones UI handlers - try: - import null_backend - import null_views - - self._phoneBackends = {self.NULL_BACKEND: null_backend.NullDialer()} - with gtk_toolbox.gtk_lock(): - self._dialpads = {self.NULL_BACKEND: null_views.Dialpad(self._widgetTree)} - self._accountViews = {self.NULL_BACKEND: null_views.AccountInfo(self._widgetTree)} - self._recentViews = {self.NULL_BACKEND: null_views.RecentCallsView(self._widgetTree)} - self._messagesViews = {self.NULL_BACKEND: null_views.MessagesView(self._widgetTree)} - self._contactsViews = {self.NULL_BACKEND: null_views.ContactsView(self._widgetTree)} - - self._dialpads[self._selectedBackendId].enable() - self._accountViews[self._selectedBackendId].enable() - self._recentViews[self._selectedBackendId].enable() - self._messagesViews[self._selectedBackendId].enable() - self._contactsViews[self._selectedBackendId].enable() - except Exception, e: - with gtk_toolbox.gtk_lock(): - self._errorDisplay.push_exception() - - # Setup maemo specifics - try: - try: - import osso - except (ImportError, OSError): - osso = None - self._osso = None - if osso is not None: - self._osso = osso.Context(constants.__app_name__, constants.__version__, False) - device = osso.DeviceState(self._osso) - device.set_device_state_callback(self._on_device_state_change, 0) - else: - logging.warning("No device state support") - - try: - import alarm_handler - self._alarmHandler = alarm_handler.AlarmHandler() - except (ImportError, OSError): - alarm_handler = None - except Exception: - with gtk_toolbox.gtk_lock(): - self._errorDisplay.push_exception() - alarm_handler = None - logging.warning("No notification support") - if hildonize.IS_HILDON_SUPPORTED: - try: - import led_handler - self._ledHandler = led_handler.LedHandler() - except Exception, e: - logging.exception('LED Handling failed: "%s"' % str(e)) - self._ledHandler = None - else: - self._ledHandler = None - - try: - import conic - except (ImportError, OSError): - conic = None - self._connection = None - if conic is not None: - self._connection = conic.Connection() - self._connection.connect("connection-event", self._on_connection_change, constants.__app_magic__) - self._connection.request_connection(conic.CONNECT_FLAG_NONE) - else: - logging.warning("No connection support") - except Exception, e: - with gtk_toolbox.gtk_lock(): - self._errorDisplay.push_exception() - - # Setup costly backends - try: - import gv_backend - import file_backend - import gv_views - - try: - os.makedirs(constants._data_path_) - except OSError, e: - if e.errno != 17: - raise - gvCookiePath = os.path.join(constants._data_path_, "gv_cookies.txt") - - self._phoneBackends.update({ - self.GV_BACKEND: gv_backend.GVDialer(gvCookiePath), - }) - with gtk_toolbox.gtk_lock(): - unifiedDialpad = gv_views.Dialpad(self._widgetTree, self._errorDisplay) - self._dialpads.update({ - self.GV_BACKEND: unifiedDialpad, - }) - self._accountViews.update({ - self.GV_BACKEND: gv_views.AccountInfo( - self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._alarmHandler, self._errorDisplay - ), - }) - self._accountViews[self.GV_BACKEND].save_everything = self._save_settings - self._recentViews.update({ - self.GV_BACKEND: gv_views.RecentCallsView( - self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay - ), - }) - self._messagesViews.update({ - self.GV_BACKEND: gv_views.MessagesView( - self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay - ), - }) - self._contactsViews.update({ - self.GV_BACKEND: gv_views.ContactsView( - self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay - ), - }) - - fsContactsPath = os.path.join(constants._data_path_, "contacts") - fileBackend = file_backend.FilesystemAddressBookFactory(fsContactsPath) - - self._dialpads[self.GV_BACKEND].number_selected = self._select_action - self._recentViews[self.GV_BACKEND].number_selected = self._select_action - self._messagesViews[self.GV_BACKEND].number_selected = self._select_action - self._contactsViews[self.GV_BACKEND].number_selected = self._select_action - - addressBooks = [ - self._phoneBackends[self.GV_BACKEND], - fileBackend, - ] - mergedBook = gv_views.MergedAddressBook(addressBooks, gv_views.MergedAddressBook.advanced_lastname_sorter) - self._contactsViews[self.GV_BACKEND].append(mergedBook) - self._contactsViews[self.GV_BACKEND].extend(addressBooks) - self._contactsViews[self.GV_BACKEND].open_addressbook(*self._contactsViews[self.GV_BACKEND].get_addressbooks().next()[0][0:2]) - - callbackMapping = { - "on_paste": self._on_paste, - "on_refresh": self._on_menu_refresh, - "on_clearcookies_clicked": self._on_clearcookies_clicked, - "on_about_activate": self._on_about_activate, - } - if hildonize.GTK_MENU_USED: - self._widgetTree.signal_autoconnect(callbackMapping) - self._notebook.connect("switch-page", self._on_notebook_switch_page) - self._widgetTree.get_widget("clearcookies").connect("clicked", self._on_clearcookies_clicked) - - with gtk_toolbox.gtk_lock(): - self._originalCurrentLabels = [ - self._notebook.get_tab_label(self._notebook.get_nth_page(pageIndex)).get_text() - for pageIndex in xrange(self._notebook.get_n_pages()) - ] - self._notebookTapHandler = gtk_toolbox.TapOrHold(self._notebook) - self._notebookTapHandler.enable() - self._notebookTapHandler.on_tap = self._reset_tab_refresh - self._notebookTapHandler.on_hold = self._on_tab_refresh - self._notebookTapHandler.on_holding = self._set_tab_refresh - self._notebookTapHandler.on_cancel = self._reset_tab_refresh - - self._initDone = True - - config = ConfigParser.SafeConfigParser() - config.read(constants._user_settings_) - with gtk_toolbox.gtk_lock(): - self.load_settings(config) - except Exception, e: - with gtk_toolbox.gtk_lock(): - self._errorDisplay.push_exception() - finally: - self._spawn_attempt_login(2) - - def _spawn_attempt_login(self, *args): - self._loginSink.send(args) - - def _attempt_login(self, numOfAttempts = 10, force = False): - """ - @note This must be run outside of the UI lock - """ - try: - assert 0 <= numOfAttempts, "That was pointless having 0 or less login attempts" - assert self._initDone, "Attempting login before app is fully loaded" - - serviceId = self.NULL_BACKEND - loggedIn = False - if not force: - try: - self.refresh_session() - serviceId = self._defaultBackendId - loggedIn = True - except Exception, e: - logging.exception('Session refresh failed with the following message "%s"' % str(e)) - - if not loggedIn: - loggedIn, serviceId = self._login_by_user(numOfAttempts) - - with gtk_toolbox.gtk_lock(): - self._change_loggedin_status(serviceId) - if loggedIn: - hildonize.show_information_banner(self._window, "Logged In") - except Exception, e: - with gtk_toolbox.gtk_lock(): - self._errorDisplay.push_exception() - - def refresh_session(self): - """ - @note Thread agnostic - """ - assert self._initDone, "Attempting login before app is fully loaded" - - loggedIn = False - if not loggedIn: - loggedIn = self._login_by_cookie() - if not loggedIn: - loggedIn = self._login_by_settings() - - if not loggedIn: - raise RuntimeError("Login Failed") - - def _login_by_cookie(self): - """ - @note Thread agnostic - """ - loggedIn = self._phoneBackends[self._defaultBackendId].is_authed() - if loggedIn: - logging.info("Logged into %r through cookies" % self._phoneBackends[self._defaultBackendId]) - return loggedIn - - def _login_by_settings(self): - """ - @note Thread agnostic - """ - username, password = self._credentials - loggedIn = self._phoneBackends[self._defaultBackendId].login(username, password) - if loggedIn: - self._credentials = username, password - logging.info("Logged into %r through settings" % self._phoneBackends[self._defaultBackendId]) - return loggedIn - - def _login_by_user(self, numOfAttempts): - """ - @note This must be run outside of the UI lock - """ - loggedIn, (username, password) = False, self._credentials - tmpServiceId = self.GV_BACKEND - for attemptCount in xrange(numOfAttempts): - if loggedIn: - break - with gtk_toolbox.gtk_lock(): - credentials = self._credentialsDialog.request_credentials( - defaultCredentials = self._credentials - ) - if not self._phoneBackends[tmpServiceId].get_callback_number(): - # subtle reminder to the users to configure things - self._notebook.set_current_page(self.ACCOUNT_TAB) - username, password = credentials - loggedIn = self._phoneBackends[tmpServiceId].login(username, password) - - if loggedIn: - serviceId = tmpServiceId - self._credentials = username, password - logging.info("Logged into %r through user request" % self._phoneBackends[serviceId]) - else: - serviceId = self.NULL_BACKEND - self._notebook.set_current_page(self.ACCOUNT_TAB) - - return loggedIn, serviceId - - def _select_action(self, action, number, message): - self.refresh_session() - if action == "select": - self._dialpads[self._selectedBackendId].set_number(number) - self._notebook.set_current_page(self.KEYPAD_TAB) - elif action == "dial": - self._on_dial_clicked(number) - elif action == "sms": - self._on_sms_clicked(number, message) - else: - assert False, "Unknown action: %s" % action - - def _change_loggedin_status(self, newStatus): - oldStatus = self._selectedBackendId - if oldStatus == newStatus: - return - - self._dialpads[oldStatus].disable() - self._accountViews[oldStatus].disable() - self._recentViews[oldStatus].disable() - self._messagesViews[oldStatus].disable() - self._contactsViews[oldStatus].disable() - - self._dialpads[newStatus].enable() - self._accountViews[newStatus].enable() - self._recentViews[newStatus].enable() - self._messagesViews[newStatus].enable() - self._contactsViews[newStatus].enable() - - if self._phoneBackends[self._selectedBackendId].get_callback_number() is None: - self._phoneBackends[self._selectedBackendId].set_sane_callback() - - self._selectedBackendId = newStatus - - self._accountViews[self._selectedBackendId].update() - self._refresh_active_tab() - - def load_settings(self, config): - """ - @note UI Thread - """ - try: - self._defaultBackendId = config.getint(constants.__pretty_app_name__, "active") - blobs = ( - config.get(constants.__pretty_app_name__, "bin_blob_%i" % i) - for i in xrange(len(self._credentials)) - ) - creds = ( - base64.b64decode(blob) - for blob in blobs - ) - self._credentials = tuple(creds) - - if self._alarmHandler is not None: - self._alarmHandler.load_settings(config, "alarm") - except ConfigParser.NoOptionError, e: - logging.exception( - "Settings file %s is missing section %s" % ( - constants._user_settings_, - e.section, - ), - ) - except ConfigParser.NoSectionError, e: - logging.exception( - "Settings file %s is missing section %s" % ( - constants._user_settings_, - e.section, - ), - ) - - for backendId, view in itertools.chain( - self._dialpads.iteritems(), - self._accountViews.iteritems(), - self._messagesViews.iteritems(), - self._recentViews.iteritems(), - self._contactsViews.iteritems(), - ): - sectionName = "%s - %s" % (backendId, view.name()) - try: - view.load_settings(config, sectionName) - except ConfigParser.NoOptionError, e: - logging.exception( - "Settings file %s is missing section %s" % ( - constants._user_settings_, - e.section, - ), - ) - except ConfigParser.NoSectionError, e: - logging.exception( - "Settings file %s is missing section %s" % ( - constants._user_settings_, - e.section, - ), - ) - - try: - previousOrientation = config.getint(constants.__pretty_app_name__, "orientation") - if previousOrientation == gtk.ORIENTATION_HORIZONTAL: - hildonize.window_to_landscape(self._window) - elif previousOrientation == gtk.ORIENTATION_VERTICAL: - hildonize.window_to_portrait(self._window) - except ConfigParser.NoOptionError, e: - logging.exception( - "Settings file %s is missing section %s" % ( - constants._user_settings_, - e.section, - ), - ) - except ConfigParser.NoSectionError, e: - logging.exception( - "Settings file %s is missing section %s" % ( - constants._user_settings_, - e.section, - ), - ) - - def save_settings(self, config): - """ - @note Thread Agnostic - """ - config.add_section(constants.__pretty_app_name__) - config.set(constants.__pretty_app_name__, "active", str(self._selectedBackendId)) - config.set(constants.__pretty_app_name__, "orientation", str(int(gtk_toolbox.get_screen_orientation()))) - for i, value in enumerate(self._credentials): - blob = base64.b64encode(value) - config.set(constants.__pretty_app_name__, "bin_blob_%i" % i, blob) - config.add_section("alarm") - if self._alarmHandler is not None: - self._alarmHandler.save_settings(config, "alarm") - - for backendId, view in itertools.chain( - self._dialpads.iteritems(), - self._accountViews.iteritems(), - self._messagesViews.iteritems(), - self._recentViews.iteritems(), - self._contactsViews.iteritems(), - ): - sectionName = "%s - %s" % (backendId, view.name()) - config.add_section(sectionName) - view.save_settings(config, sectionName) - - def _save_settings(self): - """ - @note Thread Agnostic - """ - config = ConfigParser.SafeConfigParser() - self.save_settings(config) - with open(constants._user_settings_, "wb") as configFile: - config.write(configFile) - - def _refresh_active_tab(self): - pageIndex = self._notebook.get_current_page() - if pageIndex == self.CONTACTS_TAB: - self._contactsViews[self._selectedBackendId].update(force=True) - elif pageIndex == self.RECENT_TAB: - self._recentViews[self._selectedBackendId].update(force=True) - elif pageIndex == self.MESSAGES_TAB: - self._messagesViews[self._selectedBackendId].update(force=True) - - if pageIndex in (self.RECENT_TAB, self.MESSAGES_TAB): - if self._ledHandler is not None: - self._ledHandler.off() - - def _on_close(self, *args, **kwds): - try: - if self._osso is not None: - self._osso.close() - - if self._initDone: - self._save_settings() - finally: - gtk.main_quit() - - def _on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData): - """ - For shutdown or save_unsaved_data, our only state is cookies and I think the cookie manager handles that for us. - For system_inactivity, we have no background tasks to pause - - @note Hildon specific - """ - try: - if memory_low: - for backendId in self.BACKENDS: - self._phoneBackends[backendId].clear_caches() - self._contactsViews[self._selectedBackendId].clear_caches() - gc.collect() - - if save_unsaved_data or shutdown: - self._save_settings() - except Exception, e: - self._errorDisplay.push_exception() - - def _on_connection_change(self, connection, event, magicIdentifier): - """ - @note Hildon specific - """ - try: - import conic - - status = event.get_status() - error = event.get_error() - iap_id = event.get_iap_id() - bearer = event.get_bearer_type() - - if status == conic.STATUS_CONNECTED: - if self._initDone: - self._spawn_attempt_login(2) - elif status == conic.STATUS_DISCONNECTED: - if self._initDone: - self._defaultBackendId = self._selectedBackendId - self._change_loggedin_status(self.NULL_BACKEND) - except Exception, e: - self._errorDisplay.push_exception() - - def _on_window_state_change(self, widget, event, *args): - """ - @note Hildon specific - """ - try: - if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN: - self._isFullScreen = True - else: - self._isFullScreen = False - except Exception, e: - self._errorDisplay.push_exception() - - def _on_key_press(self, widget, event, *args): - """ - @note Hildon specific - """ - try: - if ( - event.keyval == gtk.keysyms.F6 or - event.keyval == gtk.keysyms.Return and event.get_state() & gtk.gdk.CONTROL_MASK - ): - if self._isFullScreen: - self._window.unfullscreen() - else: - self._window.fullscreen() - except Exception, e: - self._errorDisplay.push_exception() - - def _on_clearcookies_clicked(self, *args): - try: - self._phoneBackends[self._selectedBackendId].logout() - self._accountViews[self._selectedBackendId].clear() - self._recentViews[self._selectedBackendId].clear() - self._messagesViews[self._selectedBackendId].clear() - self._contactsViews[self._selectedBackendId].clear() - self._change_loggedin_status(self.NULL_BACKEND) - - self._spawn_attempt_login(2, True) - except Exception, e: - self._errorDisplay.push_exception() - - def _on_notebook_switch_page(self, notebook, page, pageIndex): - try: - self._reset_tab_refresh() - - didRecentUpdate = False - didMessagesUpdate = False - - if pageIndex == self.RECENT_TAB: - didRecentUpdate = self._recentViews[self._selectedBackendId].update() - elif pageIndex == self.MESSAGES_TAB: - didMessagesUpdate = self._messagesViews[self._selectedBackendId].update() - elif pageIndex == self.CONTACTS_TAB: - self._contactsViews[self._selectedBackendId].update() - elif pageIndex == self.ACCOUNT_TAB: - self._accountViews[self._selectedBackendId].update() - - if didRecentUpdate or didMessagesUpdate: - if self._ledHandler is not None: - self._ledHandler.off() - except Exception, e: - self._errorDisplay.push_exception() - - def _set_tab_refresh(self, *args): - try: - pageIndex = self._notebook.get_current_page() - child = self._notebook.get_nth_page(pageIndex) - self._notebook.get_tab_label(child).set_text("Refresh?") - except Exception, e: - self._errorDisplay.push_exception() - return False - - def _reset_tab_refresh(self, *args): - try: - pageIndex = self._notebook.get_current_page() - child = self._notebook.get_nth_page(pageIndex) - self._notebook.get_tab_label(child).set_text(self._originalCurrentLabels[pageIndex]) - except Exception, e: - self._errorDisplay.push_exception() - return False - - def _on_tab_refresh(self, *args): - try: - self._refresh_active_tab() - self._reset_tab_refresh() - except Exception, e: - self._errorDisplay.push_exception() - return False - - def _on_sms_clicked(self, number, message): - try: - assert number, "No number specified" - assert message, "Empty message" - try: - loggedIn = self._phoneBackends[self._selectedBackendId].is_authed() - except Exception, e: - loggedIn = False - self._errorDisplay.push_exception() - return - - if not loggedIn: - self._errorDisplay.push_message( - "Backend link with GoogleVoice is not working, please try again" - ) - return - - dialed = False - try: - self._phoneBackends[self._selectedBackendId].send_sms(number, message) - hildonize.show_information_banner(self._window, "Sending to %s" % number) - dialed = True - except Exception, e: - self._errorDisplay.push_exception() - - if dialed: - self._dialpads[self._selectedBackendId].clear() - except Exception, e: - self._errorDisplay.push_exception() - - def _on_dial_clicked(self, number): - try: - assert number, "No number to call" - try: - loggedIn = self._phoneBackends[self._selectedBackendId].is_authed() - except Exception, e: - loggedIn = False - self._errorDisplay.push_exception() - return - - if not loggedIn: - self._errorDisplay.push_message( - "Backend link with GoogleVoice is not working, please try again" - ) - return - - dialed = False - try: - assert self._phoneBackends[self._selectedBackendId].get_callback_number() != "", "No callback number specified" - self._phoneBackends[self._selectedBackendId].dial(number) - hildonize.show_information_banner(self._window, "Calling %s" % number) - dialed = True - except Exception, e: - self._errorDisplay.push_exception() - - if dialed: - self._dialpads[self._selectedBackendId].clear() - except Exception, e: - self._errorDisplay.push_exception() - - def _on_menu_refresh(self, *args): - try: - self._refresh_active_tab() - except Exception, e: - self._errorDisplay.push_exception() - - def _on_paste(self, *args): - try: - contents = self._clipboard.wait_for_text() - if contents is not None: - self._dialpads[self._selectedBackendId].set_number(contents) - except Exception, e: - self._errorDisplay.push_exception() - - def _on_about_activate(self, *args): - try: - dlg = gtk.AboutDialog() - dlg.set_name(constants.__pretty_app_name__) - dlg.set_version("%s-%d" % (constants.__version__, constants.__build__)) - dlg.set_copyright("Copyright 2008 - LGPL") - dlg.set_comments("Dialcentral is a touch screen enhanced interface to your GoogleVoice account. This application is not affiliated with Google in any way") - dlg.set_website("http://gc-dialer.garage.maemo.org/") - dlg.set_authors(["", "Eric Warnke ", "Ed Page "]) - dlg.run() - dlg.destroy() - except Exception, e: - self._errorDisplay.push_exception() - - -def run_doctest(): - import doctest - - failureCount, testCount = doctest.testmod() - if not failureCount: - print "Tests Successful" - sys.exit(0) - else: - sys.exit(1) - - -def run_dialpad(): - _lock_file = os.path.join(constants._data_path_, ".lock") - #with gtk_toolbox.flock(_lock_file, 0): - gtk.gdk.threads_init() - - if hildonize.IS_HILDON_SUPPORTED: - gtk.set_application_name(constants.__pretty_app_name__) - handle = Dialcentral() - gtk.main() - - -class DummyOptions(object): - - def __init__(self): - self.test = False - - -if __name__ == "__main__": - logging.basicConfig(level=logging.DEBUG) - try: - if len(sys.argv) > 1: - try: - import optparse - except ImportError: - optparse = None - - if optparse is not None: - parser = optparse.OptionParser() - parser.add_option("-t", "--test", action="store_true", dest="test", help="Run tests") - (commandOptions, commandArgs) = parser.parse_args() - else: - commandOptions = DummyOptions() - commandArgs = [] - - if commandOptions.test: - run_doctest() - else: - run_dialpad() - finally: - logging.shutdown() diff --git a/src/dialcentral.glade b/src/dialcentral.glade deleted file mode 100644 index ba8d0ff..0000000 --- a/src/dialcentral.glade +++ /dev/null @@ -1,1292 +0,0 @@ - - - - - - Dialer - 800 - 480 - - - True - - - True - - - True - _Login - True - - - - - - True - Paste - True - - - - - - True - Refresh - True - - - - - - True - _About - True - - - - - - False - 0 - - - - - True - - - True - - - True - gtk-dialog-error - - - False - False - 0 - - - - - True - True - end - True - - - 1 - - - - - True - gtk-close - - - False - False - 2 - - - - - - - 1 - - - - - True - True - left - False - True - - - True - - - True - - - 50 - True - <span size="35000" weight="bold"></span> - True - center - - - 0 - - - - - gtk-go-back - True - True - True - True - False - - - - False - 1 - - - - - False - False - 0 - - - - - True - 4 - 3 - True - - - True - False - False - False - - - - - True - <span size="33000" weight="bold">1</span> -<span size="9000"> </span> - True - - - - - - - True - False - False - False - - - - - - - - True - <span size="30000" weight="bold">2</span> -<span size="12000">ABC</span> - True - center - - - - - 1 - 2 - - - - - True - False - False - False - - - - - - - - True - <span size="30000" weight="bold" stretch="ultraexpanded">3</span> -<span size="12000">DEF</span> - True - center - - - - - 2 - 3 - - - - - True - False - False - False - - - - - - - - True - <span size="30000" weight="bold">4</span> -<span size="12000">GHI</span> - True - center - - - - - 1 - 2 - - - - - True - False - False - False - - - - - - - - True - <span size="30000" weight="bold">5</span> -<span size="12000">JKL</span> - True - center - - - - - 1 - 2 - 1 - 2 - - - - - True - False - False - False - - - - - - - - True - <span size="30000" weight="bold">6</span> -<span size="12000">MNO</span> - True - center - - - - - 2 - 3 - 1 - 2 - - - - - True - False - False - False - - - - - - - - - True - <span size="30000" weight="bold">7</span> -<span size="12000">PQRS</span> - True - center - - - - - 2 - 3 - - - - - True - False - False - False - - - - - - - - True - <span size="30000" weight="bold">8</span> -<span size="12000">TUV</span> - True - center - - - - - 1 - 2 - 2 - 3 - - - - - True - False - False - False - - - - - - - - - True - <span size="30000" weight="bold">9</span> -<span size="12000">WXYZ</span> - True - center - - - - - 2 - 3 - 2 - 3 - - - - - True - False - False - False - - - - - True - <span size="33000" weight="bold">0</span> -<span size="9000"></span> - True - center - - - - - 1 - 2 - 3 - 4 - - - - - True - False - False - - - - True - - - True - 1 - gtk-yes - - - 0 - - - - - True - 0 - 5 - <span size="17000" weight="bold">Dial</span> - True - - - 1 - - - - - - - 2 - 3 - 3 - 4 - - - - - True - True - True - - - - True - - - True - 1 - gtk-file - - - 0 - - - - - True - 0 - 5 - <span size="17000" weight="bold">SMS</span> - True - - - 1 - - - - - - - 3 - 4 - - - - - 1 - - - - - True - False - - - - - 30 - True - Keypad - - - True - False - tab - - - - - True - vertical - - - True - True - never - - - True - True - True - horizontal - True - - - - - 0 - - - - - 1 - True - False - - - - - 30 - True - Recent - - - 1 - True - False - tab - - - - - True - vertical - - - True - True - never - automatic - - - True - True - True - horizontal - True - - - - - 0 - - - - - 2 - - - - - True - Messages - - - 2 - True - False - tab - - - - - True - vertical - - - True - True - True - - - False - 0 - - - - - True - True - never - - - True - True - False - True - True - horizontal - True - - - - - 1 - - - - - 3 - - - - - True - Contacts - - - 3 - True - False - tab - - - - - True - 11 - 7 - 2 - - - True - 0 - No Number Available - True - - - 1 - 2 - GTK_FILL - - - - - - True - 0 - 0 - 10 - Account Number: - - - - - - - - True - 0 - 0 - 10 - Callback Number: - - - 1 - 2 - - - - - - True - 0 - - - 2 - 3 - - - - - True - 0 - - - 4 - 5 - - - - - True - vertical - - - Missed Calls - True - True - False - True - - - 0 - - - - - Voicemail - True - True - False - True - - - 1 - - - - - SMS - True - True - False - True - - - 2 - - - - - 1 - 2 - 4 - 5 - - - - - Notifications - True - True - False - 0 - True - - - 3 - 4 - GTK_FILL - - - - - - Login - True - True - True - False - - - 1 - 2 - 6 - 7 - GTK_FILL - - - - - - True - 0 - - - 5 - 6 - - - - - True - True - True - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - True - True - True - - - 1 - 2 - 1 - 2 - - - - - - - - - - - - - - - 4 - True - False - - - - - 30 - True - Account - - - 4 - False - tab - - - - - 2 - - - - - - - 5 - Login - False - True - center-on-parent - True - dialog - True - True - False - mainWindow - False - - - True - 2 - - - True - - - False - False - 1 - - - - - True - 2 - 2 - - - True - Username - - - - - True - Password - - - 1 - 2 - - - - - True - True - - - 1 - 2 - - - - - True - True - False - - - 1 - 2 - 1 - 2 - - - - - 2 - - - - - True - end - - - gtk-close - True - True - True - True - - - False - False - 0 - - - - - gtk-ok - True - True - True - True - True - - - False - False - 1 - - - - - False - end - 0 - - - - - - - 5 - Select Phone Type - True - center-on-parent - 500 - 300 - True - dialog - True - True - False - - - True - 2 - - - True - vertical - - - True - True - never - automatic - - - True - True - - - - - 0 - - - - - 1 - - - - - True - - - False - 2 - - - - - True - vertical - - - True - True - never - automatic - - - True - True - True - False - - - - - False - 0 - - - - - False - 3 - - - - - True - end - - - SMS - -4 - True - True - True - - - False - False - 0 - - - - - Dial - True - True - True - - - False - False - 1 - - - - - Select - True - True - True - - - False - False - 2 - - - - - gtk-cancel - True - True - True - True - - - False - False - 3 - - - - - False - end - 0 - - - - - - - 5 - Send SMS - True - center-on-parent - 500 - 300 - True - dialog - True - True - False - - - True - vertical - 2 - - - True - vertical - - - True - True - never - automatic - - - True - True - - - - - 0 - - - - - 1 - - - - - True - - - False - 2 - - - - - True - vertical - - - True - True - never - automatic - - - True - True - word - - - - - 0 - - - - - 3 - - - - - True - - - True - Letters Left: - True - - - False - False - 0 - - - - - True - True - - - 1 - - - - - False - 4 - - - - - True - end - - - Send - True - True - True - - - False - False - 0 - - - - - gtk-cancel - True - True - True - True - - - False - False - 1 - - - - - False - end - 0 - - - - - - diff --git a/src/dialcentral.py b/src/dialcentral.py deleted file mode 100755 index 4f669ff..0000000 --- a/src/dialcentral.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/python - -import os -import sys -import logging - - -sys.path.insert(0,"/usr/lib/dialcentral/") - - -import constants -import dc_glade - - -try: - os.makedirs(constants._data_path_) -except OSError, e: - if e.errno != 17: - raise - -userLogPath = "%s/dialcentral.log" % constants._data_path_ -logging.basicConfig(level=logging.DEBUG, filename=userLogPath) -logging.info("Dialcentral %s-%s" % (constants.__version__, constants.__build__)) - -try: - dc_glade.run_dialpad() -finally: - logging.shutdown() diff --git a/src/example_custom_notifier.py b/src/example_custom_notifier.py deleted file mode 100755 index 3679b5b..0000000 --- a/src/example_custom_notifier.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -import sys - - -sys.path.insert(0,"/usr/lib/dialcentral/") - - -import alarm_notify - - -def notify_on_change(): - notifyUser = alarm_notify.is_changed() - - if notifyUser: - import subprocess - import led_handler - led = led_handler.LedHandler() - led.on() - soundOn = subprocess.call("/usr/bin/dbus-send --dest=com.nokia.osso_media_server --print-reply /com/nokia/osso_media_server com.nokia.osso_media_server.music.play_media string:file:///usr/lib/gv-notifier/alert.mp3",shell=True) - - -if __name__ == "__main__": - notify_on_change() diff --git a/src/file_backend.py b/src/file_backend.py deleted file mode 100644 index b373561..0000000 --- a/src/file_backend.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/python - -""" -DialCentral - Front end for Google's Grand Central service. -Copyright (C) 2008 Eric Warnke ericew AT gmail DOT com - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Filesystem backend for contact support -""" - - -import os -import re -import csv - - -class CsvAddressBook(object): - """ - Currently supported file format - @li Has the first line as a header - @li Escapes with quotes - @li Comma as delimiter - @li Column 0 is name, column 1 is number - """ - - _nameRe = re.compile("name", re.IGNORECASE) - _phoneRe = re.compile("phone", re.IGNORECASE) - _mobileRe = re.compile("mobile", re.IGNORECASE) - - def __init__(self, csvPath): - self.__csvPath = csvPath - self.__contacts = list( - self.read_csv(csvPath) - ) - - @classmethod - def read_csv(cls, csvPath): - try: - csvReader = iter(csv.reader(open(csvPath, "rU"))) - except IOError, e: - if e.errno != 2: - raise - return - - header = csvReader.next() - nameColumn, phoneColumns = cls._guess_columns(header) - - yieldCount = 0 - for row in csvReader: - contactDetails = [] - for (phoneType, phoneColumn) in phoneColumns: - try: - if len(row[phoneColumn]) == 0: - continue - contactDetails.append((phoneType, row[phoneColumn])) - except IndexError: - pass - if len(contactDetails) != 0: - yield str(yieldCount), row[nameColumn], contactDetails - yieldCount += 1 - - @classmethod - def _guess_columns(cls, row): - names = [] - phones = [] - for i, item in enumerate(row): - if cls._nameRe.search(item) is not None: - names.append((item, i)) - elif cls._phoneRe.search(item) is not None: - phones.append((item, i)) - elif cls._mobileRe.search(item) is not None: - phones.append((item, i)) - if len(names) == 0: - names.append(("Name", 0)) - if len(phones) == 0: - phones.append(("Phone", 1)) - - return names[0][1], phones - - def clear_caches(self): - pass - - @staticmethod - def factory_name(): - return "csv" - - @staticmethod - def contact_source_short_name(contactId): - return "csv" - - def get_contacts(self): - """ - @returns Iterable of (contact id, contact name) - """ - for contact in self.__contacts: - yield contact[0:2] - - def get_contact_details(self, contactId): - """ - @returns Iterable of (Phone Type, Phone Number) - """ - contactId = int(contactId) - return iter(self.__contacts[contactId][2]) - - -class FilesystemAddressBookFactory(object): - - FILETYPE_SUPPORT = { - "csv": CsvAddressBook, - } - - def __init__(self, path): - self.__path = path - - def clear_caches(self): - pass - - def get_addressbooks(self): - """ - @returns Iterable of (Address Book Factory, Book Id, Book Name) - """ - for root, dirs, filenames in os.walk(self.__path): - for filename in filenames: - try: - name, ext = filename.rsplit(".", 1) - except ValueError: - continue - - if ext in self.FILETYPE_SUPPORT: - yield self, os.path.join(root, filename), name - - def open_addressbook(self, bookId): - name, ext = bookId.rsplit(".", 1) - assert ext in self.FILETYPE_SUPPORT, "Unsupported file extension %s" % ext - return self.FILETYPE_SUPPORT[ext](bookId) - - @staticmethod - def factory_name(): - return "File" - - -def print_filebooks(contactPath = None): - """ - Included here for debugging. - - Either insert it into the code or launch python with the "-i" flag - """ - if contactPath is None: - contactPath = os.path.join(os.path.expanduser("~"), ".dialcentral", "contacts") - - abf = FilesystemAddressBookFactory(contactPath) - for book in abf.get_addressbooks(): - ab = abf.open_addressbook(book[1]) - print book - for contact in ab.get_contacts(): - print "\t", contact - for details in ab.get_contact_details(contact[0]): - print "\t\t", details diff --git a/src/gv_views.py b/src/gv_views.py deleted file mode 100644 index 0eac88b..0000000 --- a/src/gv_views.py +++ /dev/null @@ -1,1483 +0,0 @@ -#!/usr/bin/python2.5 - -""" -DialCentral - Front end for Google's GoogleVoice service. -Copyright (C) 2008 Mark Bergman bergman AT merctech DOT com - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -@todo Alternate UI for dialogs (stackables) -""" - -from __future__ import with_statement - -import ConfigParser -import logging - -import gobject -import pango -import gtk - -import gtk_toolbox -import hildonize -import null_backend - - -def make_ugly(prettynumber): - """ - function to take a phone number and strip out all non-numeric - characters - - >>> make_ugly("+012-(345)-678-90") - '01234567890' - """ - import re - uglynumber = re.sub('\D', '', prettynumber) - return uglynumber - - -def make_pretty(phonenumber): - """ - Function to take a phone number and return the pretty version - pretty numbers: - if phonenumber begins with 0: - ...-(...)-...-.... - if phonenumber begins with 1: ( for gizmo callback numbers ) - 1 (...)-...-.... - if phonenumber is 13 digits: - (...)-...-.... - if phonenumber is 10 digits: - ...-.... - >>> make_pretty("12") - '12' - >>> make_pretty("1234567") - '123-4567' - >>> make_pretty("2345678901") - '(234)-567-8901' - >>> make_pretty("12345678901") - '1 (234)-567-8901' - >>> make_pretty("01234567890") - '+012-(345)-678-90' - """ - if phonenumber is None or phonenumber is "": - return "" - - phonenumber = make_ugly(phonenumber) - - if len(phonenumber) < 3: - return phonenumber - - if phonenumber[0] == "0": - prettynumber = "" - prettynumber += "+%s" % phonenumber[0:3] - if 3 < len(phonenumber): - prettynumber += "-(%s)" % phonenumber[3:6] - if 6 < len(phonenumber): - prettynumber += "-%s" % phonenumber[6:9] - if 9 < len(phonenumber): - prettynumber += "-%s" % phonenumber[9:] - return prettynumber - elif len(phonenumber) <= 7: - prettynumber = "%s-%s" % (phonenumber[0:3], phonenumber[3:]) - elif len(phonenumber) > 8 and phonenumber[0] == "1": - prettynumber = "1 (%s)-%s-%s" % (phonenumber[1:4], phonenumber[4:7], phonenumber[7:]) - elif len(phonenumber) > 7: - prettynumber = "(%s)-%s-%s" % (phonenumber[0:3], phonenumber[3:6], phonenumber[6:]) - return prettynumber - - -def abbrev_relative_date(date): - """ - >>> abbrev_relative_date("42 hours ago") - '42 h' - >>> abbrev_relative_date("2 days ago") - '2 d' - >>> abbrev_relative_date("4 weeks ago") - '4 w' - """ - parts = date.split(" ") - return "%s %s" % (parts[0], parts[1][0]) - - -class MergedAddressBook(object): - """ - Merger of all addressbooks - """ - - def __init__(self, addressbookFactories, sorter = None): - self.__addressbookFactories = addressbookFactories - self.__addressbooks = None - self.__sort_contacts = sorter if sorter is not None else self.null_sorter - - def clear_caches(self): - self.__addressbooks = None - for factory in self.__addressbookFactories: - factory.clear_caches() - - def get_addressbooks(self): - """ - @returns Iterable of (Address Book Factory, Book Id, Book Name) - """ - yield self, "", "" - - def open_addressbook(self, bookId): - return self - - def contact_source_short_name(self, contactId): - if self.__addressbooks is None: - return "" - bookIndex, originalId = contactId.split("-", 1) - return self.__addressbooks[int(bookIndex)].contact_source_short_name(originalId) - - @staticmethod - def factory_name(): - return "All Contacts" - - def get_contacts(self): - """ - @returns Iterable of (contact id, contact name) - """ - if self.__addressbooks is None: - self.__addressbooks = list( - factory.open_addressbook(id) - for factory in self.__addressbookFactories - for (f, id, name) in factory.get_addressbooks() - ) - contacts = ( - ("-".join([str(bookIndex), contactId]), contactName) - for (bookIndex, addressbook) in enumerate(self.__addressbooks) - for (contactId, contactName) in addressbook.get_contacts() - ) - sortedContacts = self.__sort_contacts(contacts) - return sortedContacts - - def get_contact_details(self, contactId): - """ - @returns Iterable of (Phone Type, Phone Number) - """ - if self.__addressbooks is None: - return [] - bookIndex, originalId = contactId.split("-", 1) - return self.__addressbooks[int(bookIndex)].get_contact_details(originalId) - - @staticmethod - def null_sorter(contacts): - """ - Good for speed/low memory - """ - return contacts - - @staticmethod - def basic_firtname_sorter(contacts): - """ - Expects names in "First Last" format - """ - contactsWithKey = [ - (contactName.rsplit(" ", 1)[0], (contactId, contactName)) - for (contactId, contactName) in contacts - ] - contactsWithKey.sort() - return (contactData for (lastName, contactData) in contactsWithKey) - - @staticmethod - def basic_lastname_sorter(contacts): - """ - Expects names in "First Last" format - """ - contactsWithKey = [ - (contactName.rsplit(" ", 1)[-1], (contactId, contactName)) - for (contactId, contactName) in contacts - ] - contactsWithKey.sort() - return (contactData for (lastName, contactData) in contactsWithKey) - - @staticmethod - def reversed_firtname_sorter(contacts): - """ - Expects names in "Last, First" format - """ - contactsWithKey = [ - (contactName.split(", ", 1)[-1], (contactId, contactName)) - for (contactId, contactName) in contacts - ] - contactsWithKey.sort() - return (contactData for (lastName, contactData) in contactsWithKey) - - @staticmethod - def reversed_lastname_sorter(contacts): - """ - Expects names in "Last, First" format - """ - contactsWithKey = [ - (contactName.split(", ", 1)[0], (contactId, contactName)) - for (contactId, contactName) in contacts - ] - contactsWithKey.sort() - return (contactData for (lastName, contactData) in contactsWithKey) - - @staticmethod - def guess_firstname(name): - if ", " in name: - return name.split(", ", 1)[-1] - else: - return name.rsplit(" ", 1)[0] - - @staticmethod - def guess_lastname(name): - if ", " in name: - return name.split(", ", 1)[0] - else: - return name.rsplit(" ", 1)[-1] - - @classmethod - def advanced_firstname_sorter(cls, contacts): - contactsWithKey = [ - (cls.guess_firstname(contactName), (contactId, contactName)) - for (contactId, contactName) in contacts - ] - contactsWithKey.sort() - return (contactData for (lastName, contactData) in contactsWithKey) - - @classmethod - def advanced_lastname_sorter(cls, contacts): - contactsWithKey = [ - (cls.guess_lastname(contactName), (contactId, contactName)) - for (contactId, contactName) in contacts - ] - contactsWithKey.sort() - return (contactData for (lastName, contactData) in contactsWithKey) - - -class PhoneTypeSelector(object): - - ACTION_CANCEL = "cancel" - ACTION_SELECT = "select" - ACTION_DIAL = "dial" - ACTION_SEND_SMS = "sms" - - def __init__(self, widgetTree, gcBackend): - self._gcBackend = gcBackend - self._widgetTree = widgetTree - - self._dialog = self._widgetTree.get_widget("phonetype_dialog") - self._smsDialog = SmsEntryDialog(self._widgetTree) - - self._smsButton = self._widgetTree.get_widget("sms_button") - self._smsButton.connect("clicked", self._on_phonetype_send_sms) - - self._dialButton = self._widgetTree.get_widget("dial_button") - self._dialButton.connect("clicked", self._on_phonetype_dial) - - self._selectButton = self._widgetTree.get_widget("select_button") - self._selectButton.connect("clicked", self._on_phonetype_select) - - self._cancelButton = self._widgetTree.get_widget("cancel_button") - self._cancelButton.connect("clicked", self._on_phonetype_cancel) - - self._messagemodel = gtk.ListStore(gobject.TYPE_STRING) - self._messagesView = self._widgetTree.get_widget("phoneSelectionMessages") - self._scrollWindow = self._messagesView.get_parent() - - self._typemodel = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) - self._typeviewselection = None - self._typeview = self._widgetTree.get_widget("phonetypes") - self._typeview.connect("row-activated", self._on_phonetype_select) - - self._action = self.ACTION_CANCEL - - def run(self, contactDetails, messages = (), parent = None): - self._action = self.ACTION_CANCEL - - # Add the column to the phone selection tree view - self._typemodel.clear() - self._typeview.set_model(self._typemodel) - - textrenderer = gtk.CellRendererText() - numberColumn = gtk.TreeViewColumn("Phone Numbers", textrenderer, text=0) - self._typeview.append_column(numberColumn) - - textrenderer = gtk.CellRendererText() - typeColumn = gtk.TreeViewColumn("Phone Type", textrenderer, text=1) - self._typeview.append_column(typeColumn) - - for phoneType, phoneNumber in contactDetails: - display = " - ".join((phoneNumber, phoneType)) - display = phoneType - row = (phoneNumber, display) - self._typemodel.append(row) - - self._typeviewselection = self._typeview.get_selection() - self._typeviewselection.set_mode(gtk.SELECTION_SINGLE) - self._typeviewselection.select_iter(self._typemodel.get_iter_first()) - - # Add the column to the messages tree view - self._messagemodel.clear() - self._messagesView.set_model(self._messagemodel) - - textrenderer = gtk.CellRendererText() - textrenderer.set_property("wrap-mode", pango.WRAP_WORD) - textrenderer.set_property("wrap-width", 450) - messageColumn = gtk.TreeViewColumn("") - messageColumn.pack_start(textrenderer, expand=True) - messageColumn.add_attribute(textrenderer, "markup", 0) - messageColumn.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) - self._messagesView.append_column(messageColumn) - self._messagesView.set_headers_visible(False) - - if messages: - for message in messages: - row = (message, ) - self._messagemodel.append(row) - self._messagesView.show() - self._scrollWindow.show() - messagesSelection = self._messagesView.get_selection() - messagesSelection.select_path((len(messages)-1, )) - else: - self._messagesView.hide() - self._scrollWindow.hide() - - if parent is not None: - self._dialog.set_transient_for(parent) - - try: - self._dialog.show() - if messages: - self._messagesView.scroll_to_cell((len(messages)-1, )) - - userResponse = self._dialog.run() - finally: - self._dialog.hide() - - if userResponse == gtk.RESPONSE_OK: - phoneNumber = self._get_number() - phoneNumber = make_ugly(phoneNumber) - else: - phoneNumber = "" - if not phoneNumber: - self._action = self.ACTION_CANCEL - - if self._action == self.ACTION_SEND_SMS: - smsMessage = self._smsDialog.run(phoneNumber, messages, parent) - if not smsMessage: - phoneNumber = "" - self._action = self.ACTION_CANCEL - else: - smsMessage = "" - - self._messagesView.remove_column(messageColumn) - self._messagesView.set_model(None) - - self._typeviewselection.unselect_all() - self._typeview.remove_column(numberColumn) - self._typeview.remove_column(typeColumn) - self._typeview.set_model(None) - - return self._action, phoneNumber, smsMessage - - def _get_number(self): - model, itr = self._typeviewselection.get_selected() - if not itr: - return "" - - phoneNumber = self._typemodel.get_value(itr, 0) - return phoneNumber - - def _on_phonetype_dial(self, *args): - self._dialog.response(gtk.RESPONSE_OK) - self._action = self.ACTION_DIAL - - def _on_phonetype_send_sms(self, *args): - self._dialog.response(gtk.RESPONSE_OK) - self._action = self.ACTION_SEND_SMS - - def _on_phonetype_select(self, *args): - self._dialog.response(gtk.RESPONSE_OK) - self._action = self.ACTION_SELECT - - def _on_phonetype_cancel(self, *args): - self._dialog.response(gtk.RESPONSE_CANCEL) - self._action = self.ACTION_CANCEL - - -class SmsEntryDialog(object): - """ - @todo Add multi-SMS messages like GoogleVoice - """ - - MAX_CHAR = 160 - - def __init__(self, widgetTree): - self._widgetTree = widgetTree - self._dialog = self._widgetTree.get_widget("smsDialog") - - self._smsButton = self._widgetTree.get_widget("sendSmsButton") - self._smsButton.connect("clicked", self._on_send) - - self._cancelButton = self._widgetTree.get_widget("cancelSmsButton") - self._cancelButton.connect("clicked", self._on_cancel) - - self._letterCountLabel = self._widgetTree.get_widget("smsLetterCount") - - self._messagemodel = gtk.ListStore(gobject.TYPE_STRING) - self._messagesView = self._widgetTree.get_widget("smsMessages") - self._scrollWindow = self._messagesView.get_parent() - - self._smsEntry = self._widgetTree.get_widget("smsEntry") - self._smsEntry.get_buffer().connect("changed", self._on_entry_changed) - - def run(self, number, messages = (), parent = None): - # Add the column to the messages tree view - self._messagemodel.clear() - self._messagesView.set_model(self._messagemodel) - - textrenderer = gtk.CellRendererText() - textrenderer.set_property("wrap-mode", pango.WRAP_WORD) - textrenderer.set_property("wrap-width", 450) - messageColumn = gtk.TreeViewColumn("") - messageColumn.pack_start(textrenderer, expand=True) - messageColumn.add_attribute(textrenderer, "markup", 0) - messageColumn.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) - self._messagesView.append_column(messageColumn) - self._messagesView.set_headers_visible(False) - - if messages: - for message in messages: - row = (message, ) - self._messagemodel.append(row) - self._messagesView.show() - self._scrollWindow.show() - messagesSelection = self._messagesView.get_selection() - messagesSelection.select_path((len(messages)-1, )) - else: - self._messagesView.hide() - self._scrollWindow.hide() - - self._smsEntry.get_buffer().set_text("") - self._update_letter_count() - - if parent is not None: - self._dialog.set_transient_for(parent) - - try: - self._dialog.show() - if messages: - self._messagesView.scroll_to_cell((len(messages)-1, )) - self._smsEntry.grab_focus() - - userResponse = self._dialog.run() - finally: - self._dialog.hide() - - if userResponse == gtk.RESPONSE_OK: - entryBuffer = self._smsEntry.get_buffer() - enteredMessage = entryBuffer.get_text(entryBuffer.get_start_iter(), entryBuffer.get_end_iter()) - enteredMessage = enteredMessage[0:self.MAX_CHAR] - else: - enteredMessage = "" - - self._messagesView.remove_column(messageColumn) - self._messagesView.set_model(None) - - return enteredMessage.strip() - - def _update_letter_count(self, *args): - entryLength = self._smsEntry.get_buffer().get_char_count() - charsLeft = self.MAX_CHAR - entryLength - self._letterCountLabel.set_text(str(charsLeft)) - if charsLeft < 0: - self._smsButton.set_sensitive(False) - else: - self._smsButton.set_sensitive(True) - - def _on_entry_changed(self, *args): - self._update_letter_count() - - def _on_send(self, *args): - self._dialog.response(gtk.RESPONSE_OK) - - def _on_cancel(self, *args): - self._dialog.response(gtk.RESPONSE_CANCEL) - - -class Dialpad(object): - - def __init__(self, widgetTree, errorDisplay): - self._clipboard = gtk.clipboard_get() - self._errorDisplay = errorDisplay - self._smsDialog = SmsEntryDialog(widgetTree) - - self._numberdisplay = widgetTree.get_widget("numberdisplay") - self._smsButton = widgetTree.get_widget("sms") - self._dialButton = widgetTree.get_widget("dial") - self._backButton = widgetTree.get_widget("back") - self._phonenumber = "" - self._prettynumber = "" - - callbackMapping = { - "on_digit_clicked": self._on_digit_clicked, - } - widgetTree.signal_autoconnect(callbackMapping) - self._dialButton.connect("clicked", self._on_dial_clicked) - self._smsButton.connect("clicked", self._on_sms_clicked) - - self._originalLabel = self._backButton.get_label() - self._backTapHandler = gtk_toolbox.TapOrHold(self._backButton) - self._backTapHandler.on_tap = self._on_backspace - self._backTapHandler.on_hold = self._on_clearall - self._backTapHandler.on_holding = self._set_clear_button - self._backTapHandler.on_cancel = self._reset_back_button - - self._window = gtk_toolbox.find_parent_window(self._numberdisplay) - self._keyPressEventId = 0 - - def enable(self): - self._dialButton.grab_focus() - self._backTapHandler.enable() - self._keyPressEventId = self._window.connect("key-press-event", self._on_key_press) - - def disable(self): - self._window.disconnect(self._keyPressEventId) - self._keyPressEventId = 0 - self._reset_back_button() - self._backTapHandler.disable() - - def number_selected(self, action, number, message): - """ - @note Actual dial function is patched in later - """ - raise NotImplementedError("Horrible unknown error has occurred") - - def get_number(self): - return self._phonenumber - - def set_number(self, number): - """ - Set the number to dial - """ - try: - self._phonenumber = make_ugly(number) - self._prettynumber = make_pretty(self._phonenumber) - self._numberdisplay.set_label("%s" % (self._prettynumber)) - except TypeError, e: - self._errorDisplay.push_exception() - - def clear(self): - self.set_number("") - - @staticmethod - def name(): - return "Dialpad" - - def load_settings(self, config, section): - pass - - def save_settings(self, config, section): - """ - @note Thread Agnostic - """ - pass - - def _on_key_press(self, widget, event): - try: - if event.keyval == ord("v") and event.get_state() & gtk.gdk.CONTROL_MASK: - contents = self._clipboard.wait_for_text() - if contents is not None: - self.set_number(contents) - except Exception, e: - self._errorDisplay.push_exception() - - def _on_sms_clicked(self, widget): - try: - action = PhoneTypeSelector.ACTION_SEND_SMS - phoneNumber = self.get_number() - - message = self._smsDialog.run(phoneNumber, (), self._window) - if not message: - phoneNumber = "" - action = PhoneTypeSelector.ACTION_CANCEL - - if action == PhoneTypeSelector.ACTION_CANCEL: - return - self.number_selected(action, phoneNumber, message) - except Exception, e: - self._errorDisplay.push_exception() - - def _on_dial_clicked(self, widget): - try: - action = PhoneTypeSelector.ACTION_DIAL - phoneNumber = self.get_number() - message = "" - self.number_selected(action, phoneNumber, message) - except Exception, e: - self._errorDisplay.push_exception() - - def _on_digit_clicked(self, widget): - try: - self.set_number(self._phonenumber + widget.get_name()[-1]) - except Exception, e: - self._errorDisplay.push_exception() - - def _on_backspace(self, taps): - try: - self.set_number(self._phonenumber[:-taps]) - self._reset_back_button() - except Exception, e: - self._errorDisplay.push_exception() - - def _on_clearall(self, taps): - try: - self.clear() - self._reset_back_button() - except Exception, e: - self._errorDisplay.push_exception() - return False - - def _set_clear_button(self): - try: - self._backButton.set_label("gtk-clear") - except Exception, e: - self._errorDisplay.push_exception() - - def _reset_back_button(self): - try: - self._backButton.set_label(self._originalLabel) - except Exception, e: - self._errorDisplay.push_exception() - - -class AccountInfo(object): - - def __init__(self, widgetTree, backend, alarmHandler, errorDisplay): - self._errorDisplay = errorDisplay - self._backend = backend - self._isPopulated = False - self._alarmHandler = alarmHandler - self._notifyOnMissed = False - self._notifyOnVoicemail = False - self._notifyOnSms = False - - self._callbackList = [] - self._accountViewNumberDisplay = widgetTree.get_widget("gcnumber_display") - self._callbackSelectButton = widgetTree.get_widget("callbackSelectButton") - self._onCallbackSelectChangedId = 0 - - self._notifyCheckbox = widgetTree.get_widget("notifyCheckbox") - self._minutesEntryButton = widgetTree.get_widget("minutesEntryButton") - self._missedCheckbox = widgetTree.get_widget("missedCheckbox") - self._voicemailCheckbox = widgetTree.get_widget("voicemailCheckbox") - self._smsCheckbox = widgetTree.get_widget("smsCheckbox") - self._onNotifyToggled = 0 - self._onMinutesChanged = 0 - self._onMissedToggled = 0 - self._onVoicemailToggled = 0 - self._onSmsToggled = 0 - self._applyAlarmTimeoutId = None - - self._window = gtk_toolbox.find_parent_window(self._minutesEntryButton) - self._defaultCallback = "" - - def enable(self): - assert self._backend.is_authed(), "Attempting to enable backend while not logged in" - - self._accountViewNumberDisplay.set_use_markup(True) - self.set_account_number("") - - del self._callbackList[:] - self._onCallbackSelectChangedId = self._callbackSelectButton.connect("clicked", self._on_callbackentry_clicked) - - if self._alarmHandler is not None: - self._notifyCheckbox.set_active(self._alarmHandler.isEnabled) - self._minutesEntryButton.set_label("%d minutes" % self._alarmHandler.recurrence) - self._missedCheckbox.set_active(self._notifyOnMissed) - self._voicemailCheckbox.set_active(self._notifyOnVoicemail) - self._smsCheckbox.set_active(self._notifyOnSms) - - self._onNotifyToggled = self._notifyCheckbox.connect("toggled", self._on_notify_toggled) - self._onMinutesChanged = self._minutesEntryButton.connect("clicked", self._on_minutes_clicked) - self._onMissedToggled = self._missedCheckbox.connect("toggled", self._on_missed_toggled) - self._onVoicemailToggled = self._voicemailCheckbox.connect("toggled", self._on_voicemail_toggled) - self._onSmsToggled = self._smsCheckbox.connect("toggled", self._on_sms_toggled) - else: - self._notifyCheckbox.set_sensitive(False) - self._minutesEntryButton.set_sensitive(False) - self._missedCheckbox.set_sensitive(False) - self._voicemailCheckbox.set_sensitive(False) - self._smsCheckbox.set_sensitive(False) - - self.update(force=True) - - def disable(self): - self._callbackSelectButton.disconnect(self._onCallbackSelectChangedId) - self._onCallbackSelectChangedId = 0 - - if self._alarmHandler is not None: - self._notifyCheckbox.disconnect(self._onNotifyToggled) - self._minutesEntryButton.disconnect(self._onMinutesChanged) - self._missedCheckbox.disconnect(self._onNotifyToggled) - self._voicemailCheckbox.disconnect(self._onNotifyToggled) - self._smsCheckbox.disconnect(self._onNotifyToggled) - self._onNotifyToggled = 0 - self._onMinutesChanged = 0 - self._onMissedToggled = 0 - self._onVoicemailToggled = 0 - self._onSmsToggled = 0 - else: - self._notifyCheckbox.set_sensitive(True) - self._minutesEntryButton.set_sensitive(True) - self._missedCheckbox.set_sensitive(True) - self._voicemailCheckbox.set_sensitive(True) - self._smsCheckbox.set_sensitive(True) - - self.clear() - del self._callbackList[:] - - def get_selected_callback_number(self): - currentLabel = self._callbackSelectButton.get_label() - if currentLabel is not None: - return make_ugly(currentLabel) - else: - return "" - - def set_account_number(self, number): - """ - Displays current account number - """ - self._accountViewNumberDisplay.set_label("%s" % (number)) - - def update(self, force = False): - if not force and self._isPopulated: - return False - self._populate_callback_combo() - self.set_account_number(self._backend.get_account_number()) - return True - - def clear(self): - self._callbackSelectButton.set_label("") - self.set_account_number("") - self._isPopulated = False - - def save_everything(self): - raise NotImplementedError - - @staticmethod - def name(): - return "Account Info" - - def load_settings(self, config, section): - self._defaultCallback = config.get(section, "callback") - self._notifyOnMissed = config.getboolean(section, "notifyOnMissed") - self._notifyOnVoicemail = config.getboolean(section, "notifyOnVoicemail") - self._notifyOnSms = config.getboolean(section, "notifyOnSms") - - def save_settings(self, config, section): - """ - @note Thread Agnostic - """ - callback = self.get_selected_callback_number() - config.set(section, "callback", callback) - config.set(section, "notifyOnMissed", repr(self._notifyOnMissed)) - config.set(section, "notifyOnVoicemail", repr(self._notifyOnVoicemail)) - config.set(section, "notifyOnSms", repr(self._notifyOnSms)) - - def _populate_callback_combo(self): - self._isPopulated = True - del self._callbackList[:] - try: - callbackNumbers = self._backend.get_callback_numbers() - except Exception, e: - self._errorDisplay.push_exception() - self._isPopulated = False - return - - for number, description in callbackNumbers.iteritems(): - self._callbackList.append(make_pretty(number)) - - if not self.get_selected_callback_number(): - self._set_callback_number(self._defaultCallback) - - def _set_callback_number(self, number): - try: - if not self._backend.is_valid_syntax(number) and 0 < len(number): - self._errorDisplay.push_message("%s is not a valid callback number" % number) - elif number == self._backend.get_callback_number(): - logging.warning( - "Callback number already is %s" % ( - self._backend.get_callback_number(), - ), - ) - else: - self._backend.set_callback_number(number) - assert make_ugly(number) == make_ugly(self._backend.get_callback_number()), "Callback number should be %s but instead is %s" % ( - make_pretty(number), make_pretty(self._backend.get_callback_number()) - ) - self._callbackSelectButton.set_label(make_pretty(number)) - logging.info( - "Callback number set to %s" % ( - self._backend.get_callback_number(), - ), - ) - except Exception, e: - self._errorDisplay.push_exception() - - def _update_alarm_settings(self, recurrence): - try: - isEnabled = self._notifyCheckbox.get_active() - if isEnabled != self._alarmHandler.isEnabled or recurrence != self._alarmHandler.recurrence: - self._alarmHandler.apply_settings(isEnabled, recurrence) - finally: - self.save_everything() - self._notifyCheckbox.set_active(self._alarmHandler.isEnabled) - self._minutesEntryButton.set_label("%d Minutes" % self._alarmHandler.recurrence) - - def _on_callbackentry_clicked(self, *args): - try: - actualSelection = make_pretty(self.get_selected_callback_number()) - - userSelection = hildonize.touch_selector_entry( - self._window, - "Callback Number", - self._callbackList, - actualSelection, - ) - number = make_ugly(userSelection) - self._set_callback_number(number) - except RuntimeError, e: - logging.exception("%s" % str(e)) - except Exception, e: - self._errorDisplay.push_exception() - - def _on_notify_toggled(self, *args): - try: - if self._applyAlarmTimeoutId is not None: - gobject.source_remove(self._applyAlarmTimeoutId) - self._applyAlarmTimeoutId = None - self._applyAlarmTimeoutId = gobject.timeout_add(500, self._on_apply_timeout) - except Exception, e: - self._errorDisplay.push_exception() - - def _on_minutes_clicked(self, *args): - recurrenceChoices = [ - (1, "1 minute"), - (2, "2 minutes"), - (3, "3 minutes"), - (5, "5 minutes"), - (8, "8 minutes"), - (10, "10 minutes"), - (15, "15 minutes"), - (30, "30 minutes"), - (45, "45 minutes"), - (60, "1 hour"), - (3*60, "3 hours"), - (6*60, "6 hours"), - (12*60, "12 hours"), - ] - try: - actualSelection = self._alarmHandler.recurrence - - closestSelectionIndex = 0 - for i, possible in enumerate(recurrenceChoices): - if possible[0] <= actualSelection: - closestSelectionIndex = i - recurrenceIndex = hildonize.touch_selector( - self._window, - "Minutes", - (("%s" % m[1]) for m in recurrenceChoices), - closestSelectionIndex, - ) - recurrence = recurrenceChoices[recurrenceIndex][0] - - self._update_alarm_settings(recurrence) - except RuntimeError, e: - logging.exception("%s" % str(e)) - except Exception, e: - self._errorDisplay.push_exception() - - def _on_apply_timeout(self, *args): - try: - self._applyAlarmTimeoutId = None - - self._update_alarm_settings(self._alarmHandler.recurrence) - except Exception, e: - self._errorDisplay.push_exception() - return False - - def _on_missed_toggled(self, *args): - try: - self._notifyOnMissed = self._missedCheckbox.get_active() - self.save_everything() - except Exception, e: - self._errorDisplay.push_exception() - - def _on_voicemail_toggled(self, *args): - try: - self._notifyOnVoicemail = self._voicemailCheckbox.get_active() - self.save_everything() - except Exception, e: - self._errorDisplay.push_exception() - - def _on_sms_toggled(self, *args): - try: - self._notifyOnSms = self._smsCheckbox.get_active() - self.save_everything() - except Exception, e: - self._errorDisplay.push_exception() - - -class RecentCallsView(object): - - NUMBER_IDX = 0 - DATE_IDX = 1 - ACTION_IDX = 2 - FROM_IDX = 3 - - def __init__(self, widgetTree, backend, errorDisplay): - self._errorDisplay = errorDisplay - self._backend = backend - - self._isPopulated = False - self._recentmodel = gtk.ListStore( - gobject.TYPE_STRING, # number - gobject.TYPE_STRING, # date - gobject.TYPE_STRING, # action - gobject.TYPE_STRING, # from - ) - self._recentview = widgetTree.get_widget("recentview") - self._recentviewselection = None - self._onRecentviewRowActivatedId = 0 - - textrenderer = gtk.CellRendererText() - textrenderer.set_property("yalign", 0) - self._dateColumn = gtk.TreeViewColumn("Date") - self._dateColumn.pack_start(textrenderer, expand=True) - self._dateColumn.add_attribute(textrenderer, "text", self.DATE_IDX) - - textrenderer = gtk.CellRendererText() - textrenderer.set_property("yalign", 0) - self._actionColumn = gtk.TreeViewColumn("Action") - self._actionColumn.pack_start(textrenderer, expand=True) - self._actionColumn.add_attribute(textrenderer, "text", self.ACTION_IDX) - - textrenderer = gtk.CellRendererText() - textrenderer.set_property("yalign", 0) - textrenderer.set_property("ellipsize", pango.ELLIPSIZE_END) - textrenderer.set_property("width-chars", len("1 (555) 555-1234")) - self._numberColumn = gtk.TreeViewColumn("Number") - self._numberColumn.pack_start(textrenderer, expand=True) - self._numberColumn.add_attribute(textrenderer, "text", self.NUMBER_IDX) - - textrenderer = gtk.CellRendererText() - textrenderer.set_property("yalign", 0) - hildonize.set_cell_thumb_selectable(textrenderer) - self._nameColumn = gtk.TreeViewColumn("From") - self._nameColumn.pack_start(textrenderer, expand=True) - self._nameColumn.add_attribute(textrenderer, "text", self.FROM_IDX) - self._nameColumn.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) - - self._window = gtk_toolbox.find_parent_window(self._recentview) - self._phoneTypeSelector = PhoneTypeSelector(widgetTree, self._backend) - - self._updateSink = gtk_toolbox.threaded_stage( - gtk_toolbox.comap( - self._idly_populate_recentview, - gtk_toolbox.null_sink(), - ) - ) - - def enable(self): - assert self._backend.is_authed(), "Attempting to enable backend while not logged in" - self._recentview.set_model(self._recentmodel) - - self._recentview.append_column(self._dateColumn) - self._recentview.append_column(self._actionColumn) - self._recentview.append_column(self._numberColumn) - self._recentview.append_column(self._nameColumn) - self._recentviewselection = self._recentview.get_selection() - self._recentviewselection.set_mode(gtk.SELECTION_SINGLE) - - self._onRecentviewRowActivatedId = self._recentview.connect("row-activated", self._on_recentview_row_activated) - - def disable(self): - self._recentview.disconnect(self._onRecentviewRowActivatedId) - - self.clear() - - self._recentview.remove_column(self._dateColumn) - self._recentview.remove_column(self._actionColumn) - self._recentview.remove_column(self._nameColumn) - self._recentview.remove_column(self._numberColumn) - self._recentview.set_model(None) - - def number_selected(self, action, number, message): - """ - @note Actual dial function is patched in later - """ - raise NotImplementedError("Horrible unknown error has occurred") - - def update(self, force = False): - if not force and self._isPopulated: - return False - self._updateSink.send(()) - return True - - def clear(self): - self._isPopulated = False - self._recentmodel.clear() - - @staticmethod - def name(): - return "Recent Calls" - - def load_settings(self, config, section): - pass - - def save_settings(self, config, section): - """ - @note Thread Agnostic - """ - pass - - def _idly_populate_recentview(self): - with gtk_toolbox.gtk_lock(): - banner = hildonize.show_busy_banner_start(self._window, "Loading Recent History") - try: - self._recentmodel.clear() - self._isPopulated = True - - try: - recentItems = self._backend.get_recent() - except Exception, e: - self._errorDisplay.push_exception_with_lock() - self._isPopulated = False - recentItems = [] - - for personName, phoneNumber, date, action in recentItems: - if not personName: - personName = "Unknown" - date = abbrev_relative_date(date) - prettyNumber = phoneNumber[2:] if phoneNumber.startswith("+1") else phoneNumber - prettyNumber = make_pretty(prettyNumber) - item = (prettyNumber, date, action.capitalize(), personName) - with gtk_toolbox.gtk_lock(): - self._recentmodel.append(item) - except Exception, e: - self._errorDisplay.push_exception_with_lock() - finally: - with gtk_toolbox.gtk_lock(): - hildonize.show_busy_banner_end(banner) - - return False - - def _on_recentview_row_activated(self, treeview, path, view_column): - try: - model, itr = self._recentviewselection.get_selected() - if not itr: - return - - number = self._recentmodel.get_value(itr, self.NUMBER_IDX) - number = make_ugly(number) - contactPhoneNumbers = [("Phone", number)] - description = self._recentmodel.get_value(itr, self.FROM_IDX) - - action, phoneNumber, message = self._phoneTypeSelector.run( - contactPhoneNumbers, - messages = (description, ), - parent = self._window, - ) - if action == PhoneTypeSelector.ACTION_CANCEL: - return - assert phoneNumber, "A lack of phone number exists" - - self.number_selected(action, phoneNumber, message) - self._recentviewselection.unselect_all() - except Exception, e: - self._errorDisplay.push_exception() - - -class MessagesView(object): - - NUMBER_IDX = 0 - DATE_IDX = 1 - HEADER_IDX = 2 - MESSAGE_IDX = 3 - MESSAGES_IDX = 4 - - def __init__(self, widgetTree, backend, errorDisplay): - self._errorDisplay = errorDisplay - self._backend = backend - - self._isPopulated = False - self._messagemodel = gtk.ListStore( - gobject.TYPE_STRING, # number - gobject.TYPE_STRING, # date - gobject.TYPE_STRING, # header - gobject.TYPE_STRING, # message - object, # messages - ) - self._messageview = widgetTree.get_widget("messages_view") - self._messageviewselection = None - self._onMessageviewRowActivatedId = 0 - - self._messageRenderer = gtk.CellRendererText() - self._messageRenderer.set_property("wrap-mode", pango.WRAP_WORD) - self._messageRenderer.set_property("wrap-width", 500) - self._messageColumn = gtk.TreeViewColumn("Messages") - self._messageColumn.pack_start(self._messageRenderer, expand=True) - self._messageColumn.add_attribute(self._messageRenderer, "markup", self.MESSAGE_IDX) - self._messageColumn.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) - - self._window = gtk_toolbox.find_parent_window(self._messageview) - self._phoneTypeSelector = PhoneTypeSelector(widgetTree, self._backend) - - self._updateSink = gtk_toolbox.threaded_stage( - gtk_toolbox.comap( - self._idly_populate_messageview, - gtk_toolbox.null_sink(), - ) - ) - - def enable(self): - assert self._backend.is_authed(), "Attempting to enable backend while not logged in" - self._messageview.set_model(self._messagemodel) - self._messageview.set_headers_visible(False) - - self._messageview.append_column(self._messageColumn) - self._messageviewselection = self._messageview.get_selection() - self._messageviewselection.set_mode(gtk.SELECTION_SINGLE) - - self._onMessageviewRowActivatedId = self._messageview.connect("row-activated", self._on_messageview_row_activated) - - def disable(self): - self._messageview.disconnect(self._onMessageviewRowActivatedId) - - self.clear() - - self._messageview.remove_column(self._messageColumn) - self._messageview.set_model(None) - - def number_selected(self, action, number, message): - """ - @note Actual dial function is patched in later - """ - raise NotImplementedError("Horrible unknown error has occurred") - - def update(self, force = False): - if not force and self._isPopulated: - return False - self._updateSink.send(()) - return True - - def clear(self): - self._isPopulated = False - self._messagemodel.clear() - - @staticmethod - def name(): - return "Messages" - - def load_settings(self, config, section): - pass - - def save_settings(self, config, section): - """ - @note Thread Agnostic - """ - pass - - def _idly_populate_messageview(self): - with gtk_toolbox.gtk_lock(): - banner = hildonize.show_busy_banner_start(self._window, "Loading Messages") - try: - self._messagemodel.clear() - self._isPopulated = True - - try: - messageItems = self._backend.get_messages() - except Exception, e: - self._errorDisplay.push_exception_with_lock() - self._isPopulated = False - messageItems = [] - - for header, number, relativeDate, messages in messageItems: - prettyNumber = number[2:] if number.startswith("+1") else number - prettyNumber = make_pretty(prettyNumber) - - firstMessage = "%s - %s (%s)" % (header, prettyNumber, relativeDate) - newMessages = [firstMessage] - newMessages.extend(messages) - - number = make_ugly(number) - - row = (number, relativeDate, header, "\n".join(newMessages), newMessages) - with gtk_toolbox.gtk_lock(): - self._messagemodel.append(row) - except Exception, e: - self._errorDisplay.push_exception_with_lock() - finally: - with gtk_toolbox.gtk_lock(): - hildonize.show_busy_banner_end(banner) - - return False - - def _on_messageview_row_activated(self, treeview, path, view_column): - try: - model, itr = self._messageviewselection.get_selected() - if not itr: - return - - contactPhoneNumbers = [("Phone", self._messagemodel.get_value(itr, self.NUMBER_IDX))] - description = self._messagemodel.get_value(itr, self.MESSAGES_IDX) - - action, phoneNumber, message = self._phoneTypeSelector.run( - contactPhoneNumbers, - messages = description, - parent = self._window, - ) - if action == PhoneTypeSelector.ACTION_CANCEL: - return - assert phoneNumber, "A lock of phone number exists" - - self.number_selected(action, phoneNumber, message) - self._messageviewselection.unselect_all() - except Exception, e: - self._errorDisplay.push_exception() - - -class ContactsView(object): - - def __init__(self, widgetTree, backend, errorDisplay): - self._errorDisplay = errorDisplay - self._backend = backend - - self._addressBook = None - self._selectedComboIndex = 0 - self._addressBookFactories = [null_backend.NullAddressBook()] - - self._booksList = [] - self._bookSelectionButton = widgetTree.get_widget("addressbookSelectButton") - - self._isPopulated = False - self._contactsmodel = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING) - self._contactsviewselection = None - self._contactsview = widgetTree.get_widget("contactsview") - - self._contactColumn = gtk.TreeViewColumn("Contact") - displayContactSource = False - if displayContactSource: - textrenderer = gtk.CellRendererText() - self._contactColumn.pack_start(textrenderer, expand=False) - self._contactColumn.add_attribute(textrenderer, 'text', 0) - textrenderer = gtk.CellRendererText() - hildonize.set_cell_thumb_selectable(textrenderer) - self._contactColumn.pack_start(textrenderer, expand=True) - self._contactColumn.add_attribute(textrenderer, 'text', 1) - textrenderer = gtk.CellRendererText() - self._contactColumn.pack_start(textrenderer, expand=True) - self._contactColumn.add_attribute(textrenderer, 'text', 4) - self._contactColumn.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) - self._contactColumn.set_sort_column_id(1) - self._contactColumn.set_visible(True) - - self._onContactsviewRowActivatedId = 0 - self._onAddressbookButtonChangedId = 0 - self._window = gtk_toolbox.find_parent_window(self._contactsview) - self._phoneTypeSelector = PhoneTypeSelector(widgetTree, self._backend) - - self._updateSink = gtk_toolbox.threaded_stage( - gtk_toolbox.comap( - self._idly_populate_contactsview, - gtk_toolbox.null_sink(), - ) - ) - - def enable(self): - assert self._backend.is_authed(), "Attempting to enable backend while not logged in" - - self._contactsview.set_model(self._contactsmodel) - self._contactsview.append_column(self._contactColumn) - self._contactsviewselection = self._contactsview.get_selection() - self._contactsviewselection.set_mode(gtk.SELECTION_SINGLE) - - del self._booksList[:] - for (factoryId, bookId), (factoryName, bookName) in self.get_addressbooks(): - if factoryName and bookName: - entryName = "%s: %s" % (factoryName, bookName) - elif factoryName: - entryName = factoryName - elif bookName: - entryName = bookName - else: - entryName = "Bad name (%d)" % factoryId - row = (str(factoryId), bookId, entryName) - self._booksList.append(row) - - self._onContactsviewRowActivatedId = self._contactsview.connect("row-activated", self._on_contactsview_row_activated) - self._onAddressbookButtonChangedId = self._bookSelectionButton.connect("clicked", self._on_addressbook_button_changed) - - if len(self._booksList) <= self._selectedComboIndex: - self._selectedComboIndex = 0 - self._bookSelectionButton.set_label(self._booksList[self._selectedComboIndex][2]) - - selectedFactoryId = self._booksList[self._selectedComboIndex][0] - selectedBookId = self._booksList[self._selectedComboIndex][1] - self.open_addressbook(selectedFactoryId, selectedBookId) - - def disable(self): - self._contactsview.disconnect(self._onContactsviewRowActivatedId) - self._bookSelectionButton.disconnect(self._onAddressbookButtonChangedId) - - self.clear() - - self._bookSelectionButton.set_label("") - self._contactsview.set_model(None) - self._contactsview.remove_column(self._contactColumn) - - def number_selected(self, action, number, message): - """ - @note Actual dial function is patched in later - """ - raise NotImplementedError("Horrible unknown error has occurred") - - def get_addressbooks(self): - """ - @returns Iterable of ((Factory Id, Book Id), (Factory Name, Book Name)) - """ - for i, factory in enumerate(self._addressBookFactories): - for bookFactory, bookId, bookName in factory.get_addressbooks(): - yield (str(i), bookId), (factory.factory_name(), bookName) - - def open_addressbook(self, bookFactoryId, bookId): - bookFactoryIndex = int(bookFactoryId) - addressBook = self._addressBookFactories[bookFactoryIndex].open_addressbook(bookId) - - forceUpdate = True if addressBook is not self._addressBook else False - - self._addressBook = addressBook - self.update(force=forceUpdate) - - def update(self, force = False): - if not force and self._isPopulated: - return False - self._updateSink.send(()) - return True - - def clear(self): - self._isPopulated = False - self._contactsmodel.clear() - for factory in self._addressBookFactories: - factory.clear_caches() - self._addressBook.clear_caches() - - def append(self, book): - self._addressBookFactories.append(book) - - def extend(self, books): - self._addressBookFactories.extend(books) - - @staticmethod - def name(): - return "Contacts" - - def load_settings(self, config, sectionName): - try: - self._selectedComboIndex = config.getint(sectionName, "selectedAddressbook") - except ConfigParser.NoOptionError: - self._selectedComboIndex = 0 - - def save_settings(self, config, sectionName): - config.set(sectionName, "selectedAddressbook", str(self._selectedComboIndex)) - - def _idly_populate_contactsview(self): - with gtk_toolbox.gtk_lock(): - banner = hildonize.show_busy_banner_start(self._window, "Loading Contacts") - try: - addressBook = None - while addressBook is not self._addressBook: - addressBook = self._addressBook - with gtk_toolbox.gtk_lock(): - self._contactsview.set_model(None) - self.clear() - - try: - contacts = addressBook.get_contacts() - except Exception, e: - contacts = [] - self._isPopulated = False - self._errorDisplay.push_exception_with_lock() - for contactId, contactName in contacts: - contactType = (addressBook.contact_source_short_name(contactId), ) - self._contactsmodel.append(contactType + (contactName, "", contactId) + ("", )) - - with gtk_toolbox.gtk_lock(): - self._contactsview.set_model(self._contactsmodel) - - self._isPopulated = True - except Exception, e: - self._errorDisplay.push_exception_with_lock() - finally: - with gtk_toolbox.gtk_lock(): - hildonize.show_busy_banner_end(banner) - return False - - def _on_addressbook_button_changed(self, *args, **kwds): - try: - try: - newSelectedComboIndex = hildonize.touch_selector( - self._window, - "Addressbook", - (("%s" % m[2]) for m in self._booksList), - self._selectedComboIndex, - ) - except RuntimeError: - return - - selectedFactoryId = self._booksList[newSelectedComboIndex][0] - selectedBookId = self._booksList[newSelectedComboIndex][1] - self.open_addressbook(selectedFactoryId, selectedBookId) - self._selectedComboIndex = newSelectedComboIndex - self._bookSelectionButton.set_label(self._booksList[self._selectedComboIndex][2]) - except Exception, e: - self._errorDisplay.push_exception() - - def _on_contactsview_row_activated(self, treeview, path, view_column): - try: - model, itr = self._contactsviewselection.get_selected() - if not itr: - return - - contactId = self._contactsmodel.get_value(itr, 3) - contactName = self._contactsmodel.get_value(itr, 1) - try: - contactDetails = self._addressBook.get_contact_details(contactId) - except Exception, e: - contactDetails = [] - self._errorDisplay.push_exception() - contactPhoneNumbers = [phoneNumber for phoneNumber in contactDetails] - - if len(contactPhoneNumbers) == 0: - return - - action, phoneNumber, message = self._phoneTypeSelector.run( - contactPhoneNumbers, - messages = (contactName, ), - parent = self._window, - ) - if action == PhoneTypeSelector.ACTION_CANCEL: - return - assert phoneNumber, "A lack of phone number exists" - - self.number_selected(action, phoneNumber, message) - self._contactsviewselection.unselect_all() - except Exception, e: - self._errorDisplay.push_exception() diff --git a/src/hildonize.py b/src/hildonize.py deleted file mode 100755 index 391b365..0000000 --- a/src/hildonize.py +++ /dev/null @@ -1,646 +0,0 @@ -#!/usr/bin/env python - - -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_title(window, title): - pass - - -def _null_set_application_title(window, title): - window.set_title(title) - - -if IS_HILDON_SUPPORTED: - set_application_title = _hildon_set_application_title -else: - set_application_title = _null_set_application_title - - -def _fremantle_hildonize_window(app, window): - oldWindow = window - newWindow = hildon.StackableWindow() - oldWindow.get_child().reparent(newWindow) - app.add_window(newWindow) - return newWindow - - -def _hildon_hildonize_window(app, window): - oldWindow = window - newWindow = hildon.Window() - 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, buttons): - appMenu = hildon.AppMenu() - for button in buttons: - appMenu.append(button) - window.set_app_menu(appMenu) - gtkMenu.get_parent().remove(gtkMenu) - return appMenu - - -def _hildon_hildonize_menu(window, gtkMenu, ignoredButtons): - 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, ignoredButtons): - 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_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 _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_mark_window_rotatable(window): - # gtk documentation is unclear whether this does a "=" or a "|=" - window.set_flags(hildon.HILDON_PORTRAIT_MODE_SUPPORT) - - -def _null_mark_window_rotatable(window): - pass - - -try: - hildon.HILDON_PORTRAIT_MODE_SUPPORT - mark_window_rotatable = _hildon_mark_window_rotatable -except AttributeError: - mark_window_rotatable = _null_mark_window_rotatable - - -def _hildon_window_to_portrait(window): - # gtk documentation is unclear whether this does a "=" or a "|=" - window.set_flags(hildon.HILDON_PORTRAIT_MODE_SUPPORT) - - -def _hildon_window_to_landscape(window): - # gtk documentation is unclear whether this does a "=" or a "&= ~" - window.unset_flags(hildon.HILDON_PORTRAIT_MODE_REQUEST) - - -def _null_window_to_portrait(window): - pass - - -def _null_window_to_landscape(window): - pass - - -try: - hildon.HILDON_PORTRAIT_MODE_SUPPORT - hildon.HILDON_PORTRAIT_MODE_REQUEST - - 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() - 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() - finally: - dialog.hide() - - 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) - - -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() - finally: - dialog.hide() - - 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) - - -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() - finally: - dialog.hide() - - 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) - - -def _on_null_touch_selector_activated(treeView, path, column, dialog): - dialog.response(gtk.RESPONSE_OK) - - -def _null_touch_selector(parent, title, items, defaultIndex = -1): - 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) - hildonize_scrollwindow(scrolledWin) - - 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) - parentSize = parent.get_size() - dialog.resize(parentSize[0], max(parentSize[1]-100, 100)) - treeView.connect("row-activated", _on_null_touch_selector_activated, dialog) - - try: - dialog.show_all() - response = dialog.run() - finally: - dialog.hide() - - if response == gtk.RESPONSE_OK: - model, itr = selection.get_selected() - if itr is None: - raise RuntimeError("No selection made") - return model.get_path(itr)[0] - elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT: - raise RuntimeError("User cancelled request") - else: - raise RuntimeError("Unrecognized response %r", response) - - -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 - 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: - selectedIndex = selector.get_active(0) - 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_activated(entry, dialog, customEntry, result): - dialog.response(gtk.RESPONSE_OK) - result.append(customEntry.get_text()) - - -def _on_null_touch_selector_entry_tree_activated(treeView, path, column, dialog, selection, result): - dialog.response(gtk.RESPONSE_OK) - model, itr = selection.get_selected() - if itr is not None: - result.append(model.get_value(itr, 0)) - - -def _null_touch_selector_entry(parent, title, items, defaultItem): - 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) - hildonize_scrollwindow(scrolledWin) - - 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_CANCEL, gtk.RESPONSE_CANCEL), - ) - dialog.set_default_response(gtk.RESPONSE_CANCEL) - dialog.get_child().add(layout) - parentSize = parent.get_size() - dialog.resize(parentSize[0], max(parentSize[1]-100, 100)) - - if 0 < defaultIndex: - selection.select_path((defaultIndex, )) - else: - customEntry.set_text(defaultItem) - result = [] - customEntry.connect("activate", _on_null_touch_selector_entry_entry_activated, dialog, customEntry, result) - treeView.connect("row-activated", _on_null_touch_selector_entry_tree_activated, dialog, selection, result) - - try: - dialog.show_all() - response = dialog.run() - finally: - dialog.hide() - - if response == gtk.RESPONSE_OK: - model, itr = selection.get_selected() - if len(result) != 1: - raise RuntimeError("No selection made") - else: - return result[0] - elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT: - raise RuntimeError("User cancelled request") - else: - raise RuntimeError("Unrecognized response %r", response) - - -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: - print touch_selector(win, "Test", ["A", "B", "C", "D"], 2) - if True: - print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "C") - print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "Blah") - if False: - import pprint - name, value = "", "" - goodLocals = [ - (name, value) for (name, value) in locals().iteritems() - if not name.startswith("_") - ] - pprint.pprint(goodLocals) - if False: - import time - show_information_banner(win, "Hello World") - time.sleep(5) - if False: - import time - banner = show_busy_banner_start(win, "Hello World") - time.sleep(5) - show_busy_banner_end(banner) diff --git a/src/led_handler.py b/src/led_handler.py deleted file mode 100755 index 211036e..0000000 --- a/src/led_handler.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python - -import dbus - - -class LedHandler(object): - - def __init__(self): - self._bus = dbus.SystemBus() - self._rawMceRequest = self._bus.get_object("com.nokia.mce", "/com/nokia/mce/request") - self._mceRequest = dbus.Interface(self._rawMceRequest, dbus_interface="com.nokia.mce.request") - - self._ledPattern = "PatternCommunicationChat" - - def on(self): - self._mceRequest.req_led_pattern_activate(self._ledPattern) - - def off(self): - self._mceRequest.req_led_pattern_deactivate(self._ledPattern) - - -if __name__ == "__main__": - leds = LedHandler() - leds.off() diff --git a/src/null_views.py b/src/null_views.py deleted file mode 100644 index 41d759a..0000000 --- a/src/null_views.py +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/python2.5 - -""" -DialCentral - Front end for Google's Grand Central service. -Copyright (C) 2008 Mark Bergman bergman AT merctech DOT com - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -""" - -import gobject -import gtk - - -class Dialpad(object): - - def __init__(self, widgetTree): - self._numberdisplay = widgetTree.get_widget("numberdisplay") - self._dialButton = widgetTree.get_widget("dial") - self._smsButton = widgetTree.get_widget("sms") - - def enable(self): - self._dialButton.set_sensitive(False) - self._smsButton.set_sensitive(False) - - def disable(self): - self._dialButton.set_sensitive(True) - self._smsButton.set_sensitive(True) - - @staticmethod - def name(): - return "Dialpad" - - def load_settings(self, config, sectionName): - pass - - def save_settings(self, config, sectionName): - """ - @note Thread Agnostic - """ - pass - - -class AccountInfo(object): - - def __init__(self, widgetTree): - self._callbackList = gtk.ListStore(gobject.TYPE_STRING) - self._accountViewNumberDisplay = widgetTree.get_widget("gcnumber_display") - self._callbackSelectButton = widgetTree.get_widget("callbackSelectButton") - self._clearCookiesButton = widgetTree.get_widget("clearcookies") - - self._notifyCheckbox = widgetTree.get_widget("notifyCheckbox") - self._minutesEntryButton = widgetTree.get_widget("minutesEntryButton") - self._missedCheckbox = widgetTree.get_widget("missedCheckbox") - self._voicemailCheckbox = widgetTree.get_widget("voicemailCheckbox") - self._smsCheckbox = widgetTree.get_widget("smsCheckbox") - - def enable(self): - self._callbackSelectButton.set_sensitive(False) - self._clearCookiesButton.set_sensitive(False) - - self._notifyCheckbox.set_sensitive(False) - self._minutesEntryButton.set_sensitive(False) - self._missedCheckbox.set_sensitive(False) - self._voicemailCheckbox.set_sensitive(False) - self._smsCheckbox.set_sensitive(False) - - self._accountViewNumberDisplay.set_label("") - - def disable(self): - self._callbackSelectButton.set_sensitive(True) - self._clearCookiesButton.set_sensitive(True) - - self._notifyCheckbox.set_sensitive(True) - self._minutesEntryButton.set_sensitive(True) - self._missedCheckbox.set_sensitive(True) - self._voicemailCheckbox.set_sensitive(True) - self._smsCheckbox.set_sensitive(True) - - @staticmethod - def update(force = False): - return False - - @staticmethod - def clear(): - pass - - @staticmethod - def name(): - return "Account Info" - - def load_settings(self, config, sectionName): - pass - - def save_settings(self, config, sectionName): - """ - @note Thread Agnostic - """ - pass - - -class RecentCallsView(object): - - def __init__(self, widgetTree): - pass - - def enable(self): - pass - - def disable(self): - pass - - def update(self, force = False): - return False - - @staticmethod - def clear(): - pass - - @staticmethod - def name(): - return "Recent Calls" - - def load_settings(self, config, sectionName): - pass - - def save_settings(self, config, sectionName): - """ - @note Thread Agnostic - """ - pass - - -class MessagesView(object): - - def __init__(self, widgetTree): - pass - - def enable(self): - pass - - def disable(self): - pass - - def update(self, force = False): - return False - - @staticmethod - def clear(): - pass - - @staticmethod - def name(): - return "Messages" - - def load_settings(self, config, sectionName): - pass - - def save_settings(self, config, sectionName): - """ - @note Thread Agnostic - """ - pass - - -class ContactsView(object): - - def __init__(self, widgetTree): - self._bookSelectionButton = widgetTree.get_widget("addressbookSelectButton") - - def enable(self): - self._bookSelectionButton.set_sensitive(False) - - def disable(self): - self._bookSelectionButton.set_sensitive(True) - - def update(self, force = False): - return False - - @staticmethod - def clear(): - pass - - @staticmethod - def name(): - return "Contacts" - - def load_settings(self, config, sectionName): - pass - - def save_settings(self, config, sectionName): - """ - @note Thread Agnostic - """ - pass diff --git a/support/dialcentral.desktop b/support/dialcentral.desktop deleted file mode 100644 index ce28c88..0000000 --- a/support/dialcentral.desktop +++ /dev/null @@ -1,7 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Version=1.0 -Type=Application -Name=DialCentral -Exec=/usr/bin/run-standalone.sh /usr/bin/dialcentral.py -Icon=dialcentral diff --git a/tests/basic_data/basic.csv b/tests/basic_data/basic.csv deleted file mode 100644 index 6ffd844..0000000 --- a/tests/basic_data/basic.csv +++ /dev/null @@ -1,2 +0,0 @@ -familyname,phone,addr1,addr2,addr3,addr4,name1,name2,name3,name4 -"Last, First","555-123-4567","1234 Foo St","Austin, Texas 78727","","","First " diff --git a/tests/basic_data/empty.csv b/tests/basic_data/empty.csv deleted file mode 100644 index e69de29..0000000 diff --git a/tests/basic_data/google.csv b/tests/basic_data/google.csv deleted file mode 100644 index 3fa4d3e..0000000 --- a/tests/basic_data/google.csv +++ /dev/null @@ -1,7 +0,0 @@ -Name,E-mail,Notes,Section 1 - Description,Section 1 - Email,Section 1 - IM,Section 1 - Phone,Section 1 - Mobile,Section 1 - Pager,Section 1 - Fax,Section 1 - Company,Section 1 - Title,Section 1 - Other,Section 1 - Address,Section 2 - Description,Section 2 - Email,Section 2 - IM,Section 2 - Phone,Section 2 - Mobile,Section 2 - Pager,Section 2 - Fax,Section 2 - Company,Section 2 - Title,Section 2 - Other,Section 2 - Address,Section 3 - Description,Section 3 - Email,Section 3 - IM,Section 3 - Phone,Section 3 - Mobile,Section 3 - Pager,Section 3 - Fax,Section 3 - Company,Section 3 - Title,Section 3 - Other,Section 3 - Address -First Last,name@domain.com,"Categories: Others - - -Categories: Others",Other,name2@domain.com,,,,,,,,,,Personal,name3@domain.com; name4@domain.com; name5@domain.com; name6@domain.com,,17471234567,5551234567,,,,,, -First1 Last,,"Categories: Friends -",Personal,,,,5557654321,,,,,, diff --git a/tests/basic_data/grandcentral.csv b/tests/basic_data/grandcentral.csv deleted file mode 100644 index 4808cf2..0000000 --- a/tests/basic_data/grandcentral.csv +++ /dev/null @@ -1,3 +0,0 @@ -Name,E-mail Address,Categories,Company,Job Title,Home Address,Home Phone,Mobile Phone,Business Phone,GrandCentral,Suffix,Title,Initials,Web Page,Notes -First Last,,Family,,,1234567 Foo St Austn Tx 78727,5559983254,5554023626,5559988899,,,,,, -First1 Last,,Others,,,,5556835460,,,,,,,, diff --git a/tests/basic_data/settings.ini b/tests/basic_data/settings.ini deleted file mode 100644 index d9a6c81..0000000 --- a/tests/basic_data/settings.ini +++ /dev/null @@ -1,37 +0,0 @@ -[1 - Contacts] - -[2 - Account Info] -callback = - -[1 - Recent Calls] - -[2 - Messages] - -[0 - Messages] - -[1 - Messages] - -[2 - Dialpad] - -[2 - Contacts] - -[0 - Recent Calls] - -[DialCentral] -active = 0 -bin_blob_0 = -bin_blob_1 = - -[1 - Account Info] -callback = - -[1 - Dialpad] - -[0 - Dialpad] - -[0 - Account Info] - -[0 - Contacts] - -[2 - Recent Calls] - diff --git a/tests/dummy_hildon/__init__.py b/tests/dummy_hildon/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/dummy_hildon/hildon.py b/tests/dummy_hildon/hildon.py deleted file mode 100644 index 331e979..0000000 --- a/tests/dummy_hildon/hildon.py +++ /dev/null @@ -1,35 +0,0 @@ -import gobject -import gtk - -class FileChooserDialog(gtk.FileChooserDialog): - """ - @bug The buttons currently don't do anything - """ - - def __init__(self, *args, **kwds): - super(FileChooserDialog, self).__init__(*args, **kwds) - self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) - self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) - - -class Program(object): - - def add_window(self, window): - pass - - -class Window(gtk.Window, object): - - def __init__(self): - super(Window, self).__init__(gtk.WINDOW_TOPLEVEL) - self.set_default_size(700, 500) - - def set_menu(self, menu): - self._hildonMenu = menu - - -gobject.type_register(Window) - - -def hildon_helper_set_thumb_scrollbar(widget, value): - pass diff --git a/tests/gc_samples/__init__.py b/tests/gc_samples/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/gc_samples/dump_cookies.py b/tests/gc_samples/dump_cookies.py deleted file mode 100755 index 810a03b..0000000 --- a/tests/gc_samples/dump_cookies.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python - -import os -import urllib -import urllib2 -import traceback -import warnings - -import sys -sys.path.append("../../src") - -import browser_emu -import gc_backend - -# Create Browser -browser = browser_emu.MozillaEmulator(1) -cookieFile = os.path.join(".", ".gc_cookies.txt") -browser.cookies.filename = cookieFile - -# Login -username = sys.argv[1] -password = sys.argv[2] - -loginPostData = urllib.urlencode({ - 'Email' : username, - 'Passwd' : password, - 'service': "grandcentral", - "ltmpl": "mobile", - "btmpl": "mobile", - "PersistentCookie": "yes", -}) - -try: - loginSuccessOrFailurePage = browser.download(gc_backend.GCDialer._loginURL, loginPostData) -except urllib2.URLError, e: - warnings.warn(traceback.format_exc()) - raise RuntimeError("%s is not accesible" % gc_backend.GCDialer._loginURL) - -forwardPage = browser.download(gc_backend.GCDialer._forwardselectURL) - -tokenGroup = gc_backend.GCDialer._accessTokenRe.search(forwardPage) -if tokenGroup is None: - print forwardPage - raise RuntimeError("Could not extract authentication token from GrandCentral") -token = tokenGroup.group(1) - - -with open("cookies.txt", "w") as f: - f.writelines( - "%s: %s\n" % (c.name, c.value) - for c in browser.cookies - ) diff --git a/tests/gc_samples/generate_gc_samples.py b/tests/gc_samples/generate_gc_samples.py deleted file mode 100755 index 0608ffd..0000000 --- a/tests/gc_samples/generate_gc_samples.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python - -import os -import urllib -import urllib2 -import traceback -import warnings - -import sys -sys.path.append("../../src") - -import browser_emu -import gc_backend - -webpages = [ - ("forward", gc_backend.GCDialer._forwardselectURL), - ("login", gc_backend.GCDialer._loginURL), - ("setforward", gc_backend.GCDialer._setforwardURL), - ("clicktocall", gc_backend.GCDialer._clicktocallURL), - ("recent", gc_backend.GCDialer._inboxallURL), - ("contacts", gc_backend.GCDialer._contactsURL), -] - - -# Create Browser -browser = browser_emu.MozillaEmulator(1) -cookieFile = os.path.join(".", ".gc_cookies.txt") -browser.cookies.filename = cookieFile - -# Get Pages -for name, url in webpages: - try: - page = browser.download(url) - except StandardError, e: - print e.message - continue - with open("not_loggedin_%s.txt" % name, "w") as f: - f.write(page) - -# Login -username = sys.argv[1] -password = sys.argv[2] - -loginPostData = urllib.urlencode({ - 'username' : username, - 'password' : password, -}) - -try: - loginSuccessOrFailurePage = browser.download(gc_backend.GCDialer._loginURL, loginPostData) -except urllib2.URLError, e: - warnings.warn(traceback.format_exc()) - raise RuntimeError("%s is not accesible" % gc_backend.GCDialer._loginURL) - -forwardPage = browser.download(gc_backend.GCDialer._forwardselectURL) - -tokenGroup = gc_backend.GCDialer._accessTokenRe.search(forwardPage) -if tokenGroup is None: - print "="*60 - print forwardPage - print "="*60 - raise RuntimeError("Could not extract authentication token from GrandCentral") -token = tokenGroup.group(1) - -# Get Pages -for name, url in webpages: - try: - page = browser.download(url) - except StandardError, e: - warnings.warn(traceback.format_exc()) - continue - print "Writing to file" - with open("loggedin_%s.txt" % name, "w") as f: - f.write(page) diff --git a/tests/test_file_backend.py b/tests/test_file_backend.py deleted file mode 100644 index edd6c85..0000000 --- a/tests/test_file_backend.py +++ /dev/null @@ -1,155 +0,0 @@ -from __future__ import with_statement - -import os -import warnings - -import test_utils - -import sys -sys.path.append("../src") - -import file_backend - - -def test_factory(): - warnings.simplefilter("always") - try: - csvPath = os.path.join(os.path.dirname(__file__), "basic_data") - factory = file_backend.FilesystemAddressBookFactory(csvPath) - assert factory.factory_name() == "File" - abooks = list(factory.get_addressbooks()) - abooks.sort() - assert len(abooks) == 4 - abookNames = [abook[2] for abook in abooks] - assert abookNames == ["basic", "empty", "google", "grandcentral"], "%s" % abookNames - - for abook_factory, abookId, abookName in abooks: - abook = abook_factory.open_addressbook(abookId) - assert isinstance(abook, file_backend.CsvAddressBook) - finally: - warnings.resetwarnings() - - -def test_nonexistent_csv(): - warnings.simplefilter("always") - try: - csvPath = os.path.join(os.path.dirname(__file__), "basic_data", "nonexistent.csv") - abook = file_backend.CsvAddressBook(csvPath) - - assert abook.factory_name() == "csv" - - contacts = list(abook.get_contacts()) - assert len(contacts) == 0 - finally: - warnings.resetwarnings() - - -def test_empty_csv(): - warnings.simplefilter("always") - try: - csvPath = os.path.join(os.path.dirname(__file__), "basic_data", "empty.csv") - abook = file_backend.CsvAddressBook(csvPath) - - assert abook.factory_name() == "csv" - - contacts = list(abook.get_contacts()) - assert len(contacts) == 0 - finally: - warnings.resetwarnings() - - -def test_basic_csv(): - warnings.simplefilter("always") - try: - csvPath = os.path.join(os.path.dirname(__file__), "basic_data", "basic.csv") - abook = file_backend.CsvAddressBook(csvPath) - - assert abook.factory_name() == "csv" - - contacts = list(abook.get_contacts()) - contacts.sort() - assert len(contacts) == 1 - - contactId, contactName = contacts[0] - assert contactName == "Last, First" - assert abook.contact_source_short_name(contactId) == "csv" - - details = list(abook.get_contact_details(contactId)) - assert len(details) == 1 - details.sort() - assert details == [("phone", "555-123-4567")], "%s" % details - finally: - warnings.resetwarnings() - - -def test_google_csv(): - warnings.simplefilter("always") - try: - csvPath = os.path.join(os.path.dirname(__file__), "basic_data", "google.csv") - abook = file_backend.CsvAddressBook(csvPath) - - assert abook.factory_name() == "csv" - - contacts = list(abook.get_contacts()) - contacts.sort() - assert len(contacts) == 2 - - contactId, contactName = contacts[0] - assert contactName == "First Last" - assert abook.contact_source_short_name(contactId) == "csv" - - details = list(abook.get_contact_details(contactId)) - assert len(details) == 2 - details.sort() - assert details == [ - ("Section 2 - Mobile", "5551234567"), - ("Section 2 - Phone", "17471234567"), - ], "%s" % details - - contactId, contactName = contacts[1] - assert contactName == "First1 Last" - assert abook.contact_source_short_name(contactId) == "csv" - - details = list(abook.get_contact_details(contactId)) - assert len(details) == 1 - details.sort() - assert details == [("Section 1 - Mobile", "5557654321")], "%s" % details - finally: - warnings.resetwarnings() - - -def test_grandcentral_csv(): - warnings.simplefilter("always") - try: - csvPath = os.path.join(os.path.dirname(__file__), "basic_data", "grandcentral.csv") - abook = file_backend.CsvAddressBook(csvPath) - - assert abook.factory_name() == "csv" - - contacts = list(abook.get_contacts()) - contacts.sort() - assert len(contacts) == 2 - - contactId, contactName = contacts[0] - assert contactName == "First Last" - assert abook.contact_source_short_name(contactId) == "csv" - - details = list(abook.get_contact_details(contactId)) - assert len(details) == 3 - details.sort() - assert details == [ - ("Business Phone", "5559988899"), - ("Home Phone", "5559983254"), - ("Mobile Phone", "5554023626"), - ], "%s" % details - - contactId, contactName = contacts[1] - assert contactName == "First1 Last" - assert abook.contact_source_short_name(contactId) == "csv" - - details = list(abook.get_contact_details(contactId)) - assert len(details) == 1 - details.sort() - assert details == [("Home Phone", "5556835460")], "%s" % details - finally: - warnings.resetwarnings() diff --git a/tests/test_gc_backend.py b/tests/test_gc_backend.py deleted file mode 100644 index e60e777..0000000 --- a/tests/test_gc_backend.py +++ /dev/null @@ -1,53 +0,0 @@ -from __future__ import with_statement - -import os -import warnings -import cookielib - -import test_utils - -import sys -sys.path.append("../src") - -import gc_backend - - -def generate_mock(cookiesSucceed, username, password): - - class MockModule(object): - - class MozillaEmulator(object): - - def __init__(self, trycount = 1): - self.cookies = cookielib.LWPCookieJar() - self.trycount = trycount - - def download(self, url, - postdata = None, extraheaders = None, forbid_redirect = False, - trycount = None, only_head = False, - ): - return "" - - return MockModule - - -def test_not_logged_in(): - correctUsername, correctPassword = "", "" - MockBrowserModule = generate_mock(False, correctUsername, correctPassword) - gc_backend.browser_emu, RealBrowser = MockBrowserModule, gc_backend.browser_emu - try: - backend = gc_backend.GCDialer() - assert not backend.is_authed() - assert not backend.login("bad_name", "bad_password") - backend.logout() - with test_utils.expected(RuntimeError): - backend.dial("5551234567") - with test_utils.expected(RuntimeError): - backend.send_sms("5551234567", "Hello World") - assert backend.get_account_number() == "", "%s" % backend.get_account_number() - backend.set_sane_callback() - assert backend.get_callback_number() == "" - recent = list(backend.get_recent()) - messages = list(backend.get_messages()) - finally: - gc_backend.browser_emu = RealBrowser diff --git a/tests/test_startup.py b/tests/test_startup.py deleted file mode 100644 index 5058fc0..0000000 --- a/tests/test_startup.py +++ /dev/null @@ -1,108 +0,0 @@ -from __future__ import with_statement - -import os -import time -import warnings - -import test_utils - -import sys -sys.path.append("../src") - -import dc_glade - - -def startup(factory): - handle = factory() - with test_utils.expected(AssertionError("Attempting login before app is fully loaded")): - handle.refresh_session() - - for i in xrange(10): - if handle._initDone: - print "Completed init on iteration %d" % i - break - time.sleep(1) - assert handle._initDone - - with test_utils.expected(RuntimeError("Login Failed")): - handle.refresh_session() - - handle._save_settings() - - del handle - - -def atest_startup_with_no_data_dir_with_dummy_hildon(): - warnings.simplefilter("always") - hildonPath = os.path.join(os.path.dirname(__file__), "dummy_hildon") - sys.path.insert(0, hildonPath) - import hildon - dc_glade.hildon = hildon - try: - dc_glade.Dialcentral._data_path = os.path.join(os.path.dirname(__file__), "notexistent_data") - dc_glade.Dialcentral._user_settings = "%s/settings.ini" % dc_glade.Dialcentral._data_path - - try: - startup(dc_glade.Dialcentral) - finally: - try: - os.remove(dc_glade.Dialcentral._user_settings) - except: - pass - try: - os.removedirs(dc_glade.Dialcentral._data_path) - except: - pass - finally: - dc_glade.hildon = None - sys.path.remove(hildonPath) - warnings.resetwarnings() - - -def atest_startup_with_no_data_dir(): - warnings.simplefilter("always") - dc_glade.Dialcentral._data_path = os.path.join(os.path.dirname(__file__), "notexistent_data") - dc_glade.Dialcentral._user_settings = "%s/settings.ini" % dc_glade.Dialcentral._data_path - - try: - startup(dc_glade.Dialcentral) - finally: - try: - os.remove(dc_glade.Dialcentral._user_settings) - except: - pass - try: - os.removedirs(dc_glade.Dialcentral._data_path) - except: - pass - warnings.resetwarnings() - - -def atest_startup_with_empty_data_dir(): - warnings.simplefilter("always") - dc_glade.Dialcentral._data_path = os.path.join(os.path.dirname(__file__), "empty_data") - dc_glade.Dialcentral._user_settings = "%s/settings.ini" % dc_glade.Dialcentral._data_path - - try: - startup(dc_glade.Dialcentral) - finally: - try: - os.remove(dc_glade.Dialcentral._user_settings) - except: - pass - try: - os.removedirs(dc_glade.Dialcentral._data_path) - except: - pass - warnings.resetwarnings() - - -def atest_startup_with_basic_data_dir(): - warnings.simplefilter("always") - try: - dc_glade.Dialcentral._data_path = os.path.join(os.path.dirname(__file__), "basic_data") - dc_glade.Dialcentral._user_settings = "%s/settings.ini" % dc_glade.Dialcentral._data_path - - startup(dc_glade.Dialcentral) - finally: - warnings.resetwarnings()