Repository: Bitmessage/PyBitmessage

Issue:
Send message to this chan
The chan context menu should contain the ability to send a message to the chan.


Discussion:

Resolving patch:
diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py
--- a/src/bitmessageqt/__init__.py
+++ b/src/bitmessageqt/__init__.py
@@ -282,8 +282,6 @@ def init_identities_popup_menu(self, connectSignal=True):
                 ))
 
     def init_chan_popup_menu(self, connectSignal=True):
-        # Popup menu for the Channels tab
-        self.ui.addressContextMenuToolbar = QtGui.QToolBar()
         # Actions
         self.actionNew = self.ui.addressContextMenuToolbar.addAction(_translate(
             "MainWindow", "New"), self.on_action_YourIdentitiesNew)
@@ -304,6 +302,9 @@ def init_chan_popup_menu(self, connectSignal=True):
             _translate(
                 "MainWindow", "Copy address to clipboard"),
             self.on_action_Clipboard)
+        self.actionSend = self.ui.addressContextMenuToolbar.addAction(
+            _translate("MainWindow", "Send message to this chan"),
+            self.on_action_Send)
         self.actionSpecialAddressBehavior = self.ui.addressContextMenuToolbar.addAction(
             _translate(
                 "MainWindow", "Special address behavior..."),
@@ -354,8 +355,6 @@ def init_addressbook_popup_menu(self, connectSignal=True):
                         self.on_context_menuAddressBook)
 
     def init_subscriptions_popup_menu(self, connectSignal=True):
-        # Popup menu for the Subscriptions page
-        self.ui.subscriptionsContextMenuToolbar = QtGui.QToolBar()
         # Actions
         self.actionsubscriptionsNew = self.ui.subscriptionsContextMenuToolbar.addAction(
             _translate("MainWindow", "New"), self.on_action_SubscriptionsNew)
@@ -374,6 +373,9 @@ def init_subscriptions_popup_menu(self, connectSignal=True):
         self.actionsubscriptionsSetAvatar = self.ui.subscriptionsContextMenuToolbar.addAction(
             _translate("MainWindow", "Set avatar..."),
             self.on_action_TreeWidgetSetAvatar)
+        self.actionsubscriptionsSend = self.ui.addressContextMenuToolbar.addAction(
+            _translate("MainWindow", "Send message to this address"),
+            self.on_action_Send)
         self.ui.treeWidgetSubscriptions.setContextMenuPolicy(
             QtCore.Qt.CustomContextMenu)
         if connectSignal:
@@ -1872,7 +1874,7 @@ def click_pushButtonTTL(self):
     def click_pushButtonClear(self):
         self.ui.lineEditSubject.setText("")
         self.ui.lineEditTo.setText("")
-        self.ui.textEditMessage.setText("")
+        self.ui.textEditMessage.reset()
         self.ui.comboBoxSendFrom.setCurrentIndex(0)
 
     def click_pushButtonSend(self):
@@ -2085,10 +2087,7 @@ def click_pushButtonSend(self):
                             toAddress, toLabel, fromAddress, subject, message, ackdata)
                         queues.workerQueue.put(('sendmessage', toAddress))
 
-                        self.ui.comboBoxSendFrom.setCurrentIndex(0)
-                        self.ui.lineEditTo.setText('')
-                        self.ui.lineEditSubject.setText('')
-                        self.ui.textEditMessage.reset()
+                        self.click_pushButtonClear()
                         if self.replyFromTab is not None:
                             self.ui.tabWidget.setCurrentIndex(self.replyFromTab)
                             self.replyFromTab = None
@@ -2609,7 +2608,19 @@ def click_actionSettings(self):
                 except:
                     pass
 
+    def on_action_Send(self):
+        """Send message to current selected address"""
+        self.click_pushButtonClear()
+        account_item = self.getCurrentItem()
+        if not account_item:
+            return
+        self.ui.lineEditTo.setText(account_item.accountString())
+        self.ui.tabWidget.setCurrentIndex(
+            self.ui.tabWidget.indexOf(self.ui.send)
+        )
+
     def on_action_SpecialAddressBehaviorDialog(self):
+        """Show SpecialAddressBehaviorDialog"""
         dialogs.SpecialAddressBehaviorDialog(self, BMConfigParser())
 
     def on_action_EmailGatewayDialog(self):
@@ -3098,8 +3109,7 @@ def on_action_InboxReply(self, reply_type=None):
             self.ui.lineEditTo.setText(str(acct.fromAddress))
         else:
             self.ui.lineEditTo.setText(
-                tableWidget.item(currentInboxRow, column_from).label +
-                " <" + str(acct.fromAddress) + ">"
+                tableWidget.item(currentInboxRow, column_from).accountString()
             )
 
         # If the previous message was to a chan then we should send our
