Fixed issues with the credentials dialog
authorEd Page <eopage@byu.net>
Sat, 11 Sep 2010 17:56:58 +0000 (12:56 -0500)
committerEd Page <eopage@byu.net>
Sat, 11 Sep 2010 17:56:58 +0000 (12:56 -0500)
Got login to work on the right threads
Adding pyqtSlot decorators to receive supposed performcen improvements
Merged maeqt into qui_utils
Moved QErrorLog to qui_utils
Cleaned up the logging format

src/dialcentral.py
src/dialcentral_qt.py
src/maeqt.py [deleted file]
src/session.py
src/util/concurrent.py
src/util/qore_utils.py
src/util/qtpie.py
src/util/qtpieboard.py
src/util/qui_utils.py

index 8f3fe12..cdc5169 100755 (executable)
@@ -35,7 +35,7 @@ if __name__ == "__main__":
                if e.errno != 17:
                        raise
 
-       logFormat = '(%(asctime)s) %(levelname)-5s %(threadName)s.%(name)s: %(message)s'
+       logFormat = '(%(relativeCreated)5d) %(levelname)-5s %(threadName)s.%(name)s.%(funcName)s: %(message)s'
        logging.basicConfig(level=logging.DEBUG, filename=constants._user_logpath_, format=logFormat)
        _moduleLogger.info("%s %s-%s" % (constants.__app_name__, constants.__version__, constants.__build__))
        _moduleLogger.info("OS: %s" % (os.uname()[0], ))
index a9f529c..809756c 100755 (executable)
@@ -13,7 +13,7 @@ from PyQt4 import QtGui
 from PyQt4 import QtCore
 
 import constants
-import maeqt
+from util import qui_utils
 from util import qtpie
 from util import misc as misc_utils
 
@@ -105,19 +105,26 @@ class Dialcentral(object):
                        self._mainWindow.close()
                        self._mainWindow = None
 
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
        @misc_utils.log_exception(_moduleLogger)
        def _on_app_quit(self, checked = False):
                self.save_settings()
 
+       @QtCore.pyqtSlot(QtCore.QObject)
        @misc_utils.log_exception(_moduleLogger)
        def _on_child_close(self, obj = None):
                self._mainWindow = None
 
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
        @misc_utils.log_exception(_moduleLogger)
        def _on_toggle_fullscreen(self, checked = False):
                for window in self._walk_children():
                        window.set_fullscreen(checked)
 
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
        @misc_utils.log_exception(_moduleLogger)
        def _on_log(self, checked = False):
                with open(constants._user_logpath_, "r") as f:
@@ -125,93 +132,13 @@ class Dialcentral(object):
                        log = "".join(logLines)
                        self._clipboard.setText(log)
 
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
        @misc_utils.log_exception(_moduleLogger)
        def _on_quit(self, checked = False):
                self._close_windows()
 
 
-class QErrorLog(QtCore.QObject):
-
-       messagePushed = QtCore.pyqtSignal()
-       messagePopped = QtCore.pyqtSignal()
-
-       def __init__(self):
-               QtCore.QObject.__init__(self)
-               self._messages = []
-
-       def push_message(self, message):
-               self._messages.append(message)
-               self.messagePushed.emit()
-
-       def push_exception(self):
-               userMessage = str(sys.exc_info()[1])
-               _moduleLogger.exception(userMessage)
-               self.push_message(userMessage)
-
-       def pop_message(self):
-               del self._messages[0]
-               self.messagePopped.emit()
-
-       def peek_message(self):
-               return self._messages[0]
-
-       def __len__(self):
-               return len(self._messages)
-
-
-class ErrorDisplay(object):
-
-       def __init__(self, errorLog):
-               self._errorLog = errorLog
-               self._errorLog.messagePushed.connect(self._on_message_pushed)
-               self._errorLog.messagePopped.connect(self._on_message_popped)
-
-               errorIcon = maeqt.get_theme_icon(("dialog-error", "app_install_error", "gtk-dialog-error"))
-               self._severityIcon = errorIcon.pixmap(32, 32)
-               self._severityLabel = QtGui.QLabel()
-               self._severityLabel.setPixmap(self._severityIcon)
-
-               self._message = QtGui.QLabel()
-               self._message.setText("Boo")
-
-               closeIcon = maeqt.get_theme_icon(("window-close", "general_close", "gtk-close"))
-               self._closeLabel = QtGui.QPushButton(closeIcon, "")
-               self._closeLabel.clicked.connect(self._on_close)
-
-               self._controlLayout = QtGui.QHBoxLayout()
-               self._controlLayout.addWidget(self._severityLabel)
-               self._controlLayout.addWidget(self._message)
-               self._controlLayout.addWidget(self._closeLabel)
-
-               self._topLevelLayout = QtGui.QHBoxLayout()
-               self._topLevelLayout.addLayout(self._controlLayout)
-               self._widget = QtGui.QWidget()
-               self._widget.setLayout(self._topLevelLayout)
-               self._widget.hide()
-
-       @property
-       def toplevel(self):
-               return self._widget
-
-       @misc_utils.log_exception(_moduleLogger)
-       def _on_close(self, *args):
-               self._errorLog.pop_message()
-
-       @misc_utils.log_exception(_moduleLogger)
-       def _on_message_pushed(self):
-               if 1 <= len(self._errorLog) and self._widget.isHidden():
-                       self._message.setText(self._errorLog.peek_message())
-                       self._widget.show()
-
-       @misc_utils.log_exception(_moduleLogger)
-       def _on_message_popped(self):
-               if len(self._errorLog) == 0:
-                       self._message.setText("")
-                       self._widget.hide()
-               else:
-                       self._message.setText(self._errorLog.peek_message())
-
-
 class CredentialsDialog(object):
 
        def __init__(self):
@@ -231,28 +158,29 @@ class CredentialsDialog(object):
 
                self._layout = QtGui.QVBoxLayout()
                self._layout.addLayout(self._credLayout)
-               self._layout.addLayout(self._buttonLayout)
-
-               centralWidget = QtGui.QWidget()
-               centralWidget.setLayout(self._layout)
+               self._layout.addWidget(self._buttonLayout)
 
                self._dialog = QtGui.QDialog()
                self._dialog.setWindowTitle("Login")
-               self._dialog.setCentralWidget(centralWidget)
-               maeqt.set_autorient(self._dialog, True)
+               self._dialog.setLayout(self._layout)
+               self._dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose, False)
+               qui_utils.set_autorient(self._dialog, True)
                self._buttonLayout.accepted.connect(self._dialog.accept)
                self._buttonLayout.rejected.connect(self._dialog.reject)
 
        def run(self, defaultUsername, defaultPassword, parent=None):
-               self._dialog.setParent(parent)
-               self._usernameField.setText(defaultUsername)
-               self._passwordField.setText(defaultPassword)
+               self._dialog.setParent(parent, QtCore.Qt.Dialog)
+               try:
+                       self._usernameField.setText(defaultUsername)
+                       self._passwordField.setText(defaultPassword)
 
-               response = self._dialog.exec_()
-               if response == QtGui.QDialog.Accepted:
-                       return str(self._usernameField.text()), str(self._passwordField.text())
-               elif response == QtGui.QDialog.Rejected:
-                       raise RuntimeError("Login Cancelled")
+                       response = self._dialog.exec_()
+                       if response == QtGui.QDialog.Accepted:
+                               return str(self._usernameField.text()), str(self._passwordField.text())
+                       elif response == QtGui.QDialog.Rejected:
+                               raise RuntimeError("Login Cancelled")
+               finally:
+                       self._dialog.setParent(None, QtCore.Qt.Dialog)
 
 
 class AccountDialog(object):
@@ -277,13 +205,10 @@ class AccountDialog(object):
                self._layout.addLayout(self._credLayout)
                self._layout.addLayout(self._buttonLayout)
 
-               centralWidget = QtGui.QWidget()
-               centralWidget.setLayout(self._layout)
-
                self._dialog = QtGui.QDialog()
                self._dialog.setWindowTitle("Login")
-               self._dialog.setCentralWidget(centralWidget)
-               maeqt.set_autorient(self._dialog, True)
+               self._dialog.setLayout(self._layout)
+               qui_utils.set_autorient(self._dialog, True)
                self._buttonLayout.accepted.connect(self._dialog.accept)
                self._buttonLayout.rejected.connect(self._dialog.reject)
 
@@ -308,6 +233,8 @@ class AccountDialog(object):
                elif response == QtGui.QDialog.Rejected:
                        raise RuntimeError("Login Cancelled")
 
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
        def _on_clear(self, checked = False):
                self._doClear = True
                self._dialog.accept()
@@ -355,8 +282,8 @@ class SMSEntryWindow(object):
 
                self._window = QtGui.QMainWindow(parent)
                self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, False)
-               maeqt.set_autorient(self._window, True)
-               maeqt.set_stackable(self._window, True)
+               qui_utils.set_autorient(self._window, True)
+               qui_utils.set_stackable(self._window, True)
                self._window.setWindowTitle("Contact")
                self._window.setCentralWidget(centralWidget)
 
@@ -380,6 +307,7 @@ class SMSEntryWindow(object):
                        self._dialButton.setEnabled(False)
                        self._smsButton.setEnabled(True)
 
+       @QtCore.pyqtSlot()
        @misc_utils.log_exception(_moduleLogger)
        def _on_letter_count_changed(self):
                self._update_letter_count()
@@ -561,18 +489,22 @@ class Dialpad(object):
        def _on_clear_text(self, toggled = False):
                self._entry.clear()
 
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
        @misc_utils.log_exception(_moduleLogger)
        def _on_sms_clicked(self, checked = False):
                number = str(self._entry.text())
                self._entry.clear()
                self._session.draft.add_contact(number, [])
 
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
        @misc_utils.log_exception(_moduleLogger)
        def _on_call_clicked(self, checked = False):
                number = str(self._entry.text())
                self._entry.clear()
                self._session.draft.add_contact(number, [])
-               self._session.call()
+               self._session.draft.call()
 
 
 class History(object):
@@ -640,14 +572,17 @@ class History(object):
        def _populate_items(self):
                self._errorLog.push_message("Not supported")
 
+       @QtCore.pyqtSlot(str)
        @misc_utils.log_exception(_moduleLogger)
        def _on_filter_changed(self, newItem):
                self._selectedFilter = str(newItem)
 
+       @QtCore.pyqtSlot()
        @misc_utils.log_exception(_moduleLogger)
        def _on_history_updated(self):
                self._populate_items()
 
+       @QtCore.pyqtSlot(QtCore.QModelIndex)
        @misc_utils.log_exception(_moduleLogger)
        def _on_row_activated(self, index):
                rowIndex = index.row()
@@ -732,18 +667,22 @@ class Messages(object):
        def _populate_items(self):
                self._errorLog.push_message("Not supported")
 
+       @QtCore.pyqtSlot(str)
        @misc_utils.log_exception(_moduleLogger)
        def _on_type_filter_changed(self, newItem):
                self._selectedTypeFilter = str(newItem)
 
+       @QtCore.pyqtSlot(str)
        @misc_utils.log_exception(_moduleLogger)
        def _on_status_filter_changed(self, newItem):
                self._selectedStatusFilter = str(newItem)
 
+       @QtCore.pyqtSlot()
        @misc_utils.log_exception(_moduleLogger)
        def _on_messages_updated(self):
                self._populate_items()
 
+       @QtCore.pyqtSlot(QtCore.QModelIndex)
        @misc_utils.log_exception(_moduleLogger)
        def _on_row_activated(self, index):
                rowIndex = index.row()
@@ -803,14 +742,17 @@ class Contacts(object):
        def _populate_items(self):
                self._errorLog.push_message("Not supported")
 
+       @QtCore.pyqtSlot(str)
        @misc_utils.log_exception(_moduleLogger)
        def _on_filter_changed(self, newItem):
                self._selectedFilter = str(newItem)
 
+       @QtCore.pyqtSlot()
        @misc_utils.log_exception(_moduleLogger)
        def _on_contacts_updated(self):
                self._populate_items()
 
+       @QtCore.pyqtSlot(QtCore.QModelIndex)
        @misc_utils.log_exception(_moduleLogger)
        def _on_row_activated(self, index):
                rowIndex = index.row()
@@ -849,8 +791,10 @@ class MainWindow(object):
                self._session.loggedIn.connect(self._on_login)
                self._session.loggedOut.connect(self._on_logout)
 
-               self._errorLog = QErrorLog()
-               self._errorDisplay = ErrorDisplay(self._errorLog)
+               self._credentialsDialog = None
+
+               self._errorLog = qui_utils.QErrorLog()
+               self._errorDisplay = qui_utils.ErrorDisplay(self._errorLog)
 
                self._tabsContents = [
                        DelayedWidget(self._app)
@@ -860,7 +804,7 @@ class MainWindow(object):
                        tab.disable()
 
                self._tabWidget = QtGui.QTabWidget()
-               if maeqt.screen_orientation() == QtCore.Qt.Vertical:
+               if qui_utils.screen_orientation() == QtCore.Qt.Vertical:
                        self._tabWidget.setTabPosition(QtGui.QTabWidget.South)
                else:
                        self._tabWidget.setTabPosition(QtGui.QTabWidget.West)
@@ -877,8 +821,8 @@ class MainWindow(object):
 
                self._window = QtGui.QMainWindow(parent)
                self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
-               maeqt.set_autorient(self._window, True)
-               maeqt.set_stackable(self._window, True)
+               qui_utils.set_autorient(self._window, True)
+               qui_utils.set_stackable(self._window, True)
                self._window.setWindowTitle("%s" % constants.__pretty_app_name__)
                self._window.setCentralWidget(centralWidget)
 
@@ -968,33 +912,46 @@ class MainWindow(object):
                                self._TAB_CLASS[index](self._app, self._session, self._errorLog)
                        )
 
+       @QtCore.pyqtSlot(str)
        @misc_utils.log_exception(_moduleLogger)
        def _on_session_error(self, message):
                self._errorLog.push_message(message)
 
+       @QtCore.pyqtSlot()
        @misc_utils.log_exception(_moduleLogger)
        def _on_login(self):
                for tab in self._tabsContents:
                        tab.enable()
 
+       @QtCore.pyqtSlot()
        @misc_utils.log_exception(_moduleLogger)
        def _on_logout(self):
                for tab in self._tabsContents:
                        tab.disable()
 
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
        @misc_utils.log_exception(_moduleLogger)
-       def _on_login_requested(self):
-               pass
+       def _on_login_requested(self, checked = True):
+               if self._credentialsDialog is None:
+                       self._credentialsDialog = CredentialsDialog()
+               username, password = self._credentialsDialog.run("", "", self.window)
+               self._session.login(username, password)
 
+       @QtCore.pyqtSlot(int)
        @misc_utils.log_exception(_moduleLogger)
        def _on_tab_changed(self, index):
                self._initialize_tab(index)
 
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
        @misc_utils.log_exception(_moduleLogger)
        def _on_refresh(self, checked = True):
                index = self._tabWidget.currentIndex()
                self._tabsContents[index].refresh()
 
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
        @misc_utils.log_exception(_moduleLogger)
        def _on_import(self, checked = True):
                csvName = QtGui.QFileDialog.getOpenFileName(self._window, caption="Import", filter="CSV Files (*.csv)")
@@ -1002,6 +959,8 @@ class MainWindow(object):
                        return
                shutil.copy2(csvName, self._fsContactsPath)
 
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
        @misc_utils.log_exception(_moduleLogger)
        def _on_close_window(self, checked = True):
                self.close()
@@ -1015,7 +974,7 @@ def run():
 
 
 if __name__ == "__main__":
-       logFormat = '(%(asctime)s) %(levelname)-5s %(threadName)s.%(name)s: %(message)s'
+       logFormat = '(%(relativeCreated)5d) %(levelname)-5s %(threadName)s.%(name)s.%(funcName)s: %(message)s'
        logging.basicConfig(level=logging.DEBUG, format=logFormat)
        try:
                os.makedirs(constants._data_path_)
diff --git a/src/maeqt.py b/src/maeqt.py
deleted file mode 100644 (file)
index d5eb18b..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-from PyQt4 import QtCore
-from PyQt4 import QtGui
-
-
-def _null_set_stackable(window, isStackable):
-       pass
-
-
-def _maemo_set_stackable(window, isStackable):
-       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
-
-
-try:
-       QtCore.Qt.WA_Maemo5StackedWindow
-       set_stackable = _maemo_set_stackable
-except AttributeError:
-       set_stackable = _null_set_stackable
-
-
-def _null_set_autorient(window, isStackable):
-       pass
-
-
-def _maemo_set_autorient(window, isStackable):
-       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
-
-
-try:
-       QtCore.Qt.WA_Maemo5AutoOrientation
-       set_autorient = _maemo_set_autorient
-except AttributeError:
-       set_autorient = _null_set_autorient
-
-
-def _null_set_landscape(window, isStackable):
-       pass
-
-
-def _maemo_set_landscape(window, isStackable):
-       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
-
-
-try:
-       QtCore.Qt.WA_Maemo5LandscapeOrientation
-       set_landscape = _maemo_set_landscape
-except AttributeError:
-       set_landscape = _null_set_landscape
-
-
-def _null_set_portrait(window, isStackable):
-       pass
-
-
-def _maemo_set_portrait(window, isStackable):
-       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
-
-
-try:
-       QtCore.Qt.WA_Maemo5PortraitOrientation
-       set_portrait = _maemo_set_portrait
-except AttributeError:
-       set_portrait = _null_set_portrait
-
-
-def _null_show_progress_indicator(window, isStackable):
-       pass
-
-
-def _maemo_show_progress_indicator(window, isStackable):
-       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
-
-
-try:
-       QtCore.Qt.WA_Maemo5ShowProgressIndicator
-       show_progress_indicator = _maemo_show_progress_indicator
-except AttributeError:
-       show_progress_indicator = _null_show_progress_indicator
-
-
-def _null_mark_numbers_preferred(widget):
-       pass
-
-
-def _newqt_mark_numbers_preferred(widget):
-       widget.setInputMethodHints(QtCore.Qt.ImhPreferNumbers)
-
-
-try:
-       QtCore.Qt.ImhPreferNumbers
-       mark_numbers_preferred = _newqt_mark_numbers_preferred
-except AttributeError:
-       mark_numbers_preferred = _null_mark_numbers_preferred
-
-
-def screen_orientation():
-       geom = QtGui.QApplication.desktop().screenGeometry()
-       if geom.width() <= geom.height():
-               return QtCore.Qt.Vertical
-       else:
-               return QtCore.Qt.Horizontal
-
-
-def _null_get_theme_icon(iconNames, fallback = None):
-       icon = fallback if fallback is not None else QtGui.QIcon()
-       return icon
-
-
-def _newqt_get_theme_icon(iconNames, fallback = None):
-       for iconName in iconNames:
-               if QtGui.QIcon.hasThemeIcon(iconName):
-                       icon = QtGui.QIcon.fromTheme(iconName)
-                       break
-       else:
-               icon = fallback if fallback is not None else QtGui.QIcon()
-       return icon
-
-
-try:
-       QtGui.QIcon.fromTheme
-       get_theme_icon = _newqt_get_theme_icon
-except AttributeError:
-       get_theme_icon = _null_get_theme_icon
index 5802f52..0c650e0 100644 (file)
@@ -1,4 +1,5 @@
 import os
+import time
 import logging
 
 from PyQt4 import QtCore
@@ -6,6 +7,9 @@ from PyQt4 import QtCore
 from util import qore_utils
 from util import concurrent
 
+from backends import gv_backend
+
+
 _moduleLogger = logging.getLogger(__name__)
 
 
@@ -22,6 +26,7 @@ class Draft(QtCore.QObject):
        recipientsChanged = QtCore.pyqtSignal()
 
        def __init__(self, pool):
+               QtCore.QObject.__init__(self)
                self._contacts = {}
                self._pool = pool
 
@@ -78,11 +83,12 @@ class Session(QtCore.QObject):
        LOGGEDIN_STATE = "logged in"
 
        _LOGGEDOUT_TIME = -1
-       _LOGGINGING_TIME = 0
+       _LOGGINGIN_TIME = 0
 
        def __init__(self, cachePath = None):
                QtCore.QObject.__init__(self)
                self._pool = qore_utils.AsyncPool()
+               self._backend = None
                self._loggedInTime = self._LOGGEDOUT_TIME
                self._loginOps = []
                self._cachePath = cachePath
@@ -99,7 +105,7 @@ class Session(QtCore.QObject):
                return {
                        self._LOGGEDOUT_TIME: self.LOGGEDOUT_STATE,
                        self._LOGGINGIN_TIME: self.LOGGINGIN_STATE,
-               }.get(self._loggedInTime, default=self.LOGGEDIN_STATE)
+               }.get(self._loggedInTime, self.LOGGEDIN_STATE)
 
        @property
        def draft(self):
@@ -112,12 +118,12 @@ class Session(QtCore.QObject):
                else:
                        cookiePath = None
 
-               self._pool.start()
-               self.error.emit("Not Implemented")
+               if self._username != username or self._backend is None:
+                       self._backend = gv_backend.GVDialer(cookiePath)
 
-               # if the username is the same, do nothing
-               # else clear the in-memory caches and attempt to load from file-caches
-               # If caches went from empty to something, fire signals
+               self._pool.start()
+               le = concurrent.AsyncLinearExecution(self._pool, self._login)
+               le.start(username, password)
 
        def logout(self):
                assert self.state != self.LOGGEDOUT_STATE
@@ -126,6 +132,7 @@ class Session(QtCore.QObject):
 
        def clear(self):
                assert self.state == self.LOGGEDOUT_STATE
+               self._backend = None
                self._draft.clear()
                self._contacts = []
                self.contactsUpdated.emit()
@@ -137,25 +144,29 @@ class Session(QtCore.QObject):
                self.dndStateChange.emit(self._dnd)
 
        def update_contacts(self):
-               self._perform_op_while_loggedin(self._update_contacts)
+               le = concurrent.AsyncLinearExecution(self._pool, self._update_contacts)
+               self._perform_op_while_loggedin(le)
 
        def get_contacts(self):
                return self._contacts
 
        def update_messages(self):
-               self._perform_op_while_loggedin(self._update_messages)
+               le = concurrent.AsyncLinearExecution(self._pool, self._update_messages)
+               self._perform_op_while_loggedin(le)
 
        def get_messages(self):
                return self._messages
 
        def update_history(self):
-               self._perform_op_while_loggedin(self._update_history)
+               le = concurrent.AsyncLinearExecution(self._pool, self._update_history)
+               self._perform_op_while_loggedin(le)
 
        def get_history(self):
                return self._history
 
        def update_dnd(self):
-               self._perform_op_while_loggedin(self._update_dnd)
+               le = concurrent.AsyncLinearExecution(self._pool, self._update_dnd)
+               self._perform_op_while_loggedin(le)
 
        def set_dnd(self, dnd):
                assert self.state == self.LOGGEDIN_STATE
@@ -174,19 +185,100 @@ class Session(QtCore.QObject):
                assert self.state == self.LOGGEDIN_STATE
                self.error.emit("Not Implemented")
 
+       def _login(self, username, password):
+               self._loggedInTime = self._LOGGINGIN_TIME
+               self.stateChange.emit(self.LOGGINGIN_STATE)
+               finalState = self.LOGGEDOUT_STATE
+               try:
+                       isLoggedIn = False
+
+                       if not isLoggedIn and self._backend.is_quick_login_possible():
+                               try:
+                                       isLoggedIn = yield (
+                                               self._backend.is_authed,
+                                               (),
+                                               {},
+                                       )
+                               except Exception, e:
+                                       self.error.emit(str(e))
+                                       return
+                               if isLoggedIn:
+                                       _moduleLogger.info("Logged in through cookies")
+
+                       if not isLoggedIn:
+                               try:
+                                       isLoggedIn = yield (
+                                               self._backend.login,
+                                               (username, password),
+                                               {},
+                                       )
+                               except Exception, e:
+                                       self.error.emit(str(e))
+                                       return
+                               if isLoggedIn:
+                                       _moduleLogger.info("Logged in through credentials")
+
+                       if isLoggedIn:
+                               self._loggedInTime = time.time()
+                               self._username = username
+                               finalState = self.LOGGEDIN_STATE
+                               self.loggedIn.emit()
+                               # if the username is the same, do nothing
+                               # else clear the in-memory caches and attempt to load from file-caches
+                               # If caches went from empty to something, fire signals
+                               # Fire off queued async ops
+               except Exception, e:
+                       self.error.emit(str(e))
+               finally:
+                       self.stateChange.emit(finalState)
+
        def _update_contacts(self):
-               le = concurrent.AsyncLinearExecution(self._asyncPool, self._login)
-               le.start()
                self.error.emit("Not Implemented")
+               try:
+                       isLoggedIn = yield (
+                               self._backend.is_authed,
+                               (),
+                               {},
+                       )
+               except Exception, e:
+                       self.error.emit(str(e))
+                       return
 
        def _update_messages(self):
                self.error.emit("Not Implemented")
+               try:
+                       isLoggedIn = yield (
+                               self._backend.is_authed,
+                               (),
+                               {},
+                       )
+               except Exception, e:
+                       self.error.emit(str(e))
+                       return
 
        def _update_history(self):
                self.error.emit("Not Implemented")
+               try:
+                       isLoggedIn = yield (
+                               self._backend.is_authed,
+                               (),
+                               {},
+                       )
+               except Exception, e:
+                       self.error.emit(str(e))
+                       return
 
        def _update_dnd(self):
                self.error.emit("Not Implemented")
+               try:
+                       isLoggedIn = yield (
+                               self._backend.is_authed,
+                               (),
+                               {},
+                       )
+               except Exception, e:
+                       self.error.emit(str(e))
+                       return
 
        def _perform_op_while_loggedin(self, op):
                if self.state == self.LOGGEDIN_STATE:
@@ -194,9 +286,9 @@ class Session(QtCore.QObject):
                else:
                        self._push_login_op(op)
 
-       def _push_login_op(self, op):
+       def _push_login_op(self, asyncOp):
                assert self.state != self.LOGGEDIN_STATE
-               if op in self._loginOps:
-                       _moduleLogger.info("Skipping queueing duplicate op: %r" % op)
+               if asyncOp in self._loginOps:
+                       _moduleLogger.info("Skipping queueing duplicate op: %r" % asyncOp)
                        return
-               self._loginOps.append(op)
+               self._loginOps.append(asyncOp)
index 812de24..2124aeb 100644 (file)
@@ -66,6 +66,18 @@ class AsyncLinearExecution(object):
                                self.on_error,
                        )
 
+       def __repr__(self):
+               return "<async %s at 0x%x>" % (self._func.__name__, id(self))
+
+       def __hash__(self):
+               return hash(self._func)
+
+       def __eq__(self, other):
+               return self._func == other._func
+
+       def __ne__(self, other):
+               return self._func != other._func
+
 
 def synchronized(lock):
        """
index f7d9dc5..a592d34 100644 (file)
@@ -8,46 +8,54 @@ import misc
 _moduleLogger = logging.getLogger(__name__)
 
 
-class ParentThreadSignals(QtCore.QObject):
+class QThread44(QtCore.QThread):
+       """
+       This is to imitate QThread in Qt 4.4+ for when running on older version
+       See http://labs.trolltech.com/blogs/2010/06/17/youre-doing-it-wrong
+       (On Lucid I have Qt 4.7 and this is still an issue)
+       """
 
-       taskComplete  = QtCore.pyqtSignal(object)
+       def __init__(self, parent = None):
+               QtCore.QThread.__init__(self, parent)
 
+       def run(self):
+               self.exec_()
 
-class WorkerThreadSignals(QtCore.QObject):
 
-       addTask = QtCore.pyqtSignal(object)
+class _ParentThread(QtCore.QObject):
 
+       def __init__(self, pool):
+               QtCore.QObject.__init__(self)
+               self._pool = pool
 
-class AsyncPool(QtCore.QObject):
+       @QtCore.pyqtSlot(object)
+       @misc.log_exception(_moduleLogger)
+       def _on_task_complete(self, taskResult):
+               on_success, on_error, isError, result = taskResult
+               if not self._pool._isRunning:
+                       if isError:
+                               _moduleLogger.error("Masking: %s" % (result, ))
+                       isError = True
+                       result = StopIteration("Cancelling all callbacks")
+               callback = on_success if not isError else on_error
+               try:
+                       callback(result)
+               except Exception:
+                       _moduleLogger.exception("Callback errored")
 
-       def __init__(self):
-               _moduleLogger.info("main?")
-               self._thread = QtCore.QThread()
-               self._isRunning = True
-               self._parent = ParentThreadSignals()
-               self._parent.taskComplete.connect(self._on_task_complete)
-               self._worker = WorkerThreadSignals()
-               self._worker.moveToThread(self._thread)
-               self._worker.addTask.connect(self._on_task_added)
 
-       def start(self):
-               _moduleLogger.info("main?")
-               self._thread.exec_()
+class _WorkerThread(QtCore.QObject):
 
-       def stop(self):
-               _moduleLogger.info("main?")
-               self._isRunning = False
+       taskComplete  = QtCore.pyqtSignal(object)
 
-       def add_task(self, func, args, kwds, on_success, on_error):
-               _moduleLogger.info("main?")
-               assert self._isRunning
-               task = func, args, kwds, on_success, on_error
-               self._worker.addTask.emit(task)
+       def __init__(self, pool):
+               QtCore.QObject.__init__(self)
+               self._pool = pool
 
+       @QtCore.pyqtSlot(object)
        @misc.log_exception(_moduleLogger)
        def _on_task_added(self, task):
-               _moduleLogger.info("worker?")
-               if not self._isRunning:
+               if not self._pool._isRunning:
                        _moduleLogger.error("Dropping task")
 
                func, args, kwds, on_success, on_error = task
@@ -61,20 +69,39 @@ class AsyncPool(QtCore.QObject):
                        isError = True
 
                taskResult = on_success, on_error, isError, result
-               self._parent.taskComplete.emit(taskResult)
+               self.taskComplete.emit(taskResult)
 
+       @QtCore.pyqtSlot()
        @misc.log_exception(_moduleLogger)
-       def _on_task_complete(self, taskResult):
-               _moduleLogger.info("main?")
-               on_success, on_error, isError, result = taskResult
-               if not self._isRunning:
-                       if isError:
-                               _moduleLogger.error("Masking: %s" % (result, ))
-                       isError = True
-                       result = StopIteration("Cancelling all callbacks")
-               callback = on_success if not isError else on_error
-               try:
-                       callback(result)
-               except Exception:
-                       _moduleLogger.exception("Callback errored")
-               return False
+       def _on_stop_requested(self):
+               self._thread.quit()
+
+
+class AsyncPool(QtCore.QObject):
+
+       _addTask = QtCore.pyqtSignal(object)
+       _stopPool = QtCore.pyqtSignal()
+
+       def __init__(self):
+               QtCore.QObject.__init__(self)
+               self._thread = QThread44()
+               self._isRunning = True
+               self._parent = _ParentThread(self)
+               self._worker = _WorkerThread(self)
+               self._worker.moveToThread(self._thread)
+
+               self._addTask.connect(self._worker._on_task_added)
+               self._worker.taskComplete.connect(self._parent._on_task_complete)
+               self._stopPool.connect(self._worker._on_stop_requested)
+
+       def start(self):
+               self._thread.start()
+
+       def stop(self):
+               self._isRunning = False
+               self._stopPool.emit()
+
+       def add_task(self, func, args, kwds, on_success, on_error):
+               assert self._isRunning
+               task = func, args, kwds, on_success, on_error
+               self._addTask.emit(task)
index 884d5ce..4751ae3 100755 (executable)
@@ -584,6 +584,7 @@ class QPieButton(QtGui.QWidget):
                self._popupLocation = mouseEvent.globalPos()
                self._delayPopupTimer.start()
 
+       @QtCore.pyqtSlot()
        @misc_utils.log_exception(_moduleLogger)
        def _on_delayed_popup(self):
                assert self._popupLocation is not None
index 80c43d0..c7094f4 100755 (executable)
@@ -7,7 +7,6 @@ import os
 import warnings
 
 from PyQt4 import QtGui
-from PyQt4 import QtCore
 
 import qtpie
 
index e69de29..47697db 100644 (file)
@@ -0,0 +1,217 @@
+import sys
+import logging
+
+from PyQt4 import QtCore
+from PyQt4 import QtGui
+
+import misc
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+class QErrorLog(QtCore.QObject):
+
+       messagePushed = QtCore.pyqtSignal()
+       messagePopped = QtCore.pyqtSignal()
+
+       def __init__(self):
+               QtCore.QObject.__init__(self)
+               self._messages = []
+
+       def push_message(self, message):
+               self._messages.append(message)
+               self.messagePushed.emit()
+
+       def push_exception(self):
+               userMessage = str(sys.exc_info()[1])
+               _moduleLogger.exception(userMessage)
+               self.push_message(userMessage)
+
+       def pop_message(self):
+               del self._messages[0]
+               self.messagePopped.emit()
+
+       def peek_message(self):
+               return self._messages[0]
+
+       def __len__(self):
+               return len(self._messages)
+
+
+class ErrorDisplay(object):
+
+       def __init__(self, errorLog):
+               self._errorLog = errorLog
+               self._errorLog.messagePushed.connect(self._on_message_pushed)
+               self._errorLog.messagePopped.connect(self._on_message_popped)
+
+               errorIcon = get_theme_icon(("dialog-error", "app_install_error", "gtk-dialog-error"))
+               self._severityIcon = errorIcon.pixmap(32, 32)
+               self._severityLabel = QtGui.QLabel()
+               self._severityLabel.setPixmap(self._severityIcon)
+
+               self._message = QtGui.QLabel()
+               self._message.setText("Boo")
+
+               closeIcon = get_theme_icon(("window-close", "general_close", "gtk-close"))
+               self._closeLabel = QtGui.QPushButton(closeIcon, "")
+               self._closeLabel.clicked.connect(self._on_close)
+
+               self._controlLayout = QtGui.QHBoxLayout()
+               self._controlLayout.addWidget(self._severityLabel)
+               self._controlLayout.addWidget(self._message)
+               self._controlLayout.addWidget(self._closeLabel)
+
+               self._topLevelLayout = QtGui.QHBoxLayout()
+               self._topLevelLayout.addLayout(self._controlLayout)
+               self._widget = QtGui.QWidget()
+               self._widget.setLayout(self._topLevelLayout)
+               self._widget.hide()
+
+       @property
+       def toplevel(self):
+               return self._widget
+
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
+       @misc.log_exception(_moduleLogger)
+       def _on_close(self, checked = False):
+               self._errorLog.pop_message()
+
+       @QtCore.pyqtSlot()
+       @misc.log_exception(_moduleLogger)
+       def _on_message_pushed(self):
+               if 1 <= len(self._errorLog) and self._widget.isHidden():
+                       self._message.setText(self._errorLog.peek_message())
+                       self._widget.show()
+
+       @QtCore.pyqtSlot()
+       @misc.log_exception(_moduleLogger)
+       def _on_message_popped(self):
+               if len(self._errorLog) == 0:
+                       self._message.setText("")
+                       self._widget.hide()
+               else:
+                       self._message.setText(self._errorLog.peek_message())
+
+
+def _null_set_stackable(window, isStackable):
+       pass
+
+
+def _maemo_set_stackable(window, isStackable):
+       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
+
+
+try:
+       QtCore.Qt.WA_Maemo5StackedWindow
+       set_stackable = _maemo_set_stackable
+except AttributeError:
+       set_stackable = _null_set_stackable
+
+
+def _null_set_autorient(window, isStackable):
+       pass
+
+
+def _maemo_set_autorient(window, isStackable):
+       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
+
+
+try:
+       QtCore.Qt.WA_Maemo5AutoOrientation
+       set_autorient = _maemo_set_autorient
+except AttributeError:
+       set_autorient = _null_set_autorient
+
+
+def _null_set_landscape(window, isStackable):
+       pass
+
+
+def _maemo_set_landscape(window, isStackable):
+       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
+
+
+try:
+       QtCore.Qt.WA_Maemo5LandscapeOrientation
+       set_landscape = _maemo_set_landscape
+except AttributeError:
+       set_landscape = _null_set_landscape
+
+
+def _null_set_portrait(window, isStackable):
+       pass
+
+
+def _maemo_set_portrait(window, isStackable):
+       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
+
+
+try:
+       QtCore.Qt.WA_Maemo5PortraitOrientation
+       set_portrait = _maemo_set_portrait
+except AttributeError:
+       set_portrait = _null_set_portrait
+
+
+def _null_show_progress_indicator(window, isStackable):
+       pass
+
+
+def _maemo_show_progress_indicator(window, isStackable):
+       window.setAttribute(QtCore.Qt.WA_Maemo5StackedWindow, isStackable)
+
+
+try:
+       QtCore.Qt.WA_Maemo5ShowProgressIndicator
+       show_progress_indicator = _maemo_show_progress_indicator
+except AttributeError:
+       show_progress_indicator = _null_show_progress_indicator
+
+
+def _null_mark_numbers_preferred(widget):
+       pass
+
+
+def _newqt_mark_numbers_preferred(widget):
+       widget.setInputMethodHints(QtCore.Qt.ImhPreferNumbers)
+
+
+try:
+       QtCore.Qt.ImhPreferNumbers
+       mark_numbers_preferred = _newqt_mark_numbers_preferred
+except AttributeError:
+       mark_numbers_preferred = _null_mark_numbers_preferred
+
+
+def screen_orientation():
+       geom = QtGui.QApplication.desktop().screenGeometry()
+       if geom.width() <= geom.height():
+               return QtCore.Qt.Vertical
+       else:
+               return QtCore.Qt.Horizontal
+
+
+def _null_get_theme_icon(iconNames, fallback = None):
+       icon = fallback if fallback is not None else QtGui.QIcon()
+       return icon
+
+
+def _newqt_get_theme_icon(iconNames, fallback = None):
+       for iconName in iconNames:
+               if QtGui.QIcon.hasThemeIcon(iconName):
+                       icon = QtGui.QIcon.fromTheme(iconName)
+                       break
+       else:
+               icon = fallback if fallback is not None else QtGui.QIcon()
+       return icon
+
+
+try:
+       QtGui.QIcon.fromTheme
+       get_theme_icon = _newqt_get_theme_icon
+except AttributeError:
+       get_theme_icon = _null_get_theme_icon
+