X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fgv_views.py;h=f57995ce2848c65ef85d179773a4f1e9f3bccd05;hb=9708c3b670d58c0370a45e28dcbd0abc9d8276a8;hp=4273973b2a0d1f0790f617cacd0f431adf6128b7;hpb=632e3344384b245164db891e19455a73142d457e;p=gc-dialer diff --git a/src/gv_views.py b/src/gv_views.py index 4273973..f57995c 100644 --- a/src/gv_views.py +++ b/src/gv_views.py @@ -3,6 +3,7 @@ from __future__ import with_statement from __future__ import division +import datetime import string import itertools import logging @@ -56,10 +57,22 @@ class Dialpad(object): self._entryLayout.addWidget(self._entry, 1000) self._entryLayout.addWidget(self._back, 1, QtCore.Qt.AlignCenter) - self._smsButton = QtGui.QPushButton("SMS") + smsIcon = self._app.get_icon("messages.png") + self._smsButton = QtGui.QPushButton(smsIcon, "SMS") self._smsButton.clicked.connect(self._on_sms_clicked) - self._callButton = QtGui.QPushButton("Call") + self._smsButton.setSizePolicy(QtGui.QSizePolicy( + QtGui.QSizePolicy.MinimumExpanding, + QtGui.QSizePolicy.MinimumExpanding, + QtGui.QSizePolicy.PushButton, + )) + callIcon = self._app.get_icon("dialpad.png") + self._callButton = QtGui.QPushButton(callIcon, "Call") self._callButton.clicked.connect(self._on_call_clicked) + self._callButton.setSizePolicy(QtGui.QSizePolicy( + QtGui.QSizePolicy.MinimumExpanding, + QtGui.QSizePolicy.MinimumExpanding, + QtGui.QSizePolicy.PushButton, + )) self._padLayout = QtGui.QGridLayout() rows = [0, 0, 0, 1, 1, 1, 2, 2, 2] @@ -79,13 +92,18 @@ class Dialpad(object): self._padLayout.addWidget(self._generate_key_button(num, letters), row, column) self._zerothButton = QtGui.QPushButton("0") self._zerothButton.clicked.connect(lambda: self._on_keypress("0")) + self._zerothButton.setSizePolicy(QtGui.QSizePolicy( + QtGui.QSizePolicy.MinimumExpanding, + QtGui.QSizePolicy.MinimumExpanding, + QtGui.QSizePolicy.PushButton, + )) self._padLayout.addWidget(self._smsButton, 3, 0) self._padLayout.addWidget(self._zerothButton) self._padLayout.addWidget(self._callButton, 3, 2) self._layout = QtGui.QVBoxLayout() - self._layout.addLayout(self._entryLayout) - self._layout.addLayout(self._padLayout) + self._layout.addLayout(self._entryLayout, 0) + self._layout.addLayout(self._padLayout, 1000000) self._widget = QtGui.QWidget() self._widget.setLayout(self._layout) @@ -115,48 +133,125 @@ class Dialpad(object): def _generate_key_button(self, center, letters): button = QtGui.QPushButton("%s\n%s" % (center, letters)) + button.setSizePolicy(QtGui.QSizePolicy( + QtGui.QSizePolicy.MinimumExpanding, + QtGui.QSizePolicy.MinimumExpanding, + QtGui.QSizePolicy.PushButton, + )) button.clicked.connect(lambda: self._on_keypress(center)) return button @misc_utils.log_exception(_moduleLogger) def _on_keypress(self, key): - self._entry.insert(key) + with qui_utils.notify_error(self._errorLog): + self._entry.insert(key) @misc_utils.log_exception(_moduleLogger) def _on_backspace(self, toggled = False): - self._entry.backspace() + with qui_utils.notify_error(self._errorLog): + self._entry.backspace() @misc_utils.log_exception(_moduleLogger) def _on_clear_text(self, toggled = False): - self._entry.clear() + with qui_utils.notify_error(self._errorLog): + self._entry.clear() @QtCore.pyqtSlot() @QtCore.pyqtSlot(bool) @misc_utils.log_exception(_moduleLogger) def _on_sms_clicked(self, checked = False): - number = misc_utils.make_ugly(str(self._entry.text())) - self._entry.clear() + with qui_utils.notify_error(self._errorLog): + number = misc_utils.make_ugly(str(self._entry.text())) + self._entry.clear() - contactId = number - title = misc_utils.make_pretty(number) - description = misc_utils.make_pretty(number) - numbersWithDescriptions = [(number, "")] - self._session.draft.add_contact(contactId, title, description, numbersWithDescriptions) + contactId = number + title = misc_utils.make_pretty(number) + description = misc_utils.make_pretty(number) + numbersWithDescriptions = [(number, "")] + self._session.draft.add_contact(contactId, None, title, description, numbersWithDescriptions) @QtCore.pyqtSlot() @QtCore.pyqtSlot(bool) @misc_utils.log_exception(_moduleLogger) def _on_call_clicked(self, checked = False): - number = misc_utils.make_ugly(str(self._entry.text())) - self._entry.clear() + with qui_utils.notify_error(self._errorLog): + number = misc_utils.make_ugly(str(self._entry.text())) + self._entry.clear() + + contactId = number + title = misc_utils.make_pretty(number) + description = misc_utils.make_pretty(number) + numbersWithDescriptions = [(number, "")] + self._session.draft.clear() + self._session.draft.add_contact(contactId, None, title, description, numbersWithDescriptions) + self._session.draft.call() + + +class TimeCategories(object): + + _NOW_SECTION = 0 + _TODAY_SECTION = 1 + _WEEK_SECTION = 2 + _MONTH_SECTION = 3 + _REST_SECTION = 4 + _MAX_SECTIONS = 5 + + _NO_ELAPSED = datetime.timedelta(hours=1) + _WEEK_ELAPSED = datetime.timedelta(weeks=1) + _MONTH_ELAPSED = datetime.timedelta(days=30) + + def __init__(self, parentItem): + self._timeItems = [ + QtGui.QStandardItem(description) + for (i, description) in zip( + xrange(self._MAX_SECTIONS), + ["Now", "Today", "Week", "Month", "Past"], + ) + ] + for item in self._timeItems: + item.setEditable(False) + item.setCheckable(False) + row = (item, ) + parentItem.appendRow(row) + + self._today = datetime.datetime(1900, 1, 1) + + self.prepare_for_update(self._today) + + def prepare_for_update(self, newToday): + self._today = newToday + for item in self._timeItems: + item.removeRows(0, item.rowCount()) + try: + hour = self._today.strftime("%X") + day = self._today.strftime("%x") + except ValueError: + _moduleLogger.exception("Can't format times") + hour = "Now" + day = "Today" + self._timeItems[self._NOW_SECTION].setText(hour) + self._timeItems[self._TODAY_SECTION].setText(day) + + def add_row(self, rowDate, row): + elapsedTime = self._today - rowDate + todayTuple = self._today.timetuple() + rowTuple = rowDate.timetuple() + if elapsedTime < self._NO_ELAPSED: + section = self._NOW_SECTION + elif todayTuple[0:3] == rowTuple[0:3]: + section = self._TODAY_SECTION + elif elapsedTime < self._WEEK_ELAPSED: + section = self._WEEK_SECTION + elif elapsedTime < self._MONTH_ELAPSED: + section = self._MONTH_SECTION + else: + section = self._REST_SECTION + self._timeItems[section].appendRow(row) - contactId = number - title = misc_utils.make_pretty(number) - description = misc_utils.make_pretty(number) - numbersWithDescriptions = [(number, "")] - self._session.draft.clear() - self._session.draft.add_contact(contactId, title, description, numbersWithDescriptions) - self._session.draft.call() + def get_item(self, timeIndex, rowIndex, column): + timeItem = self._timeItems[timeIndex] + item = timeItem.child(rowIndex, column) + return item class History(object): @@ -165,7 +260,12 @@ class History(object): FROM_IDX = 1 MAX_IDX = 2 - HISTORY_ITEM_TYPES = ["Received", "Missed", "Placed", "All"] + HISTORY_RECEIVED = "Received" + HISTORY_MISSED = "Missed" + HISTORY_PLACED = "Placed" + HISTORY_ALL = "All" + + HISTORY_ITEM_TYPES = [HISTORY_RECEIVED, HISTORY_MISSED, HISTORY_PLACED, HISTORY_ALL] HISTORY_COLUMNS = ["Details", "From"] assert len(HISTORY_COLUMNS) == MAX_IDX @@ -182,9 +282,23 @@ class History(object): self.HISTORY_ITEM_TYPES.index(self._selectedFilter) ) self._typeSelection.currentIndexChanged[str].connect(self._on_filter_changed) + refreshIcon = qui_utils.get_theme_icon( + ("view-refresh", "general_refresh", "gtk-refresh", ) + ) + self._refreshButton = QtGui.QPushButton(refreshIcon, "") + self._refreshButton.clicked.connect(self._on_refresh_clicked) + self._refreshButton.setSizePolicy(QtGui.QSizePolicy( + QtGui.QSizePolicy.Minimum, + QtGui.QSizePolicy.Minimum, + QtGui.QSizePolicy.PushButton, + )) + self._managerLayout = QtGui.QHBoxLayout() + self._managerLayout.addWidget(self._typeSelection, 1000) + self._managerLayout.addWidget(self._refreshButton, 0) self._itemStore = QtGui.QStandardItemModel() self._itemStore.setHorizontalHeaderLabels(self.HISTORY_COLUMNS) + self._categoryManager = TimeCategories(self._itemStore) self._itemView = QtGui.QTreeView() self._itemView.setModel(self._itemStore) @@ -194,11 +308,12 @@ class History(object): self._itemView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self._itemView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self._itemView.setHeaderHidden(True) + self._itemView.setItemsExpandable(False) self._itemView.header().setResizeMode(QtGui.QHeaderView.ResizeToContents) self._itemView.activated.connect(self._on_row_activated) self._layout = QtGui.QVBoxLayout() - self._layout.addWidget(self._typeSelection) + self._layout.addLayout(self._managerLayout) self._layout.addWidget(self._itemView) self._widget = QtGui.QWidget() self._widget.setLayout(self._layout) @@ -232,82 +347,111 @@ class History(object): self._itemView.clear() def refresh(self, force=True): - self._session.update_history(force) + self._itemView.setFocus(QtCore.Qt.OtherFocusReason) + + if self._selectedFilter == self.HISTORY_RECEIVED: + self._session.update_history(self._session.HISTORY_RECEIVED, force) + elif self._selectedFilter == self.HISTORY_MISSED: + self._session.update_history(self._session.HISTORY_MISSED, force) + elif self._selectedFilter == self.HISTORY_PLACED: + self._session.update_history(self._session.HISTORY_PLACED, force) + elif self._selectedFilter == self.HISTORY_ALL: + self._session.update_history(self._session.HISTORY_ALL, force) + else: + assert False, "How did we get here?" + + if self._app.notifyOnMissed and self._app.alarmHandler.alarmType == self._app.alarmHandler.ALARM_BACKGROUND: + self._app.ledHandler.off() def _populate_items(self): - self._itemStore.clear() + self._categoryManager.prepare_for_update(self._session.get_when_history_updated()) history = self._session.get_history() history.sort(key=lambda item: item["time"], reverse=True) for event in history: - if self._selectedFilter in [self.HISTORY_ITEM_TYPES[-1], event["action"]]: - relTime = misc_utils.abbrev_relative_date(event["relTime"]) - action = event["action"] - number = event["number"] - prettyNumber = misc_utils.make_pretty(number) - name = event["name"] - if not name or name == number: - name = event["location"] - if not name: - name = "Unknown" - - detailsItem = QtGui.QStandardItem("%s - %s\n%s" % (relTime, action, prettyNumber)) - detailsFont = detailsItem.font() - detailsFont.setPointSize(detailsFont.pointSize() - 4) - detailsItem.setFont(detailsFont) - nameItem = QtGui.QStandardItem(name) - nameFont = nameItem.font() - nameFont.setPointSize(nameFont.pointSize() + 4) - nameItem.setFont(nameFont) - row = detailsItem, nameItem - for item in row: - item.setEditable(False) - item.setCheckable(False) - if item is not nameItem: - itemFont = item.font() - itemFont.setPointSize(max(itemFont.pointSize() - 3, 5)) - item.setFont(itemFont) - row[0].setData(event) - self._itemStore.appendRow(row) + if self._selectedFilter not in [self.HISTORY_ITEM_TYPES[-1], event["action"]]: + continue + + relTime = misc_utils.abbrev_relative_date(event["relTime"]) + action = event["action"] + number = event["number"] + prettyNumber = misc_utils.make_pretty(number) + name = event["name"] + if not name or name == number: + name = event["location"] + if not name: + name = "Unknown" + + detailsItem = QtGui.QStandardItem("%s - %s\n%s" % (relTime, action, prettyNumber)) + detailsFont = detailsItem.font() + detailsFont.setPointSize(max(detailsFont.pointSize() - 7, 5)) + detailsItem.setFont(detailsFont) + nameItem = QtGui.QStandardItem(name) + nameFont = nameItem.font() + nameFont.setPointSize(nameFont.pointSize() + 4) + nameItem.setFont(nameFont) + row = detailsItem, nameItem + for item in row: + item.setEditable(False) + item.setCheckable(False) + row[0].setData(event) + self._categoryManager.add_row(event["time"], row) + self._itemView.expandAll() @QtCore.pyqtSlot(str) @misc_utils.log_exception(_moduleLogger) def _on_filter_changed(self, newItem): - self._selectedFilter = str(newItem) - self._populate_items() + with qui_utils.notify_error(self._errorLog): + self._selectedFilter = str(newItem) + self._populate_items() @QtCore.pyqtSlot() @misc_utils.log_exception(_moduleLogger) def _on_history_updated(self): - self._populate_items() + with qui_utils.notify_error(self._errorLog): + self._populate_items() + + @QtCore.pyqtSlot() + @misc_utils.log_exception(_moduleLogger) + def _on_refresh_clicked(self, arg = None): + with qui_utils.notify_error(self._errorLog): + self.refresh(force=True) @QtCore.pyqtSlot(QtCore.QModelIndex) @misc_utils.log_exception(_moduleLogger) def _on_row_activated(self, index): - rowIndex = index.row() - item = self._itemStore.item(rowIndex, 0) - contactDetails = item.data().toPyObject() - - title = str(self._itemStore.item(rowIndex, self.FROM_IDX).text()) - number = str(contactDetails[QtCore.QString("number")]) - contactId = number # ids don't seem too unique so using numbers - - descriptionRows = [] - for i in xrange(self._itemStore.rowCount()): - iItem = self._itemStore.item(i, 0) - iContactDetails = iItem.data().toPyObject() - iNumber = str(iContactDetails[QtCore.QString("number")]) - if number != iNumber: - continue - relTime = misc_utils.abbrev_relative_date(iContactDetails[QtCore.QString("relTime")]) - action = str(iContactDetails[QtCore.QString("action")]) - number = str(iContactDetails[QtCore.QString("number")]) - prettyNumber = misc_utils.make_pretty(number) - rowItems = relTime, action, prettyNumber - descriptionRows.append("%s" % "".join(rowItems)) - description = "%s
" % "".join(descriptionRows) - numbersWithDescriptions = [(str(contactDetails[QtCore.QString("number")]), "")] - self._session.draft.add_contact(contactId, title, description, numbersWithDescriptions) + with qui_utils.notify_error(self._errorLog): + timeIndex = index.parent() + if not timeIndex.isValid(): + return + timeRow = timeIndex.row() + row = index.row() + detailsItem = self._categoryManager.get_item(timeRow, row, self.DETAILS_IDX) + fromItem = self._categoryManager.get_item(timeRow, row, self.FROM_IDX) + contactDetails = detailsItem.data().toPyObject() + + title = unicode(fromItem.text()) + number = str(contactDetails[QtCore.QString("number")]) + contactId = number # ids don't seem too unique so using numbers + + descriptionRows = [] + for t in xrange(self._itemStore.rowCount()): + randomTimeItem = self._itemStore.item(t, 0) + for i in xrange(randomTimeItem.rowCount()): + iItem = randomTimeItem.child(i, 0) + iContactDetails = iItem.data().toPyObject() + iNumber = str(iContactDetails[QtCore.QString("number")]) + if number != iNumber: + continue + relTime = misc_utils.abbrev_relative_date(iContactDetails[QtCore.QString("relTime")]) + action = str(iContactDetails[QtCore.QString("action")]) + number = str(iContactDetails[QtCore.QString("number")]) + prettyNumber = misc_utils.make_pretty(number) + rowItems = relTime, action, prettyNumber + descriptionRows.append("%s" % "".join(rowItems)) + description = "%s
" % "".join(descriptionRows) + numbersWithDescriptions = [(str(contactDetails[QtCore.QString("number")]), "")] + self._session.draft.add_contact(contactId, None, title, description, numbersWithDescriptions) class Messages(object): @@ -323,7 +467,7 @@ class Messages(object): ALL_STATUS = "Any" MESSAGE_STATUSES = [UNREAD_STATUS, UNARCHIVED_STATUS, ALL_STATUS] - _MIN_MESSAGES_SHOWN = 4 + _MIN_MESSAGES_SHOWN = 1 def __init__(self, app, session, errorLog): self._selectedTypeFilter = self.ALL_TYPES @@ -347,12 +491,25 @@ class Messages(object): ) self._statusSelection.currentIndexChanged[str].connect(self._on_status_filter_changed) + refreshIcon = qui_utils.get_theme_icon( + ("view-refresh", "general_refresh", "gtk-refresh", ) + ) + self._refreshButton = QtGui.QPushButton(refreshIcon, "") + self._refreshButton.clicked.connect(self._on_refresh_clicked) + self._refreshButton.setSizePolicy(QtGui.QSizePolicy( + QtGui.QSizePolicy.Minimum, + QtGui.QSizePolicy.Minimum, + QtGui.QSizePolicy.PushButton, + )) + self._selectionLayout = QtGui.QHBoxLayout() - self._selectionLayout.addWidget(self._typeSelection) - self._selectionLayout.addWidget(self._statusSelection) + self._selectionLayout.addWidget(self._typeSelection, 1000) + self._selectionLayout.addWidget(self._statusSelection, 1000) + self._selectionLayout.addWidget(self._refreshButton, 0) self._itemStore = QtGui.QStandardItemModel() self._itemStore.setHorizontalHeaderLabels(["Messages"]) + self._categoryManager = TimeCategories(self._itemStore) self._htmlDelegate = qui_utils.QHtmlDelegate() self._itemView = QtGui.QTreeView() @@ -363,8 +520,10 @@ class Messages(object): self._itemView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self._itemView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self._itemView.setHeaderHidden(True) + self._itemView.setItemsExpandable(False) self._itemView.setItemDelegate(self._htmlDelegate) self._itemView.activated.connect(self._on_row_activated) + self._itemView.header().sectionResized.connect(self._on_column_resized) self._layout = QtGui.QVBoxLayout() self._layout.addLayout(self._selectionLayout) @@ -409,10 +568,25 @@ class Messages(object): self._itemView.clear() def refresh(self, force=True): - self._session.update_messages(force) + self._itemView.setFocus(QtCore.Qt.OtherFocusReason) + + if self._selectedTypeFilter == self.NO_MESSAGES: + pass + elif self._selectedTypeFilter == self.TEXT_MESSAGES: + self._session.update_messages(self._session.MESSAGE_TEXTS, force) + elif self._selectedTypeFilter == self.VOICEMAIL_MESSAGES: + self._session.update_messages(self._session.MESSAGE_VOICEMAILS, force) + elif self._selectedTypeFilter == self.ALL_TYPES: + self._session.update_messages(self._session.MESSAGE_ALL, force) + else: + assert False, "How did we get here?" + + if self._app.notifyOnSms or self._app.notifyOnVoicemail and self._app.alarmHandler.alarmType == self._app.alarmHandler.ALARM_BACKGROUND: + self._app.ledHandler.off() def _populate_items(self): - self._itemStore.clear() + self._categoryManager.prepare_for_update(self._session.get_when_messages_updated()) + rawMessages = self._session.get_messages() rawMessages.sort(key=lambda item: item["time"], reverse=True) for item in rawMessages: @@ -423,90 +597,115 @@ class Messages(object): self.UNARCHIVED_STATUS: isUnarchived, self.ALL_STATUS: True, }[self._selectedStatusFilter] - visibleType = self._selectedTypeFilter in [item["type"], self.ALL_TYPES] - if visibleType and visibleStatus: - relTime = misc_utils.abbrev_relative_date(item["relTime"]) - number = item["number"] - prettyNumber = misc_utils.make_pretty(number) - name = item["name"] - if not name or name == number: - name = item["location"] - if not name: - name = "Unknown" - - messageParts = list(item["messageParts"]) - if len(messageParts) == 0: - messages = ("No Transcription", ) - elif len(messageParts) == 1: - if messageParts[0][1]: - messages = (messageParts[0][1], ) - else: - messages = ("No Transcription", ) - else: - messages = [ - "%s: %s" % (messagePart[0], messagePart[1]) - for messagePart in messageParts - ] - - firstMessage = "%s - %s (%s)" % (name, prettyNumber, relTime) - - expandedMessages = [firstMessage] - expandedMessages.extend(messages) - if (self._MIN_MESSAGES_SHOWN + 1) < len(messages): - secondMessage = "%d Messages Hidden..." % (len(messages) - self._MIN_MESSAGES_SHOWN, ) - collapsedMessages = [firstMessage, secondMessage] - collapsedMessages.extend(messages[-(self._MIN_MESSAGES_SHOWN+0):]) - else: - collapsedMessages = expandedMessages + if not (visibleType and visibleStatus): + continue - item = dict(item.iteritems()) - item["collapsedMessages"] = "
\n".join(collapsedMessages) - item["expandedMessages"] = "
\n".join(expandedMessages) + relTime = misc_utils.abbrev_relative_date(item["relTime"]) + number = item["number"] + prettyNumber = misc_utils.make_pretty(number) + name = item["name"] + if not name or name == number: + name = item["location"] + if not name: + name = "Unknown" - messageItem = QtGui.QStandardItem(item["collapsedMessages"]) - messageItem.setData(item) - messageItem.setEditable(False) - messageItem.setCheckable(False) - row = (messageItem, ) - self._itemStore.appendRow(row) + messageParts = list(item["messageParts"]) + if len(messageParts) == 0: + messages = ("No Transcription", ) + elif len(messageParts) == 1: + if messageParts[0][1]: + messages = (messageParts[0][1], ) + else: + messages = ("No Transcription", ) + else: + messages = [ + "%s: %s" % (messagePart[0], messagePart[1]) + for messagePart in messageParts + ] + + firstMessage = "%s
%s
(%s)" % (name, prettyNumber, relTime) + + expandedMessages = [firstMessage] + expandedMessages.extend(messages) + if self._MIN_MESSAGES_SHOWN < len(messages): + secondMessage = "%d Messages Hidden..." % (len(messages) - self._MIN_MESSAGES_SHOWN, ) + collapsedMessages = [firstMessage, secondMessage] + collapsedMessages.extend(messages[-(self._MIN_MESSAGES_SHOWN+0):]) + else: + collapsedMessages = expandedMessages + + item = dict(item.iteritems()) + item["collapsedMessages"] = "
\n".join(collapsedMessages) + item["expandedMessages"] = "
\n".join(expandedMessages) + + messageItem = QtGui.QStandardItem(item["collapsedMessages"]) + messageItem.setData(item) + messageItem.setEditable(False) + messageItem.setCheckable(False) + row = (messageItem, ) + self._categoryManager.add_row(item["time"], row) + self._itemView.expandAll() @QtCore.pyqtSlot(str) @misc_utils.log_exception(_moduleLogger) def _on_type_filter_changed(self, newItem): - self._selectedTypeFilter = str(newItem) - self._populate_items() + with qui_utils.notify_error(self._errorLog): + self._selectedTypeFilter = str(newItem) + self._populate_items() @QtCore.pyqtSlot(str) @misc_utils.log_exception(_moduleLogger) def _on_status_filter_changed(self, newItem): - self._selectedStatusFilter = str(newItem) - self._populate_items() + with qui_utils.notify_error(self._errorLog): + self._selectedStatusFilter = str(newItem) + self._populate_items() + + @QtCore.pyqtSlot() + @misc_utils.log_exception(_moduleLogger) + def _on_refresh_clicked(self, arg = None): + with qui_utils.notify_error(self._errorLog): + self.refresh(force=True) @QtCore.pyqtSlot() @misc_utils.log_exception(_moduleLogger) def _on_messages_updated(self): - self._populate_items() + with qui_utils.notify_error(self._errorLog): + self._populate_items() @QtCore.pyqtSlot(QtCore.QModelIndex) @misc_utils.log_exception(_moduleLogger) def _on_row_activated(self, index): - rowIndex = index.row() - item = self._itemStore.item(rowIndex, 0) - contactDetails = item.data().toPyObject() + with qui_utils.notify_error(self._errorLog): + timeIndex = index.parent() + if not timeIndex.isValid(): + return + timeRow = timeIndex.row() + row = index.row() + item = self._categoryManager.get_item(timeRow, row, 0) + contactDetails = item.data().toPyObject() + + name = unicode(contactDetails[QtCore.QString("name")]) + number = str(contactDetails[QtCore.QString("number")]) + if not name or name == number: + name = unicode(contactDetails[QtCore.QString("location")]) + if not name: + name = "Unknown" - name = str(contactDetails[QtCore.QString("name")]) - number = str(contactDetails[QtCore.QString("number")]) - if not name or name == number: - name = str(contactDetails[QtCore.QString("location")]) - if not name: - name = "Unknown" + if str(contactDetails[QtCore.QString("type")]) == "Voicemail": + messageId = str(contactDetails[QtCore.QString("id")]) + else: + messageId = None + contactId = str(contactDetails[QtCore.QString("contactId")]) + title = name + description = unicode(contactDetails[QtCore.QString("expandedMessages")]) + numbersWithDescriptions = [(number, "")] + self._session.draft.add_contact(contactId, messageId, title, description, numbersWithDescriptions) - contactId = str(contactDetails[QtCore.QString("id")]) - title = name - description = str(contactDetails[QtCore.QString("expandedMessages")]) - numbersWithDescriptions = [(number, "")] - self._session.draft.add_contact(contactId, title, description, numbersWithDescriptions) + @QtCore.pyqtSlot(QtCore.QModelIndex) + @misc_utils.log_exception(_moduleLogger) + def _on_column_resized(self, index, oldSize, newSize): + self._htmlDelegate.setWidth(newSize, self._itemStore) class Contacts(object): @@ -516,7 +715,7 @@ class Contacts(object): def __init__(self, app, session, errorLog): self._app = app self._session = session - self._session.contactsUpdated.connect(self._on_contacts_updated) + self._session.accountUpdated.connect(self._on_contacts_updated) self._errorLog = errorLog self._addressBookFactories = [ null_backend.NullAddressBookFactory(), @@ -528,6 +727,19 @@ class Contacts(object): self._listSelection.addItems([]) self._listSelection.currentIndexChanged[str].connect(self._on_filter_changed) self._activeList = "None" + refreshIcon = qui_utils.get_theme_icon( + ("view-refresh", "general_refresh", "gtk-refresh", ) + ) + self._refreshButton = QtGui.QPushButton(refreshIcon, "") + self._refreshButton.clicked.connect(self._on_refresh_clicked) + self._refreshButton.setSizePolicy(QtGui.QSizePolicy( + QtGui.QSizePolicy.Minimum, + QtGui.QSizePolicy.Minimum, + QtGui.QSizePolicy.PushButton, + )) + self._managerLayout = QtGui.QHBoxLayout() + self._managerLayout.addWidget(self._listSelection, 1000) + self._managerLayout.addWidget(self._refreshButton, 0) self._itemStore = QtGui.QStandardItemModel() self._itemStore.setHorizontalHeaderLabels(["Contacts"]) @@ -545,7 +757,7 @@ class Contacts(object): self._itemView.activated.connect(self._on_row_activated) self._layout = QtGui.QVBoxLayout() - self._layout.addWidget(self._listSelection) + self._layout.addLayout(self._managerLayout) self._layout.addWidget(self._itemView) self._widget = QtGui.QWidget() self._widget.setLayout(self._layout) @@ -583,7 +795,8 @@ class Contacts(object): self._itemView.clear() def refresh(self, force=True): - self._backend.update_contacts(force) + self._itemView.setFocus(QtCore.Qt.OtherFocusReason) + self._backend.update_account(force) @property def _backend(self): @@ -637,10 +850,15 @@ class Contacts(object): if not name: name = "Unknown" numbers = item["numbers"] + nameItem = QtGui.QStandardItem(name) nameItem.setEditable(False) nameItem.setCheckable(False) nameItem.setData(item) + nameItemFont = nameItem.font() + nameItemFont.setPointSize(max(nameItemFont.pointSize() + 4, 5)) + nameItem.setFont(nameItemFont) + row = (nameItem, ) rowKey = name[0].upper() rowKey = rowKey if rowKey in self._alphaItem else "#" @@ -665,52 +883,62 @@ class Contacts(object): @QtCore.pyqtSlot(str) @misc_utils.log_exception(_moduleLogger) def _on_filter_changed(self, newItem): - self._activeList = str(newItem) - self.refresh(force=False) - self._populate_items() + with qui_utils.notify_error(self._errorLog): + self._activeList = str(newItem) + self.refresh(force=False) + self._populate_items() + + @QtCore.pyqtSlot() + @misc_utils.log_exception(_moduleLogger) + def _on_refresh_clicked(self, arg = None): + with qui_utils.notify_error(self._errorLog): + self.refresh(force=True) @QtCore.pyqtSlot() @misc_utils.log_exception(_moduleLogger) def _on_contacts_updated(self): - self._populate_items() + with qui_utils.notify_error(self._errorLog): + self._populate_items() @QtCore.pyqtSlot(QtCore.QModelIndex) @misc_utils.log_exception(_moduleLogger) def _on_row_activated(self, index): - letterIndex = index.parent() - assert letterIndex.isValid() - letterRow = letterIndex.row() - letter = list(self._prefixes())[letterRow] - letterItem = self._alphaItem[letter] - rowIndex = index.row() - item = letterItem.child(rowIndex, 0) - contactDetails = item.data().toPyObject() - - name = str(contactDetails[QtCore.QString("name")]) - if not name: - name = str(contactDetails[QtCore.QString("location")]) - if not name: - name = "Unknown" - - contactId = str(contactDetails[QtCore.QString("contactId")]) - numbers = contactDetails[QtCore.QString("numbers")] - numbers = [ - dict( - (str(k), str(v)) - for (k, v) in number.iteritems() - ) - for number in numbers - ] - numbersWithDescriptions = [ - ( - number["phoneNumber"], - self._choose_phonetype(number), - ) - for number in numbers - ] - title = name - description = name - self._session.draft.add_contact(contactId, title, description, numbersWithDescriptions) + with qui_utils.notify_error(self._errorLog): + letterIndex = index.parent() + if not letterIndex.isValid(): + return + letterRow = letterIndex.row() + letter = list(self._prefixes())[letterRow] + letterItem = self._alphaItem[letter] + rowIndex = index.row() + item = letterItem.child(rowIndex, 0) + contactDetails = item.data().toPyObject() + + name = unicode(contactDetails[QtCore.QString("name")]) + if not name: + name = unicode(contactDetails[QtCore.QString("location")]) + if not name: + name = "Unknown" + + contactId = str(contactDetails[QtCore.QString("contactId")]) + numbers = contactDetails[QtCore.QString("numbers")] + numbers = [ + dict( + (str(k), str(v)) + for (k, v) in number.iteritems() + ) + for number in numbers + ] + numbersWithDescriptions = [ + ( + number["phoneNumber"], + self._choose_phonetype(number), + ) + for number in numbers + ] + title = name + description = name + self._session.draft.add_contact(contactId, None, title, description, numbersWithDescriptions) @staticmethod def _choose_phonetype(numberDetails):