diff --git a/res/ui/mainwindow.ui b/res/ui/mainwindow.ui index 8d2640f9de52e2dd757291c6e525abbca593730e..f980d5dc26cdea5dd76edf5edcc6a83efaa903f2 100644 --- a/res/ui/mainwindow.ui +++ b/res/ui/mainwindow.ui @@ -121,7 +121,12 @@ <property name="title"> <string>Account</string> </property> - <addaction name="actionChange_account"/> + <widget class="QMenu" name="menuChange_account"> + <property name="title"> + <string>Change account</string> + </property> + </widget> + <addaction name="menuChange_account"/> <addaction name="actionAdd_account"/> <addaction name="separator"/> <addaction name="actionSave"/> @@ -138,11 +143,6 @@ <addaction name="menuEdit"/> </widget> <widget class="QStatusBar" name="statusbar"/> - <action name="actionChange_account"> - <property name="text"> - <string>Change account</string> - </property> - </action> <action name="actionManage_accounts"> <property name="text"> <string>Manage accounts</string> @@ -203,6 +203,11 @@ <string>Quit</string> </property> </action> + <action name="actionAccount"> + <property name="text"> + <string>Account</string> + </property> + </action> </widget> <resources/> <connections> @@ -229,8 +234,8 @@ <slot>save()</slot> <hints> <hint type="sourcelabel"> - <x>225</x> - <y>199</y> + <x>-1</x> + <y>-1</y> </hint> <hint type="destinationlabel"> <x>225</x> diff --git a/src/cutecoin/core/__init__.py b/src/cutecoin/core/__init__.py index 35bd0972f17a5657c70dad493e1c84be3820a86c..908b1a8df8b7f8abb900cf1f582d3eebafbe24a1 100644 --- a/src/cutecoin/core/__init__.py +++ b/src/cutecoin/core/__init__.py @@ -4,17 +4,20 @@ Created on 1 févr. 2014 @author: inso ''' -from cutecoin.core import config -from cutecoin.core.exceptions import KeyAlreadyUsed - +import os +import logging import json + from cutecoin.core import config +from cutecoin.core.exceptions import KeyAlreadyUsed from cutecoin.models.account import factory -import os class Core(object): - + ''' + Managing core application datas : + Accounts list and general configuration + ''' def __init__(self, argv): ''' Constructor @@ -24,8 +27,11 @@ class Core(object): config.parseArguments(argv) self.load() - def getAccounts(self): - return self.accounts + def getAccount(self, name): + for a in self.accounts: + logging.debug('Name : ' + a.name + '/' + name) + if name == a.name: + return a def addAccount(self, account): for a in self.accounts: @@ -40,22 +46,24 @@ class Core(object): def load(self): - if (os.path.exists(config.data['home'])): - json_data=open(config.data['home'], 'w+') + if not os.path.exists(config.parameters['home']): + logging.info("Creating home directory") + os.makedirs((config.parameters['home'])) + + if (os.path.exists(config.parameters['data']) \ + and os.path.isfile(config.parameters['data'])): + json_data=open(config.parameters['data'], 'r') data = json.load(json_data) json_data.close() for accountData in data['localAccounts']: self.accounts.append(factory.loadAccount(accountData)) - def save(self): - with open(config.data['home'], 'w+') as outfile: + with open(config.parameters['data'], 'w') as outfile: json.dump(self.jsonify(), outfile, indent = 4, sort_keys=True) - - def jsonifyAccounts(self): data = [] for account in self.accounts: diff --git a/src/cutecoin/core/config.py b/src/cutecoin/core/config.py index 74b13d1fe3e6d3b5d9b1afe8932879a4e4bbb4ca..7efb38bdcdb0bde645eac878640a02dce1e26d61 100644 --- a/src/cutecoin/core/config.py +++ b/src/cutecoin/core/config.py @@ -6,7 +6,13 @@ Created on 7 févr. 2014 import logging from optparse import OptionParser -data = { 'home' : '~/.cutecoin'} +import os.path + + +home = os.path.expanduser("~") + +parameters = { 'home' : home + '/.config/cutecoin/', + 'data' : home + '/.config/cutecoin/' 'data'} def parseArguments(argv): parser = OptionParser() @@ -20,7 +26,7 @@ def parseArguments(argv): help="Print DEBUG messages to stdout") - parser.add_option("--home", dest="home", default="~/.cutecoin", + parser.add_option("--home", dest="home", default=parameters['home'], help="Set another home for cutecoin.") (options, args) = parser.parse_args(argv) @@ -32,6 +38,6 @@ def parseArguments(argv): else: logging.getLogger().propagate = False - data['home'] = options.home + parameters['home'] = options.home pass \ No newline at end of file diff --git a/src/cutecoin/core/exceptions.py b/src/cutecoin/core/exceptions.py index ec4bc921fa79c794a3a6ed79f2beb9f7337d1b8f..de9ce9419f628b941fce2776ebec77c411bda091 100644 --- a/src/cutecoin/core/exceptions.py +++ b/src/cutecoin/core/exceptions.py @@ -45,7 +45,7 @@ class KeyAlreadyUsed(Error): Constructor ''' super(KeyAlreadyUsed, self) \ - .__init("Cannot add account " + newAccount.name + " : " \ + .__init__("Cannot add account " + newAccount.name + " : " \ " the pgpKey " + keyId + " is already used by " + foundAccount.name) diff --git a/src/cutecoin/gui/mainWindow.py b/src/cutecoin/gui/mainWindow.py index 91b8ef70f7347c8996ca647dde03d66f587a82eb..d8a3ed49fa4f8cea986c046cd42e795bd5376ee1 100644 --- a/src/cutecoin/gui/mainWindow.py +++ b/src/cutecoin/gui/mainWindow.py @@ -4,13 +4,17 @@ Created on 1 févr. 2014 @author: inso ''' from cutecoin.gen_resources.mainwindow_uic import Ui_MainWindow -from PyQt5.QtWidgets import QMainWindow +from PyQt5.QtWidgets import QMainWindow, QAction, QErrorMessage +from PyQt5.QtCore import QSignalMapper from cutecoin.gui.addAccountDialog import AddAccountDialog from cutecoin.gui.communityTabWidget import CommunityTabWidget from cutecoin.models.account.wallets.listModel import WalletsListModel from cutecoin.models.wallet.listModel import WalletListModel from cutecoin.models.transaction.sentListModel import SentListModel from cutecoin.models.transaction.receivedListModel import ReceivedListModel +from cutecoin.core.exceptions import KeyAlreadyUsed + +import logging class MainWindow(QMainWindow, Ui_MainWindow): ''' @@ -26,6 +30,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): super(MainWindow, self).__init__() self.setupUi(self) self.core = core + self.refreshMainWindow() def openAddAccountDialog(self): self.addAccountDialog = AddAccountDialog(self) @@ -34,23 +39,43 @@ class MainWindow(QMainWindow, Ui_MainWindow): def actionAddAccount(self): self.addAccountDialog.account.name = self.addAccountDialog.accountName.text() - self.core.addAccount(self.addAccountDialog.account) + try: + self.core.addAccount(self.addAccountDialog.account) + except KeyAlreadyUsed as e: + QErrorMessage(self).showMessage(e.message) + self.refreshMainWindow() def save(self): self.core.save() + def actionChangeAccount(self, accountName): + self.core.currentAccount = self.core.getAccount(accountName) + logging.info('Changing account to ' + self.core.currentAccount.name) + self.refreshMainWindow() + + ''' Refresh main window When the selected account changes, all the widgets in the window have to be refreshed ''' def refreshMainWindow(self): + self.menuChange_account.clear() + signalMapper = QSignalMapper(self) + + for account in self.core.accounts: + action = QAction(account.name, self) + self.menuChange_account.addAction(action) + signalMapper.setMapping(action, account.name) + action.triggered.connect(signalMapper.map) + signalMapper.mapped[str].connect(self.actionChangeAccount) + if self.core.currentAccount == None: self.accountTabs.setEnabled(False) else: self.accountTabs.setEnabled(True) - self.accountNameLabel = self.core.currentAccount.name + self.accountNameLabel.setText("Current account : " + self.core.currentAccount.name) self.walletsList.setModel(WalletsListModel(self.core.currentAccount)) self.walletContent.setModel(WalletListModel(self.core.currentAccount.wallets.walletsList[0])) for community in self.core.currentAccount.communities.communitiesList: @@ -58,4 +83,3 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.transactionsSent.setModel(SentListModel(self.core.currentAccount)) self.transactionsReceived.setModel(ReceivedListModel(self.core.currentAccount)) - diff --git a/src/cutecoin/models/account/communities/treeModel.py b/src/cutecoin/models/account/communities/treeModel.py deleted file mode 100644 index 13988dd7ee07df6bbd47ce2b89236d57c2a880cb..0000000000000000000000000000000000000000 --- a/src/cutecoin/models/account/communities/treeModel.py +++ /dev/null @@ -1,105 +0,0 @@ -''' -Created on 5 févr. 2014 - -@author: inso -''' - -from PyQt5.QtCore import QAbstractItemModel, Qt, QModelIndex -from cutecoin.models.account.communities.itemModel import CommunitiesItemModel -from cutecoin.models.community.itemModel import CommunityItemModel -from cutecoin.models.node.itemModel import MainNodeItem, NodeItem - -#TODO: Use it somewhere or remove it from the code - -class CommunitiesTreeModel(QAbstractItemModel): - ''' - A Qt abstract item model to display communities in a tree - ''' - def __init__(self, account): - ''' - Constructor - ''' - super(CommunitiesTreeModel, self).__init__(None) - self.communities = account.communities - self.rootItem = CommunitiesItemModel(account) - self.refreshTreeNodes() - - def columnCount(self, parent): - return 1 - - def data(self, index, role): - if not index.isValid(): - return None - - if role != Qt.DisplayRole: - return None - - item = index.internalPointer() - - return item.data - - def flags(self, index): - if not index.isValid(): - return Qt.NoItemFlags - - return Qt.ItemIsEnabled | Qt.ItemIsSelectable - - def headerData(self, section, orientation, role): - if orientation == Qt.Horizontal and role == Qt.DisplayRole: - return "Communities nodes" - - return None - - def index(self, row, column, parent): - if not self.hasIndex(row, column, parent): - return QModelIndex() - - if not parent.isValid(): - parentItem = self.rootItem - else: - parentItem = parent.internalPointer() - - childItem = parentItem.child(row) - if childItem: - return self.createIndex(row, column, childItem) - else: - return QModelIndex() - - def parent(self, index): - if not index.isValid(): - return QModelIndex() - - childItem = index.internalPointer() - parentItem = childItem.parent() - - if parentItem == self.rootItem: - return QModelIndex() - - return self.createIndex(parentItem.row(), 0, parentItem) - - def rowCount(self, parent): - if parent.column() > 0: - return 0 - - if not parent.isValid(): - parentItem = self.rootItem - else: - parentItem = parent.internalPointer() - - return parentItem.childCount() - - - def refreshTreeNodes(self): - for community in self.communities.communitiesList: - communityItem = CommunityItemModel(community, self) - self.rootItem.appendChild(communityItem) - for mainNode in community.knownNodes: - mainNodeItem = MainNodeItem(mainNode, communityItem) - communityItem.appendChild(mainNodeItem) - for node in mainNode.downstreamPeers(): - nodeItem = NodeItem(node, mainNodeItem) - mainNodeItem.appendChild(nodeItem) - - - - diff --git a/src/cutecoin/models/account/factory.py b/src/cutecoin/models/account/factory.py index 07d40bca323dad599dc1b5ad7debd26cb9c9a949..f37a46edb6e3ec93c9f7a524db15c61046b4abc4 100644 --- a/src/cutecoin/models/account/factory.py +++ b/src/cutecoin/models/account/factory.py @@ -32,5 +32,5 @@ def loadAccount(jsonData): account.communities.communitiesList.append(communityFactory.loadCommunity(communityData)) account.wallets = Wallets() for walletData in jsonData['wallets']: - account.wallets.walletsList.append(walletFactory.loadWallet(jsonData)) + account.wallets.walletsList.append(walletFactory.loadWallet(walletData)) return account \ No newline at end of file diff --git a/src/cutecoin/models/coin/__init__.py b/src/cutecoin/models/coin/__init__.py index 4ed5473499e04e56f4d0f114e221997b5ef95232..c7945b8b4636481e7ac633aa8119775b8e12e0f3 100644 --- a/src/cutecoin/models/coin/__init__.py +++ b/src/cutecoin/models/coin/__init__.py @@ -9,7 +9,7 @@ import math class Coin(object): ''' - classdocs + A coin parsing a regex to read its value ''' diff --git a/src/cutecoin/models/community/__init__.py b/src/cutecoin/models/community/__init__.py index c86cecbb101bc5f40b1da61c64ce7577ce145c7c..657864f0b437999403e5bc4ad649bc3dadbf5e0c 100644 --- a/src/cutecoin/models/community/__init__.py +++ b/src/cutecoin/models/community/__init__.py @@ -15,7 +15,9 @@ class Community(object): ''' def __init__(self): ''' - Constructor + A community is a group of nodes using the same currency. + They are all using the same amendment and are syncing their datas. + An account is a member of a community if he is a member of the current amendment. ''' self.knownNodes = [] self.currency = "" @@ -30,12 +32,12 @@ class Community(object): members.append(f['value']) return members - def issuances(self): + def issuances(self, accountFingerprint): ''' Listing issuances the accounted emitted ''' #TODO:Return issuances - #issuances = self.ucoinRequest(ucoin.hdc.amendments.view.Members(amendmentId) + #issuances = self.ucoinRequest(ucoin.hdc.transactions.sender.Issuance()) return [] def ucoinRequest(self, request, get_args={}): diff --git a/src/cutecoin/models/community/factory.py b/src/cutecoin/models/community/factory.py index eb9ffdc34b18ee5dee89ac4740e8a3e92cc5c4fd..46118c0835f867ce56a12e1d4bf6902fc827ea1d 100644 --- a/src/cutecoin/models/community/factory.py +++ b/src/cutecoin/models/community/factory.py @@ -18,7 +18,7 @@ def createCommunity(mainNode): def loadCommunity(jsonData): community = Community() for nodeData in jsonData['nodes']: - community.knownNodes.append(MainNode(jsonData['server'], jsonData['port'])) + community.knownNodes.append(MainNode(nodeData['server'], nodeData['port'])) community.currency = jsonData['currency'] return community diff --git a/src/cutecoin/models/node/__init__.py b/src/cutecoin/models/node/__init__.py index be33fcb5e5b4995a3ec76975b077def74dd420ee..0d2c5d8fcdfe574bf799c44a35307b02ad2d4cea 100644 --- a/src/cutecoin/models/node/__init__.py +++ b/src/cutecoin/models/node/__init__.py @@ -8,7 +8,7 @@ import ucoinpy as ucoin class Node(object): ''' - classdocs + A ucoin node ''' def __init__(self, server, port): ''' @@ -25,6 +25,10 @@ class Node(object): class MainNode(Node): + ''' + MainNode is a node the community is reading to get informations. + The account sends data one of the community main nodes. + ''' def downstreamPeers(self): ucoin.settings['server'] = self.server ucoin.settings['port'] = self.port diff --git a/src/cutecoin/models/person/factory.py b/src/cutecoin/models/person/factory.py index 12fa25c823aad6efc052361eeea05577e9b41481..def3b6ee1c6544d97873b419c3a335f930703315 100644 --- a/src/cutecoin/models/person/factory.py +++ b/src/cutecoin/models/person/factory.py @@ -8,8 +8,6 @@ from cutecoin.models.person import Person import ucoinpy as ucoin def createPerson(pgpFingerprint, community): - #TODO: Raise an exception and display a popup if member isnt found - #Maybe generate a person whose name is the fingerprint, and email is 'unknown' keys = community.ucoinRequest(ucoin.pks.Lookup(), get_args={'search':"0x"+pgpFingerprint, 'op':'index'})['keys'] if len(keys) > 0: diff --git a/src/cutecoin/models/transaction/__init__.py b/src/cutecoin/models/transaction/__init__.py index 26e4347f266f6f9519877210e7397cf2be2e4eb9..f46b086c801e3c1e477105e5ccca12f614655059 100644 --- a/src/cutecoin/models/transaction/__init__.py +++ b/src/cutecoin/models/transaction/__init__.py @@ -10,7 +10,8 @@ from cutecoin.models.person import factory class Transaction(object): ''' - classdocs + A transaction which can be a transfer or an issuance. + At the moment the difference is not made ''' def __init__(self, senderFingerprint, increment, community): self.increment = increment diff --git a/src/cutecoin/models/wallet/__init__.py b/src/cutecoin/models/wallet/__init__.py index 6ba8e60ec45052678117610bcd0d00088cd995f0..cd54073b456d25536577e2e92865eebbe1e8f0af 100644 --- a/src/cutecoin/models/wallet/__init__.py +++ b/src/cutecoin/models/wallet/__init__.py @@ -10,7 +10,8 @@ from cutecoin.models.coin import Coin class Wallet(object): ''' - classdocs + A wallet is list of coins. + It's only used to sort coins. '''