@@ -3114,8 +3124,7 @@ def on_action_InboxReply(self, reply_type=None):
                 self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow))
             else:
                 self.ui.lineEditTo.setText(
-                    tableWidget.item(currentInboxRow, column_to).label +
-                    " <" + str(acct.toAddress) + ">"
+                    tableWidget.item(currentInboxRow, column_to).accountString()
                 )
 
         self.setSendFromComboBox(toAddressAtCurrentInboxRow)
@@ -3349,73 +3358,58 @@ def on_action_AddressBookDelete(self):
         while self.ui.tableWidgetAddressBook.selectedIndexes() != []:
             currentRow = self.ui.tableWidgetAddressBook.selectedIndexes()[
                 0].row()
-            labelAtCurrentRow = self.ui.tableWidgetAddressBook.item(
-                currentRow, 0).text().toUtf8()
-            addressAtCurrentRow = self.ui.tableWidgetAddressBook.item(
-                currentRow, 1).text()
-            sqlExecute('''DELETE FROM addressbook WHERE label=? AND address=?''',
-                       str(labelAtCurrentRow), str(addressAtCurrentRow))
+            item = self.ui.tableWidgetAddressBook.item(currentRow, 0)
+            sqlExecute(
+                'DELETE FROM addressbook WHERE label=? AND address=?',
+                item.label, item.address)
             self.ui.tableWidgetAddressBook.removeRow(currentRow)
-            self.rerenderMessagelistFromLabels()
-            self.rerenderMessagelistToLabels()
+        self.rerenderMessagelistFromLabels()
+        self.rerenderMessagelistToLabels()
 
     def on_action_AddressBookClipboard(self):
-        fullStringOfAddresses = ''
-        listOfSelectedRows = {}
-        for i in range(len(self.ui.tableWidgetAddressBook.selectedIndexes())):
-            listOfSelectedRows[
-                self.ui.tableWidgetAddressBook.selectedIndexes()[i].row()] = 0
-        for currentRow in listOfSelectedRows:
-            addressAtCurrentRow = self.ui.tableWidgetAddressBook.item(
-                currentRow, 1).text()
-            if fullStringOfAddresses == '':
-                fullStringOfAddresses = addressAtCurrentRow
+        addresses_string = ''
+        for item in self.getAddressbookSelectedItems():
+            if addresses_string == '':
+                addresses_string = item.address
             else:
-                fullStringOfAddresses += ', ' + str(addressAtCurrentRow)
+                addresses_string += ', ' + item.address
         clipboard = QtGui.QApplication.clipboard()
-        clipboard.setText(fullStringOfAddresses)
+        clipboard.setText(addresses_string)
 
     def on_action_AddressBookSend(self):
