diff --git a/res/ui/account_cfg.ui b/res/ui/account_cfg.ui index b4dadc108853b1fdb00bca75ca0ac93a64850904..015a34e0101ba6a13d1dd0c413862294f80b460d 100644 --- a/res/ui/account_cfg.ui +++ b/res/ui/account_cfg.ui @@ -57,6 +57,33 @@ </item> </layout> </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <property name="topMargin"> + <number>6</number> + </property> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Wallets</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="spinbox_wallets"> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="value"> + <number>1</number> + </property> + </widget> + </item> + </layout> + </item> <item> <spacer name="verticalSpacer_4"> <property name="orientation"> @@ -387,7 +414,7 @@ <sender>edit_account_name</sender> <signal>textChanged(QString)</signal> <receiver>AccountConfigurationDialog</receiver> - <slot>action_edit_account_name()</slot> + <slot>action_edit_account_parameters()</slot> <hints> <hint type="sourcelabel"> <x>240</x> @@ -415,6 +442,22 @@ </hint> </hints> </connection> + <connection> + <sender>spinbox_wallets</sender> + <signal>valueChanged(int)</signal> + <receiver>AccountConfigurationDialog</receiver> + <slot>action_edit_account_parameters()</slot> + <hints> + <hint type="sourcelabel"> + <x>285</x> + <y>127</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>118</y> + </hint> + </hints> + </connection> </connections> <slots> <slot>open_process_add_community()</slot> @@ -426,7 +469,7 @@ <slot>open_import_key()</slot> <slot>open_generate_account_key()</slot> <slot>action_edit_account_key()</slot> - <slot>action_edit_account_name()</slot> + <slot>action_edit_account_parameters()</slot> <slot>action_show_pubkey()</slot> </slots> </ui> diff --git a/res/ui/currency_tab.ui b/res/ui/currency_tab.ui index 8202b52816ffd30139d4cb7fec24c388b79bd49a..ce62a5d2b8b88036901c295288c26762e45b530c 100644 --- a/res/ui/currency_tab.ui +++ b/res/ui/currency_tab.ui @@ -37,7 +37,11 @@ </attribute> <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QListView" name="list_wallets"/> + <widget class="QListView" name="list_wallets"> + <property name="contextMenuPolicy"> + <enum>Qt::CustomContextMenu</enum> + </property> + </widget> </item> <item> <widget class="QListView" name="list_wallet_content"/> @@ -87,5 +91,42 @@ </layout> </widget> <resources/> - <connections/> + <connections> + <connection> + <sender>list_wallets</sender> + <signal>clicked(QModelIndex)</signal> + <receiver>CurrencyTabWidget</receiver> + <slot>refresh_wallet_content(QModelIndex)</slot> + <hints> + <hint type="sourcelabel"> + <x>113</x> + <y>162</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>149</y> + </hint> + </hints> + </connection> + <connection> + <sender>list_wallets</sender> + <signal>customContextMenuRequested(QPoint)</signal> + <receiver>CurrencyTabWidget</receiver> + <slot>wallet_context_menu(QPoint)</slot> + <hints> + <hint type="sourcelabel"> + <x>113</x> + <y>162</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>149</y> + </hint> + </hints> + </connection> + </connections> + <slots> + <slot>refresh_wallet_content(QModelIndex)</slot> + <slot>wallet_context_menu(QPoint)</slot> + </slots> </ui> diff --git a/src/cutecoin/core/account.py b/src/cutecoin/core/account.py index 52b47a12695c96e098112a596a9cffb7810ef2cd..fb48e6eca75244d71112e6fbc369ca5f1be0fb98 100644 --- a/src/cutecoin/core/account.py +++ b/src/cutecoin/core/account.py @@ -98,19 +98,16 @@ class Account(object): community = Community.create(currency, peer) self.communities.append(community) - - wallet = Wallet.create(self.next_walletid(), self.pubkey, - currency, "Default wallet") - self.wallets.append(wallet) - return community - def next_walletid(self): - wid = 0 - for w in self.wallets: - if w.walletid > wid: - wid = w.walletid + 1 - return wid + def set_walletpool_size(self, size, password): + logging.debug("Defining wallet pool size") + if len(self.wallets) < size: + for i in range(len(self.wallets), size): + wallet = Wallet.create(i, self.salt, password, "Wallet {0}".format(i)) + self.wallets.append(wallet) + else: + self.wallets = self.wallets[:size] def certify(self, password, community, pubkey): certified = Person.lookup(pubkey, community) diff --git a/src/cutecoin/core/community.py b/src/cutecoin/core/community.py index 2b6e24afdfe146f2d7ade405694209f4be33c936..29d53e9438922fd9c131d14f91115eb76b2658ba 100644 --- a/src/cutecoin/core/community.py +++ b/src/cutecoin/core/community.py @@ -97,7 +97,6 @@ class Community(object): return members def request(self, request, req_args={}, get_args={}): - logging.debug("Peers : {0}".format(self.peers)) for peer in self.peers: e = next(e for e in peer.endpoints if type(e) is BMAEndpoint) # We request the current block every five minutes @@ -125,8 +124,8 @@ class Community(object): self.requests_cache = {cache_key: data} else: if cache_key in self.requests_cache.keys(): - logging.debug("Cache : {0} : {1}".format(cache_key, - self.requests_cache[cache_key])) + #logging.debug("Cache : {0} : {1}".format(cache_key, + # self.requests_cache[cache_key])) return self.requests_cache[cache_key] # If we cant find it, we request for it else: diff --git a/src/cutecoin/core/wallet.py b/src/cutecoin/core/wallet.py index 64ffea2ad902df169a0e54edfa4c42520a531bfc..0aa4b721e626cf11f250e8bf24ce69bffb9f8be7 100644 --- a/src/cutecoin/core/wallet.py +++ b/src/cutecoin/core/wallet.py @@ -17,28 +17,30 @@ class Wallet(object): A wallet is used to manage money with a unique key. ''' - def __init__(self, walletid, pubkey, currency, name): + def __init__(self, walletid, pubkey, name): ''' Constructor ''' self.coins = [] self.walletid = walletid self.pubkey = pubkey - self.currency = currency self.name = name self.inputs_cache = None @classmethod - def create(cls, walletid, pubkey, currency, name): - return cls(walletid, pubkey, currency, name) + def create(cls, walletid, salt, password, name): + if walletid == 0: + key = SigningKey(salt, password) + else: + key = SigningKey("{0}{1}".format(salt, walletid), password) + return cls(walletid, key.pubkey, name) @classmethod def load(cls, json_data): walletid = json_data['walletid'] pubkey = json_data['pubkey'] name = json_data['name'] - currency = json_data['currency'] - return cls(walletid, pubkey, currency, name) + return cls(walletid, pubkey, name) def __eq__(self, other): return (self.keyid == other.keyid) @@ -138,11 +140,10 @@ class Wallet(object): def get_text(self, community): return "%s : \n \ %d %s \n \ -%.2f UD" % (self.name, self.value(community), self.currency, +%.2f UD" % (self.name, self.value(community), community.currency, self.relative_value(community)) def jsonify(self): return {'walletid': self.walletid, 'pubkey': self.pubkey, - 'name': self.name, - 'currency': self.currency} + 'name': self.name} diff --git a/src/cutecoin/gui/currency_tab.py b/src/cutecoin/gui/currency_tab.py index 04716b1d2ab0a68e1c8aac76e5bff91d663450b5..4f937d0fa5dc616438a11f876c5d5a9ae236f289 100644 --- a/src/cutecoin/gui/currency_tab.py +++ b/src/cutecoin/gui/currency_tab.py @@ -5,8 +5,8 @@ Created on 2 févr. 2014 ''' import logging -from PyQt5.QtWidgets import QWidget, QErrorMessage -from PyQt5.QtCore import QModelIndex +from PyQt5.QtWidgets import QWidget, QMenu, QAction, QApplication +from PyQt5.QtCore import QModelIndex, Qt from cutecoin.gen_resources.currency_tab_uic import Ui_CurrencyTabWidget from cutecoin.gui.community_tab import CommunityTabWidget from cutecoin.models.sent import SentListModel @@ -46,7 +46,9 @@ class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): self.tabs_account.addTab(tab_community, "Community") def refresh_wallets(self): - wallets_list_model = WalletsListModel(self.app.current_account) + wallets_list_model = WalletsListModel(self.app.current_account, + self.community) + wallets_list_model.dataChanged.connect(self.wallet_changed) self.list_wallets.setModel(wallets_list_model) self.refresh_wallet_content(QModelIndex()) @@ -54,3 +56,36 @@ class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): current_wallet = self.app.current_account.wallets[index.row()] wallet_list_model = WalletListModel(current_wallet, self.community) self.list_wallet_content.setModel(wallet_list_model) + + def wallet_context_menu(self, point): + index = self.list_wallets.indexAt(point) + model = self.list_wallets.model() + if index.row() < model.rowCount(None): + wallet = model.wallets[index.row()] + logging.debug(wallet) + menu = QMenu(model.data(index, Qt.DisplayRole), self) + + rename = QAction("Rename", self) + rename.triggered.connect(self.rename_wallet) + rename.setData(index) + + copy_pubkey = QAction("Copy pubkey to clipboard", self) + copy_pubkey.triggered.connect(self.copy_pubkey_to_clipboard) + copy_pubkey.setData(wallet) + + menu.addAction(rename) + menu.addAction(copy_pubkey) + # Show the context menu. + menu.exec_(self.list_wallets.mapToGlobal(point)) + + def rename_wallet(self): + index = self.sender().data() + self.list_wallets.edit(index) + + def copy_pubkey_to_clipboard(self): + wallet = self.sender().data() + clipboard = QApplication.clipboard() + clipboard.setText(wallet.pubkey) + + def wallet_changed(self): + self.app.save(self.app.current_account) diff --git a/src/cutecoin/gui/process_cfg_account.py b/src/cutecoin/gui/process_cfg_account.py index c6e05b840775cfaefd52164e4d6a029c2c3f6692..ad23a63f330f6ec63b4ab26df18fbb2f2c8692b1 100644 --- a/src/cutecoin/gui/process_cfg_account.py +++ b/src/cutecoin/gui/process_cfg_account.py @@ -11,7 +11,7 @@ from cutecoin.gui.process_cfg_community import ProcessConfigureCommunity from cutecoin.models.communities import CommunitiesListModel from cutecoin.tools.exceptions import KeyAlreadyUsed, Error -from PyQt5.QtWidgets import QDialog, QErrorMessage, QFileDialog, QMessageBox +from PyQt5.QtWidgets import QDialog, QErrorMessage, QInputDialog, QMessageBox, QLineEdit class Step(): @@ -47,6 +47,8 @@ class StepPageInit(Step): self.config_dialog.edit_account_name.setText(self.config_dialog.account.name) model = CommunitiesListModel(self.config_dialog.account) self.config_dialog.list_communities.setModel(model) + nb_wallets = len(self.config_dialog.account.wallets) + self.config_dialog.spinbox_wallets.setValue(nb_wallets) self.config_dialog.button_previous.setEnabled(False) self.config_dialog.button_next.setEnabled(False) @@ -109,8 +111,7 @@ class StepPageCommunities(Step): port = self.config_dialog.spinbox_port.value() account = self.config_dialog.account self.config_dialog.community = account.add_community(server, port) - account.wallets.add_wallet(0, - self.config_dialog.community) + self.config_dialog.refresh() def display_page(self): @@ -147,6 +148,7 @@ class ProcessConfigureAccount(QDialog, Ui_AccountConfigurationDialog): else: self.stacked_pages.removeWidget(self.stacked_pages.widget(1)) step_init.next_step = step_communities + self.button_next.setEnabled(True) self.setWindowTitle("Configure " + self.account.name) def open_process_add_community(self): @@ -181,9 +183,10 @@ class ProcessConfigureAccount(QDialog, Ui_AccountConfigurationDialog): salt = self.edit_email.text() password = self.edit_password.text() pubkey = SigningKey(salt, password).pubkey - QMessageBox.information(self, "Public key", "These parameters pubkeys are : {0}".format(pubkey)) + QMessageBox.information(self, "Public key", + "These parameters pubkeys are : {0}".format(pubkey)) - def action_edit_account_name(self): + def action_edit_account_parameters(self): if self.step.is_valid(): self.button_next.setEnabled(True) else: @@ -217,12 +220,28 @@ class ProcessConfigureAccount(QDialog, Ui_AccountConfigurationDialog): self.step.display_page() def accept(self): + password = "" if self.account not in self.app.accounts: self.account.name = self.edit_account_name.text() try: self.app.add_account(self.account) except KeyAlreadyUsed as e: QErrorMessage(self).showMessage(e.message) + password = self.edit_password.text() + else: + message = "Please enter your password" + + while not self.account.check_password(password): + password = QInputDialog.getText(self, "Account password", + message, + QLineEdit.Password) + message = "Error, wrong password. Please enter your password" + if password[1] is True: + password = password[0] + else: + return + nb_wallets = self.spinbox_wallets.value() + self.account.set_walletpool_size(nb_wallets, password) self.app.save(self.account) self.accepted.emit() self.close() diff --git a/src/cutecoin/gui/process_cfg_community.py b/src/cutecoin/gui/process_cfg_community.py index d719cd881ed3edf4fb2316d3a7cd75dea3dcd013..07b562e320946e5bc23a28c86db559b4101ee12d 100644 --- a/src/cutecoin/gui/process_cfg_community.py +++ b/src/cutecoin/gui/process_cfg_community.py @@ -98,10 +98,6 @@ class ProcessConfigureCommunity(QDialog, Ui_CommunityConfigurationDialog): self.account = account self.step = None self.peers = [] - self.wallet_edit = {} - - for w in self.account.wallets: - self.wallet_edit[w.name] = False step_init = StepPageInit(self) step_add_peers = StepPageAddpeers(self) diff --git a/src/cutecoin/gui/transfer.py b/src/cutecoin/gui/transfer.py index 029771805e0aff22a60ded0441e8f9874c292937..cbdbafa67ddf8ef214b56fc4dca6e3b8657ad1f3 100644 --- a/src/cutecoin/gui/transfer.py +++ b/src/cutecoin/gui/transfer.py @@ -40,7 +40,7 @@ class TransferMoneyDialog(QDialog, Ui_TransferMoneyDialog): self.combo_contact.addItem(contact.name) def accept(self): - message = self.edit_message.text() + comment = self.edit_message.text() if self.radio_contact.isChecked(): index = self.combo_contact.currentIndex() @@ -48,18 +48,15 @@ class TransferMoneyDialog(QDialog, Ui_TransferMoneyDialog): else: recipient = self.edit_pubkey.text() amount = self.spinbox_amount.value() - password = QInputDialog.getText(self, "Wallet password", - "Please enter your password", - QLineEdit.Password) - if password[1] is True: - password = password[0] - else: - return - while not self.wallet.check_password(self.sender.salt, password): - password = QInputDialog.getText(self, "Wallet password", - "Wrong password.\nPlease enter your password", - QLineEdit.Password) + password = "" + message = "Please enter your password" + + while not self.sender.check_password(password): + password = QInputDialog.getText(self, "Account password", + message, + QLineEdit.Password) + message = "Error, wrong password. Please enter your password" if password[1] is True: password = password[0] else: @@ -67,7 +64,7 @@ class TransferMoneyDialog(QDialog, Ui_TransferMoneyDialog): try: self.wallet.send_money(self.sender.salt, password, self.community, - recipient, amount, message) + recipient, amount, comment) QMessageBox.information(self, "Money transfer", "Success transfering {0} {1} to {2}".format(amount, self.community.currency, diff --git a/src/cutecoin/models/wallets.py b/src/cutecoin/models/wallets.py index d43560b495b8334ecb078f4529b21556f48ec1c1..a2f9dabb1a8ecaba136b1eb8c566d6e188052ea4 100644 --- a/src/cutecoin/models/wallets.py +++ b/src/cutecoin/models/wallets.py @@ -5,32 +5,41 @@ Created on 8 févr. 2014 ''' from PyQt5.QtCore import QAbstractListModel, Qt +import logging class WalletsListModel(QAbstractListModel): ''' - A Qt abstract item model to display communities in a tree + A Qt list model to display wallets and edit their names ''' - def __init__(self, account, parent=None): + def __init__(self, account, community, parent=None): ''' Constructor ''' super(WalletsListModel, self).__init__(parent) self.wallets = account.wallets - self.communities = account.communities + self.community = community def rowCount(self, parent): - return len(self.wallets) * len(self.communities) + return len(self.wallets) def data(self, index, role): + row = index.row() if role == Qt.DisplayRole: - row = index.row() - index_community = row % len(self.communities) - index_wallet = int(row / len(self.communities)) - value = self.wallets[index_wallet].get_text(self.communities[index_community]) + value = self.wallets[row].get_text(self.community) return value + elif role == Qt.EditRole: + return self.wallets[row].name + + def setData(self, index, value, role): + if role == Qt.EditRole: + row = index.row() + self.wallets[row].name = value + self.dataChanged.emit(index, index) + return True + return False def flags(self, index): - return Qt.ItemIsSelectable | Qt.ItemIsEnabled + return Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable