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], ))
from PyQt4 import QtCore
import constants
-import maeqt
+from util import qui_utils
from util import qtpie
from util import misc as misc_utils
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:
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):
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):
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)
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()
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)
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()
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):
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()
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()
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()
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)
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)
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)
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)")
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()
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_)
+++ /dev/null
-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
import os
+import time
import logging
from PyQt4 import QtCore
from util import qore_utils
from util import concurrent
+from backends import gv_backend
+
+
_moduleLogger = logging.getLogger(__name__)
recipientsChanged = QtCore.pyqtSignal()
def __init__(self, pool):
+ QtCore.QObject.__init__(self)
self._contacts = {}
self._pool = pool
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
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):
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
def clear(self):
assert self.state == self.LOGGEDOUT_STATE
+ self._backend = None
self._draft.clear()
self._contacts = []
self.contactsUpdated.emit()
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
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:
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)
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):
"""
_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
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)
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
import warnings
from PyQt4 import QtGui
-from PyQt4 import QtCore
import qtpie
+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
+