-        listOfSelectedRows = {}
-        for i in range(len(self.ui.tableWidgetAddressBook.selectedIndexes())):
-            listOfSelectedRows[
-                self.ui.tableWidgetAddressBook.selectedIndexes()[i].row()] = 0
-        for currentRow in listOfSelectedRows:
-            addressAtCurrentRow = self.ui.tableWidgetAddressBook.item(
-                currentRow, 0).address
-            labelAtCurrentRow = self.ui.tableWidgetAddressBook.item(
-                currentRow, 0).label
-            stringToAdd = labelAtCurrentRow + " <" + addressAtCurrentRow + ">"
-            if self.ui.lineEditTo.text() == '':
-                self.ui.lineEditTo.setText(stringToAdd)
-            else:
-                self.ui.lineEditTo.setText(unicode(
-                    self.ui.lineEditTo.text().toUtf8(), encoding="UTF-8") + '; ' + stringToAdd)
-        if listOfSelectedRows == {}:
-            self.updateStatusBar(_translate(
+        selected_items = self.getAddressbookSelectedItems()
+
+        if not selected_items:  # FIXME: impossible
+            return self.updateStatusBar(_translate(
                 "MainWindow", "No addresses selected."))
-        else:
-            self.statusbar.clearMessage()
-            self.ui.tabWidget.setCurrentIndex(
-                self.ui.tabWidget.indexOf(self.ui.send)
-            )
+
+        addresses_string = unicode(
+            self.ui.lineEditTo.text().toUtf8(), 'utf-8')
+        for item in selected_items:
+            address_string = item.accountString()
+            if not addresses_string:
+                addresses_string = address_string
+            else:
+                addresses_string += '; ' + address_string
+
+        self.ui.lineEditTo.setText(addresses_string)
+        self.statusbar.clearMessage()
+        self.ui.tabWidget.setCurrentIndex(
+            self.ui.tabWidget.indexOf(self.ui.send)
+        )
 
     def on_action_AddressBookSubscribe(self):
-        listOfSelectedRows = {}
-        for i in range(len(self.ui.tableWidgetAddressBook.selectedIndexes())):
-            listOfSelectedRows[self.ui.tableWidgetAddressBook.selectedIndexes()[i].row()] = 0
-        for currentRow in listOfSelectedRows:
-            addressAtCurrentRow = str(self.ui.tableWidgetAddressBook.item(currentRow,1).text())
-            # Then subscribe to it... provided it's not already in the address book
-            if shared.isAddressInMySubscriptionsList(addressAtCurrentRow):
+        for item in self.getAddressbookSelectedItems():
+            # Then subscribe to it...
+            # provided it's not already in the address book
+            if shared.isAddressInMySubscriptionsList(item.address):
                 self.updateStatusBar(_translate(
                     "MainWindow",
                     "Error: You cannot add the same address to your"
                     " subscriptions twice. Perhaps rename the existing"
                     " one if you want."))
                 continue
-            labelAtCurrentRow = self.ui.tableWidgetAddressBook.item(currentRow,0).text().toUtf8()
-            self.addSubscription(addressAtCurrentRow, labelAtCurrentRow)
+            self.addSubscription(item.address, item.label)
             self.ui.tabWidget.setCurrentIndex(
                 self.ui.tabWidget.indexOf(self.ui.subscriptions)
             )
@@ -3508,6 +3502,7 @@ def on_context_menuSubscriptions(self, point):
             self.popMenuSubscriptions.addAction(self.actionsubscriptionsSetAvatar)
             self.popMenuSubscriptions.addSeparator()
             self.popMenuSubscriptions.addAction(self.actionsubscriptionsClipboard)
+            self.popMenuSubscriptions.addAction(self.actionsubscriptionsSend)
             self.popMenuSubscriptions.addSeparator()
             # preloaded gui.menu plugins with prefix 'address'
             for plugin in self.menu_plugins['address']:
@@ -3655,11 +3650,8 @@ def getCurrentItem(self, treeWidget=None):
         if treeWidget is None:
             treeWidget = self.getCurrentTreeWidget()
         if treeWidget:
-            currentItem = treeWidget.currentItem()
-            if currentItem:
-                return currentItem
-        return False
-    
+            return treeWidget.currentItem()
+
     def getCurrentAccount(self, treeWidget=None):
         currentItem = self.getCurrentItem(treeWidget)
         if currentItem:
@@ -3689,6 +3681,13 @@ def setCurrentItemColor(self, color):
             currentItem = treeWidget.currentItem()
             currentItem.setForeground(0, brush)
 
+    def getAddressbookSelectedItems(self):
+        return [
+            self.ui.tableWidgetAddressBook.item(i.row(), 0)
+            for i in self.ui.tableWidgetAddressBook.selectedIndexes()
+            if i.column() == 0
+        ]
+
     def on_action_YourIdentitiesNew(self):
         self.click_NewAddressDialog()
 
@@ -3946,14 +3945,15 @@ def on_context_menuChan(self, point):
             self.popMenu.addAction(self.actionNew)
             self.popMenu.addAction(self.actionDelete)
             self.popMenu.addSeparator()
-            self.popMenu.addAction(self.actionClipboard)
-            self.popMenu.addSeparator()
             if currentItem.isEnabled:
                 self.popMenu.addAction(self.actionDisable)
             else:
                 self.popMenu.addAction(self.actionEnable)
             self.popMenu.addAction(self.actionSetAvatar)
             self.popMenu.addSeparator()
+            self.popMenu.addAction(self.actionClipboard)
+            self.popMenu.addAction(self.actionSend)
+            self.popMenu.addSeparator()
             # preloaded gui.menu plugins with prefix 'address'
             for plugin in self.menu_plugins['address']:
                 self.popMenu.addAction(plugin)
diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py
--- a/src/bitmessageqt/bitmessageui.py
+++ b/src/bitmessageqt/bitmessageui.py
@@ -654,6 +654,10 @@ def setupUi(self, MainWindow):
         # Popup menu actions container for the Sent page
         # pylint: disable=attribute-defined-outside-init
         self.sentContextMenuToolbar = QtGui.QToolBar()
+        # Popup menu actions container for chans tree
+        self.addressContextMenuToolbar = QtGui.QToolBar()
+        # Popup menu actions container for subscriptions tree
+        self.subscriptionsContextMenuToolbar = QtGui.QToolBar()
 
     def updateNetworkSwitchMenuLabel(self, dontconnect=None):
         if dontconnect is None:
diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py
--- a/src/bitmessageqt/foldertree.py
+++ b/src/bitmessageqt/foldertree.py
@@ -56,6 +56,14 @@ def folderBrush(self):
         brush.setStyle(QtCore.Qt.NoBrush)
         return brush
 
+    def accountString(self):
+        """Account string suitable for use in To: field: label <address>"""
+        label = self._getLabel()
+        return (
+            self.address if label == self.address
+            else '%s <%s>' % (label, self.address)
+        )
+
     def setAddress(self, address):
         """Set bitmessage address of the object"""
         if address is None:
@@ -359,6 +367,9 @@ class BMAddressWidget(BMTableWidgetItem, AccountMixin):
     def _setup(self):
         self.setEnabled(True)
 
+    def _getLabel(self):
+        return self.label
+
     def data(self, role):
         """Return object data (QT UI)"""
         if role == QtCore.Qt.ToolTipRole:


Test patch: