4 DialCentral - Front end for Google's GoogleVoice service.
5 Copyright (C) 2008 Mark Bergman bergman AT merctech DOT com
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 from __future__ import with_statement
42 _moduleLogger = logging.getLogger("dc_glade")
43 PROFILE_STARTUP = False
46 def getmtime_nothrow(path):
48 return os.path.getmtime(path)
53 def display_error_message(msg):
54 error_dialog = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg)
56 def close(dialog, response):
58 error_dialog.connect("response", close)
62 class Dialcentral(object):
65 os.path.join(os.path.dirname(__file__), "dialcentral.glade"),
66 os.path.join(os.path.dirname(__file__), "../lib/dialcentral.glade"),
67 '/usr/lib/dialcentral/dialcentral.glade',
77 # 1 Was GrandCentral support so the gap was maintained for compatibility
79 BACKENDS = (NULL_BACKEND, GV_BACKEND)
82 self._initDone = False
83 self._connection = None
85 self._deviceState = None
86 self._clipboard = gtk.clipboard_get()
88 self._credentials = ("", "")
89 self._selectedBackendId = self.NULL_BACKEND
90 self._defaultBackendId = self.GV_BACKEND
91 self._phoneBackends = None
93 self._accountViews = None
94 self._messagesViews = None
95 self._historyViews = None
96 self._contactsViews = None
97 self._alarmHandler = None
98 self._ledHandler = None
99 self._originalCurrentLabels = []
101 for path in self._glade_files:
102 if os.path.isfile(path):
103 self._widgetTree = gtk.glade.XML(path)
106 display_error_message("Cannot find dialcentral.glade")
110 self._window = self._widgetTree.get_widget("mainWindow")
111 self._notebook = self._widgetTree.get_widget("notebook")
112 self._errorDisplay = gtk_toolbox.ErrorDisplay(self._widgetTree)
113 self._credentialsDialog = gtk_toolbox.LoginWindow(self._widgetTree)
115 self._isFullScreen = False
116 self._app = hildonize.get_app_class()()
117 self._window = hildonize.hildonize_window(self._app, self._window)
118 hildonize.hildonize_text_entry(self._widgetTree.get_widget("usernameentry"))
119 hildonize.hildonize_password_entry(self._widgetTree.get_widget("passwordentry"))
121 for scrollingWidgetName in (
122 'history_scrolledwindow',
123 'message_scrolledwindow',
124 'contacts_scrolledwindow',
125 "smsMessages_scrolledwindow",
127 scrollingWidget = self._widgetTree.get_widget(scrollingWidgetName)
128 assert scrollingWidget is not None, scrollingWidgetName
129 hildonize.hildonize_scrollwindow(scrollingWidget)
130 for scrollingWidgetName in (
131 "smsMessage_scrolledEntry",
133 scrollingWidget = self._widgetTree.get_widget(scrollingWidgetName)
134 assert scrollingWidget is not None, scrollingWidgetName
135 hildonize.hildonize_scrollwindow_with_viewport(scrollingWidget)
139 "addressbookSelectButton",
143 "callbackSelectButton",
144 "minutesEntryButton",
146 "phoneTypeSelection",
148 button = self._widgetTree.get_widget(buttonName)
149 assert button is not None, buttonName
150 hildonize.set_button_thumb_selectable(button)
152 menu = hildonize.hildonize_menu(
154 self._widgetTree.get_widget("dialpad_menubar"),
156 if not hildonize.GTK_MENU_USED:
157 button = gtk.Button("New Login")
158 button.connect("clicked", self._on_clearcookies_clicked)
161 button= gtk.Button("Refresh")
162 button.connect("clicked", self._on_menu_refresh)
167 self._window.connect("key-press-event", self._on_key_press)
168 self._window.connect("window-state-event", self._on_window_state_change)
169 if not hildonize.IS_HILDON_SUPPORTED:
170 _moduleLogger.warning("No hildonization support")
172 hildonize.set_application_title(self._window, "%s" % constants.__pretty_app_name__)
174 self._window.connect("destroy", self._on_close)
175 self._window.set_default_size(800, 300)
176 self._window.show_all()
178 self._loginSink = gtk_toolbox.threaded_stage(
181 gtk_toolbox.null_sink(),
185 if not PROFILE_STARTUP:
186 backgroundSetup = threading.Thread(target=self._idle_setup)
187 backgroundSetup.setDaemon(True)
188 backgroundSetup.start()
192 def _idle_setup(self):
194 If something can be done after the UI loads, push it here so it's not blocking the UI
196 # Barebones UI handlers
198 from backends import null_backend
201 self._phoneBackends = {self.NULL_BACKEND: null_backend.NullDialer()}
202 with gtk_toolbox.gtk_lock():
203 self._dialpads = {self.NULL_BACKEND: null_views.Dialpad(self._widgetTree)}
204 self._accountViews = {self.NULL_BACKEND: null_views.AccountInfo(self._widgetTree)}
205 self._historyViews = {self.NULL_BACKEND: null_views.CallHistoryView(self._widgetTree)}
206 self._messagesViews = {self.NULL_BACKEND: null_views.MessagesView(self._widgetTree)}
207 self._contactsViews = {self.NULL_BACKEND: null_views.ContactsView(self._widgetTree)}
209 self._dialpads[self._selectedBackendId].enable()
210 self._accountViews[self._selectedBackendId].enable()
211 self._historyViews[self._selectedBackendId].enable()
212 self._messagesViews[self._selectedBackendId].enable()
213 self._contactsViews[self._selectedBackendId].enable()
215 with gtk_toolbox.gtk_lock():
216 self._errorDisplay.push_exception()
218 # Setup maemo specifics
222 except (ImportError, OSError):
225 self._deviceState = None
227 self._osso = osso.Context(constants.__app_name__, constants.__version__, False)
228 self._deviceState = osso.DeviceState(self._osso)
229 self._deviceState.set_device_state_callback(self._on_device_state_change, 0)
231 _moduleLogger.warning("No device state support")
235 if alarm_handler.AlarmHandler is not alarm_handler._NoneAlarmHandler:
236 self._alarmHandler = alarm_handler.AlarmHandler()
238 self._alarmHandler = None
239 except (ImportError, OSError):
242 with gtk_toolbox.gtk_lock():
243 self._errorDisplay.push_exception()
245 if alarm_handler is None:
246 _moduleLogger.warning("No notification support")
247 if hildonize.IS_HILDON_SUPPORTED:
250 self._ledHandler = led_handler.LedHandler()
252 _moduleLogger.exception('LED Handling failed: "%s"' % str(e))
253 self._ledHandler = None
255 self._ledHandler = None
259 except (ImportError, OSError):
261 self._connection = None
262 if conic is not None:
263 self._connection = conic.Connection()
264 self._connection.connect("connection-event", self._on_connection_change, constants.__app_magic__)
265 self._connection.request_connection(conic.CONNECT_FLAG_NONE)
267 _moduleLogger.warning("No connection support")
269 with gtk_toolbox.gtk_lock():
270 self._errorDisplay.push_exception()
272 # Setup costly backends
274 from backends import gv_backend
275 from backends import file_backend
277 from backends import merge_backend
280 os.makedirs(constants._data_path_)
284 gvCookiePath = os.path.join(constants._data_path_, "gv_cookies.txt")
286 self._phoneBackends.update({
287 self.GV_BACKEND: gv_backend.GVDialer(gvCookiePath),
289 with gtk_toolbox.gtk_lock():
290 unifiedDialpad = gv_views.Dialpad(self._widgetTree, self._errorDisplay)
291 self._dialpads.update({
292 self.GV_BACKEND: unifiedDialpad,
294 self._accountViews.update({
295 self.GV_BACKEND: gv_views.AccountInfo(
296 self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._alarmHandler, self._errorDisplay
299 self._accountViews[self.GV_BACKEND].save_everything = self._save_settings
300 self._historyViews.update({
301 self.GV_BACKEND: gv_views.CallHistoryView(
302 self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay
305 self._messagesViews.update({
306 self.GV_BACKEND: gv_views.MessagesView(
307 self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay
310 self._contactsViews.update({
311 self.GV_BACKEND: gv_views.ContactsView(
312 self._widgetTree, self._phoneBackends[self.GV_BACKEND], self._errorDisplay
316 fsContactsPath = os.path.join(constants._data_path_, "contacts")
317 fileBackend = file_backend.FilesystemAddressBookFactory(fsContactsPath)
319 self._dialpads[self.GV_BACKEND].number_selected = self._select_action
320 self._historyViews[self.GV_BACKEND].number_selected = self._select_action
321 self._messagesViews[self.GV_BACKEND].number_selected = self._select_action
322 self._contactsViews[self.GV_BACKEND].number_selected = self._select_action
325 self._phoneBackends[self.GV_BACKEND],
328 mergedBook = merge_backend.MergedAddressBook(addressBooks, merge_backend.MergedAddressBook.basic_firtname_sorter)
329 self._contactsViews[self.GV_BACKEND].append(mergedBook)
330 self._contactsViews[self.GV_BACKEND].extend(addressBooks)
331 self._contactsViews[self.GV_BACKEND].open_addressbook(*self._contactsViews[self.GV_BACKEND].get_addressbooks().next()[0][0:2])
334 "on_paste": self._on_paste,
335 "on_refresh": self._on_menu_refresh,
336 "on_clearcookies_clicked": self._on_clearcookies_clicked,
337 "on_about_activate": self._on_about_activate,
339 if hildonize.GTK_MENU_USED:
340 self._widgetTree.signal_autoconnect(callbackMapping)
341 self._notebook.connect("switch-page", self._on_notebook_switch_page)
342 self._widgetTree.get_widget("clearcookies").connect("clicked", self._on_clearcookies_clicked)
344 with gtk_toolbox.gtk_lock():
345 self._originalCurrentLabels = [
346 self._notebook.get_tab_label(self._notebook.get_nth_page(pageIndex)).get_text()
347 for pageIndex in xrange(self._notebook.get_n_pages())
349 self._notebookTapHandler = gtk_toolbox.TapOrHold(self._notebook)
350 self._notebookTapHandler.enable()
351 self._notebookTapHandler.on_tap = self._reset_tab_refresh
352 self._notebookTapHandler.on_hold = self._on_tab_refresh
353 self._notebookTapHandler.on_holding = self._set_tab_refresh
354 self._notebookTapHandler.on_cancel = self._reset_tab_refresh
356 config = ConfigParser.SafeConfigParser()
357 config.read(constants._user_settings_)
358 with gtk_toolbox.gtk_lock():
359 self.load_settings(config)
361 with gtk_toolbox.gtk_lock():
362 self._errorDisplay.push_exception()
364 self._initDone = True
365 self._spawn_attempt_login()
367 def _spawn_attempt_login(self, *args):
368 self._loginSink.send(args)
370 def _attempt_login(self, force = False):
372 @note This must be run outside of the UI lock
375 assert self._initDone, "Attempting login before app is fully loaded"
377 serviceId = self.NULL_BACKEND
379 if not force and self._defaultBackendId != self.NULL_BACKEND:
380 with gtk_toolbox.gtk_lock():
381 banner = hildonize.show_busy_banner_start(self._window, "Logging In...")
383 self.refresh_session()
384 serviceId = self._defaultBackendId
387 _moduleLogger.exception('Session refresh failed with the following message "%s"' % str(e))
389 with gtk_toolbox.gtk_lock():
390 hildonize.show_busy_banner_end(banner)
393 loggedIn, serviceId = self._login_by_user()
395 with gtk_toolbox.gtk_lock():
396 self._change_loggedin_status(serviceId)
398 hildonize.show_information_banner(self._window, "Logged In")
400 hildonize.show_information_banner(self._window, "Login Failed")
401 if not self._phoneBackends[self._defaultBackendId].get_callback_number():
402 # subtle reminder to the users to configure things
403 self._notebook.set_current_page(self.ACCOUNT_TAB)
406 with gtk_toolbox.gtk_lock():
407 self._errorDisplay.push_exception()
409 def refresh_session(self):
411 @note Thread agnostic
413 assert self._initDone, "Attempting login before app is fully loaded"
417 loggedIn = self._login_by_cookie()
419 loggedIn = self._login_by_settings()
422 raise RuntimeError("Login Failed")
424 def _login_by_cookie(self):
426 @note Thread agnostic
430 isQuickLoginPossible = self._phoneBackends[self._defaultBackendId].is_quick_login_possible()
431 if self._credentials != ("", "") and isQuickLoginPossible:
433 loggedIn = self._phoneBackends[self._defaultBackendId].is_authed()
436 _moduleLogger.info("Logged into %r through cookies" % self._phoneBackends[self._defaultBackendId])
438 # If the cookies are bad, scratch them completely
439 self._phoneBackends[self._defaultBackendId].logout()
443 def _login_by_settings(self):
445 @note Thread agnostic
447 if self._credentials == ("", ""):
448 # Don't bother with the settings if they are blank
451 username, password = self._credentials
452 loggedIn = self._phoneBackends[self._defaultBackendId].login(username, password)
454 self._credentials = username, password
455 _moduleLogger.info("Logged into %r through settings" % self._phoneBackends[self._defaultBackendId])
458 def _login_by_user(self):
460 @note This must be run outside of the UI lock
462 loggedIn, (username, password) = False, self._credentials
463 tmpServiceId = self.GV_BACKEND
465 with gtk_toolbox.gtk_lock():
466 credentials = self._credentialsDialog.request_credentials(
467 defaultCredentials = self._credentials
469 banner = hildonize.show_busy_banner_start(self._window, "Logging In...")
471 username, password = credentials
472 loggedIn = self._phoneBackends[tmpServiceId].login(username, password)
474 with gtk_toolbox.gtk_lock():
475 hildonize.show_busy_banner_end(banner)
478 serviceId = tmpServiceId
479 self._credentials = username, password
480 _moduleLogger.info("Logged into %r through user request" % self._phoneBackends[serviceId])
482 # Hint to the user that they are not logged in
483 serviceId = self.NULL_BACKEND
484 self._notebook.set_current_page(self.ACCOUNT_TAB)
486 return loggedIn, serviceId
488 def _select_action(self, action, number, message):
489 self.refresh_session()
491 self._on_dial_clicked(number)
492 elif action == "sms":
493 self._on_sms_clicked(number, message)
495 assert False, "Unknown action: %s" % action
497 def _change_loggedin_status(self, newStatus):
498 oldStatus = self._selectedBackendId
499 if oldStatus == newStatus:
502 self._dialpads[oldStatus].disable()
503 self._accountViews[oldStatus].disable()
504 self._historyViews[oldStatus].disable()
505 self._messagesViews[oldStatus].disable()
506 self._contactsViews[oldStatus].disable()
508 self._dialpads[newStatus].enable()
509 self._accountViews[newStatus].enable()
510 self._historyViews[newStatus].enable()
511 self._messagesViews[newStatus].enable()
512 self._contactsViews[newStatus].enable()
514 self._selectedBackendId = newStatus
516 self._accountViews[self._selectedBackendId].update()
517 self._refresh_active_tab()
519 def load_settings(self, config):
524 if not PROFILE_STARTUP:
525 self._defaultBackendId = config.getint(constants.__pretty_app_name__, "active")
527 self._defaultBackendId = self.NULL_BACKEND
529 config.get(constants.__pretty_app_name__, "bin_blob_%i" % i)
530 for i in xrange(len(self._credentials))
533 base64.b64decode(blob)
536 self._credentials = tuple(creds)
538 if self._alarmHandler is not None:
539 self._alarmHandler.load_settings(config, "alarm")
541 isFullscreen = config.getboolean(constants.__pretty_app_name__, "fullscreen")
543 self._window.fullscreen()
544 except ConfigParser.NoOptionError, e:
545 _moduleLogger.exception(
546 "Settings file %s is missing section %s" % (
547 constants._user_settings_,
551 except ConfigParser.NoSectionError, e:
552 _moduleLogger.exception(
553 "Settings file %s is missing section %s" % (
554 constants._user_settings_,
559 for backendId, view in itertools.chain(
560 self._dialpads.iteritems(),
561 self._accountViews.iteritems(),
562 self._messagesViews.iteritems(),
563 self._historyViews.iteritems(),
564 self._contactsViews.iteritems(),
566 sectionName = "%s - %s" % (backendId, view.name())
568 view.load_settings(config, sectionName)
569 except ConfigParser.NoOptionError, e:
570 _moduleLogger.exception(
571 "Settings file %s is missing section %s" % (
572 constants._user_settings_,
576 except ConfigParser.NoSectionError, e:
577 _moduleLogger.exception(
578 "Settings file %s is missing section %s" % (
579 constants._user_settings_,
585 previousOrientation = config.getint(constants.__pretty_app_name__, "orientation")
586 if previousOrientation == gtk.ORIENTATION_HORIZONTAL:
587 hildonize.window_to_landscape(self._window)
588 elif previousOrientation == gtk.ORIENTATION_VERTICAL:
589 hildonize.window_to_portrait(self._window)
590 except ConfigParser.NoOptionError, e:
591 _moduleLogger.exception(
592 "Settings file %s is missing section %s" % (
593 constants._user_settings_,
597 except ConfigParser.NoSectionError, e:
598 _moduleLogger.exception(
599 "Settings file %s is missing section %s" % (
600 constants._user_settings_,
605 def save_settings(self, config):
607 @note Thread Agnostic
609 # Because we now only support GVoice, if there are user credentials,
610 # always assume its using the GVoice backend
611 if self._credentials[0] and self._credentials[1]:
612 backend = self.GV_BACKEND
614 backend = self.NULL_BACKEND
616 config.add_section(constants.__pretty_app_name__)
617 config.set(constants.__pretty_app_name__, "active", str(backend))
618 config.set(constants.__pretty_app_name__, "orientation", str(int(gtk_toolbox.get_screen_orientation())))
619 config.set(constants.__pretty_app_name__, "fullscreen", str(self._isFullScreen))
620 for i, value in enumerate(self._credentials):
621 blob = base64.b64encode(value)
622 config.set(constants.__pretty_app_name__, "bin_blob_%i" % i, blob)
623 config.add_section("alarm")
624 if self._alarmHandler is not None:
625 self._alarmHandler.save_settings(config, "alarm")
627 for backendId, view in itertools.chain(
628 self._dialpads.iteritems(),
629 self._accountViews.iteritems(),
630 self._messagesViews.iteritems(),
631 self._historyViews.iteritems(),
632 self._contactsViews.iteritems(),
634 sectionName = "%s - %s" % (backendId, view.name())
635 config.add_section(sectionName)
636 view.save_settings(config, sectionName)
638 def _save_settings(self):
640 @note Thread Agnostic
642 config = ConfigParser.SafeConfigParser()
643 self.save_settings(config)
644 with open(constants._user_settings_, "wb") as configFile:
645 config.write(configFile)
647 def _refresh_active_tab(self):
648 pageIndex = self._notebook.get_current_page()
649 if pageIndex == self.CONTACTS_TAB:
650 self._contactsViews[self._selectedBackendId].update(force=True)
651 elif pageIndex == self.RECENT_TAB:
652 self._historyViews[self._selectedBackendId].update(force=True)
653 elif pageIndex == self.MESSAGES_TAB:
654 self._messagesViews[self._selectedBackendId].update(force=True)
656 if pageIndex in (self.RECENT_TAB, self.MESSAGES_TAB):
657 if self._ledHandler is not None:
658 self._ledHandler.off()
660 @gtk_toolbox.log_exception(_moduleLogger)
661 def _on_close(self, *args, **kwds):
664 self._save_settings()
667 self._deviceState.close()
668 except AttributeError:
669 pass # Either None or close was removed (in Fremantle)
672 except AttributeError:
673 pass # Either None or close was removed (in Fremantle)
677 def _on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData):
679 For shutdown or save_unsaved_data, our only state is cookies and I think the cookie manager handles that for us.
680 For system_inactivity, we have no background tasks to pause
682 @note Hildon specific
686 for backendId in self.BACKENDS:
687 self._phoneBackends[backendId].clear_caches()
688 self._contactsViews[self._selectedBackendId].clear_caches()
691 if save_unsaved_data or shutdown:
692 self._save_settings()
694 self._errorDisplay.push_exception()
696 def _on_connection_change(self, connection, event, magicIdentifier):
698 @note Hildon specific
703 status = event.get_status()
704 error = event.get_error()
705 iap_id = event.get_iap_id()
706 bearer = event.get_bearer_type()
708 if status == conic.STATUS_CONNECTED:
710 self._spawn_attempt_login()
711 elif status == conic.STATUS_DISCONNECTED:
713 self._defaultBackendId = self._selectedBackendId
714 self._change_loggedin_status(self.NULL_BACKEND)
716 self._errorDisplay.push_exception()
718 def _on_window_state_change(self, widget, event, *args):
720 @note Hildon specific
723 if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
724 self._isFullScreen = True
726 self._isFullScreen = False
728 self._errorDisplay.push_exception()
730 def _on_key_press(self, widget, event, *args):
732 @note Hildon specific
734 RETURN_TYPES = (gtk.keysyms.Return, gtk.keysyms.ISO_Enter, gtk.keysyms.KP_Enter)
737 event.keyval == gtk.keysyms.F6 or
738 event.keyval in RETURN_TYPES and event.get_state() & gtk.gdk.CONTROL_MASK
740 if self._isFullScreen:
741 self._window.unfullscreen()
743 self._window.fullscreen()
744 elif event.keyval == gtk.keysyms.l and event.get_state() & gtk.gdk.CONTROL_MASK:
745 with open(constants._user_logpath_, "r") as f:
746 logLines = f.xreadlines()
747 log = "".join(logLines)
748 self._clipboard.set_text(str(log))
750 event.keyval in (gtk.keysyms.w, gtk.keysyms.q) and
751 event.get_state() & gtk.gdk.CONTROL_MASK
753 self._window.destroy()
754 elif event.keyval == gtk.keysyms.r and event.get_state() & gtk.gdk.CONTROL_MASK:
755 self._refresh_active_tab()
757 self._errorDisplay.push_exception()
759 def _on_clearcookies_clicked(self, *args):
761 self._phoneBackends[self._selectedBackendId].logout()
762 self._accountViews[self._selectedBackendId].clear()
763 self._historyViews[self._selectedBackendId].clear()
764 self._messagesViews[self._selectedBackendId].clear()
765 self._contactsViews[self._selectedBackendId].clear()
766 self._change_loggedin_status(self.NULL_BACKEND)
768 self._spawn_attempt_login(True)
770 self._errorDisplay.push_exception()
772 def _on_notebook_switch_page(self, notebook, page, pageIndex):
774 self._reset_tab_refresh()
776 didRecentUpdate = False
777 didMessagesUpdate = False
779 if pageIndex == self.RECENT_TAB:
780 didRecentUpdate = self._historyViews[self._selectedBackendId].update()
781 elif pageIndex == self.MESSAGES_TAB:
782 didMessagesUpdate = self._messagesViews[self._selectedBackendId].update()
783 elif pageIndex == self.CONTACTS_TAB:
784 self._contactsViews[self._selectedBackendId].update()
785 elif pageIndex == self.ACCOUNT_TAB:
786 self._accountViews[self._selectedBackendId].update()
788 if didRecentUpdate or didMessagesUpdate:
789 if self._ledHandler is not None:
790 self._ledHandler.off()
792 self._errorDisplay.push_exception()
794 def _set_tab_refresh(self, *args):
796 pageIndex = self._notebook.get_current_page()
797 child = self._notebook.get_nth_page(pageIndex)
798 self._notebook.get_tab_label(child).set_text("Refresh?")
800 self._errorDisplay.push_exception()
803 def _reset_tab_refresh(self, *args):
805 pageIndex = self._notebook.get_current_page()
806 child = self._notebook.get_nth_page(pageIndex)
807 self._notebook.get_tab_label(child).set_text(self._originalCurrentLabels[pageIndex])
809 self._errorDisplay.push_exception()
812 def _on_tab_refresh(self, *args):
814 self._refresh_active_tab()
815 self._reset_tab_refresh()
817 self._errorDisplay.push_exception()
820 def _on_sms_clicked(self, number, message):
822 assert number, "No number specified"
823 assert message, "Empty message"
825 loggedIn = self._phoneBackends[self._selectedBackendId].is_authed()
828 self._errorDisplay.push_exception()
832 self._errorDisplay.push_message(
833 "Backend link with GoogleVoice is not working, please try again"
839 self._phoneBackends[self._selectedBackendId].send_sms(number, message)
840 hildonize.show_information_banner(self._window, "Sending to %s" % number)
841 _moduleLogger.info("Sending SMS to %s" % number)
844 self._errorDisplay.push_exception()
847 self._dialpads[self._selectedBackendId].clear()
849 self._errorDisplay.push_exception()
851 def _on_dial_clicked(self, number):
853 assert number, "No number to call"
855 loggedIn = self._phoneBackends[self._selectedBackendId].is_authed()
858 self._errorDisplay.push_exception()
862 self._errorDisplay.push_message(
863 "Backend link with GoogleVoice is not working, please try again"
869 assert self._phoneBackends[self._selectedBackendId].get_callback_number() != "", "No callback number specified"
870 self._phoneBackends[self._selectedBackendId].call(number)
871 hildonize.show_information_banner(self._window, "Calling %s" % number)
872 _moduleLogger.info("Calling %s" % number)
875 self._errorDisplay.push_exception()
878 self._dialpads[self._selectedBackendId].clear()
880 self._errorDisplay.push_exception()
882 def _on_menu_refresh(self, *args):
884 self._refresh_active_tab()
886 self._errorDisplay.push_exception()
888 def _on_paste(self, *args):
890 contents = self._clipboard.wait_for_text()
891 if contents is not None:
892 self._dialpads[self._selectedBackendId].set_number(contents)
894 self._errorDisplay.push_exception()
896 def _on_about_activate(self, *args):
898 dlg = gtk.AboutDialog()
899 dlg.set_name(constants.__pretty_app_name__)
900 dlg.set_version("%s-%d" % (constants.__version__, constants.__build__))
901 dlg.set_copyright("Copyright 2008 - LGPL")
902 dlg.set_comments("Dialcentral is a touch screen enhanced interface to your GoogleVoice account. This application is not affiliated with Google in any way")
903 dlg.set_website("http://gc-dialer.garage.maemo.org/")
904 dlg.set_authors(["<z2n@merctech.com>", "Eric Warnke <ericew@gmail.com>", "Ed Page <eopage@byu.net>"])
908 self._errorDisplay.push_exception()
914 failureCount, testCount = doctest.testmod()
916 print "Tests Successful"
923 _lock_file = os.path.join(constants._data_path_, ".lock")
924 #with gtk_toolbox.flock(_lock_file, 0):
925 gtk.gdk.threads_init()
927 if hildonize.IS_HILDON_SUPPORTED:
928 gtk.set_application_name(constants.__pretty_app_name__)
929 handle = Dialcentral()
930 if not PROFILE_STARTUP:
934 class DummyOptions(object):
940 if __name__ == "__main__":
941 logging.basicConfig(level=logging.DEBUG)
943 if len(sys.argv) > 1:
949 if optparse is not None:
950 parser = optparse.OptionParser()
951 parser.add_option("-t", "--test", action="store_true", dest="test", help="Run tests")
952 (commandOptions, commandArgs) = parser.parse_args()
954 commandOptions = DummyOptions()
957 if commandOptions.test: