<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.4.5 on Fri Apr 10 14:52:59 2009 -->
+<!--Generated with glade3 3.4.5 on Mon Apr 13 18:40:41 2009 -->
<glade-interface>
<widget class="GtkWindow" id="mainWindow">
<property name="default_width">800</property>
</widget>
</child>
<child>
+ <widget class="GtkImageMenuItem" id="disconnectMenuItem">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">gtk-disconnect</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </widget>
+ </child>
+ <child>
<widget class="GtkImageMenuItem" id="quitMenuItem">
<property name="visible">True</property>
<property name="label" translatable="yes">gtk-quit</property>
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
- <widget class="GtkComboBox" id="serviceCombo">
- <property name="visible">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
<widget class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">2</property>
<child>
- <widget class="GtkLabel" id="username_label">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Username</property>
- </widget>
- </child>
- <child>
- <widget class="GtkLabel" id="password_label">
+ <widget class="GtkEntry" id="passwordentry">
<property name="visible">True</property>
- <property name="label" translatable="yes">Password</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
</widget>
<packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</packing>
</child>
<child>
- <widget class="GtkEntry" id="passwordentry">
+ <widget class="GtkLabel" id="password_label">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="visibility">False</property>
+ <property name="label" translatable="yes">Password</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
+ <child>
+ <widget class="GtkLabel" id="username_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Username</property>
+ </widget>
+ </child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
+ <child>
+ <widget class="GtkComboBox" id="serviceCombo">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<child>
- <widget class="GtkHBox" id="edit-hbox2">
+ <widget class="GtkLabel" id="edit-nameLabel">
<property name="visible">True</property>
- <child>
- <widget class="GtkEntry" id="edit-taskNameEntry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="has_focus">True</property>
- <property name="is_focus">True</property>
- <property name="can_default">True</property>
- <property name="has_default">True</property>
- <property name="receives_default">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkHButtonBox" id="edit-hbuttonbox2">
- <property name="visible">True</property>
- <child>
- <widget class="GtkButton" id="edit-pasteTaskNameButton">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="label" translatable="yes">gtk-paste</property>
- <property name="use_stock">True</property>
- <property name="response_id">0</property>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
+ <property name="label" translatable="yes">Name</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="edit-priorityLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Priority</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="edit-dueDateLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Due Date</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkComboBox" id="edit-priorityChoiceCombo">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="items" translatable="yes">None
+1
+2
+3</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
</packing>
</child>
<child>
</packing>
</child>
<child>
- <widget class="GtkComboBox" id="edit-priorityChoiceCombo">
+ <widget class="GtkHBox" id="edit-hbox2">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="items" translatable="yes">None
-1
-2
-3</property>
+ <child>
+ <widget class="GtkEntry" id="edit-taskNameEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="is_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkHButtonBox" id="edit-hbuttonbox2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkButton" id="edit-pasteTaskNameButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-paste</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="y_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="edit-dueDateLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Due Date</property>
- </widget>
- <packing>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
</packing>
</child>
- <child>
- <widget class="GtkLabel" id="edit-priorityLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Priority</property>
- </widget>
- <packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="edit-nameLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Name</property>
- </widget>
- </child>
</widget>
<packing>
<property name="position">1</property>
import doneit_glade
-doneit.run_doneit()
+doneit_glade.run_doneit()
import os
import threading
import warnings
+import ConfigParser
import gtk
import gtk.glade
_user_settings = "%s/settings.ini" % _user_data
def __init__(self):
- self._todoUIs = []
+ self._todoUIs = {}
self._todoUI = None
self._osso = None
self._deviceIsOnline = True
self._connection = None
+ self._fallbackUIName = ""
+ self._defaultUIName = ""
for path in self._glade_files:
if os.path.isfile(path):
def _idle_setup(self):
# Barebones UI handlers
import gtk_null
- gtk.gdk.threads_enter()
- try:
- self._todoUIs = [
- gtk_null.GtkNull(self._widgetTree),
- ]
- finally:
- gtk.gdk.threads_leave()
+ with gtk_toolbox.gtk_lock():
+ nullView = gtk_null.GtkNull(self._widgetTree)
+ self._todoUIs[nullView.name()] = nullView
+ self._todoUI = nullView
+ self._todoUI.enable()
+ self._fallbackUIName = nullView.name()
# Setup maemo specifics
try:
# Setup costly backends
import gtk_rtmilk
- gtk.gdk.threads_enter()
- try:
- self._todoUIs.extend([
- gtk_rtmilk.GtkRtMilk(self._widgetTree),
- ])
- self._todoUI = self._todoUIs[1]
- self._todoUI.enable()
- finally:
- gtk.gdk.threads_leave()
+ with gtk_toolbox.gtk_lock():
+ rtmView = gtk_rtmilk.GtkRtMilk(self._widgetTree)
+ self._todoUIs[rtmView.name()] = rtmView
+ self._defaultUIName = rtmView.name()
+
+ config = ConfigParser.SafeConfigParser()
+ config.read(self._user_settings)
+ with gtk_toolbox.gtk_lock():
+ self.load_settings(config)
def display_error_message(self, msg):
+ """
+ @note UI Thread
+ """
error_dialog = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, msg)
def close(dialog, response, editor):
error_dialog.connect("response", close, self)
error_dialog.run()
+ def load_settings(self, config):
+ """
+ @note UI Thread
+ """
+ for todoUI in self._todoUIs.itervalues():
+ try:
+ todoUI.load_settings(config)
+ except ConfigParser.NoSectionError, e:
+ warnings.warn(
+ "Settings file %s is missing section %s" % (
+ self._user_settings,
+ e.section,
+ ),
+ stacklevel=2
+ )
+
+ try:
+ activeUIName = config.get(self.__pretty_app_name__, "active")
+ except ConfigParser.NoSectionError, e:
+ activeUIName = ""
+ warnings.warn(
+ "Settings file %s is missing section %s" % (
+ self._user_settings,
+ e.section,
+ ),
+ stacklevel=2
+ )
+
+ try:
+ self._switch_ui(activeUIName)
+ except KeyError, e:
+ self._switch_ui(self._defaultUIName)
+
+ def save_settings(self, config):
+ """
+ @note Thread Agnostic
+ """
+ config.add_section(self.__pretty_app_name__)
+ config.set(self.__pretty_app_name__, "active", self._todoUI.name())
+
+ for todoUI in self._todoUIs.itervalues():
+ todoUI.save_settings(config)
+
+ def _switch_ui(self, uiName):
+ """
+ @note UI Thread
+ """
+ newActiveUI = self._todoUIs[uiName]
+ try:
+ newActiveUI.login()
+ except RuntimeError:
+ return # User cancelled the operation
+
+ self._todoUI.disable()
+ self._todoUI = newActiveUI
+ self._todoUI.enable()
+
+ if uiName != self._fallbackUIName:
+ self._defaultUIName = uiName
+
+ def _save_settings(self):
+ """
+ @note Thread Agnostic
+ """
+ config = ConfigParser.SafeConfigParser()
+ self.save_settings(config)
+ with open(self._user_settings, "wb") as configFile:
+ config.write(configFile)
+
def _on_device_state_change(self, shutdown, save_unsaved_data, memory_low, system_inactivity, message, userData):
"""
For system_inactivity, we have no background tasks to pause
gc.collect()
if save_unsaved_data or shutdown:
- pass
+ self._save_settings()
def _on_connection_change(self, connection, event, magicIdentifier):
"""
if status == conic.STATUS_CONNECTED:
self._deviceIsOnline = True
+ self._switch_ui(self._defaultUIName)
elif status == conic.STATUS_DISCONNECTED:
self._deviceIsOnline = False
+ self._switch_ui(self._fallbackUIName)
def _on_window_state_change(self, widget, event, *args):
"""
self._isFullScreen = False
def _on_close(self, *args, **kwds):
- if self._osso is not None:
- self._osso.close()
-
try:
- pass
+ if self._osso is not None:
+ self._osso.close()
+
+ self._save_settings()
finally:
gtk.main_quit()
else:
self.__window.fullscreen()
+ def _on_logout(self, *args):
+ self._todoUI.logout()
+ self._switch_ui(self._fallbackUIName)
+
def _on_about_activate(self, *args):
dlg = gtk.AboutDialog()
dlg.set_name(self.__pretty_app_name__)
"""
@note Thread agnostic
"""
- self._todoItemTree = widgetTree.get_widget("todoItemTree")
- self._todoDetailsTree = widgetTree.get_widget("todoDetailsTree")
- self._todoDetailsScroll = widgetTree.get_widget("todoDetailsScroll")
+ self._projectsCombo = widgetTree.get_widget("projectsCombo")
+ self._addTaskButton = widgetTree.get_widget("add-addTaskButton")
- self._completeButton = widgetTree.get_widget("completeButton")
- self._editButton = widgetTree.get_widget("editButton")
- self._addButton = widgetTree.get_widget("addButton")
-
- self._manager = None
+ self._manager = null.NullManager("", "")
@staticmethod
def name():
return "None"
+ def load_settings(self, config):
+ pass
+
+ def save_settings(self, config):
+ pass
+
+ def login(self):
+ pass
+
+ def logout(self):
+ pass
+
def enable(self):
"""
@note UI Thread
"""
- self._manager = null.NullManager("", "")
-
- self._todoDetailsScroll.hide()
-
- self._completeButton.set_sensitive(False)
- self._editButton.set_sensitive(False)
- self._addButton.set_sensitive(False)
+ self._projectsCombo.set_sensitive(False)
+ self._addTaskButton.set_sensitive(False)
def disable(self):
"""
@note UI Thread
"""
- self._todoDetailsScroll.hide()
-
- self._completeButton.set_sensitive(True)
- self._editButton.set_sensitive(True)
- self._addButton.set_sensitive(True)
-
- self._manager = None
+ self._projectsCombo.set_sensitive(True)
+ self._addTaskButton.set_sensitive(True)
import webbrowser
import datetime
import urlparse
+import base64
import gobject
import gtk
return token
-def start_session(credentialsDialog):
+def get_credentials(credentialsDialog):
# @todo Figure out storage of credentials
username, password = credentialsDialog.request_credentials()
token = get_token(username, rtmilk.RtMilkManager.API_KEY, rtmilk.RtMilkManager.SECRET)
- return rtmilk.RtMilkManager(username, password, token)
+ return username, password, token
class GtkRtMilk(object):
self._onClearId = None
self._onPasteId = None
- self._credentials = gtk_toolbox.LoginWindow(widgetTree)
+ self._credentialsDialog = gtk_toolbox.LoginWindow(widgetTree)
+ self._credentials = "", "", ""
self._manager = None
@staticmethod
def name():
return "Remember The Milk"
- def enable(self):
+ def load_settings(self, config):
+ """
+ @note Thread Agnostic
+ """
+ username = config.get(self.name(), "username")
+ password = None
+ blobbedToken = config.get(self.name(), "bin_blob")
+ token = base64.b64decode(blobbedToken)
+ self._credentials = username, password, token
+
+ def save_settings(self, config):
+ """
+ @note Thread Agnostic
+ """
+ config.add_section(self.name())
+ config.set(self.name(), "username", self._credentials[0])
+ blobbedToken = base64.b64encode(self._credentials[2])
+ config.set(self.name(), "bin_blob", blobbedToken)
+
+ def login(self):
"""
@note UI Thread
"""
- self._manager = start_session(self._credentials)
+ if self._manager is not None:
+ return
+
+ credentials = self._credentials
+ while True:
+ try:
+ self._manager = rtmilk.RtMilkManager(*credentials)
+ self._credentials = credentials
+ return # Login succeeded
+ except rtmapi.AuthStateMachine.NoData:
+ # Login failed, grab new credentials
+ credentials = get_credentials(self._credentialsDialog)
+
+ def logout(self):
+ """
+ @note Thread Agnostic
+ """
+ self._credentials = "", "", ""
+ self._manager = None
+ def enable(self):
+ """
+ @note UI Thread
+ """
self._projectsList.clear()
self._populate_projects()