From ffa7024ba37af4b1795d8f63e630df1279989e80 Mon Sep 17 00:00:00 2001
From: Inso <insomniak.fr@gmail.com>
Date: Sun, 8 Feb 2015 22:01:52 +0100
Subject: [PATCH] Added the possibility to edit contacts and remove them

---
 res/ui/{add_contact.ui => contact.ui} | 12 +++---
 res/ui/mainwindow.ui                  |  6 +++
 src/cutecoin/core/account.py          | 13 +++---
 src/cutecoin/gui/add_contact.py       | 48 ----------------------
 src/cutecoin/gui/community_tab.py     | 10 ++---
 src/cutecoin/gui/contact.py           | 59 +++++++++++++++++++++++++++
 src/cutecoin/gui/mainwindow.py        | 37 ++++++++++++++---
 src/cutecoin/gui/wot_tab.py           |  5 ++-
 src/cutecoin/tools/exceptions.py      | 14 +++++++
 9 files changed, 131 insertions(+), 73 deletions(-)
 rename res/ui/{add_contact.ui => contact.ui} (90%)
 delete mode 100644 src/cutecoin/gui/add_contact.py
 create mode 100644 src/cutecoin/gui/contact.py

diff --git a/res/ui/add_contact.ui b/res/ui/contact.ui
similarity index 90%
rename from res/ui/add_contact.ui
rename to res/ui/contact.ui
index ac9d87ad..8fb07867 100644
--- a/res/ui/add_contact.ui
+++ b/res/ui/contact.ui
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
- <class>AddContactDialog</class>
- <widget class="QDialog" name="AddContactDialog">
+ <class>ConfigureContactDialog</class>
+ <widget class="QDialog" name="ConfigureContactDialog">
   <property name="geometry">
    <rect>
     <x>0</x>
@@ -59,7 +59,7 @@
   <connection>
    <sender>button_box</sender>
    <signal>accepted()</signal>
-   <receiver>AddContactDialog</receiver>
+   <receiver>ConfigureContactDialog</receiver>
    <slot>accept()</slot>
    <hints>
     <hint type="sourcelabel">
@@ -75,7 +75,7 @@
   <connection>
    <sender>button_box</sender>
    <signal>rejected()</signal>
-   <receiver>AddContactDialog</receiver>
+   <receiver>ConfigureContactDialog</receiver>
    <slot>reject()</slot>
    <hints>
     <hint type="sourcelabel">
@@ -91,7 +91,7 @@
   <connection>
    <sender>edit_pubkey</sender>
    <signal>textChanged(QString)</signal>
-   <receiver>AddContactDialog</receiver>
+   <receiver>ConfigureContactDialog</receiver>
    <slot>pubkey_edited()</slot>
    <hints>
     <hint type="sourcelabel">
@@ -107,7 +107,7 @@
   <connection>
    <sender>edit_name</sender>
    <signal>textChanged(QString)</signal>
-   <receiver>AddContactDialog</receiver>
+   <receiver>ConfigureContactDialog</receiver>
    <slot>name_edited()</slot>
    <hints>
     <hint type="sourcelabel">
diff --git a/res/ui/mainwindow.ui b/res/ui/mainwindow.ui
index 9a2dec6b..3f259944 100644
--- a/res/ui/mainwindow.ui
+++ b/res/ui/mainwindow.ui
@@ -176,6 +176,11 @@
     <string>Set as default</string>
    </property>
   </action>
+  <action name="actionAbout">
+   <property name="text">
+    <string>About</string>
+   </property>
+  </action>
  </widget>
  <resources/>
  <connections>
@@ -335,5 +340,6 @@
   <slot>export_account()</slot>
   <slot>open_certification_dialog()</slot>
   <slot>set_as_default_account()</slot>
+  <slot>open_about_dialog()</slot>
  </slots>
 </ui>
diff --git a/src/cutecoin/core/account.py b/src/cutecoin/core/account.py
index 14dd247b..a8bccbb2 100644
--- a/src/cutecoin/core/account.py
+++ b/src/cutecoin/core/account.py
@@ -18,7 +18,7 @@ import time
 from .wallet import Wallet
 from .community import Community
 from .person import Person
-from ..tools.exceptions import NoPeerAvailable
+from ..tools.exceptions import NoPeerAvailable, ContactAlreadyExists
 
 
 def quantitative(units, community):
@@ -119,11 +119,12 @@ class Account(object):
         return (key.pubkey == self.pubkey)
 
     def add_contact(self, person):
-        same_contact = [contact for contact in self.contacts if person.pubkey == contact.pubkey]
-        if len(same_contact) == 0:
-            self.contacts.append(person)
-            return True
-        return False
+        same_contact = [contact for contact in self.contacts
+                        if person.pubkey == contact.pubkey]
+
+        if len(same_contact) > 0:
+            raise ContactAlreadyExists(person.uid, same_contact[0].uid)
+        self.contacts.append(person)
 
     def add_community(self, community):
         logging.debug("Adding a community")
diff --git a/src/cutecoin/gui/add_contact.py b/src/cutecoin/gui/add_contact.py
deleted file mode 100644
index b004ce0f..00000000
--- a/src/cutecoin/gui/add_contact.py
+++ /dev/null
@@ -1,48 +0,0 @@
-'''
-Created on 2 févr. 2014
-
-@author: inso
-'''
-import re
-from PyQt5.QtWidgets import QDialog, QDialogButtonBox
-
-
-from cutecoin.core.person import Person
-
-from cutecoin.gen_resources.add_contact_uic import Ui_AddContactDialog
-
-
-class AddContactDialog(QDialog, Ui_AddContactDialog):
-
-    '''
-    classdocs
-    '''
-
-    def __init__(self, account, parent=None):
-        '''
-        Constructor
-        '''
-        super().__init__()
-        self.setupUi(self)
-        self.account = account
-        self.main_window = parent
-        self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
-
-    def accept(self):
-        name = self.edit_name.text()
-        pubkey = self.edit_pubkey.text()
-        result = self.account.add_contact(Person(name, pubkey))
-        if result:
-            self.main_window.menu_contacts_list.addAction(name)
-            self.main_window.app.save(self.account)
-        super().accept()
-
-    def name_edited(self, new_name):
-        name_ok = len(new_name) > 0
-        self.button_box.button(QDialogButtonBox.Ok).setEnabled(name_ok)
-
-    def pubkey_edited(self, new_pubkey):
-        pattern = re.compile("([1-9A-Za-z][^OIl]{42,45})")
-        self.button_box.button(
-            QDialogButtonBox.Ok).setEnabled(
-            pattern.match(new_pubkey)is not None)
diff --git a/src/cutecoin/gui/community_tab.py b/src/cutecoin/gui/community_tab.py
index c56f8600..a75308fb 100644
--- a/src/cutecoin/gui/community_tab.py
+++ b/src/cutecoin/gui/community_tab.py
@@ -11,7 +11,7 @@ from PyQt5.QtWidgets import QWidget, QMessageBox, QAction, QMenu, QDialog, \
                             QAbstractItemView
 from ..models.members import MembersFilterProxyModel, MembersTableModel
 from ..gen_resources.community_tab_uic import Ui_CommunityTabWidget
-from .add_contact import AddContactDialog
+from cutecoin.gui.contact import ConfigureContactDialog
 from .wot_tab import WotTabWidget
 from .transfer import TransferMoneyDialog
 from .password_asker import PasswordAskerDialog
@@ -88,11 +88,11 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget):
             menu.exec_(self.table_community_members.mapToGlobal(point))
 
     def add_member_as_contact(self):
-        dialog = AddContactDialog(self.account, self.window())
         person = self.sender().data()
-        dialog.edit_name.setText(person.name)
-        dialog.edit_pubkey.setText(person.pubkey)
-        dialog.exec_()
+        dialog = ConfigureContactDialog(self.account, self.window(), person)
+        result = dialog.exec_()
+        if result == QDialog.Accepted:
+            self.window().refresh_contacts()
 
     def send_money_to_member(self):
         dialog = TransferMoneyDialog(self.account, self.password_asker)
diff --git a/src/cutecoin/gui/contact.py b/src/cutecoin/gui/contact.py
new file mode 100644
index 00000000..3a0cd82d
--- /dev/null
+++ b/src/cutecoin/gui/contact.py
@@ -0,0 +1,59 @@
+'''
+Created on 2 févr. 2014
+
+@author: inso
+'''
+import re
+from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QMessageBox
+from ..core.person import Person
+from ..tools.exceptions import ContactAlreadyExists
+from ..gen_resources.contact_uic import Ui_ConfigureContactDialog
+
+
+class ConfigureContactDialog(QDialog, Ui_ConfigureContactDialog):
+
+    '''
+    classdocs
+    '''
+
+    def __init__(self, account, parent=None, contact=None):
+        '''
+        Constructor
+        '''
+        super().__init__()
+        self.setupUi(self)
+        self.account = account
+        self.main_window = parent
+        self.contact = contact
+        if contact:
+            self.edit_name.setText(contact.name)
+            self.edit_pubkey.setText(contact.pubkey)
+
+        self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
+
+    def accept(self):
+        name = self.edit_name.text()
+        pubkey = self.edit_pubkey.text()
+        if self.contact:
+            self.contact.name = name
+            self.contact.pubkey = pubkey
+        else:
+            try:
+                self.account.add_contact(Person(name, pubkey))
+            except ContactAlreadyExists as e:
+                QMessageBox.critical(self, "Contact already exists",
+                            str(e),
+                            QMessageBox.Ok)
+                return
+        self.main_window.app.save(self.account)
+        super().accept()
+
+    def name_edited(self, new_name):
+        name_ok = len(new_name) > 0
+        self.button_box.button(QDialogButtonBox.Ok).setEnabled(name_ok)
+
+    def pubkey_edited(self, new_pubkey):
+        pattern = re.compile("([1-9A-Za-z][^OIl]{42,45})")
+        self.button_box.button(
+            QDialogButtonBox.Ok).setEnabled(
+            pattern.match(new_pubkey)is not None)
diff --git a/src/cutecoin/gui/mainwindow.py b/src/cutecoin/gui/mainwindow.py
index 16826ad0..55ce5008 100644
--- a/src/cutecoin/gui/mainwindow.py
+++ b/src/cutecoin/gui/mainwindow.py
@@ -12,7 +12,7 @@ from PyQt5.QtGui import QIcon
 from .process_cfg_account import ProcessConfigureAccount
 from .transfer import TransferMoneyDialog
 from .currency_tab import CurrencyTabWidget
-from .add_contact import AddContactDialog
+from cutecoin.gui.contact import ConfigureContactDialog
 from .import_account import ImportAccountDialog
 from .certification import CertificationDialog
 from .password_asker import PasswordAskerDialog
@@ -129,6 +129,20 @@ class MainWindow(QMainWindow, Ui_MainWindow):
         timer.timeout.connect(self.update_time)
         timer.start(next_time - current_time)
 
+    @pyqtSlot()
+    def delete_contact(self):
+        contact = self.sender().data()
+        self.app.current_account.contacts.remove(contact)
+        self.refresh_contacts()
+
+    @pyqtSlot()
+    def edit_contact(self):
+        contact = self.sender().data()
+        dialog = ConfigureContactDialog(self.app.current_account, self, contact)
+        result = dialog.exec_()
+        if result == QDialog.Accepted:
+            self.window().refresh_contacts()
+
     def action_change_account(self, account_name):
         self.busybar.show()
         self.status_label.setText("Loading account {0}".format(account_name))
@@ -149,7 +163,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
         dialog.exec_()
 
     def open_add_contact_dialog(self):
-        AddContactDialog(self.app.current_account, self).exec_()
+        dialog = ConfigureContactDialog(self.app.current_account, self)
+        result = dialog.exec_()
+        if result == QDialog.Accepted:
+            self.window().refresh_contacts()
 
     def open_configure_account_dialog(self):
         dialog = ProcessConfigureAccount(self.app, self.app.current_account)
@@ -173,6 +190,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
                                              QIcon(":/icons/currency_icon"),
                                              community.name())
 
+    def refresh_contacts(self):
+        self.menu_contacts_list.clear()
+        for contact in self.app.current_account.contacts:
+            contact_menu = self.menu_contacts_list.addMenu(contact.name)
+            edit_action = contact_menu.addAction("Edit")
+            edit_action.triggered.connect(self.edit_contact)
+            edit_action.setData(contact)
+            delete_action = contact_menu.addAction("Delete")
+            delete_action.setData(contact)
+            delete_action.triggered.connect(self.delete_contact)
+
     def set_as_default_account(self):
         self.app.default_account = self.app.current_account.name
         logging.debug(self.app.current_account)
@@ -237,10 +265,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
                     QMessageBox.critical(self, ":(",
                                 str(e),
                                 QMessageBox.Ok)
-
-            self.menu_contacts_list.clear()
-            for contact in self.app.current_account.contacts:
-                self.menu_contacts_list.addAction(contact.name)
+            self.refresh_contacts()
 
     def import_account(self):
         dialog = ImportAccountDialog(self.app, self)
diff --git a/src/cutecoin/gui/wot_tab.py b/src/cutecoin/gui/wot_tab.py
index 9357eff6..73e04924 100644
--- a/src/cutecoin/gui/wot_tab.py
+++ b/src/cutecoin/gui/wot_tab.py
@@ -9,10 +9,11 @@ from ..gen_resources.wot_tab_uic import Ui_WotTabWidget
 from cutecoin.gui.views.wot import NODE_STATUS_HIGHLIGHTED, NODE_STATUS_SELECTED, NODE_STATUS_OUT, ARC_STATUS_STRONG, ARC_STATUS_WEAK
 from ucoinpy.api import bma
 from .certification import CertificationDialog
-from .add_contact import AddContactDialog
+from cutecoin.gui.contact import ConfigureContactDialog
 from .transfer import TransferMoneyDialog
 from cutecoin.core.person import Person
 
+
 class WotTabWidget(QWidget, Ui_WotTabWidget):
     def __init__(self, account, community, password_asker, parent=None):
         """
@@ -361,7 +362,7 @@ class WotTabWidget(QWidget, Ui_WotTabWidget):
         # check if contact already exists...
         if metadata['id'] == self.account.pubkey or metadata['id'] in [contact.pubkey for contact in self.account.contacts]:
             return False
-        dialog = AddContactDialog(self.account, self.window())
+        dialog = ConfigureContactDialog(self.account, self.window())
         dialog.edit_name.setText(metadata['text'])
         dialog.edit_pubkey.setText(metadata['id'])
         dialog.exec_()
diff --git a/src/cutecoin/tools/exceptions.py b/src/cutecoin/tools/exceptions.py
index a240dbe1..6813277f 100644
--- a/src/cutecoin/tools/exceptions.py
+++ b/src/cutecoin/tools/exceptions.py
@@ -165,3 +165,17 @@ class NoPeerAvailable(Error):
         super() .__init__(
             "No peer answered in {0} community ({1} peers available)"
             .format(currency, peers))
+
+
+class ContactAlreadyExists(Error):
+    '''
+    Exception raised when a community doesn't have any
+    peer available.
+    '''
+    def __init__(self, new_contact, already_contact):
+        '''
+        Constructor
+        '''
+        super() .__init__(
+            "Cannot add {0}, he/she has the same pubkey as {1} contact"
+            .format(new_contact, already_contact))
-- 
GitLab