From 98313d594fe25413d765e14f57f89cf984bafe41 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 29 Apr 2016 02:03:48 +0200 Subject: [PATCH] Sender autocompletion Sender autocompletion now works, and is based on the l labels in the addressbook (i.e. all addressbook entries, all subscriptions and chans). Repurposed C code from https://stackoverflow.com/questions/21773348/how-to-force-qcompleter-to-check-second-word-in-qlineedit --- src/bitmessageqt/__init__.py | 14 +++++++-- src/bitmessageqt/bitmessageui.py | 7 +++++ src/bitmessageqt/foldertree.py | 54 ++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e166577b..06c6f70b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -659,6 +659,9 @@ class MyForm(settingsmixin.SMainWindow): # Initialize addressbook QtCore.QObject.connect(self.ui.tableWidgetAddressBook, QtCore.SIGNAL( "itemChanged(QTableWidgetItem *)"), self.tableWidgetAddressBookItemChanged) + # This is necessary for the completer to work if multiple recipients + QtCore.QObject.connect(self.ui.lineEditTo, QtCore.SIGNAL( + "cursorPositionChanged(int, int)"), self.ui.lineEditTo.completer().onCursorPositionChanged) # show messages from message list QtCore.QObject.connect(self.ui.tableWidgetInbox, QtCore.SIGNAL( @@ -1889,18 +1892,21 @@ class MyForm(settingsmixin.SMainWindow): label, address = row newRows[address] = [label, AccountMixin.NORMAL] + completerList = [] for address in sorted(oldRows, key = lambda x: oldRows[x][2], reverse = True): if address in newRows: + completerList.append(newRows[address][0] + " <" + address + ">") newRows.pop(address) else: self.ui.tableWidgetAddressBook.removeRow(oldRows[address][2]) for address in newRows: addRow(address, newRows[address][0], newRows[address][1]) + completerList.append(newRows[address][0] + " <" + address + ">") # sort self.ui.tableWidgetAddressBook.sortByColumn(0, Qt.AscendingOrder) self.ui.tableWidgetAddressBook.setSortingEnabled(True) - + self.ui.lineEditTo.completer().model().setStringList(completerList) def rerenderSubscriptions(self): self.rerenderTabTreeSubscriptions() @@ -1956,7 +1962,11 @@ class MyForm(settingsmixin.SMainWindow): toAddressesList)) # remove duplicate addresses. If the user has one address with a BM- and the same address without the BM-, this will not catch it. They'll send the message to the person twice. for toAddress in toAddressesList: if toAddress != '': - if toAddress.find("@") >= 0: + # label plus address + if "<" in toAddress and ">" in toAddress: + toAddress = toAddress.split('<')[1].split('>')[0] + # email address + elif toAddress.find("@") >= 0: if isinstance(acct, GatewayAccount): acct.createMessage(toAddress, fromAddress, subject, message) subject = acct.subject diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 1a0e87ec..1761dfe3 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -8,6 +8,7 @@ # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui +from foldertree import AddressBookCompleter from messageview import MessageView from messagecompose import MessageCompose import settingsmixin @@ -185,6 +186,11 @@ class Ui_MainWindow(object): self.tableWidgetAddressBook.horizontalHeader().setStretchLastSection(True) self.tableWidgetAddressBook.verticalHeader().setVisible(False) self.verticalSplitter_2.addWidget(self.tableWidgetAddressBook) + self.addressBookCompleter = AddressBookCompleter() + self.addressBookCompleter.setCompletionMode(QtGui.QCompleter.PopupCompletion) + self.addressBookCompleter.setCaseSensitivity(QtCore.Qt.CaseInsensitive) + self.addressBookCompleterModel = QtGui.QStringListModel() + self.addressBookCompleter.setModel(self.addressBookCompleterModel) self.pushButtonAddAddressBook = QtGui.QPushButton(self.send) self.pushButtonAddAddressBook.setObjectName(_fromUtf8("pushButtonAddAddressBook")) self.pushButtonAddAddressBook.resize(200, self.pushButtonAddAddressBook.height()) @@ -239,6 +245,7 @@ class Ui_MainWindow(object): self.lineEditTo = QtGui.QLineEdit(self.sendDirect) self.lineEditTo.setObjectName(_fromUtf8("lineEditTo")) self.gridLayout_2.addWidget(self.lineEditTo, 1, 1, 1, 1) + self.lineEditTo.setCompleter(self.addressBookCompleter) self.gridLayout_2_Widget = QtGui.QWidget() self.gridLayout_2_Widget.setLayout(self.gridLayout_2) self.verticalSplitter_5.addWidget(self.gridLayout_2_Widget) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index d3c7817f..e77ea74b 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -1,4 +1,5 @@ from PyQt4 import QtCore, QtGui +from string import find, rfind, rstrip, lstrip from helper_sql import * from utils import * @@ -478,3 +479,56 @@ class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem): Ui_AddressBookWidgetItem.__init__(self, address, type) self.address = address self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + +class AddressBookCompleter(QtGui.QCompleter): + def __init__(self): + super(QtGui.QCompleter, self).__init__() + self.cursorPos = -1 + + def onCursorPositionChanged(self, oldPos, newPos): + if oldPos != self.cursorPos: + self.cursorPos = -1 + + def splitPath(self, path): + stringList = [] + text = unicode(path.toUtf8()) + splitIndex = rfind(text[0:self.widget().cursorPosition()], ";") + 1 + str = text[splitIndex:self.widget().cursorPosition()] + str = rstrip(lstrip(str)) + stringList.append(str) + return stringList + + def pathFromIndex(self, index): + autoString = unicode(index.data(QtCore.Qt.EditRole).toString()) + text = unicode(self.widget().text().toUtf8()) + + # If cursor position was saved, restore it, else save it + if self.cursorPos != -1: + self.widget().setCursorPosition(self.cursorPos) + else: + self.cursorPos = self.widget().cursorPosition() + + # Get current prosition + curIndex = self.widget().cursorPosition() + + # prev_delimiter_index should actually point at final white space AFTER the delimiter + # Get index of last delimiter before current position + prevDelimiterIndex = rfind(text[0:curIndex], ";") + while text[prevDelimiterIndex + 1] == " ": + prevDelimiterIndex += 1 + + # Get index of first delimiter after current position (or EOL if no delimiter after cursor) + nextDelimiterIndex = find(text, ";", curIndex) + if nextDelimiterIndex == -1: + nextDelimiterIndex = len(text) + + # Get part of string that occurs before cursor + part1 = text[0:prevDelimiterIndex + 1] + + # Get string value from before auto finished string is selected + pre = text[prevDelimiterIndex + 1:curIndex - 1]; + + # Get part of string that occurs AFTER cursor + part2 = text[nextDelimiterIndex:] + + return part1 + autoString + part2;