Adding notification support back in and fixing a dialog bug
[gc-dialer] / src / dialogs.py
index 82145f6..35c0312 100644 (file)
@@ -10,6 +10,7 @@ import logging
 from PyQt4 import QtGui
 from PyQt4 import QtCore
 
+import constants
 from util import qui_utils
 from util import misc as misc_utils
 
@@ -71,6 +72,62 @@ class CredentialsDialog(object):
                finally:
                        self._dialog.setParent(None, QtCore.Qt.Dialog)
 
+       def close(self):
+               self._dialog.reject()
+
+       @QtCore.pyqtSlot()
+       @QtCore.pyqtSlot(bool)
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_close_window(self, checked = True):
+               self._dialog.reject()
+
+
+class AboutDialog(object):
+
+       def __init__(self, app):
+               self._title = QtGui.QLabel(
+                       "<h1>%s</h1><h3>Version: %s</h3>" % (
+                               constants.__pretty_app_name__, constants.__version__
+                       )
+               )
+               self._title.setTextFormat(QtCore.Qt.RichText)
+               self._title.setAlignment(QtCore.Qt.AlignCenter)
+               self._copyright = QtGui.QLabel("<h6>Developed by Ed Page<h6><h6>Icons: See website</h6>")
+               self._copyright.setTextFormat(QtCore.Qt.RichText)
+               self._copyright.setAlignment(QtCore.Qt.AlignCenter)
+               self._link = QtGui.QLabel('<a href="http://gc-dialer.garage.maemo.org">DialCentral Website</a>')
+               self._link.setTextFormat(QtCore.Qt.RichText)
+               self._link.setAlignment(QtCore.Qt.AlignCenter)
+               self._link.setOpenExternalLinks(True)
+
+               self._layout = QtGui.QVBoxLayout()
+               self._layout.addWidget(self._title)
+               self._layout.addWidget(self._copyright)
+               self._layout.addWidget(self._link)
+
+               self._dialog = QtGui.QDialog()
+               self._dialog.setWindowTitle("About")
+               self._dialog.setLayout(self._layout)
+               qui_utils.set_autorient(self._dialog, True)
+
+               self._closeWindowAction = QtGui.QAction(None)
+               self._closeWindowAction.setText("Close")
+               self._closeWindowAction.setShortcut(QtGui.QKeySequence("CTRL+w"))
+               self._closeWindowAction.triggered.connect(self._on_close_window)
+
+               self._dialog.addAction(self._closeWindowAction)
+               self._dialog.addAction(app.quitAction)
+               self._dialog.addAction(app.fullscreenAction)
+
+       def run(self, parent=None):
+               self._dialog.setParent(parent)
+
+               response = self._dialog.exec_()
+               return response
+
+       def close(self):
+               self._dialog.reject()
+
        @QtCore.pyqtSlot()
        @QtCore.pyqtSlot(bool)
        @misc_utils.log_exception(_moduleLogger)
@@ -80,21 +137,63 @@ class CredentialsDialog(object):
 
 class AccountDialog(object):
 
-       # @bug Can't configure callback number
+       # @bug Can't enter custom callback numbers
+
+
+       _RECURRENCE_CHOICES = [
+               (1, "1 minute"),
+               (2, "2 minutes"),
+               (3, "3 minutes"),
+               (5, "5 minutes"),
+               (8, "8 minutes"),
+               (10, "10 minutes"),
+               (15, "15 minutes"),
+               (30, "30 minutes"),
+               (45, "45 minutes"),
+               (60, "1 hour"),
+               (3*60, "3 hours"),
+               (6*60, "6 hours"),
+               (12*60, "12 hours"),
+       ]
 
        def __init__(self, app):
                self._doClear = False
 
                self._accountNumberLabel = QtGui.QLabel("NUMBER NOT SET")
+               self._notificationButton = QtGui.QCheckBox("Notifications")
+               self._notificationButton.stateChanged.connect(self._on_notification_change)
+               self._notificationTimeSelector = QtGui.QComboBox()
+               #self._notificationTimeSelector.setEditable(True)
+               self._notificationTimeSelector.setInsertPolicy(QtGui.QComboBox.InsertAtTop)
+               for _, label in self._RECURRENCE_CHOICES:
+                       self._notificationTimeSelector.addItem(label)
+               self._missedCallsNotificationButton = QtGui.QCheckBox("Missed Calls")
+               self._voicemailNotificationButton = QtGui.QCheckBox("Voicemail")
+               self._smsNotificationButton = QtGui.QCheckBox("SMS")
                self._clearButton = QtGui.QPushButton("Clear Account")
                self._clearButton.clicked.connect(self._on_clear)
+               self._callbackSelector = QtGui.QComboBox()
+               #self._callbackSelector.setEditable(True)
+               self._callbackSelector.setInsertPolicy(QtGui.QComboBox.InsertAtTop)
+
+               self._update_notification_state()
 
                self._credLayout = QtGui.QGridLayout()
                self._credLayout.addWidget(QtGui.QLabel("Account"), 0, 0)
                self._credLayout.addWidget(self._accountNumberLabel, 0, 1)
                self._credLayout.addWidget(QtGui.QLabel("Callback"), 1, 0)
-               self._credLayout.addWidget(QtGui.QLabel(""), 2, 0)
-               self._credLayout.addWidget(self._clearButton, 2, 1)
+               self._credLayout.addWidget(self._callbackSelector, 1, 1)
+               self._credLayout.addWidget(self._notificationButton, 2, 0)
+               self._credLayout.addWidget(self._notificationTimeSelector, 2, 1)
+               self._credLayout.addWidget(QtGui.QLabel(""), 3, 0)
+               self._credLayout.addWidget(self._missedCallsNotificationButton, 3, 1)
+               self._credLayout.addWidget(QtGui.QLabel(""), 4, 0)
+               self._credLayout.addWidget(self._voicemailNotificationButton, 4, 1)
+               self._credLayout.addWidget(QtGui.QLabel(""), 5, 0)
+               self._credLayout.addWidget(self._smsNotificationButton, 5, 1)
+
+               self._credLayout.addWidget(QtGui.QLabel(""), 6, 0)
+               self._credLayout.addWidget(self._clearButton, 6, 1)
                self._credLayout.addWidget(QtGui.QLabel(""), 3, 0)
 
                self._loginButton = QtGui.QPushButton("&Apply")
@@ -106,7 +205,7 @@ class AccountDialog(object):
                self._layout.addWidget(self._buttonLayout)
 
                self._dialog = QtGui.QDialog()
-               self._dialog.setWindowTitle("Login")
+               self._dialog.setWindowTitle("Account")
                self._dialog.setLayout(self._layout)
                qui_utils.set_autorient(self._dialog, True)
                self._buttonLayout.accepted.connect(self._dialog.accept)
@@ -125,11 +224,82 @@ class AccountDialog(object):
        def doClear(self):
                return self._doClear
 
+       def setIfNotificationsSupported(self, isSupported):
+               if isSupported:
+                       self._notificationButton.setVisible(True)
+                       self._notificationTimeSelector.setVisible(True)
+                       self._missedCallsNotificationButton.setVisible(True)
+                       self._voicemailNotificationButton.setVisible(True)
+                       self._smsNotificationButton.setVisible(True)
+               else:
+                       self._notificationButton.setVisible(False)
+                       self._notificationTimeSelector.setVisible(False)
+                       self._missedCallsNotificationButton.setVisible(False)
+                       self._voicemailNotificationButton.setVisible(False)
+                       self._smsNotificationButton.setVisible(False)
+
        accountNumber = property(
                lambda self: str(self._accountNumberLabel.text()),
                lambda self, num: self._accountNumberLabel.setText(num),
        )
 
+       notifications = property(
+               lambda self: self._notificationButton.isChecked(),
+               lambda self, enabled: self._notificationButton.setChecked(enabled),
+       )
+
+       notifyOnMissed = property(
+               lambda self: self._missedCallsNotificationButton.isChecked(),
+               lambda self, enabled: self._missedCallsNotificationButton.setChecked(enabled),
+       )
+
+       notifyOnVoicemail = property(
+               lambda self: self._voicemailNotificationButton.isChecked(),
+               lambda self, enabled: self._voicemailNotificationButton.setChecked(enabled),
+       )
+
+       notifyOnSms = property(
+               lambda self: self._smsNotificationButton.isChecked(),
+               lambda self, enabled: self._smsNotificationButton.setChecked(enabled),
+       )
+
+       def _get_notification_time(self):
+               index = self._notificationTimeSelector.currentIndex()
+               minutes = self._RECURRENCE_CHOICES[index][0]
+               return minutes
+
+       def _set_notification_time(self, minutes):
+               for i, (time, _) in enumerate(self._RECURRENCE_CHOICES):
+                       if time == minutes:
+                               self._callbackSelector.setCurrentIndex(i)
+                               break
+               else:
+                               self._callbackSelector.setCurrentIndex(0)
+
+       notificationTime = property(_get_notification_time, _set_notification_time)
+
+       @property
+       def selectedCallback(self):
+               index = self._callbackSelector.currentIndex()
+               data = str(self._callbackSelector.itemData(index).toPyObject())
+               return data
+
+       def set_callbacks(self, choices, default):
+               self._callbackSelector.clear()
+
+               self._callbackSelector.addItem("Not Set", "")
+
+               uglyDefault = misc_utils.make_ugly(default)
+               for i, (number, description) in enumerate(choices.iteritems()):
+                       prettyNumber = misc_utils.make_pretty(number)
+                       uglyNumber = misc_utils.make_ugly(number)
+                       if not uglyNumber:
+                               continue
+
+                       self._callbackSelector.addItem("%s - %s" % (prettyNumber, description), uglyNumber)
+                       if uglyNumber == uglyDefault:
+                               self._callbackSelector.setCurrentIndex(i)
+
        def run(self, parent=None):
                self._doClear = False
                self._dialog.setParent(parent)
@@ -137,6 +307,25 @@ class AccountDialog(object):
                response = self._dialog.exec_()
                return response
 
+       def close(self):
+               self._dialog.reject()
+
+       def _update_notification_state(self):
+               if self._notificationButton.isChecked():
+                       self._notificationTimeSelector.setEnabled(True)
+                       self._missedCallsNotificationButton.setEnabled(True)
+                       self._voicemailNotificationButton.setEnabled(True)
+                       self._smsNotificationButton.setEnabled(True)
+               else:
+                       self._notificationTimeSelector.setEnabled(False)
+                       self._missedCallsNotificationButton.setEnabled(False)
+                       self._voicemailNotificationButton.setEnabled(False)
+                       self._smsNotificationButton.setEnabled(False)
+
+       @QtCore.pyqtSlot(int)
+       def _on_notification_change(self, state):
+               self._update_notification_state()
+
        @QtCore.pyqtSlot()
        @QtCore.pyqtSlot(bool)
        def _on_clear(self, checked = False):
@@ -154,8 +343,6 @@ class SMSEntryWindow(object):
 
        MAX_CHAR = 160
 
-       # @bug on n900 no scrolling for history qtextedit
-
        def __init__(self, parent, app, session, errorLog):
                self._session = session
                self._session.draft.recipientsChanged.connect(self._on_recipients_changed)
@@ -174,11 +361,9 @@ class SMSEntryWindow(object):
                self._targetLayout = QtGui.QVBoxLayout()
                self._targetList = QtGui.QWidget()
                self._targetList.setLayout(self._targetLayout)
-               self._history = QtGui.QTextEdit()
-               self._history.setReadOnly(True)
-               self._history.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignBottom)
-               self._history.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
-               self._history.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+               self._history = QtGui.QLabel()
+               self._history.setTextFormat(QtCore.Qt.RichText)
+               self._history.setWordWrap(True)
                self._smsEntry = QtGui.QTextEdit()
                self._smsEntry.textChanged.connect(self._on_letter_count_changed)
 
@@ -240,9 +425,18 @@ class SMSEntryWindow(object):
                viewMenu = self._window.menuBar().addMenu("&View")
                viewMenu.addAction(app.fullscreenAction)
 
+               self._scrollTimer = QtCore.QTimer()
+               self._scrollTimer.setInterval(0)
+               self._scrollTimer.setSingleShot(True)
+               self._scrollTimer.timeout.connect(self._on_delayed_scroll_to_bottom)
+
                self._window.show()
                self._update_recipients()
 
+       def close(self):
+               self._window.destroy()
+               self._window = None
+
        def _update_letter_count(self):
                count = self._smsEntry.toPlainText().size()
                numTexts, numCharInText = divmod(count, self.MAX_CHAR)
@@ -278,10 +472,10 @@ class SMSEntryWindow(object):
 
                        self._targetList.setVisible(False)
                        if description:
-                               self._history.setHtml(description)
+                               self._history.setText(description)
                                self._history.setVisible(True)
                        else:
-                               self._history.setHtml("")
+                               self._history.setText("")
                                self._history.setVisible(False)
                        self._populate_number_selector(self._singleNumberSelector, cid, numbers)
 
@@ -318,7 +512,7 @@ class SMSEntryWindow(object):
                                rowWidget = QtGui.QWidget()
                                rowWidget.setLayout(rowLayout)
                                self._targetLayout.addWidget(rowWidget)
-                       self._history.setHtml("")
+                       self._history.setText("")
                        self._history.setVisible(False)
                        self._singleNumberSelector.setVisible(False)
 
@@ -328,8 +522,7 @@ class SMSEntryWindow(object):
                        self._smsEntry.setFocus(QtCore.Qt.OtherFocusReason)
 
        def _populate_number_selector(self, selector, cid, numbers):
-               while 0 < selector.count():
-                       selector.removeItem(0)
+               selector.clear()
 
                if len(numbers) == 1:
                        numbers, defaultIndex = _get_contact_numbers(self._session, cid, numbers[0])
@@ -358,11 +551,15 @@ class SMSEntryWindow(object):
                )
 
        def _scroll_to_bottom(self):
+               self._scrollTimer.start()
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_delayed_scroll_to_bottom(self):
                self._scrollEntry.ensureWidgetVisible(self._smsEntry)
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_sms_clicked(self, arg):
-               message = str(self._smsEntry.toPlainText())
+               message = unicode(self._smsEntry.toPlainText())
                self._session.draft.send(message)
                self._smsEntry.setPlainText("")
 
@@ -423,7 +620,7 @@ class SMSEntryWindow(object):
                self._smsButton.setVisible(True)
                self._dialButton.setVisible(True)
 
-               self._errorLog.push_message(message)
+               self._errorLog.push_error(message)
 
        @QtCore.pyqtSlot()
        @misc_utils.log_exception(_moduleLogger)
@@ -447,7 +644,7 @@ def _get_contact_numbers(session, contactId, numberDescription):
                except KeyError:
                        contactPhoneNumbers = []
                contactPhoneNumbers = [
-                       (contactPhoneNumber["phoneNumber"], contactPhoneNumber["phoneType"])
+                       (contactPhoneNumber["phoneNumber"], contactPhoneNumber.get("phoneType", "Unknown"))
                        for contactPhoneNumber in contactPhoneNumbers
                ]
                if contactPhoneNumbers: