diff --git a/.directory b/.directory deleted file mode 100644 index de51075e152260b6d88c4d3f721338105408795d..0000000000000000000000000000000000000000 --- a/.directory +++ /dev/null @@ -1,6 +0,0 @@ -[Dolphin] -Timestamp=2014,2,16,12,25,25 -Version=3 - -[Settings] -HiddenFilesShown=true diff --git a/.gitignore b/.gitignore index 948cf62d5b1c6619443d6a1763f5b1afc5beb3f5..5b0725e771e14b14e9ddb521692744b1d961170d 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,5 @@ nosetests.xml # Generated files src/cutecoin/gen_resources/* src/icons_rc.py +out +.directory diff --git a/README.md b/README.md index beb816a74478926f66b3565b11a170ab5ae6305f..29f2768719c2dc58a984eadab5a4757193ad6f2e 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Qt Client for [Ucoin](http://www.ucoin.io) project. * The executable is generated in "build" folder, named "cutecoin" ### How to download latest release - * Go to the [current release](https://github.com/ucoin-io/cutecoin/releases/tag/0.9.0) + * Go to the [current release](https://github.com/ucoin-io/cutecoin/releases/tag/0.9.1) * Download the package corresponding to your operating system * Unzip and start "cutecoin" :) * Join our beta community by contacting us on ucoin forums : forum.ucoin.io diff --git a/lib/ucoinpy/documents/block.py b/lib/ucoinpy/documents/block.py index 64c3a7c7f87904cba0e4eb4cc593e01cd607adba..58a1b3bf8e9d29543fbd65b956b9bc144d0b2f04 100644 --- a/lib/ucoinpy/documents/block.py +++ b/lib/ucoinpy/documents/block.py @@ -291,6 +291,6 @@ PreviousIssuer: {1}\n".format(self.prev_hash, self.prev_issuer) doc += "Transactions:\n" for transaction in self.transactions: - doc += "{0}\n".format(transaction.inline()) + doc += "{0}\n".format(transaction.compact()) return doc diff --git a/out b/out deleted file mode 100644 index e12ea92500276eb841d5c26e64e37c798c52cde8..0000000000000000000000000000000000000000 --- a/out +++ /dev/null @@ -1,654 +0,0 @@ -['/home/inso/code/ucoin/cutecoin', '/usr/lib/python34.zip', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-linux', '/usr/lib/python3.4/lib-dynload', '/usr/lib/python3.4/site-packages', '/home/inso/code/ucoin/cutecoin/lib', '/home/inso/code/ucoin/cutecoin/src'] -running build -running build_exe -copying /usr/lib/python3.4/site-packages/cx_Freeze/bases/Console -> build/exe.linux-x86_64-3.4/cutecoin -copying /usr/lib/libpython3.4m.so.1.0 -> build/exe.linux-x86_64-3.4/libpython3.4m.so.1.0 -writing zip file build/exe.linux-x86_64-3.4/library.zip - - Name File - ---- ---- -m BUILD_CONSTANTS -P PyQt5 /usr/lib/python3.4/site-packages/PyQt5/__init__.py -m PyQt5.QtCore /usr/lib/python3.4/site-packages/PyQt5/QtCore.so -m PyQt5.QtGui /usr/lib/python3.4/site-packages/PyQt5/QtGui.so -m PyQt5.QtWidgets /usr/lib/python3.4/site-packages/PyQt5/QtWidgets.so -m __future__ /usr/lib/python3.4/__future__.py -m _ast -m _bisect /usr/lib/python3.4/lib-dynload/_bisect.cpython-34m.so -m _bootlocale -m _bz2 /usr/lib/python3.4/lib-dynload/_bz2.cpython-34m.so -m _codecs -m _codecs_cn /usr/lib/python3.4/lib-dynload/_codecs_cn.cpython-34m.so -m _codecs_hk /usr/lib/python3.4/lib-dynload/_codecs_hk.cpython-34m.so -m _codecs_iso2022 /usr/lib/python3.4/lib-dynload/_codecs_iso2022.cpython-34m.so -m _codecs_jp /usr/lib/python3.4/lib-dynload/_codecs_jp.cpython-34m.so -m _codecs_kr /usr/lib/python3.4/lib-dynload/_codecs_kr.cpython-34m.so -m _codecs_tw /usr/lib/python3.4/lib-dynload/_codecs_tw.cpython-34m.so -m _collections -m _collections_abc -m _ctypes /usr/lib/python3.4/lib-dynload/_ctypes.cpython-34m.so -m _datetime /usr/lib/python3.4/lib-dynload/_datetime.cpython-34m.so -m _dummy_thread -m _functools -m _hashlib /usr/lib/python3.4/lib-dynload/_hashlib.cpython-34m.so -m _heapq /usr/lib/python3.4/lib-dynload/_heapq.cpython-34m.so -m _imp -m _io -m _json /usr/lib/python3.4/lib-dynload/_json.cpython-34m.so -m _locale -m _lzma /usr/lib/python3.4/lib-dynload/_lzma.cpython-34m.so -m _md5 /usr/lib/python3.4/lib-dynload/_md5.cpython-34m.so -m _multibytecodec /usr/lib/python3.4/lib-dynload/_multibytecodec.cpython-34m.so -m _opcode /usr/lib/python3.4/lib-dynload/_opcode.cpython-34m.so -m _operator -m _osx_support /usr/lib/python3.4/_osx_support.py -m _posixsubprocess /usr/lib/python3.4/lib-dynload/_posixsubprocess.cpython-34m.so -m _random /usr/lib/python3.4/lib-dynload/_random.cpython-34m.so -m _sha1 /usr/lib/python3.4/lib-dynload/_sha1.cpython-34m.so -m _sha256 /usr/lib/python3.4/lib-dynload/_sha256.cpython-34m.so -m _sha512 /usr/lib/python3.4/lib-dynload/_sha512.cpython-34m.so -m _socket /usr/lib/python3.4/lib-dynload/_socket.cpython-34m.so -m _sre -m _ssl /usr/lib/python3.4/lib-dynload/_ssl.cpython-34m.so -m _stat -m _string -m _strptime -m _struct /usr/lib/python3.4/lib-dynload/_struct.cpython-34m.so -m _thread -m _threading_local -m _warnings -m _weakref -m _weakrefset -m abc -m argparse -m array /usr/lib/python3.4/lib-dynload/array.cpython-34m.so -m ast /usr/lib/python3.4/ast.py -m atexit -m base58 /usr/lib/python3.4/site-packages/base58.py -m base64 -m bdb /usr/lib/python3.4/bdb.py -m binascii /usr/lib/python3.4/lib-dynload/binascii.cpython-34m.so -m bisect /usr/lib/python3.4/bisect.py -m builtins -m bz2 -m calendar -m cgi /usr/lib/python3.4/cgi.py -m cmd /usr/lib/python3.4/cmd.py -m code /usr/lib/python3.4/code.py -m codecs -m codeop /usr/lib/python3.4/codeop.py -P collections -m collections.abc -m contextlib -m copy -m copyreg -P ctypes /usr/lib/python3.4/ctypes/__init__.py -m ctypes._endian /usr/lib/python3.4/ctypes/_endian.py -P ctypes.macholib /usr/lib/python3.4/ctypes/macholib/__init__.py -m ctypes.macholib.dyld /usr/lib/python3.4/ctypes/macholib/dyld.py -m ctypes.macholib.dylib /usr/lib/python3.4/ctypes/macholib/dylib.py -m ctypes.macholib.framework /usr/lib/python3.4/ctypes/macholib/framework.py -m ctypes.util /usr/lib/python3.4/ctypes/util.py -P cutecoin /home/inso/code/ucoin/cutecoin/src/cutecoin/__init__.py -m cutecoin.__init__ /home/inso/code/ucoin/cutecoin/src/cutecoin/__init__.py -P cutecoin.core /home/inso/code/ucoin/cutecoin/src/cutecoin/core/__init__.py -m cutecoin.core.account /home/inso/code/ucoin/cutecoin/src/cutecoin/core/account.py -m cutecoin.core.app /home/inso/code/ucoin/cutecoin/src/cutecoin/core/app.py -m cutecoin.core.community /home/inso/code/ucoin/cutecoin/src/cutecoin/core/community.py -m cutecoin.core.config /home/inso/code/ucoin/cutecoin/src/cutecoin/core/config.py -m cutecoin.core.person /home/inso/code/ucoin/cutecoin/src/cutecoin/core/person.py -m cutecoin.core.wallet /home/inso/code/ucoin/cutecoin/src/cutecoin/core/wallet.py -P cutecoin.gen_resources /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/__init__.py -m cutecoin.gen_resources.account_cfg_uic /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/account_cfg_uic.py -m cutecoin.gen_resources.add_contact_uic /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/add_contact_uic.py -m cutecoin.gen_resources.certification_uic /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/certification_uic.py -m cutecoin.gen_resources.community_cfg_uic /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/community_cfg_uic.py -m cutecoin.gen_resources.community_tab_uic /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/community_tab_uic.py -m cutecoin.gen_resources.currency_tab_uic /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/currency_tab_uic.py -m cutecoin.gen_resources.import_account_uic /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/import_account_uic.py -m cutecoin.gen_resources.mainwindow_uic /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/mainwindow_uic.py -m cutecoin.gen_resources.password_asker_uic /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/password_asker_uic.py -m cutecoin.gen_resources.transfer_uic /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/transfer_uic.py -m cutecoin.gen_resources.wot_tab_uic /home/inso/code/ucoin/cutecoin/src/cutecoin/gen_resources/wot_tab_uic.py -P cutecoin.gui /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/__init__.py -m cutecoin.gui.add_contact /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/add_contact.py -m cutecoin.gui.certification /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/certification.py -m cutecoin.gui.community_tab /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/community_tab.py -m cutecoin.gui.currency_tab /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/currency_tab.py -m cutecoin.gui.import_account /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/import_account.py -m cutecoin.gui.mainwindow /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/mainwindow.py -m cutecoin.gui.password_asker /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/password_asker.py -m cutecoin.gui.process_cfg_account /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/process_cfg_account.py -m cutecoin.gui.process_cfg_community /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/process_cfg_community.py -m cutecoin.gui.transfer /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/transfer.py -P cutecoin.gui.views /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/views/__init__.py -m cutecoin.gui.views.wot /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/views/wot.py -m cutecoin.gui.wot_tab /home/inso/code/ucoin/cutecoin/src/cutecoin/gui/wot_tab.py -P cutecoin.models /home/inso/code/ucoin/cutecoin/src/cutecoin/models/__init__.py -m cutecoin.models.communities /home/inso/code/ucoin/cutecoin/src/cutecoin/models/communities.py -m cutecoin.models.members /home/inso/code/ucoin/cutecoin/src/cutecoin/models/members.py -m cutecoin.models.peer /home/inso/code/ucoin/cutecoin/src/cutecoin/models/peer.py -m cutecoin.models.peering /home/inso/code/ucoin/cutecoin/src/cutecoin/models/peering.py -m cutecoin.models.received /home/inso/code/ucoin/cutecoin/src/cutecoin/models/received.py -m cutecoin.models.sent /home/inso/code/ucoin/cutecoin/src/cutecoin/models/sent.py -m cutecoin.models.wallet /home/inso/code/ucoin/cutecoin/src/cutecoin/models/wallet.py -m cutecoin.models.wallets /home/inso/code/ucoin/cutecoin/src/cutecoin/models/wallets.py -P cutecoin.tools /home/inso/code/ucoin/cutecoin/src/cutecoin/tools/__init__.py -m cutecoin.tools.exceptions /home/inso/code/ucoin/cutecoin/src/cutecoin/tools/exceptions.py -m cutecoin__main__ src/cutecoin/main.py -m cx_Freeze__init__ /usr/lib/python3.4/site-packages/cx_Freeze/initscripts/Console.py -m datetime -m difflib /usr/lib/python3.4/difflib.py -m dis /usr/lib/python3.4/dis.py -P distutils /usr/lib/python3.4/distutils/__init__.py -m distutils.debug /usr/lib/python3.4/distutils/debug.py -m distutils.errors /usr/lib/python3.4/distutils/errors.py -m distutils.log /usr/lib/python3.4/distutils/log.py -m distutils.spawn /usr/lib/python3.4/distutils/spawn.py -m distutils.sysconfig /usr/lib/python3.4/distutils/sysconfig.py -m distutils.text_file /usr/lib/python3.4/distutils/text_file.py -m doctest /usr/lib/python3.4/doctest.py -m dummy_threading -P email /usr/lib/python3.4/email/__init__.py -m email._encoded_words /usr/lib/python3.4/email/_encoded_words.py -m email._header_value_parser /usr/lib/python3.4/email/_header_value_parser.py -m email._parseaddr /usr/lib/python3.4/email/_parseaddr.py -m email._policybase /usr/lib/python3.4/email/_policybase.py -m email.base64mime /usr/lib/python3.4/email/base64mime.py -m email.charset /usr/lib/python3.4/email/charset.py -m email.contentmanager /usr/lib/python3.4/email/contentmanager.py -m email.encoders /usr/lib/python3.4/email/encoders.py -m email.errors /usr/lib/python3.4/email/errors.py -m email.feedparser /usr/lib/python3.4/email/feedparser.py -m email.generator /usr/lib/python3.4/email/generator.py -m email.header /usr/lib/python3.4/email/header.py -m email.headerregistry /usr/lib/python3.4/email/headerregistry.py -m email.iterators /usr/lib/python3.4/email/iterators.py -m email.message /usr/lib/python3.4/email/message.py -m email.parser /usr/lib/python3.4/email/parser.py -m email.policy /usr/lib/python3.4/email/policy.py -m email.quoprimime /usr/lib/python3.4/email/quoprimime.py -m email.utils /usr/lib/python3.4/email/utils.py -P encodings -m encodings.aliases -m encodings.ascii -m encodings.base64_codec -m encodings.big5 -m encodings.big5hkscs -m encodings.bz2_codec -m encodings.charmap -m encodings.cp037 -m encodings.cp1006 -m encodings.cp1026 -m encodings.cp1125 -m encodings.cp1140 -m encodings.cp1250 -m encodings.cp1251 -m encodings.cp1252 -m encodings.cp1253 -m encodings.cp1254 -m encodings.cp1255 -m encodings.cp1256 -m encodings.cp1257 -m encodings.cp1258 -m encodings.cp273 -m encodings.cp424 -m encodings.cp437 -m encodings.cp500 -m encodings.cp65001 -m encodings.cp720 -m encodings.cp737 -m encodings.cp775 -m encodings.cp850 -m encodings.cp852 -m encodings.cp855 -m encodings.cp856 -m encodings.cp857 -m encodings.cp858 -m encodings.cp860 -m encodings.cp861 -m encodings.cp862 -m encodings.cp863 -m encodings.cp864 -m encodings.cp865 -m encodings.cp866 -m encodings.cp869 -m encodings.cp874 -m encodings.cp875 -m encodings.cp932 -m encodings.cp949 -m encodings.cp950 -m encodings.euc_jis_2004 -m encodings.euc_jisx0213 -m encodings.euc_jp -m encodings.euc_kr -m encodings.gb18030 -m encodings.gb2312 -m encodings.gbk -m encodings.hex_codec -m encodings.hp_roman8 -m encodings.hz -m encodings.idna -m encodings.iso2022_jp -m encodings.iso2022_jp_1 -m encodings.iso2022_jp_2 -m encodings.iso2022_jp_2004 -m encodings.iso2022_jp_3 -m encodings.iso2022_jp_ext -m encodings.iso2022_kr -m encodings.iso8859_1 -m encodings.iso8859_10 -m encodings.iso8859_11 -m encodings.iso8859_13 -m encodings.iso8859_14 -m encodings.iso8859_15 -m encodings.iso8859_16 -m encodings.iso8859_2 -m encodings.iso8859_3 -m encodings.iso8859_4 -m encodings.iso8859_5 -m encodings.iso8859_6 -m encodings.iso8859_7 -m encodings.iso8859_8 -m encodings.iso8859_9 -m encodings.johab -m encodings.koi8_r -m encodings.koi8_u -m encodings.latin_1 -m encodings.mac_arabic -m encodings.mac_centeuro -m encodings.mac_croatian -m encodings.mac_cyrillic -m encodings.mac_farsi -m encodings.mac_greek -m encodings.mac_iceland -m encodings.mac_latin2 -m encodings.mac_roman -m encodings.mac_romanian -m encodings.mac_turkish -m encodings.mbcs -m encodings.palmos -m encodings.ptcp154 -m encodings.punycode -m encodings.quopri_codec -m encodings.raw_unicode_escape -m encodings.rot_13 -m encodings.shift_jis -m encodings.shift_jis_2004 -m encodings.shift_jisx0213 -m encodings.tis_620 -m encodings.undefined -m encodings.unicode_escape -m encodings.unicode_internal -m encodings.utf_16 -m encodings.utf_16_be -m encodings.utf_16_le -m encodings.utf_32 -m encodings.utf_32_be -m encodings.utf_32_le -m encodings.utf_7 -m encodings.utf_8 -m encodings.utf_8_sig -m encodings.uu_codec -m encodings.zlib_codec -m enum /usr/lib/python3.4/enum.py -m errno -m fnmatch /usr/lib/python3.4/fnmatch.py -m ftplib /usr/lib/python3.4/ftplib.py -m functools -m gc -m genericpath -m getopt /usr/lib/python3.4/getopt.py -m getpass /usr/lib/python3.4/getpass.py -m gettext -m glob /usr/lib/python3.4/glob.py -m grp /usr/lib/python3.4/lib-dynload/grp.cpython-34m.so -m gzip /usr/lib/python3.4/gzip.py -m hashlib /usr/lib/python3.4/hashlib.py -m heapq -m hmac /usr/lib/python3.4/hmac.py -P html /usr/lib/python3.4/html/__init__.py -m html.entities /usr/lib/python3.4/html/entities.py -P http /usr/lib/python3.4/http/__init__.py -m http.client /usr/lib/python3.4/http/client.py -m http.cookiejar /usr/lib/python3.4/http/cookiejar.py -m http.cookies /usr/lib/python3.4/http/cookies.py -m http.server /usr/lib/python3.4/http/server.py -m icons_rc /home/inso/code/ucoin/cutecoin/src/icons_rc.py -m imp /usr/lib/python3.4/imp.py -P importlib /usr/lib/python3.4/importlib/__init__.py -P importlib /usr/lib/python3.4/importlib/__init__.py -m importlib._bootstrap -m importlib._bootstrap /usr/lib/python3.4/importlib/_bootstrap.py -m importlib.machinery /usr/lib/python3.4/importlib/machinery.py -m importlib.util /usr/lib/python3.4/importlib/util.py -m inspect /usr/lib/python3.4/inspect.py -m io -m itertools -P json /usr/lib/python3.4/json/__init__.py -m json.decoder /usr/lib/python3.4/json/decoder.py -m json.encoder /usr/lib/python3.4/json/encoder.py -m json.scanner /usr/lib/python3.4/json/scanner.py -m keyword -P libnacl /usr/lib/python3.4/site-packages/libnacl/__init__.py -m libnacl.base /usr/lib/python3.4/site-packages/libnacl/base.py -m libnacl.blake /usr/lib/python3.4/site-packages/libnacl/blake.py -m libnacl.dual /usr/lib/python3.4/site-packages/libnacl/dual.py -m libnacl.encode /usr/lib/python3.4/site-packages/libnacl/encode.py -m libnacl.public /usr/lib/python3.4/site-packages/libnacl/public.py -m libnacl.secret /usr/lib/python3.4/site-packages/libnacl/secret.py -m libnacl.sign /usr/lib/python3.4/site-packages/libnacl/sign.py -m libnacl.utils /usr/lib/python3.4/site-packages/libnacl/utils.py -m libnacl.version /usr/lib/python3.4/site-packages/libnacl/version.py -m linecache -m locale -P logging /usr/lib/python3.4/logging/__init__.py -m lzma /usr/lib/python3.4/lzma.py -m marshal -m math /usr/lib/python3.4/lib-dynload/math.cpython-34m.so -m mimetypes /usr/lib/python3.4/mimetypes.py -m netrc /usr/lib/python3.4/netrc.py -m numbers /usr/lib/python3.4/numbers.py -m opcode /usr/lib/python3.4/opcode.py -m operator -m optparse -m os -m pdb /usr/lib/python3.4/pdb.py -m pkgutil /usr/lib/python3.4/pkgutil.py -m platform /usr/lib/python3.4/platform.py -m plistlib /usr/lib/python3.4/plistlib.py -m posix -m posixpath -m pprint /usr/lib/python3.4/pprint.py -m pwd -m py_compile /usr/lib/python3.4/py_compile.py -m pydoc /usr/lib/python3.4/pydoc.py -P pydoc_data /usr/lib/python3.4/pydoc_data/__init__.py -m pydoc_data.topics /usr/lib/python3.4/pydoc_data/topics.py -m pyexpat /usr/lib/python3.4/lib-dynload/pyexpat.cpython-34m.so -P pylibscrypt /usr/lib/python3.4/site-packages/pylibscrypt/__init__.py -m pylibscrypt.common /usr/lib/python3.4/site-packages/pylibscrypt/common.py -m pylibscrypt.mcf /usr/lib/python3.4/site-packages/pylibscrypt/mcf.py -m pylibscrypt.pbkdf2 /usr/lib/python3.4/site-packages/pylibscrypt/pbkdf2.py -m pylibscrypt.pylibscrypt /usr/lib/python3.4/site-packages/pylibscrypt/pylibscrypt.py -m pylibscrypt.pylibsodium /usr/lib/python3.4/site-packages/pylibscrypt/pylibsodium.py -m pylibscrypt.pylibsodium_salsa /usr/lib/python3.4/site-packages/pylibscrypt/pylibsodium_salsa.py -m pylibscrypt.pypyscrypt_inline /usr/lib/python3.4/site-packages/pylibscrypt/pypyscrypt_inline.py -m pylibscrypt.pyscrypt /usr/lib/python3.4/site-packages/pylibscrypt/pyscrypt.py -m pylibscrypt.tests /usr/lib/python3.4/site-packages/pylibscrypt/tests.py -m queue /usr/lib/python3.4/queue.py -m quopri -m random /usr/lib/python3.4/random.py -m re -m readline /usr/lib/python3.4/lib-dynload/readline.cpython-34m.so -m reprlib -P requests /usr/lib/python3.4/site-packages/requests/__init__.py -m requests.adapters /usr/lib/python3.4/site-packages/requests/adapters.py -m requests.api /usr/lib/python3.4/site-packages/requests/api.py -m requests.auth /usr/lib/python3.4/site-packages/requests/auth.py -m requests.certs /usr/lib/python3.4/site-packages/requests/certs.py -m requests.compat /usr/lib/python3.4/site-packages/requests/compat.py -m requests.cookies /usr/lib/python3.4/site-packages/requests/cookies.py -m requests.exceptions /usr/lib/python3.4/site-packages/requests/exceptions.py -m requests.hooks /usr/lib/python3.4/site-packages/requests/hooks.py -m requests.models /usr/lib/python3.4/site-packages/requests/models.py -P requests.packages /usr/lib/python3.4/site-packages/requests/packages/__init__.py -P requests.packages.chardet /usr/lib/python3.4/site-packages/requests/packages/chardet/__init__.py -m requests.packages.chardet.big5freq /usr/lib/python3.4/site-packages/requests/packages/chardet/big5freq.py -m requests.packages.chardet.big5prober /usr/lib/python3.4/site-packages/requests/packages/chardet/big5prober.py -m requests.packages.chardet.chardistribution /usr/lib/python3.4/site-packages/requests/packages/chardet/chardistribution.py -m requests.packages.chardet.charsetgroupprober /usr/lib/python3.4/site-packages/requests/packages/chardet/charsetgroupprober.py -m requests.packages.chardet.charsetprober /usr/lib/python3.4/site-packages/requests/packages/chardet/charsetprober.py -m requests.packages.chardet.codingstatemachine /usr/lib/python3.4/site-packages/requests/packages/chardet/codingstatemachine.py -m requests.packages.chardet.compat /usr/lib/python3.4/site-packages/requests/packages/chardet/compat.py -m requests.packages.chardet.constants /usr/lib/python3.4/site-packages/requests/packages/chardet/constants.py -m requests.packages.chardet.cp949prober /usr/lib/python3.4/site-packages/requests/packages/chardet/cp949prober.py -m requests.packages.chardet.escprober /usr/lib/python3.4/site-packages/requests/packages/chardet/escprober.py -m requests.packages.chardet.escsm /usr/lib/python3.4/site-packages/requests/packages/chardet/escsm.py -m requests.packages.chardet.eucjpprober /usr/lib/python3.4/site-packages/requests/packages/chardet/eucjpprober.py -m requests.packages.chardet.euckrfreq /usr/lib/python3.4/site-packages/requests/packages/chardet/euckrfreq.py -m requests.packages.chardet.euckrprober /usr/lib/python3.4/site-packages/requests/packages/chardet/euckrprober.py -m requests.packages.chardet.euctwfreq /usr/lib/python3.4/site-packages/requests/packages/chardet/euctwfreq.py -m requests.packages.chardet.euctwprober /usr/lib/python3.4/site-packages/requests/packages/chardet/euctwprober.py -m requests.packages.chardet.gb2312freq /usr/lib/python3.4/site-packages/requests/packages/chardet/gb2312freq.py -m requests.packages.chardet.gb2312prober /usr/lib/python3.4/site-packages/requests/packages/chardet/gb2312prober.py -m requests.packages.chardet.hebrewprober /usr/lib/python3.4/site-packages/requests/packages/chardet/hebrewprober.py -m requests.packages.chardet.jisfreq /usr/lib/python3.4/site-packages/requests/packages/chardet/jisfreq.py -m requests.packages.chardet.jpcntx /usr/lib/python3.4/site-packages/requests/packages/chardet/jpcntx.py -m requests.packages.chardet.langbulgarianmodel /usr/lib/python3.4/site-packages/requests/packages/chardet/langbulgarianmodel.py -m requests.packages.chardet.langcyrillicmodel /usr/lib/python3.4/site-packages/requests/packages/chardet/langcyrillicmodel.py -m requests.packages.chardet.langgreekmodel /usr/lib/python3.4/site-packages/requests/packages/chardet/langgreekmodel.py -m requests.packages.chardet.langhebrewmodel /usr/lib/python3.4/site-packages/requests/packages/chardet/langhebrewmodel.py -m requests.packages.chardet.langhungarianmodel /usr/lib/python3.4/site-packages/requests/packages/chardet/langhungarianmodel.py -m requests.packages.chardet.langthaimodel /usr/lib/python3.4/site-packages/requests/packages/chardet/langthaimodel.py -m requests.packages.chardet.latin1prober /usr/lib/python3.4/site-packages/requests/packages/chardet/latin1prober.py -m requests.packages.chardet.mbcharsetprober /usr/lib/python3.4/site-packages/requests/packages/chardet/mbcharsetprober.py -m requests.packages.chardet.mbcsgroupprober /usr/lib/python3.4/site-packages/requests/packages/chardet/mbcsgroupprober.py -m requests.packages.chardet.mbcssm /usr/lib/python3.4/site-packages/requests/packages/chardet/mbcssm.py -m requests.packages.chardet.sbcharsetprober /usr/lib/python3.4/site-packages/requests/packages/chardet/sbcharsetprober.py -m requests.packages.chardet.sbcsgroupprober /usr/lib/python3.4/site-packages/requests/packages/chardet/sbcsgroupprober.py -m requests.packages.chardet.sjisprober /usr/lib/python3.4/site-packages/requests/packages/chardet/sjisprober.py -m requests.packages.chardet.universaldetector /usr/lib/python3.4/site-packages/requests/packages/chardet/universaldetector.py -m requests.packages.chardet.utf8prober /usr/lib/python3.4/site-packages/requests/packages/chardet/utf8prober.py -P requests.packages.urllib3 /usr/lib/python3.4/site-packages/requests/packages/urllib3/__init__.py -m requests.packages.urllib3._collections /usr/lib/python3.4/site-packages/requests/packages/urllib3/_collections.py -m requests.packages.urllib3.connection /usr/lib/python3.4/site-packages/requests/packages/urllib3/connection.py -m requests.packages.urllib3.connectionpool /usr/lib/python3.4/site-packages/requests/packages/urllib3/connectionpool.py -P requests.packages.urllib3.contrib /usr/lib/python3.4/site-packages/requests/packages/urllib3/contrib/__init__.py -m requests.packages.urllib3.contrib.pyopenssl /usr/lib/python3.4/site-packages/requests/packages/urllib3/contrib/pyopenssl.py -m requests.packages.urllib3.exceptions /usr/lib/python3.4/site-packages/requests/packages/urllib3/exceptions.py -m requests.packages.urllib3.fields /usr/lib/python3.4/site-packages/requests/packages/urllib3/fields.py -m requests.packages.urllib3.filepost /usr/lib/python3.4/site-packages/requests/packages/urllib3/filepost.py -P requests.packages.urllib3.packages /usr/lib/python3.4/site-packages/requests/packages/urllib3/packages/__init__.py -m requests.packages.urllib3.packages.ordered_dict /usr/lib/python3.4/site-packages/requests/packages/urllib3/packages/ordered_dict.py -m requests.packages.urllib3.packages.six /usr/lib/python3.4/site-packages/requests/packages/urllib3/packages/six.py -P requests.packages.urllib3.packages.ssl_match_hostname /usr/lib/python3.4/site-packages/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py -m requests.packages.urllib3.packages.ssl_match_hostname._implementation /usr/lib/python3.4/site-packages/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py -m requests.packages.urllib3.poolmanager /usr/lib/python3.4/site-packages/requests/packages/urllib3/poolmanager.py -m requests.packages.urllib3.request /usr/lib/python3.4/site-packages/requests/packages/urllib3/request.py -m requests.packages.urllib3.response /usr/lib/python3.4/site-packages/requests/packages/urllib3/response.py -P requests.packages.urllib3.util /usr/lib/python3.4/site-packages/requests/packages/urllib3/util/__init__.py -m requests.packages.urllib3.util.connection /usr/lib/python3.4/site-packages/requests/packages/urllib3/util/connection.py -m requests.packages.urllib3.util.request /usr/lib/python3.4/site-packages/requests/packages/urllib3/util/request.py -m requests.packages.urllib3.util.response /usr/lib/python3.4/site-packages/requests/packages/urllib3/util/response.py -m requests.packages.urllib3.util.retry /usr/lib/python3.4/site-packages/requests/packages/urllib3/util/retry.py -m requests.packages.urllib3.util.ssl_ /usr/lib/python3.4/site-packages/requests/packages/urllib3/util/ssl_.py -m requests.packages.urllib3.util.timeout /usr/lib/python3.4/site-packages/requests/packages/urllib3/util/timeout.py -m requests.packages.urllib3.util.url /usr/lib/python3.4/site-packages/requests/packages/urllib3/util/url.py -m requests.sessions /usr/lib/python3.4/site-packages/requests/sessions.py -m requests.status_codes /usr/lib/python3.4/site-packages/requests/status_codes.py -m requests.structures /usr/lib/python3.4/site-packages/requests/structures.py -m requests.utils /usr/lib/python3.4/site-packages/requests/utils.py -m scrypt /usr/lib/python3.4/site-packages/scrypt.py -m select /usr/lib/python3.4/lib-dynload/select.cpython-34m.so -m selectors /usr/lib/python3.4/selectors.py -m shlex /usr/lib/python3.4/shlex.py -m shutil /usr/lib/python3.4/shutil.py -m signal -m sip /usr/lib/python3.4/site-packages/sip.so -m socket /usr/lib/python3.4/socket.py -m socketserver /usr/lib/python3.4/socketserver.py -m sre_compile -m sre_constants -m sre_parse -m ssl /usr/lib/python3.4/ssl.py -m stat -m string /usr/lib/python3.4/string.py -m stringprep -m struct -m subprocess /usr/lib/python3.4/subprocess.py -m sys -m tarfile /usr/lib/python3.4/tarfile.py -m tempfile /usr/lib/python3.4/tempfile.py -m termios /usr/lib/python3.4/lib-dynload/termios.cpython-34m.so -m textwrap -m threading -m time /usr/lib/python3.4/lib-dynload/time.cpython-34m.so -m token -m tokenize -m traceback -m tty /usr/lib/python3.4/tty.py -m types -P ucoinpy /home/inso/code/ucoin/cutecoin/lib/ucoinpy/__init__.py -P ucoinpy.api /home/inso/code/ucoin/cutecoin/lib/ucoinpy/api/__init__.py -P ucoinpy.api.bma /home/inso/code/ucoin/cutecoin/lib/ucoinpy/api/bma/__init__.py -P ucoinpy.api.bma.blockchain /home/inso/code/ucoin/cutecoin/lib/ucoinpy/api/bma/blockchain/__init__.py -P ucoinpy.api.bma.network /home/inso/code/ucoin/cutecoin/lib/ucoinpy/api/bma/network/__init__.py -P ucoinpy.api.bma.network.peering /home/inso/code/ucoin/cutecoin/lib/ucoinpy/api/bma/network/peering/__init__.py -P ucoinpy.api.bma.tx /home/inso/code/ucoin/cutecoin/lib/ucoinpy/api/bma/tx/__init__.py -P ucoinpy.api.bma.wot /home/inso/code/ucoin/cutecoin/lib/ucoinpy/api/bma/wot/__init__.py -P ucoinpy.documents /home/inso/code/ucoin/cutecoin/lib/ucoinpy/documents/__init__.py -m ucoinpy.documents.block /home/inso/code/ucoin/cutecoin/lib/ucoinpy/documents/block.py -m ucoinpy.documents.certification /home/inso/code/ucoin/cutecoin/lib/ucoinpy/documents/certification.py -m ucoinpy.documents.membership /home/inso/code/ucoin/cutecoin/lib/ucoinpy/documents/membership.py -m ucoinpy.documents.peer /home/inso/code/ucoin/cutecoin/lib/ucoinpy/documents/peer.py -m ucoinpy.documents.transaction /home/inso/code/ucoin/cutecoin/lib/ucoinpy/documents/transaction.py -P ucoinpy.key /home/inso/code/ucoin/cutecoin/lib/ucoinpy/key/__init__.py -m unicodedata /usr/lib/python3.4/lib-dynload/unicodedata.cpython-34m.so -P unittest /usr/lib/python3.4/unittest/__init__.py -m unittest.case /usr/lib/python3.4/unittest/case.py -m unittest.loader /usr/lib/python3.4/unittest/loader.py -m unittest.main /usr/lib/python3.4/unittest/main.py -m unittest.result /usr/lib/python3.4/unittest/result.py -m unittest.runner /usr/lib/python3.4/unittest/runner.py -m unittest.signals /usr/lib/python3.4/unittest/signals.py -m unittest.suite /usr/lib/python3.4/unittest/suite.py -m unittest.util /usr/lib/python3.4/unittest/util.py -P urllib /usr/lib/python3.4/urllib/__init__.py -m urllib.error /usr/lib/python3.4/urllib/error.py -m urllib.parse /usr/lib/python3.4/urllib/parse.py -m urllib.request /usr/lib/python3.4/urllib/request.py -m urllib.response /usr/lib/python3.4/urllib/response.py -m uu /usr/lib/python3.4/uu.py -m uuid /usr/lib/python3.4/uuid.py -m warnings -m weakref -m webbrowser /usr/lib/python3.4/webbrowser.py -P xml /usr/lib/python3.4/xml/__init__.py -P xml.parsers /usr/lib/python3.4/xml/parsers/__init__.py -m xml.parsers.expat /usr/lib/python3.4/xml/parsers/expat.py -m zipfile /usr/lib/python3.4/zipfile.py -m zipimport -m zlib /usr/lib/python3.4/lib-dynload/zlib.cpython-34m.so - -Missing modules: -? Cookie imported from requests.compat -? OpenSSL.SSL imported from requests.packages.urllib3.contrib.pyopenssl -? Queue imported from requests.packages.urllib3.connectionpool -? StringIO imported from requests.compat, requests.packages.urllib3.packages.six -? __main__ imported from bdb, pdb -? _abcoll imported from requests.packages.urllib3.packages.ordered_dict -? _dummy_threading imported from dummy_threading -? _scproxy imported from urllib.request -? _winapi imported from subprocess -? backports.ssl_match_hostname imported from requests.packages.urllib3.packages.ssl_match_hostname -? ce imported from os -? certifi imported from requests.certs -? cookielib imported from requests.compat -? dummy_thread imported from requests.packages.urllib3.packages.ordered_dict -? httplib imported from requests.packages.urllib3.connection -? java.lang imported from platform -? msgpack imported from libnacl.base, libnacl.utils -? msvcrt imported from getpass, subprocess -? ndg.httpsclient.ssl_peer_verification imported from requests.packages.urllib3.contrib.pyopenssl -? ndg.httpsclient.subj_alt_name imported from requests.packages.urllib3.contrib.pyopenssl -? netbios imported from uuid -? nt imported from os, shutil -? ntpath imported from os -? nturl2path imported from urllib.request -? org.python.core imported from copy -? os.path imported from os, pkgutil, py_compile, requests.certs, shutil, unittest.util -? pbkdf2 imported from pylibscrypt.pylibsodium_salsa, pylibscrypt.pypyscrypt_inline -? pyasn1.codec.der imported from requests.packages.urllib3.contrib.pyopenssl -? pyasn1.type imported from requests.packages.urllib3.contrib.pyopenssl -? simplejson imported from requests.compat -? thread imported from requests.packages.urllib3.packages.ordered_dict -? ucoinpy.api.bma.network.logging imported from ucoinpy.api.bma.network.peering -? urllib.getproxies imported from requests.compat -? urllib.proxy_bypass imported from requests.compat -? urllib.quote imported from requests.compat -? urllib.quote_plus imported from requests.compat -? urllib.unquote imported from requests.compat -? urllib.unquote_plus imported from requests.compat -? urllib.urlencode imported from requests.compat, requests.packages.urllib3.request -? urllib2 imported from requests.compat -? urlparse imported from requests.compat, requests.packages.urllib3.poolmanager -? vms_lib imported from platform -? win32api imported from platform -? win32con imported from platform -? win32wnet imported from uuid -? winreg imported from mimetypes, platform, urllib.request -This is not necessarily a problem - the modules may not be needed on this platform. - -copying /usr/lib/python3.4/site-packages/PyQt5/QtCore.so -> build/exe.linux-x86_64-3.4/PyQt5.QtCore.so -copying /usr/lib/python3.4/site-packages/PyQt5/QtGui.so -> build/exe.linux-x86_64-3.4/PyQt5.QtGui.so -copying /usr/lib/python3.4/site-packages/PyQt5/QtWidgets.so -> build/exe.linux-x86_64-3.4/PyQt5.QtWidgets.so -copying /usr/lib/python3.4/lib-dynload/_bisect.cpython-34m.so -> build/exe.linux-x86_64-3.4/_bisect.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_bz2.cpython-34m.so -> build/exe.linux-x86_64-3.4/_bz2.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_codecs_cn.cpython-34m.so -> build/exe.linux-x86_64-3.4/_codecs_cn.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_codecs_hk.cpython-34m.so -> build/exe.linux-x86_64-3.4/_codecs_hk.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_codecs_iso2022.cpython-34m.so -> build/exe.linux-x86_64-3.4/_codecs_iso2022.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_codecs_jp.cpython-34m.so -> build/exe.linux-x86_64-3.4/_codecs_jp.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_codecs_kr.cpython-34m.so -> build/exe.linux-x86_64-3.4/_codecs_kr.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_codecs_tw.cpython-34m.so -> build/exe.linux-x86_64-3.4/_codecs_tw.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_ctypes.cpython-34m.so -> build/exe.linux-x86_64-3.4/_ctypes.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_datetime.cpython-34m.so -> build/exe.linux-x86_64-3.4/_datetime.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_hashlib.cpython-34m.so -> build/exe.linux-x86_64-3.4/_hashlib.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_heapq.cpython-34m.so -> build/exe.linux-x86_64-3.4/_heapq.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_json.cpython-34m.so -> build/exe.linux-x86_64-3.4/_json.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_lzma.cpython-34m.so -> build/exe.linux-x86_64-3.4/_lzma.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_md5.cpython-34m.so -> build/exe.linux-x86_64-3.4/_md5.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_multibytecodec.cpython-34m.so -> build/exe.linux-x86_64-3.4/_multibytecodec.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_opcode.cpython-34m.so -> build/exe.linux-x86_64-3.4/_opcode.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_posixsubprocess.cpython-34m.so -> build/exe.linux-x86_64-3.4/_posixsubprocess.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_random.cpython-34m.so -> build/exe.linux-x86_64-3.4/_random.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_sha1.cpython-34m.so -> build/exe.linux-x86_64-3.4/_sha1.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_sha256.cpython-34m.so -> build/exe.linux-x86_64-3.4/_sha256.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_sha512.cpython-34m.so -> build/exe.linux-x86_64-3.4/_sha512.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_socket.cpython-34m.so -> build/exe.linux-x86_64-3.4/_socket.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_ssl.cpython-34m.so -> build/exe.linux-x86_64-3.4/_ssl.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/_struct.cpython-34m.so -> build/exe.linux-x86_64-3.4/_struct.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/array.cpython-34m.so -> build/exe.linux-x86_64-3.4/array.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/binascii.cpython-34m.so -> build/exe.linux-x86_64-3.4/binascii.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/grp.cpython-34m.so -> build/exe.linux-x86_64-3.4/grp.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/math.cpython-34m.so -> build/exe.linux-x86_64-3.4/math.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/pyexpat.cpython-34m.so -> build/exe.linux-x86_64-3.4/pyexpat.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/readline.cpython-34m.so -> build/exe.linux-x86_64-3.4/readline.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/select.cpython-34m.so -> build/exe.linux-x86_64-3.4/select.cpython-34m.so -copying /usr/lib/python3.4/site-packages/sip.so -> build/exe.linux-x86_64-3.4/sip.so -copying /usr/lib/python3.4/lib-dynload/termios.cpython-34m.so -> build/exe.linux-x86_64-3.4/termios.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/time.cpython-34m.so -> build/exe.linux-x86_64-3.4/time.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/unicodedata.cpython-34m.so -> build/exe.linux-x86_64-3.4/unicodedata.cpython-34m.so -copying /usr/lib/python3.4/lib-dynload/zlib.cpython-34m.so -> build/exe.linux-x86_64-3.4/zlib.cpython-34m.so -copying /usr/lib/qt/plugins/imageformats/libqjp2.so -> build/exe.linux-x86_64-3.4/imageformats/libqjp2.so -copying /usr/lib/qt/plugins/imageformats/libqsvg.so -> build/exe.linux-x86_64-3.4/imageformats/libqsvg.so -copying /usr/lib/qt/plugins/imageformats/libqwbmp.so -> build/exe.linux-x86_64-3.4/imageformats/libqwbmp.so -copying /usr/lib/qt/plugins/imageformats/libqtga.so -> build/exe.linux-x86_64-3.4/imageformats/libqtga.so -copying /usr/lib/qt/plugins/imageformats/libqdds.so -> build/exe.linux-x86_64-3.4/imageformats/libqdds.so -copying /usr/lib/qt/plugins/imageformats/libqicns.so -> build/exe.linux-x86_64-3.4/imageformats/libqicns.so -copying /usr/lib/qt/plugins/imageformats/libqgif.so -> build/exe.linux-x86_64-3.4/imageformats/libqgif.so -copying /usr/lib/qt/plugins/imageformats/libqmng.so -> build/exe.linux-x86_64-3.4/imageformats/libqmng.so -copying /usr/lib/qt/plugins/imageformats/libqwebp.so -> build/exe.linux-x86_64-3.4/imageformats/libqwebp.so -copying /usr/lib/qt/plugins/imageformats/libqjpeg.so -> build/exe.linux-x86_64-3.4/imageformats/libqjpeg.so -copying /usr/lib/qt/plugins/imageformats/libqtiff.so -> build/exe.linux-x86_64-3.4/imageformats/libqtiff.so -copying /usr/lib/qt/plugins/imageformats/libqico.so -> build/exe.linux-x86_64-3.4/imageformats/libqico.so -copying /usr/lib/kde4/plugins/imageformats/kimg_eps.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_eps.so -copying /usr/lib/kde4/plugins/imageformats/kimg_webp.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_webp.so -copying /usr/lib/kde4/plugins/imageformats/kimg_ras.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_ras.so -copying /usr/lib/kde4/plugins/imageformats/kimg_exr.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_exr.so -copying /usr/lib/kde4/plugins/imageformats/kimg_dds.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_dds.so -copying /usr/lib/kde4/plugins/imageformats/kimg_jp2.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_jp2.so -copying /usr/lib/kde4/plugins/imageformats/kimg_pcx.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_pcx.so -copying /usr/lib/kde4/plugins/imageformats/kimg_tga.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_tga.so -copying /usr/lib/kde4/plugins/imageformats/kimg_rgb.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_rgb.so -copying /usr/lib/kde4/plugins/imageformats/kimg_xview.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_xview.so -copying /usr/lib/kde4/plugins/imageformats/kimg_pic.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_pic.so -copying /usr/lib/kde4/plugins/imageformats/kimg_xcf.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_xcf.so -copying /usr/lib/kde4/plugins/imageformats/kimg_psd.so -> build/exe.linux-x86_64-3.4/imageformats/kimg_psd.so -copying /usr/lib/qt/plugins/platforms/libqminimalegl.so -> build/exe.linux-x86_64-3.4/platforms/libqminimalegl.so -copying /usr/lib/qt/plugins/platforms/libqeglfs.so -> build/exe.linux-x86_64-3.4/platforms/libqeglfs.so -copying /usr/lib/qt/plugins/platforms/libqminimal.so -> build/exe.linux-x86_64-3.4/platforms/libqminimal.so -copying /usr/lib/qt/plugins/platforms/libqkms.so -> build/exe.linux-x86_64-3.4/platforms/libqkms.so -copying /usr/lib/qt/plugins/platforms/libqxcb.so -> build/exe.linux-x86_64-3.4/platforms/libqxcb.so -copying /usr/lib/qt/plugins/platforms/libqlinuxfb.so -> build/exe.linux-x86_64-3.4/platforms/libqlinuxfb.so -copying /usr/lib/qt/plugins/platforms/libqoffscreen.so -> build/exe.linux-x86_64-3.4/platforms/libqoffscreen.so diff --git a/res/icons/.directory b/res/icons/.directory deleted file mode 100644 index 3be210363988903713c784f95f6e80c82e8d46cc..0000000000000000000000000000000000000000 --- a/res/icons/.directory +++ /dev/null @@ -1,6 +0,0 @@ -[Dolphin] -PreviewsShown=true -SortRole=date -Timestamp=2015,3,14,11,40,36 -Version=3 -ViewMode=1 diff --git a/res/icons/connected.svg b/res/icons/connected.svg new file mode 100644 index 0000000000000000000000000000000000000000..c6a97c9c66be3ebf88117731bd8e14d55542ef8b --- /dev/null +++ b/res/icons/connected.svg @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="100" + height="100" + viewBox="0 0 100 100" + id="svg3336" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="connected.svg"> + <defs + id="defs3338"> + <linearGradient + inkscape:collect="always" + id="linearGradient4150"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop4152" /> + <stop + style="stop-color:#ffffff;stop-opacity:0.04620462" + offset="1" + id="stop4154" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4150" + id="radialGradient4162" + cx="52.325901" + cy="1005.1627" + fx="52.325901" + fy="1005.1627" + r="42.926411" + gradientTransform="matrix(1.539681,0,0,1.5451884,-68.190831,-562.49866)" + gradientUnits="userSpaceOnUse" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2.8284271" + inkscape:cx="18.741815" + inkscape:cy="33.829638" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + units="px" + inkscape:snap-bbox="false" + inkscape:window-width="1366" + inkscape:window-height="709" + inkscape:window-x="-4" + inkscape:window-y="0" + inkscape:window-maximized="1" /> + <metadata + id="metadata3341"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Calque 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-952.36216)"> + <ellipse + style="opacity:1;fill:#17d017;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="path3346" + cx="51.785713" + cy="1005.5765" + rx="41.785713" + ry="40.714287" /> + <ellipse + style="opacity:0.65;fill:url(#radialGradient4162);fill-opacity:1;stroke:none;stroke-width:1.25129819;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="path4148" + cx="12.374369" + cy="990.66699" + rx="64.928177" + ry="65.10495" /> + </g> +</svg> diff --git a/res/icons/disconnected.svg b/res/icons/disconnected.svg new file mode 100644 index 0000000000000000000000000000000000000000..6647ff69d1f4db23fc7130d611543229eb42b3af --- /dev/null +++ b/res/icons/disconnected.svg @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="100" + height="100" + viewBox="0 0 100 100" + id="svg3336" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="disconnected.svg"> + <defs + id="defs3338"> + <linearGradient + inkscape:collect="always" + id="linearGradient4150"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop4152" /> + <stop + style="stop-color:#ffffff;stop-opacity:0.04620462" + offset="1" + id="stop4154" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4150" + id="radialGradient4162" + cx="52.325901" + cy="1005.1627" + fx="52.325901" + fy="1005.1627" + r="42.926411" + gradientTransform="matrix(1.539681,0,0,1.5451884,-50.51316,-559.67022)" + gradientUnits="userSpaceOnUse" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2.8284271" + inkscape:cx="18.741815" + inkscape:cy="33.829638" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + units="px" + inkscape:snap-bbox="false" + inkscape:window-width="1366" + inkscape:window-height="709" + inkscape:window-x="-4" + inkscape:window-y="0" + inkscape:window-maximized="1" /> + <metadata + id="metadata3341"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Calque 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-952.36216)"> + <ellipse + style="opacity:1;fill:#c60002;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="path3346" + cx="51.785713" + cy="1005.5765" + rx="41.785713" + ry="40.714287" /> + <ellipse + style="opacity:0.65;fill:url(#radialGradient4162);fill-opacity:1;stroke:none;stroke-width:1.25129819;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="path4148" + cx="30.05204" + cy="993.49536" + rx="64.928177" + ry="65.10495" /> + </g> +</svg> diff --git a/res/icons/icons.qrc b/res/icons/icons.qrc index 1a4f76b7d38c25821de754c1a48f84c5b7180c83..f53129c9c7cbed6c60f20bdd8799eba72b4e621d 100644 --- a/res/icons/icons.qrc +++ b/res/icons/icons.qrc @@ -1,5 +1,6 @@ <RCC> <qresource prefix="icons"> + <file alias="cutecoin_logo">logo.svg</file> <file alias="add_account_icon">noun_7440_cc.svg</file> <file alias="ucoin_info_icon">noun_76373_cc.svg</file> <file alias="import_icon">noun_62479_cc.svg</file> @@ -12,5 +13,8 @@ <file alias="wallet_icon">noun_29542_cc.svg</file> <file alias="tx_icon">noun_63271_cc.svg</file> <file alias="currency_icon">noun_43022_cc.svg</file> + <file alias="connected">connected.svg</file> + <file alias="weak_connect">weak_connect.svg</file> + <file alias="disconnected">disconnected.svg</file> </qresource> </RCC> diff --git a/res/icons/logo.svg b/res/icons/logo.svg index f006a91eba57e31516ccec7804ed62486b9d3fc5..ced94ff1b076911bc0012469fd8d376abf5b5a3d 100644 --- a/res/icons/logo.svg +++ b/res/icons/logo.svg @@ -20,24 +20,24 @@ id="defs4"> <inkscape:perspective sodipodi:type="inkscape:persp3d" - inkscape:vp_x="-152.85715 : 543.09471 : 1" + inkscape:vp_x="-152.85715 : 539.09471 : 1" inkscape:vp_y="0 : 999.99996 : 0" - inkscape:vp_z="591.23733 : 543.09471 : 1" - inkscape:persp3d-origin="219.19009 : 367.70102 : 1" + inkscape:vp_z="591.23733 : 539.09471 : 1" + inkscape:persp3d-origin="219.19009 : 363.70102 : 1" id="perspective4215" /> <inkscape:perspective sodipodi:type="inkscape:persp3d" - inkscape:vp_x="-3.5714286 : 663.80899 : 1" + inkscape:vp_x="-3.5714286 : 659.80899 : 1" inkscape:vp_y="0 : 999.99996 : 0" - inkscape:vp_z="740.52304 : 663.80899 : 1" - inkscape:persp3d-origin="368.4758 : 488.41529 : 1" + inkscape:vp_z="740.52304 : 659.80899 : 1" + inkscape:persp3d-origin="368.4758 : 484.41529 : 1" id="perspective4213" /> <inkscape:perspective sodipodi:type="inkscape:persp3d" - inkscape:vp_x="-65.71428 : 814.52323 : 1" + inkscape:vp_x="-65.71428 : 810.52323 : 1" inkscape:vp_y="0 : 999.99998 : 0" - inkscape:vp_z="678.38021 : 814.52323 : 1" - inkscape:persp3d-origin="306.33296 : 639.12959 : 1" + inkscape:vp_z="678.38021 : 810.52323 : 1" + inkscape:persp3d-origin="306.33296 : 635.12959 : 1" id="perspective4136" /> </defs> <sodipodi:namedview @@ -66,7 +66,7 @@ <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> + <dc:title></dc:title> </cc:Work> </rdf:RDF> </metadata> @@ -87,43 +87,43 @@ id="path4209" style="fill:#afafde;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="13" - d="m 216.7752,646.83956 76.79622,90.01915 -79.23203,61.74483 -63.39792,-119.29806 z" - points="293.57142,736.85871 214.33939,798.60354 150.94147,679.30548 216.7752,646.83956 " /> + d="m 216.7752,650.83956 76.79622,90.01915 -79.23203,61.74482 -63.39792,-119.29806 z" + points="293.57142,740.85871 214.33939,802.60353 150.94147,683.30547 216.7752,650.83956 " /> <path sodipodi:type="inkscape:box3dside" id="path4201" style="fill:#353564;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="6" - d="m 216.7752,358.90965 0,287.92991 -65.83373,32.46592 0,-324.12195 z" - points="216.7752,646.83956 150.94147,679.30548 150.94147,355.18353 216.7752,358.90965 " /> + d="m 216.7752,362.90964 0,287.92992 -65.83373,32.46591 0,-324.12195 z" + points="216.7752,650.83956 150.94147,683.30547 150.94147,359.18352 216.7752,362.90964 " /> <path sodipodi:type="inkscape:box3dside" id="path4205" style="fill:#8686bf;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="3" - d="m 216.7752,358.90965 76.79622,-10.33151 0,388.28057 -76.79622,-90.01915 z" - points="293.57142,348.57814 293.57142,736.85871 216.7752,646.83956 216.7752,358.90965 " /> + d="m 216.7752,362.90964 76.79622,-10.33151 0,388.28058 -76.79622,-90.01915 z" + points="293.57142,352.57813 293.57142,740.85871 216.7752,650.83956 216.7752,362.90964 " /> <path sodipodi:type="inkscape:box3dside" id="path4203" style="fill:#4d4d9f;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="5" - d="m 216.7752,358.90965 76.79622,-10.33151 -79.23203,-7.08647 -63.39792,13.69186 z" - points="293.57142,348.57814 214.33939,341.49167 150.94147,355.18353 216.7752,358.90965 " /> + d="m 216.7752,362.90964 76.79622,-10.33151 -79.23203,-7.08646 -63.39792,13.69185 z" + points="293.57142,352.57813 214.33939,345.49167 150.94147,359.18352 216.7752,362.90964 " /> <path sodipodi:type="inkscape:box3dside" id="path4207" style="fill:#d7d7ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="14" - d="m 293.57142,348.57814 0,388.28057 -79.23203,61.74483 0,-457.11187 z" - points="293.57142,736.85871 214.33939,798.60354 214.33939,341.49167 293.57142,348.57814 " /> + d="m 293.57142,352.57813 0,388.28058 -79.23203,61.74482 0,-457.11186 z" + points="293.57142,740.85871 214.33939,802.60353 214.33939,345.49167 293.57142,352.57813 " /> <path sodipodi:type="inkscape:box3dside" id="path4211" style="fill:#e9e9ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="11" - d="m 150.94147,355.18353 63.39792,-13.69186 0,457.11187 -63.39792,-119.29806 z" - points="214.33939,341.49167 214.33939,798.60354 150.94147,679.30548 150.94147,355.18353 " /> + d="m 150.94147,359.18352 63.39792,-13.69185 0,457.11186 -63.39792,-119.29806 z" + points="214.33939,345.49167 214.33939,802.60353 150.94147,683.30547 150.94147,359.18352 " /> </g> <g sodipodi:type="inkscape:box3d" @@ -137,43 +137,43 @@ id="path4148" style="fill:#afafde;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="13" - d="M 549.75488,777.7698 286.42855,677.13997 151.20944,751.61148 509.65875,1037.299 Z" - points="286.42855,677.13997 151.20944,751.61148 509.65875,1037.299 549.75488,777.7698 " /> + d="M 549.75488,781.76979 286.42855,681.13997 151.20944,755.61147 509.65875,1041.299 Z" + points="286.42855,681.13997 151.20944,755.61147 509.65875,1041.299 549.75488,781.76979 " /> <path sodipodi:type="inkscape:box3dside" id="path4146" style="fill:#d7d7ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="14" - d="m 286.42855,628.41064 0,48.72933 -135.21911,74.47151 0,-70.34662 z" - points="286.42855,677.13997 151.20944,751.61148 151.20944,681.26486 286.42855,628.41064 " /> + d="m 286.42855,632.41063 0,48.72934 -135.21911,74.4715 0,-70.34662 z" + points="286.42855,681.13997 151.20944,755.61147 151.20944,685.26485 286.42855,632.41063 " /> <path sodipodi:type="inkscape:box3dside" id="path4144" style="fill:#8686bf;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="3" - d="m 549.75488,699.83005 -263.32633,-71.41941 0,48.72933 263.32633,100.62983 z" - points="286.42855,628.41064 286.42855,677.13997 549.75488,777.7698 549.75488,699.83005 " /> + d="m 549.75488,703.83004 -263.32633,-71.41941 0,48.72934 263.32633,100.62982 z" + points="286.42855,632.41063 286.42855,681.13997 549.75488,781.76979 549.75488,703.83004 " /> <path sodipodi:type="inkscape:box3dside" id="path4142" style="fill:#4d4d9f;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="5" - d="M 549.75488,699.83005 286.42855,628.41064 151.20944,681.26486 509.65875,884.02418 Z" - points="286.42855,628.41064 151.20944,681.26486 509.65875,884.02418 549.75488,699.83005 " /> + d="M 549.75488,703.83004 286.42855,632.41063 151.20944,685.26485 509.65875,888.02418 Z" + points="286.42855,632.41063 151.20944,685.26485 509.65875,888.02418 549.75488,703.83004 " /> <path sodipodi:type="inkscape:box3dside" id="path4140" style="fill:#353564;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="6" - d="m 549.75488,699.83005 0,77.93975 -40.09613,259.5292 0,-153.27482 z" - points="549.75488,777.7698 509.65875,1037.299 509.65875,884.02418 549.75488,699.83005 " /> + d="m 549.75488,703.83004 0,77.93975 -40.09613,259.52921 0,-153.27482 z" + points="549.75488,781.76979 509.65875,1041.299 509.65875,888.02418 549.75488,703.83004 " /> <path sodipodi:type="inkscape:box3dside" id="path4150" style="fill:#e9e9ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="11" - d="m 509.65875,884.02418 -358.44931,-202.75932 0,70.34662 358.44931,285.68752 z" - points="151.20944,681.26486 151.20944,751.61148 509.65875,1037.299 509.65875,884.02418 " /> + d="m 509.65875,888.02418 -358.44931,-202.75933 0,70.34662 358.44931,285.68753 z" + points="151.20944,685.26485 151.20944,755.61147 509.65875,1041.299 509.65875,888.02418 " /> </g> <g sodipodi:type="inkscape:box3d" @@ -187,43 +187,43 @@ id="path4269" style="fill:#afafde;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="13" - d="M 277.14286,632.17551 487.14285,814.42729 549.97426,708.82208 350.6785,593.51412 Z" - points="487.14285,814.42729 549.97426,708.82208 350.6785,593.51412 277.14286,632.17551 " /> + d="M 277.14286,636.1755 487.14285,818.42729 549.97426,712.82208 350.6785,597.51411 Z" + points="487.14285,818.42729 549.97426,712.82208 350.6785,597.51411 277.14286,636.1755 " /> <path sodipodi:type="inkscape:box3dside" id="path4261" style="fill:#353564;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="6" - d="m 277.14286,434.72492 0,197.45059 73.53564,-38.66139 0,-166.11637 z" - points="277.14286,632.17551 350.6785,593.51412 350.6785,427.39775 277.14286,434.72492 " /> + d="m 277.14286,438.72491 0,197.45059 73.53564,-38.66139 0,-166.11637 z" + points="277.14286,636.1755 350.6785,597.51411 350.6785,431.39774 277.14286,438.72491 " /> <path sodipodi:type="inkscape:box3dside" id="path4271" style="fill:#e9e9ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="11" - d="m 350.6785,427.39775 199.29576,21.85335 0,259.57098 L 350.6785,593.51412 Z" - points="549.97426,449.2511 549.97426,708.82208 350.6785,593.51412 350.6785,427.39775 " /> + d="m 350.6785,431.39774 199.29576,21.85336 0,259.57098 L 350.6785,597.51411 Z" + points="549.97426,453.2511 549.97426,712.82208 350.6785,597.51411 350.6785,431.39774 " /> <path sodipodi:type="inkscape:box3dside" id="path4263" style="fill:#4d4d9f;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="5" - d="M 277.14286,434.72492 487.14285,469.26558 549.97426,449.2511 350.6785,427.39775 Z" - points="487.14285,469.26558 549.97426,449.2511 350.6785,427.39775 277.14286,434.72492 " /> + d="M 277.14286,438.72491 487.14285,473.26557 549.97426,453.2511 350.6785,431.39774 Z" + points="487.14285,473.26557 549.97426,453.2511 350.6785,431.39774 277.14286,438.72491 " /> <path sodipodi:type="inkscape:box3dside" id="path4267" style="fill:#d7d7ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="14" - d="m 487.14285,469.26558 0,345.16171 62.83141,-105.60521 0,-259.57098 z" - points="487.14285,814.42729 549.97426,708.82208 549.97426,449.2511 487.14285,469.26558 " /> + d="m 487.14285,473.26557 0,345.16172 62.83141,-105.60521 0,-259.57098 z" + points="487.14285,818.42729 549.97426,712.82208 549.97426,453.2511 487.14285,473.26557 " /> <path sodipodi:type="inkscape:box3dside" id="path4265" style="fill:#8686bf;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="3" - d="m 277.14286,434.72492 209.99999,34.54066 0,345.16171 -209.99999,-182.25178 z" - points="487.14285,469.26558 487.14285,814.42729 277.14286,632.17551 277.14286,434.72492 " /> + d="m 277.14286,438.72491 209.99999,34.54066 0,345.16172 L 277.14286,636.1755 Z" + points="487.14285,473.26557 487.14285,818.42729 277.14286,636.1755 277.14286,438.72491 " /> </g> <g sodipodi:type="inkscape:box3d" @@ -237,43 +237,43 @@ id="path4195" style="fill:#afafde;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="13" - d="M 231.71574,351.43508 549.16317,472.67635 489.01481,581.98921 150.62926,372.05707 Z" - points="549.16317,472.67635 489.01481,581.98921 150.62926,372.05707 231.71574,351.43508 " /> + d="M 231.71574,355.43508 549.16317,476.67634 489.01481,585.9892 150.62926,376.05706 Z" + points="549.16317,476.67634 489.01481,585.9892 150.62926,376.05706 231.71574,355.43508 " /> <path sodipodi:type="inkscape:box3dside" id="path4187" style="fill:#353564;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="6" - d="m 231.71574,314.07675 0,37.35833 -81.08648,20.62199 0,-44.14028 z" - points="231.71574,351.43508 150.62926,372.05707 150.62926,327.91679 231.71574,314.07675 " /> + d="m 231.71574,318.07674 0,37.35834 -81.08648,20.62198 0,-44.14028 z" + points="231.71574,355.43508 150.62926,376.05706 150.62926,331.91678 231.71574,318.07674 " /> <path sodipodi:type="inkscape:box3dside" id="path4191" style="fill:#8686bf;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="3" - d="m 231.71574,314.07675 317.44743,81.36867 0,77.23093 -317.44743,-121.24127 z" - points="549.16317,395.44542 549.16317,472.67635 231.71574,351.43508 231.71574,314.07675 " /> + d="m 231.71574,318.07674 317.44743,81.36867 0,77.23093 -317.44743,-121.24126 z" + points="549.16317,399.44541 549.16317,476.67634 231.71574,355.43508 231.71574,318.07674 " /> <path sodipodi:type="inkscape:box3dside" id="path4189" style="fill:#4d4d9f;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="5" - d="M 231.71574,314.07675 549.16317,395.44542 489.01481,468.80858 150.62926,327.91679 Z" - points="549.16317,395.44542 489.01481,468.80858 150.62926,327.91679 231.71574,314.07675 " /> + d="M 231.71574,318.07674 549.16317,399.44541 489.01481,472.80857 150.62926,331.91678 Z" + points="549.16317,399.44541 489.01481,472.80857 150.62926,331.91678 231.71574,318.07674 " /> <path sodipodi:type="inkscape:box3dside" id="path4193" style="fill:#d7d7ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="14" - d="m 549.16317,395.44542 0,77.23093 -60.14836,109.31286 0,-113.18063 z" - points="549.16317,472.67635 489.01481,581.98921 489.01481,468.80858 549.16317,395.44542 " /> + d="m 549.16317,399.44541 0,77.23093 -60.14836,109.31286 0,-113.18063 z" + points="549.16317,476.67634 489.01481,585.9892 489.01481,472.80857 549.16317,399.44541 " /> <path sodipodi:type="inkscape:box3dside" id="path4197" style="fill:#e9e9ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" inkscape:box3dsidetype="11" - d="m 150.62926,327.91679 338.38555,140.89179 0,113.18063 -338.38555,-209.93214 z" - points="489.01481,468.80858 489.01481,581.98921 150.62926,372.05707 150.62926,327.91679 " /> + d="m 150.62926,331.91678 338.38555,140.89179 0,113.18063 -338.38555,-209.93214 z" + points="489.01481,472.80857 489.01481,585.9892 150.62926,376.05706 150.62926,331.91678 " /> </g> </g> </svg> diff --git a/res/icons/weak_connect.svg b/res/icons/weak_connect.svg new file mode 100644 index 0000000000000000000000000000000000000000..a00e5213659a9eeefa6b2157af47c737d6a01be5 --- /dev/null +++ b/res/icons/weak_connect.svg @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="100" + height="100" + viewBox="0 0 100 100" + id="svg3336" + version="1.1" + inkscape:version="0.91 r13725" + sodipodi:docname="weak_connect.svg"> + <defs + id="defs3338"> + <linearGradient + inkscape:collect="always" + id="linearGradient4150"> + <stop + style="stop-color:#ffffff;stop-opacity:1;" + offset="0" + id="stop4152" /> + <stop + style="stop-color:#ffffff;stop-opacity:0.04620462" + offset="1" + id="stop4154" /> + </linearGradient> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient4150" + id="radialGradient4162" + cx="52.325901" + cy="1005.1627" + fx="52.325901" + fy="1005.1627" + r="42.926411" + gradientTransform="matrix(1.539681,0,0,1.5451884,-51.927374,-565.68063)" + gradientUnits="userSpaceOnUse" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2.8284271" + inkscape:cx="18.741815" + inkscape:cy="33.829638" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + units="px" + inkscape:snap-bbox="false" + inkscape:window-width="1366" + inkscape:window-height="709" + inkscape:window-x="-4" + inkscape:window-y="0" + inkscape:window-maximized="1" /> + <metadata + id="metadata3341"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Calque 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-952.36216)"> + <ellipse + style="opacity:1;fill:#fff41c;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="path3346" + cx="51.785713" + cy="1005.5765" + rx="41.785713" + ry="40.714287" /> + <ellipse + style="opacity:0.65;fill:url(#radialGradient4162);fill-opacity:1;stroke:none;stroke-width:1.25129819;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="path4148" + cx="28.637825" + cy="987.48499" + rx="64.928177" + ry="65.10495" /> + </g> +</svg> diff --git a/res/ui/community_cfg.ui b/res/ui/community_cfg.ui index 2908765829329949d9523aa57373d6ccec16b3e2..9c17e89ff35b30851b3d74b4c1aa6d76966ed9eb 100644 --- a/res/ui/community_cfg.ui +++ b/res/ui/community_cfg.ui @@ -261,5 +261,6 @@ <slot>next()</slot> <slot>previous()</slot> <slot>current_wallet_changed(int)</slot> + <slot>remove_node()</slot> </slots> </ui> diff --git a/res/ui/mainwindow.ui b/res/ui/mainwindow.ui index ada0cd670a14596f261917b5b88e459f4432bece..b13f53a19eb23c77d9342aeea03e5b49f50269cc 100644 --- a/res/ui/mainwindow.ui +++ b/res/ui/mainwindow.ui @@ -13,6 +13,10 @@ <property name="windowTitle"> <string notr="true">CuteCoin</string> </property> + <property name="windowIcon"> + <iconset resource="../icons/icons.qrc"> + <normaloff>:/icons/cutecoin_logo</normaloff>:/icons/cutecoin_logo</iconset> + </property> <widget class="QWidget" name="centralwidget"> <layout class="QVBoxLayout" name="verticalLayout_6"> <item> @@ -33,7 +37,7 @@ <x>0</x> <y>0</y> <width>681</width> - <height>25</height> + <height>31</height> </rect> </property> <widget class="QMenu" name="menu_account"> @@ -183,7 +187,9 @@ </property> </action> </widget> - <resources/> + <resources> + <include location="../icons/icons.qrc"/> + </resources> <connections> <connection> <sender>action_add_account</sender> diff --git a/res/ui/transactions_tab.ui b/res/ui/transactions_tab.ui index c610144a4d775e588be3924997a0088f029d1b75..e316da4c956d7711dde481e1bddbf0bf270ebb74 100644 --- a/res/ui/transactions_tab.ui +++ b/res/ui/transactions_tab.ui @@ -114,8 +114,41 @@ </hint> </hints> </connection> + <connection> + <sender>date_from</sender> + <signal>dateChanged(QDate)</signal> + <receiver>transactionsTabWidget</receiver> + <slot>dates_changed()</slot> + <hints> + <hint type="sourcelabel"> + <x>102</x> + <y>28</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>149</y> + </hint> + </hints> + </connection> + <connection> + <sender>date_to</sender> + <signal>dateChanged(QDate)</signal> + <receiver>transactionsTabWidget</receiver> + <slot>dates_changed()</slot> + <hints> + <hint type="sourcelabel"> + <x>297</x> + <y>28</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>149</y> + </hint> + </hints> + </connection> </connections> <slots> <slot>history_context_menu()</slot> + <slot>dates_changed()</slot> </slots> </ui> diff --git a/src/cutecoin/__init__.py b/src/cutecoin/__init__.py index e6ed9679fb238228bc293198797b9f570f657b37..15d06a58407740e20faf870a3e898afcece4a42e 100644 --- a/src/cutecoin/__init__.py +++ b/src/cutecoin/__init__.py @@ -1,2 +1,2 @@ -__version_info__ = ('0', '9', '0') +__version_info__ = ('0', '9', '1') __version__ = '.'.join(__version_info__) diff --git a/src/cutecoin/core/app.py b/src/cutecoin/core/app.py index c3c45bce0cdca352cb534f720818d5e76935c335..3893d1438b44325b500998d6da20f8c5a4caeffe 100644 --- a/src/cutecoin/core/app.py +++ b/src/cutecoin/core/app.py @@ -92,6 +92,8 @@ class Application(QObject): self.accounts.pop(account.name) if self.current_account == account: self.current_account = None + with open(config.parameters['data'], 'w') as outfile: + json.dump(self.jsonify(), outfile, indent=4, sort_keys=True) def change_current_account(self, account): ''' @@ -181,6 +183,7 @@ class Application(QObject): with open(network_path, 'r') as json_data: data = json.load(json_data) if 'version' in data and data['version'] == __version__: + logging.debug("Merging network : {0}".format(data)) community.load_merge_network(data['network']) else: os.remove(network_path) @@ -296,7 +299,7 @@ class Application(QObject): data = json.load(json_data) account = Account.load(data) account.name = name - self.accounts.append(account) + self.add_account(account) self.save(account) def export_account(self, file, account): @@ -359,4 +362,4 @@ class Application(QObject): logging.debug("Found version : {0}".format(latest_version)) if version != self.available_version: self.available_version = version - self.version_requested.emit() \ No newline at end of file + self.version_requested.emit() diff --git a/src/cutecoin/core/community.py b/src/cutecoin/core/community.py index e3e3a4f8e13dbfeef22e6a1445ab5f8844be41d7..da9fd989b4aa7aed4b54933bee811cb69a07eaf3 100644 --- a/src/cutecoin/core/community.py +++ b/src/cutecoin/core/community.py @@ -19,7 +19,7 @@ from requests.exceptions import RequestException class Cache(): - _saved_requests = [str(bma.blockchain.Block)] + _saved_requests = [str(bma.blockchain.Block), str(bma.blockchain.Parameters)] def __init__(self, community): ''' @@ -49,8 +49,7 @@ class Cache(): :return: The cache as a dict in json format ''' - data = {k: self.data[k] for k in self.data.keys() - if k[0] in Cache._saved_requests} + data = {k: self.data[k] for k in self.data.keys()} entries = [] for d in data: entries.append({'key': d, @@ -63,9 +62,12 @@ class Cache(): Refreshing the cache just clears every last requests which cannot be saved because they can change from one block to another. ''' - self.latest_block = self.community.current_blockid()['number'] - self.data = {k: self.data[k] for k in self.data.keys() - if k[0] in Cache._saved_requests} + logging.debug("Refresh : {0}/{1}".format(self.latest_block, + self.community.network.latest_block)) + if self.latest_block < self.community.network.latest_block: + self.latest_block = self.community.network.latest_block + self.data = {k: self.data[k] for k in self.data.keys() + if k[0] in Cache._saved_requests} def request(self, request, req_args={}, get_args={}): ''' @@ -78,19 +80,17 @@ class Cache(): ''' cache_key = (str(request), str(tuple(frozenset(sorted(req_args.keys())))), - str(tuple(frozenset(sorted(req_args.items())))), + str(tuple(frozenset(sorted(req_args.values())))), str(tuple(frozenset(sorted(get_args.keys())))), - str(tuple(frozenset(sorted(get_args.items()))))) + str(tuple(frozenset(sorted(get_args.values()))))) if cache_key not in self.data.keys(): result = self.community.request(request, req_args, get_args, cached=False) - - # Do not cache block 0 - if self.latest_block == 0: - return result - else: - self.data[cache_key] = result + # For block 0, we should have a different behaviour + # Community members and certifications + # Should be requested without caching + self.data[cache_key] = result return self.data[cache_key] else: return self.data[cache_key] @@ -104,8 +104,6 @@ class Community(QObject): but nothing exists in ucoin to assert that a currency name is unique. ''' - new_block_mined = pyqtSignal(int) - def __init__(self, currency, network): ''' Initialize community attributes with a currency and a network. @@ -120,7 +118,6 @@ class Community(QObject): self.currency = currency self._network = network self._cache = Cache(self) - self._cache.refresh() @classmethod @@ -259,11 +256,16 @@ class Community(QObject): :return: The monetary mass value ''' try: - block = self.request(bma.blockchain.Current) + # Get cached block by block number + block_number = self.network.latest_block + block = self.request(bma.blockchain.Block, + req_args={'number': block_number}) return block['monetaryMass'] except ValueError as e: if '404' in e: return 0 + except NoPeerAvailable as e: + return 0 @property def nb_members(self): @@ -273,20 +275,16 @@ class Community(QObject): :return: The community members number ''' try: - block = self.request(bma.blockchain.Current) + # Get cached block by block number + block_number = self.network.latest_block + block = self.request(bma.blockchain.Block, + req_args={'number': block_number}) return block['membersCount'] except ValueError as e: if '404' in e: return 0 - - @property - def nodes(self): - ''' - Get the known community nodes - - :return: All community known nodes - ''' - return self._network.all_nodes + except NoPeerAvailable as e: + return 0 @property def network(self): @@ -297,6 +295,16 @@ class Community(QObject): ''' return self._network + def network_quality(self): + ''' + Get a ratio of the synced nodes vs the rest + ''' + synced = len(self._network.synced_nodes) + #online = len(self._network.online_nodes) + total = len(self._network.nodes) + ratio_synced = synced / total + return ratio_synced + @property def parameters(self): ''' @@ -310,14 +318,21 @@ class Community(QObject): ''' return time.time() - certtime > self.parameters['sigValidity'] - @property - def add_peer(self, peer): + def add_node(self, node): ''' Add a peer to the community. :param peer: The new peer as a ucoinpy Peer object. ''' - self._network.add_node(Node.from_peer(peer)) + self._network.add_root_node(node) + + def remove_node(self, index): + ''' + Remove a node from the community. + + :param index: The index of the removed node. + ''' + self._network.remove_root_node(index) def get_block(self, number=None): ''' @@ -380,7 +395,7 @@ class Community(QObject): if cached: return self._cache.request(request, req_args, get_args) else: - nodes = self._network.online_nodes + nodes = self._network.synced_nodes for node in nodes: try: req = request(node.endpoint.conn_handler(), **req_args) @@ -398,9 +413,10 @@ class Community(QObject): continue else: raise - except RequestException: + except RequestException as e: + logging.debug("Error : {1} : {0}".format(str(e), + str(request))) continue - raise NoPeerAvailable(self.currency, len(nodes)) def post(self, request, req_args={}, post_args={}): @@ -460,7 +476,7 @@ class Community(QObject): if not ok: raise value_error - if tries == len(self.nodes): + if tries == len(nodes): raise NoPeerAvailable(self.currency, len(nodes)) def jsonify(self): @@ -469,6 +485,11 @@ class Community(QObject): :return: The community as a dict in json format. ''' + + nodes_data = [] + for node in self._network.root_nodes: + nodes_data.append(node.jsonify_root_node()) + data = {'currency': self.currency, - 'peers': self._network.jsonify()} - return data \ No newline at end of file + 'peers': nodes_data} + return data diff --git a/src/cutecoin/core/net/network.py b/src/cutecoin/core/net/network.py index 61f960d3498840878c30fb85138374437349fc19..4a85193fbd8ece7cbe1866208765bfd36be2b2c1 100644 --- a/src/cutecoin/core/net/network.py +++ b/src/cutecoin/core/net/network.py @@ -8,15 +8,17 @@ from .node import Node import logging import time -from PyQt5.QtCore import QObject, pyqtSignal +from PyQt5.QtCore import pyqtSignal, pyqtSlot, QMutex, QCoreApplication +from ..watching.watcher import Watcher -class Network(QObject): +class Network(Watcher): ''' A network is managing nodes polling and crawling of a given community. ''' nodes_changed = pyqtSignal() + new_block_mined = pyqtSignal(int) stopped_perpetual_crawling = pyqtSignal() def __init__(self, currency, nodes): @@ -24,15 +26,17 @@ class Network(QObject): Constructor of a network :param str currency: The currency name of the community - :param list nodes: The nodes of the network + :param list nodes: The root nodes of the network ''' super().__init__() + self._root_nodes = nodes + self._nodes = [] + self._mutex = QMutex() self.currency = currency - self._nodes = nodes - for n in self._nodes: - n.changed.connect(self.nodes_changed) + self.nodes = nodes self._must_crawl = False self._is_perpetual = False + self._block_found = self.latest_block @classmethod def create(cls, node): @@ -45,11 +49,6 @@ class Network(QObject): ''' nodes = [node] network = cls(node.currency, nodes) - nodes = network.crawling() - block_max = max([n.block for n in nodes]) - for node in nodes: - node.check_sync(block_max) - network._nodes = nodes return network def merge_with_json(self, json_data): @@ -61,16 +60,15 @@ class Network(QObject): ''' for data in json_data: node = Node.from_json(self.currency, data) - self._nodes.append(node) - logging.debug("Loading : {:}".format(data['pubkey'])) - for n in self._nodes: - try: - n.changed.disconnect() - except TypeError: - pass - self._nodes = self.crawling() - for n in self._nodes: - n.changed.connect(self.nodes_changed) + if node.pubkey not in [n.pubkey for n in self.nodes]: + self.add_node(node) + logging.debug("Loading : {:}".format(data['pubkey'])) + else: + other_node = [n for n in self.nodes if n.pubkey == node.pubkey][0] + if other_node.block < node.block: + other_node.block = node.block + other_node.last_change = node.last_change + other_node.state = node.state @classmethod def from_json(cls, currency, json_data): @@ -84,11 +82,8 @@ class Network(QObject): for data in json_data: node = Node.from_json(currency, data) nodes.append(node) - logging.debug("Loading : {:}".format(data['pubkey'])) - block_max = max([n.block for n in nodes]) - for node in nodes: - node.check_sync(block_max) - return cls(currency, nodes) + network = cls(currency, nodes) + return network def jsonify(self): ''' @@ -97,7 +92,7 @@ class Network(QObject): :return: The network as a dict in json format. ''' data = [] - for node in self._nodes: + for node in self.nodes: data.append(node.jsonify()) return data @@ -113,26 +108,91 @@ class Network(QObject): else: return True + @property + def synced_nodes(self): + ''' + Get nodes which are in the ONLINE state. + ''' + return [n for n in self.nodes if n.state == Node.ONLINE] + @property def online_nodes(self): ''' Get nodes which are in the ONLINE state. ''' - return [n for n in self._nodes if n.state == Node.ONLINE] + return [n for n in self.nodes if n.state in (Node.ONLINE, Node.DESYNCED)] @property - def all_nodes(self): + def nodes(self): ''' Get all knew nodes. ''' - return self._nodes.copy() + return self._nodes + + @property + def root_nodes(self): + ''' + Get root nodes. + ''' + return self._root_nodes + + @nodes.setter + def nodes(self, new_nodes): + ''' + Set new nodes + ''' + self._mutex.lock() + try: + for n in self.nodes: + try: + n.disconnect() + except TypeError: + logging.debug("Error disconnecting node {0}".format(n.pubkey[:5])) + + self._nodes = [] + for n in new_nodes: + self.add_node(n) + finally: + self._mutex.unlock() + + @property + def latest_block(self): + ''' + Get latest block known + ''' + return max([n.block for n in self.nodes]) - def add_nodes(self, node): + def add_node(self, node): ''' Add a node to the network. ''' self._nodes.append(node) - node.changed.connect(self.nodes_changed) + node.changed.connect(self.handle_change) + logging.debug("{:} connected".format(node.pubkey)) + + def add_root_node(self, node): + ''' + Add a node to the root nodes list + ''' + self._root_nodes.append(node) + + def remove_root_node(self, index): + ''' + Remove a node from the root nodes list + ''' + self._root_nodes.pop(index) + + def moveToThread(self, thread): + for n in self.nodes: + n.moveToThread(thread) + super().moveToThread(thread) + + def watch(self): + self.stopped_perpetual_crawling.connect(self.watching_stopped) + self.start_perpetual_crawling() + + def stop(self): + self.stop_crawling() def start_perpetual_crawling(self): ''' @@ -141,21 +201,52 @@ class Network(QObject): ''' self._must_crawl = True while self.continue_crawling(): + emit_change = False nodes = self.crawling(interval=10) new_inlines = [n.endpoint.inline() for n in nodes] - last_inlines = [n.endpoint.inline() for n in self._nodes] - - hash_new_nodes = hash(tuple(frozenset(sorted(new_inlines)))) - hash_last_nodes = hash(tuple(frozenset(sorted(last_inlines)))) + last_inlines = [n.endpoint.inline() for n in self.nodes] + hash_new_nodes = str(tuple(frozenset(sorted(new_inlines)))) + hash_last_nodes = str(tuple(frozenset(sorted(last_inlines)))) if hash_new_nodes != hash_last_nodes: - self._nodes = nodes + logging.debug("Nodes changed...") + self.nodes = nodes + emit_change = True + + for node in self.nodes: + if node.last_change + 3600 < time.time() and \ + node.state in (Node.OFFLINE, Node.CORRUPTED): + try: + node.changed.disconnect() + except TypeError: + logging.debug("Error : {0} not connected".format(node.pubkey)) + self.nodes.remove(node) + emit_change = True + + if emit_change: self.nodes_changed.emit() - for n in self._nodes: - n.changed.connect(self.nodes_changed) + QCoreApplication.processEvents() + self.stopped_perpetual_crawling.emit() + @pyqtSlot() + def handle_change(self): + node = self.sender() + logging.debug("Handle change") + if node.state in (Node.ONLINE, Node.DESYNCED): + node.check_sync(self.latest_block) + logging.debug("{0} -> {1}".format(self.latest_block, self.latest_block)) + if self._block_found < self.latest_block: + logging.debug("New block found : {0}".format(self.latest_block)) + self.new_block_mined.emit(self.latest_block) + + QCoreApplication.processEvents() + logging.debug("Syncing : {0} : last changed {1} : unsynced : {2}".format(node.pubkey[:5], + node.last_change, time.time() - node.last_change)) + + self.nodes_changed.emit() + def crawling(self, interval=0): ''' One network crawling. @@ -164,28 +255,17 @@ class Network(QObject): ''' nodes = [] traversed_pubkeys = [] - for n in self._nodes.copy(): + knew_pubkeys = [n.pubkey for n in self.nodes] + for n in self.nodes: logging.debug(traversed_pubkeys) logging.debug("Peering : next to read : {0} : {1}".format(n.pubkey, (n.pubkey not in traversed_pubkeys))) - if n.pubkey not in traversed_pubkeys and self.continue_crawling(): - n.peering_traversal(nodes, + if self.continue_crawling(): + n.peering_traversal(knew_pubkeys, nodes, traversed_pubkeys, interval, self.continue_crawling) + QCoreApplication.processEvents() time.sleep(interval) - block_max = max([n.block for n in nodes]) - for node in [n for n in nodes if n.state == Node.ONLINE]: - node.check_sync(block_max) - - for node in self._nodes: - if node.last_change + 3600 < time.time() and \ - node.state in (Node.OFFLINE, Node.CORRUPTED): - try: - node.changed.disconnect() - except TypeError: - pass - self._nodes.remove(node) - logging.debug("Nodes found : {0}".format(nodes)) return nodes diff --git a/src/cutecoin/core/net/node.py b/src/cutecoin/core/net/node.py index 622bc2cf2871bd823b179cfa08386c1397579ad5..8f2be8009e6b215a707d403a9ae6b48cee438309 100644 --- a/src/cutecoin/core/net/node.py +++ b/src/cutecoin/core/net/node.py @@ -7,11 +7,13 @@ Created on 21 févr. 2015 from ucoinpy.documents.peer import Peer, BMAEndpoint, Endpoint from ucoinpy.api import bma from ucoinpy.api.bma import ConnectionHandler -from requests.exceptions import RequestException +from requests.exceptions import RequestException, ConnectionError from ...tools.exceptions import InvalidNodeCurrency, PersonNotFoundError from ..person import Person import logging import time +import ctypes +import sys from PyQt5.QtCore import QObject, pyqtSignal @@ -42,7 +44,7 @@ class Node(QObject): self._endpoints = endpoints self._uid = uid self._pubkey = pubkey - self._block = block + self.block = block self._state = state self._neighbours = [] self._currency = currency @@ -69,7 +71,7 @@ class Node(QObject): node = cls(peer.currency, peer.endpoints, "", peer.pubkey, 0, Node.ONLINE, time.time()) - node.refresh_state() + logging.debug("Node from address : {:}".format(str(node))) return node @classmethod @@ -87,7 +89,7 @@ class Node(QObject): node = cls(peer.currency, peer.endpoints, "", "", 0, Node.ONLINE, time.time()) - node.refresh_state() + logging.debug("Node from peer : {:}".format(str(node))) return node @classmethod @@ -95,8 +97,10 @@ class Node(QObject): endpoints = [] uid = "" pubkey = "" + block = 0 last_change = time.time() - + state = Node.ONLINE + logging.debug(data) for endpoint_data in data['endpoints']: endpoints.append(Endpoint.from_inline(endpoint_data)) @@ -112,16 +116,38 @@ class Node(QObject): if 'last_change' in data: last_change = data['last_change'] - node = cls(currency, endpoints, uid, pubkey, 0, - Node.ONLINE, last_change) - node.refresh_state() + if 'block' in data: + block = data['block'] + + if 'state' in data: + state = data['state'] + else: + logging.debug("Error : no state in node") + + node = cls(currency, endpoints, uid, pubkey, block, + state, last_change) + logging.debug("Node from json : {:}".format(str(node))) return node + def jsonify_root_node(self): + logging.debug("Saving root node : {:}".format(str(self))) + data = {'pubkey': self._pubkey, + 'uid': self._uid, + 'currency': self._currency} + endpoints = [] + for e in self._endpoints: + endpoints.append(e.inline()) + data['endpoints'] = endpoints + return data + def jsonify(self): + logging.debug("Saving node : {:}".format(str(self))) data = {'pubkey': self._pubkey, 'uid': self._uid, 'currency': self._currency, - 'last_change': self._last_change} + 'state': self._state, + 'last_change': self._last_change, + 'block': self.block} endpoints = [] for e in self._endpoints: endpoints.append(e.inline()) @@ -140,6 +166,10 @@ class Node(QObject): def block(self): return self._block + @block.setter + def block(self, new_block): + self._block = new_block + @property def state(self): return self._state @@ -160,16 +190,26 @@ class Node(QObject): def last_change(self): return self._last_change - def _change_state(self, new_state): - if self.state != new_state: - self._last_change = time.time() + @last_change.setter + def last_change(self, val): + logging.debug("{:} | Changed state : {:}".format(self.pubkey[:5], + val)) + self._last_change = val + + @state.setter + def state(self, new_state): + logging.debug("{:} | Last state : {:} / new state : {:}".format(self.pubkey[:5], + self.state, new_state)) + if self._state != new_state: + self.last_change = time.time() self._state = new_state def check_sync(self, block): - if self._block < block: - self._change_state(Node.DESYNCED) + logging.debug("Check sync") + if self.block < block: + self.state = Node.DESYNCED else: - self._change_state(Node.ONLINE) + self.state = Node.ONLINE def _request_uid(self): uid = "" @@ -190,10 +230,18 @@ class Node(QObject): return uid def refresh_state(self): + logging.debug("Refresh state") emit_change = False try: informations = bma.network.Peering(self.endpoint.conn_handler()).get() - block = bma.blockchain.Current(self.endpoint.conn_handler()).get() + node_pubkey = informations["pubkey"] + try: + block = bma.blockchain.Current(self.endpoint.conn_handler()).get() + block_number = block["number"] + except ValueError as e: + if '404' in e: + block_number = 0 + peers_data = bma.network.peering.Peers(self.endpoint.conn_handler()).get() neighbours = [] for p in peers_data: @@ -201,34 +249,62 @@ class Node(QObject): p['value']['signature'])) neighbours.append(peer.endpoints) - block_number = block["number"] - node_pubkey = informations["pubkey"] node_currency = informations["currency"] - except ValueError as e: - if '404' in e: - block_number = 0 - except RequestException: - self._change_state(Node.OFFLINE) - emit_change = True + node_uid = self._request_uid() + + #If the nodes goes back online... + if self.state in (Node.OFFLINE, Node.CORRUPTED): + self.state = Node.ONLINE + logging.debug("Change : new state online") + emit_change = True + except ConnectionError as e: + logging.debug(str(e)) + + if self.state != Node.OFFLINE: + self.state = Node.OFFLINE + logging.debug("Change : new state offine") + emit_change = True + # Dirty hack to reload resolv.conf on linux + if 'Connection aborted' in str(e) and 'gaierror' in str(e): + logging.debug("Connection Aborted") + if 'linux' in sys.platform: + try: + libc = ctypes.CDLL('libc.so.6') + res_init = getattr(libc, '__res_init') + res_init(None) + except: + logging.error('Error calling libc.__res_init') + except RequestException as e: + logging.debug(str(e)) + if self.state != Node.OFFLINE: + self.state = Node.OFFLINE + logging.debug("Change : new state offine") + emit_change = True # If not is offline, do not refresh last data if self.state != Node.OFFLINE: # If not changed its currency, consider it corrupted if node_currency != self._currency: - self._change_state(Node.CORRUPTED) + self.state = Node.CORRUPTED + logging.debug("Change : new state corrupted") emit_change = True else: - node_uid = self._request_uid() - - if block_number != self._block: - self._block = block_number + if block_number != self.block: + logging.debug("Change : new block {0} -> {1}".format(self.block, + block_number)) + self.block = block_number + logging.debug("Changed block {0} -> {1}".format(self.block, + block_number)) emit_change = True if node_pubkey != self._pubkey: + logging.debug("Change : new pubkey {0} -> {1}".format(self._pubkey, + node_pubkey)) self._pubkey = node_pubkey emit_change = True if node_uid != self._uid: + logging.debug("Change : new uid") self._uid = node_uid emit_change = True @@ -240,12 +316,14 @@ class Node(QObject): hash_last_neighbours = hash(tuple(frozenset(sorted(last_inlines)))) if hash_new_neighbours != hash_last_neighbours: self._neighbours = neighbours + logging.debug("Change : new neighbours {0} -> {1}".format(last_inlines, + new_inlines)) emit_change = True if emit_change: self.changed.emit() - def peering_traversal(self, found_nodes, + def peering_traversal(self, knew_pubkeys, found_nodes, traversed_pubkeys, interval, continue_crawling): logging.debug("Read {0} peering".format(self.pubkey)) @@ -257,23 +335,24 @@ class Node(QObject): if self.state != Node.CORRUPTED: logging.debug("Found : {0} node".format(self.pubkey)) found_nodes.append(self) - try: logging.debug(self.neighbours) for n in self.neighbours: - e = next(e for e in n if type(e) is BMAEndpoint) - peering = bma.network.Peering(e.conn_handler()).get() + try: + e = next(e for e in n if type(e) is BMAEndpoint) + peering = bma.network.Peering(e.conn_handler()).get() + except: + continue peer = Peer.from_signed_raw("{0}{1}\n".format(peering['raw'], peering['signature'])) - node = Node.from_peer(self._currency, peer) - logging.debug(traversed_pubkeys) - logging.debug("Traversing : next to read : {0} : {1}".format(node.pubkey, - (node.pubkey not in traversed_pubkeys))) - if node.pubkey not in traversed_pubkeys and continue_crawling(): - node.peering_traversal(found_nodes, - traversed_pubkeys, interval, continue_crawling()) + if peer.pubkey not in traversed_pubkeys and \ + peer.pubkey not in knew_pubkeys and continue_crawling(): + node = Node.from_peer(self._currency, peer) + logging.debug(traversed_pubkeys) + logging.debug("Traversing : next to read : {0} : {1}".format(node.pubkey, + (node.pubkey not in traversed_pubkeys))) + node.peering_traversal(knew_pubkeys, found_nodes, + traversed_pubkeys, interval, continue_crawling) time.sleep(interval) - except RequestException as e: - self._change_state(Node.OFFLINE) def __str__(self): return ','.join([str(self.pubkey), str(self.endpoint.server), str(self.endpoint.port), str(self.block), diff --git a/src/cutecoin/core/person.py b/src/cutecoin/core/person.py index 0afdf4b0effc4be4ff245d7d656676aca473a267..4e66d309030a5c5a4649da8362f5c2e2eb2dc16a 100644 --- a/src/cutecoin/core/person.py +++ b/src/cutecoin/core/person.py @@ -12,7 +12,8 @@ from ucoinpy import PROTOCOL_VERSION from ucoinpy.documents.certification import SelfCertification from ucoinpy.documents.membership import Membership from ..tools.exceptions import Error, PersonNotFoundError,\ - MembershipNotFoundError + MembershipNotFoundError, \ + NoPeerAvailable from PyQt5.QtCore import QMutex @@ -51,6 +52,7 @@ class cached(object): except KeyError: value = self.func(inst, community) inst._cache[community.currency][self.func.__name__] = value + finally: inst._cache_mutex.unlock() @@ -115,12 +117,13 @@ class Person(object): for result in data['results']: if result["pubkey"] == pubkey: uids = result['uids'] - for uid in uids: - if uid["meta"]["timestamp"] > timestamp: - timestamp = uid["meta"]["timestamp"] - uid = uid["uid"] + person_uid = "" + for uid_data in uids: + if uid_data["meta"]["timestamp"] > timestamp: + timestamp = uid_data["meta"]["timestamp"] + person_uid = uid_data["uid"] - person = cls(uid, pubkey, {}) + person = cls(person_uid, pubkey, {}) Person._instances[pubkey] = person logging.debug("{0}".format(Person._instances.keys())) return person @@ -219,6 +222,9 @@ class Person(object): except ValueError as e: if '400' in str(e): raise MembershipNotFoundError(self.pubkey, community.name) + except Exception as e: + logging.debug('bma.blockchain.Membership request error : ' + str(e)) + raise MembershipNotFoundError(self.pubkey, community.name) #TODO: Manage 'OUT' memberships ? Maybe ? @cached @@ -247,6 +253,9 @@ class Person(object): except ValueError as e: if '400' in str(e): raise MembershipNotFoundError(self.pubkey, community.name) + except Exception as e: + logging.debug('bma.blockchain.Membership request error : ' + str(e)) + raise MembershipNotFoundError(self.pubkey, community.name) return membership_data @@ -263,6 +272,9 @@ class Person(object): return certifiers['isMember'] except ValueError: return False + except Exception as e: + logging.debug('bma.wot.CertifiersOf request error : ' + str(e)) + return False @cached def certifiers_of(self, community): @@ -285,14 +297,20 @@ class Person(object): # convert api data to certifiers list certifiers = list() # add certifiers of uid - for certifier in data['results'][0]['uids'][0]['others']: - # for each uid found for this pubkey... - for uid in certifier['uids']: - # add a certifier - certifier['uid'] = uid - certifier['cert_time'] = dict() - certifier['cert_time']['medianTime'] = community.get_block(certifier['meta']['block_number']).mediantime - certifiers.append(certifier) + + for result in data['results']: + if result["pubkey"] == self.pubkey: + for uid_data in result['uids']: + for certifier_data in uid_data['others']: + for uid in certifier_data['uids']: + # add a certifier + certifier = {} + certifier['uid'] = uid + certifier['pubkey'] = certifier_data['pubkey'] + certifier['isMember'] = certifier_data['isMember'] + certifier['cert_time'] = dict() + certifier['cert_time']['medianTime'] = community.get_block(certifier_data['meta']['block_number']).mediantime + certifiers.append(certifier) return certifiers @@ -340,10 +358,12 @@ class Person(object): return list() certified_list = list() - for certified in data['results'][0]['signed']: - certified['cert_time'] = dict() - certified['cert_time']['medianTime'] = certified['meta']['timestamp'] - certified_list.append(certified) + for result in data['results']: + if result["pubkey"] == self.pubkey: + for certified in result['signed']: + certified['cert_time'] = dict() + certified['cert_time']['medianTime'] = certified['meta']['timestamp'] + certified_list.append(certified) return certified_list @@ -383,31 +403,31 @@ class Person(object): :return: True if a changed was made by the reload. ''' self._cache_mutex.lock() + change = False try: if community.currency not in self._cache: self._cache[community.currency] = {} - change = False - before = self._cache[community.currency][func.__name__] - - value = func(self, community) - - if not change: - if type(value) is dict: - hash_before = (hash(tuple(frozenset(sorted(before.keys())))), - hash(tuple(frozenset(sorted(before.items()))))) - hash_after = (hash(tuple(frozenset(sorted(value.keys())))), - hash(tuple(frozenset(sorted(value.items()))))) - change = hash_before != hash_after - elif type(value) is bool: - change = before != value - - self._cache[community.currency][func.__name__] = value + try: + before = self._cache[community.currency][func.__name__] + except KeyError: + change = True - except KeyError: - change = True - except Error: - return False + try: + value = func(self, community) + + if not change: + if type(value) is dict: + hash_before = (str(tuple(frozenset(sorted(before.keys())))), + str(tuple(frozenset(sorted(before.items()))))) + hash_after = (str(tuple(frozenset(sorted(value.keys())))), + str(tuple(frozenset(sorted(value.items()))))) + change = hash_before != hash_after + elif type(value) is bool: + change = before != value + self._cache[community.currency][func.__name__] = value + except Error: + return False finally: self._cache_mutex.unlock() return change diff --git a/src/cutecoin/core/transfer.py b/src/cutecoin/core/transfer.py index ddf144c10fccdd7f9b704cbc8c0c3676dc57dae6..b01a44267d65eac1dfdc34218632f3b8fb986740 100644 --- a/src/cutecoin/core/transfer.py +++ b/src/cutecoin/core/transfer.py @@ -46,6 +46,8 @@ class Transfer(object): assert('issuer' in metadata) assert('amount' in metadata) assert('comment' in metadata) + assert('issuer_uid' in metadata) + assert('receiver_uid' in metadata) self.txdoc = txdoc self.state = state diff --git a/src/cutecoin/core/wallet.py b/src/cutecoin/core/wallet.py index 3589bc2af35f68961337b1baf3c969e464262435..5479d48b5c79e2e3fb294b42c9aacbcbf787300d 100644 --- a/src/cutecoin/core/wallet.py +++ b/src/cutecoin/core/wallet.py @@ -10,8 +10,9 @@ from ucoinpy.documents.block import Block from ucoinpy.documents.transaction import InputSource, OutputSource, Transaction from ucoinpy.key import SigningKey -from ..tools.exceptions import NotEnoughMoneyError, NoPeerAvailable +from ..tools.exceptions import NotEnoughMoneyError, NoPeerAvailable, PersonNotFoundError from .transfer import Transfer, Received +from .person import Person from PyQt5.QtCore import QObject, pyqtSignal @@ -28,7 +29,6 @@ class Cache(): def load_from_json(self, data): self._transfers = [] - logging.debug(data) data_sent = data['transfers'] for s in data_sent: @@ -61,15 +61,27 @@ class Cache(): return [t for t in self._transfers if t.state != Transfer.DROPPED] def _parse_transaction(self, community, tx, block_number, mediantime): - + logging.debug(tx) receivers = [o.pubkey for o in tx.outputs if o.pubkey != tx.issuers[0]] + try: + issuer_uid = Person.lookup(tx.issuers[0], community).uid + except PersonNotFoundError: + issuer_uid = "" + + try: + receiver_uid = Person.lookup(receivers[0], community).uid + except PersonNotFoundError: + receiver_uid = "" + metadata = {'block': block_number, 'time': mediantime, 'comment': tx.comment, 'issuer': tx.issuers[0], - 'receiver': receivers[0]} + 'issuer_uid': issuer_uid, + 'receiver': receivers[0], + 'receiver_uid': receiver_uid} in_issuers = len([i for i in tx.issuers if i == self.wallet.pubkey]) > 0 @@ -357,11 +369,23 @@ class Wallet(QObject): key = SigningKey("{0}{1}".format(salt, self.walletid), password) logging.debug("Sender pubkey:{0}".format(key.pubkey)) + try: + issuer_uid = Person.lookup(key.pubkey, community).uid + except PersonNotFoundError: + issuer_uid = "" + + try: + receiver_uid = Person.lookup(recipient, community).uid + except PersonNotFoundError: + receiver_uid = "" + metadata = {'block': block_number, 'time': time, 'amount': amount, 'issuer': key.pubkey, + 'issuer_uid': issuer_uid, 'receiver': recipient, + 'receiver_uid': receiver_uid, 'comment': message } transfer = Transfer.initiate(metadata) diff --git a/src/cutecoin/core/watching/blockchain.py b/src/cutecoin/core/watching/blockchain.py index 20ff37af1f39d26e6ff8f1fa1438f70c57fd3492..cc6ae2746b688b3ca18b45f279b9bfc4173d697c 100644 --- a/src/cutecoin/core/watching/blockchain.py +++ b/src/cutecoin/core/watching/blockchain.py @@ -18,30 +18,25 @@ class BlockchainWatcher(Watcher): self.community = community self.time_to_wait = int(self.community.parameters['avgGenTime'] / 10) self.exiting = False - blockid = self.community.current_blockid() - self.last_block = blockid['number'] + self.last_block = self.community.network.latest_block def watch(self): - while not self.exiting: - time.sleep(self.time_to_wait) - try: - blockid = self.community.current_blockid() - block_number = blockid['number'] - if self.last_block != block_number: + try: + block_number = self.community.network.latest_block + if self.last_block != block_number: + if not self.exiting: + self.community.refresh_cache() + for w in self.account.wallets: if not self.exiting: - self.community.refresh_cache() - for w in self.account.wallets: - if not self.exiting: - w.refresh_cache(self.community) + w.refresh_cache(self.community) - logging.debug("New block, {0} mined in {1}".format(block_number, - self.community.currency)) - self.community.new_block_mined.emit(block_number) - self.last_block = block_number - except NoPeerAvailable: - pass - except RequestException as e: - self.error.emit("Cannot check new block : {0}".format(str(e))) + logging.debug("New block, {0} mined in {1}".format(block_number, + self.community.currency)) + self.last_block = block_number + except NoPeerAvailable: + pass + except RequestException as e: + self.error.emit("Cannot check new block : {0}".format(str(e))) self.watching_stopped.emit() def stop(self): diff --git a/src/cutecoin/core/watching/monitor.py b/src/cutecoin/core/watching/monitor.py index 866453da004f7db59595f1dec05bad76591771f2..b2181a2a8289d0ecd3fec7fc5a081e0bc73ac1f6 100644 --- a/src/cutecoin/core/watching/monitor.py +++ b/src/cutecoin/core/watching/monitor.py @@ -7,7 +7,6 @@ Created on 18 mars 2015 from PyQt5.QtCore import QThread, Qt from .blockchain import BlockchainWatcher from .persons import PersonsWatcher -from .network import NetworkWatcher import logging @@ -30,22 +29,16 @@ class Monitor(object): return self._blockchain_watchers[community.name] def network_watcher(self, community): - return self._network_watchers[community.name] + return self._networks[community.name] def persons_watcher(self, community): return self._persons_watchers[community.name] - def restart_persons_watching(self, community): - watcher = self.persons_watcher(community) - thread = watcher.thread() - logging.debug("Persons watching thread is : {0}".format(thread.isFinished())) - thread.start() - def connect_watcher_to_thread(self, watcher): thread = QThread() watcher.moveToThread(thread) thread.started.connect(watcher.watch) - success = watcher.watching_stopped.connect(thread.exit, Qt.DirectConnection) + watcher.watching_stopped.connect(thread.exit, Qt.DirectConnection) self.threads_pool.append(thread) @@ -59,13 +52,12 @@ class Monitor(object): self.connect_watcher_to_thread(bc_watcher) self._blockchain_watchers[c.name] = bc_watcher - network_watcher = NetworkWatcher(c) - self.connect_watcher_to_thread(network_watcher) - self._network_watchers[c.name] = network_watcher + self.connect_watcher_to_thread(c.network) + self._network_watchers[c.name] = c.network - def start_watching(self): - for thread in self.threads_pool: - thread.start() + def start_network_watchers(self): + for watcher in self._network_watchers.values(): + watcher.thread().start() def stop_watching(self): for watcher in self._persons_watchers.values(): @@ -85,3 +77,8 @@ class Monitor(object): self.threads_pool.remove(watcher.thread()) watcher.deleteLater() watcher.thread().deleteLater() + + self.threads_pool = [] + self._blockchain_watchers = {} + self._network_watchers = {} + self._persons_watchers = {} diff --git a/src/cutecoin/core/watching/network.py b/src/cutecoin/core/watching/network.py deleted file mode 100644 index 0f7e8b094c73e89f9621f559cfbce355c99223ce..0000000000000000000000000000000000000000 --- a/src/cutecoin/core/watching/network.py +++ /dev/null @@ -1,26 +0,0 @@ -''' -Created on 27 févr. 2015 - -@author: inso -''' - -from .watcher import Watcher - - -class NetworkWatcher(Watcher): - ''' - This will crawl the network to always - have up to date informations about the nodes - ''' - - def __init__(self, community): - super().__init__() - self.community = community - - def watch(self): - self.community.network.stopped_perpetual_crawling.connect(self.watching_stopped) - self.community.network.start_perpetual_crawling() - - def stop(self): - self.community.network.stop_crawling() - diff --git a/src/cutecoin/gui/community_tab.py b/src/cutecoin/gui/community_tab.py index 4ae8ed19402704c4feb917b1de20976c037696b9..5f0f89f842065f2ac18829075b45a2ab33376a9a 100644 --- a/src/cutecoin/gui/community_tab.py +++ b/src/cutecoin/gui/community_tab.py @@ -27,7 +27,7 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget): classdocs ''' - def __init__(self, account, community, password_asker, parent): + def __init__(self, app, account, community, password_asker, parent): """ Init :param cutecoin.core.account.Account account: Accoun instance @@ -37,15 +37,12 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget): :return: """ super().__init__() - logging.debug("Info") self.setupUi(self) self.parent = parent self.community = community self.account = account self.password_asker = password_asker - logging.debug("Table") members_model = MembersTableModel(community) - logging.debug("Filter") proxy_members = MembersFilterProxyModel() proxy_members.setSourceModel(members_model) self.table_community_members.setModel(proxy_members) @@ -59,7 +56,7 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget): self.button_membership.setText("Send membership demand") self.button_leaving.hide() - self.wot_tab = WotTabWidget(account, community, password_asker, self) + self.wot_tab = WotTabWidget(app, account, community, password_asker, self) self.tabs_information.addTab(self.wot_tab, QIcon(':/icons/wot_icon'), "WoT") def member_context_menu(self, point): @@ -109,7 +106,8 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget): def menu_add_as_contact(self): person = self.sender().data() - self.add_member_as_contact(person) + self.add_member_as_contact({'name': person.uid, + 'pubkey': person.pubkey}) def menu_send_money(self): person = self.sender().data() @@ -140,7 +138,7 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget): dialog.radio_pubkey.setChecked(True) if dialog.exec_() == QDialog.Accepted: currency_tab = self.window().currencies_tabwidget.currentWidget() - currency_tab.table_history.model().invalidate() + currency_tab.tab_history.table_history.model().invalidate() def certify_member(self, person): dialog = CertificationDialog(self.account, self.password_asker) diff --git a/src/cutecoin/gui/contact.py b/src/cutecoin/gui/contact.py index 284bda8aa27caf30dde2d4b82da1f7fd639332e0..b2b43d7298c1a6c779b9f03702958c3c9b7b60c9 100644 --- a/src/cutecoin/gui/contact.py +++ b/src/cutecoin/gui/contact.py @@ -32,6 +32,8 @@ class ConfigureContactDialog(QDialog, Ui_ConfigureContactDialog): 'pubkey': contact.pubkey} elif type(contact) is dict: self.contact = contact + else: + self.contact = None if index_edit is not None: self.contact = account.contacts[index_edit] diff --git a/src/cutecoin/gui/currency_tab.py b/src/cutecoin/gui/currency_tab.py index e5d633154b221185c169d09b3629307196b3ba15..88a2f616fd88f0b993c71db468e9f22ac3c912cf 100644 --- a/src/cutecoin/gui/currency_tab.py +++ b/src/cutecoin/gui/currency_tab.py @@ -36,27 +36,25 @@ class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): self.community = community self.password_asker = password_asker self.status_label = status_label - logging.debug("Com") - self.tab_community = CommunityTabWidget(self.app.current_account, - self.community, - self.password_asker, - self) - logging.debug("Wal") + self.tab_community = CommunityTabWidget(self.app, + self.app.current_account, + self.community, + self.password_asker, + self) + self.tab_wallets = WalletsTabWidget(self.app, self.app.current_account, self.community, self.password_asker) - logging.debug("Net") self.tab_network = NetworkTabWidget(self.community) - logging.debug("Connect") - self.community.new_block_mined.connect(self.refresh_block) + self.community.network.new_block_mined.connect(self.refresh_block) + self.community.network.nodes_changed.connect(self.refresh_status) persons_watcher = self.app.monitor.persons_watcher(self.community) persons_watcher.person_changed.connect(self.tab_community.refresh_person) bc_watcher = self.app.monitor.blockchain_watcher(self.community) bc_watcher.error.connect(self.display_error) - logging.debug("Connected") person = Person.lookup(self.app.current_account.pubkey, self.community) try: @@ -104,7 +102,8 @@ class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): QIcon(':/icons/tx_icon'), "Transactions") - self.tab_community = CommunityTabWidget(self.app.current_account, + self.tab_community = CommunityTabWidget(self.app, + self.app.current_account, self.community, self.password_asker, self) @@ -130,10 +129,7 @@ class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): QIcon(":/icons/network_icon"), "Network") self.tab_informations.refresh() - blockid = self.community.current_blockid() - block_number = blockid['number'] - self.status_label.setText("Connected : Block {0}" - .format(block_number)) + self.refresh_status() self.refresh_wallets() @pyqtSlot(str) @@ -144,6 +140,7 @@ class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): @pyqtSlot(int) def refresh_block(self, block_number): + logging.debug("Refesh block") if self.tab_wallets: self.tab_wallets.refresh() @@ -152,20 +149,30 @@ class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): QModelIndex(), QModelIndex(), []) - self.app.monitor.restart_persons_watching(self.community) - - text = "Connected : Block {0}".format(block_number) - self.status_label.setText(text) + self.app.monitor.blockchain_watcher(self.community).thread().start() + self.app.monitor.persons_watcher(self.community).thread().start() + self.refresh_status() + + @pyqtSlot() + def refresh_status(self): + logging.debug("Refresh status") + if self.community.network_quality() > 0.66: + icon = '<img src=":/icons/connected" width="12" height="12"/>' + text = " Block {0}".format(self.community.network.latest_block) + elif self.community.network_quality() > 0.33: + icon = '<img src=":/icons/weak_connect" width="12" height="12"/>' + text = " Block {0}".format(self.community.network.latest_block) + else: + icon = '<img src=":/icons/disconnected" width="12" height="12"/>' + text = " Block {0}".format(self.community.network.latest_block) + self.status_label.setText("{0}{1}".format(icon, text)) def refresh_wallets(self): if self.app.current_account: self.tab_wallets.refresh() def showEvent(self, event): - blockid = self.community.current_blockid() - block_number = blockid['number'] - self.status_label.setText("Connected : Block {0}" - .format(block_number)) + self.refresh_status() def referential_changed(self): if self.tab_history.table_history.model(): diff --git a/src/cutecoin/gui/import_account.py b/src/cutecoin/gui/import_account.py index 5fd598c811bbb9d50fdbda4d37d38c621fb27cae..5550e5a99a7e6d7dafdeb562de9cafaf476e911a 100644 --- a/src/cutecoin/gui/import_account.py +++ b/src/cutecoin/gui/import_account.py @@ -58,7 +58,7 @@ class ImportAccountDialog(QDialog, Ui_ImportAccountDialog): self.label_errors.setText("Please enter a name") return for account in self.app.accounts: - if name == account.name: + if name == account: self.button_box.button(QDialogButtonBox.Ok).setEnabled(False) self.label_errors.setText("Name already exists") return diff --git a/src/cutecoin/gui/mainwindow.py b/src/cutecoin/gui/mainwindow.py index 480f56ea9b9555781e797a2fb256e6b5debeffb6..05912506cff60a16b7d29c7b5b95d5d0dd710675 100644 --- a/src/cutecoin/gui/mainwindow.py +++ b/src/cutecoin/gui/mainwindow.py @@ -5,10 +5,9 @@ Created on 1 févr. 2014 ''' from ..gen_resources.mainwindow_uic import Ui_MainWindow from ..gen_resources.about_uic import Ui_AboutPopup -from ..gen_resources.homescreen_uic import Ui_HomeScreenWidget from PyQt5.QtWidgets import QMainWindow, QAction, QFileDialog, QProgressBar, \ - QMessageBox, QLabel, QComboBox, QDialog, QApplication + QMessageBox, QLabel, QComboBox, QDialog, QApplication from PyQt5.QtCore import QSignalMapper, QObject, QThread, \ pyqtSlot, pyqtSignal, QDate, QDateTime, QTimer, QUrl, Qt from PyQt5.QtGui import QIcon, QDesktopServices @@ -44,33 +43,27 @@ class Loader(QObject): @pyqtSlot() def load(self): if self.account_name != "": - try: - account = self.app.get_account(self.account_name) - self.app.change_current_account(account) - except requests.exceptions.RequestException as e: - self.connection_error.emit(str(e)) - self.loaded.emit() - except NoPeerAvailable as e: - self.connection_error.emit(str(e)) - self.loaded.emit() + account = self.app.get_account(self.account_name) + self.app.change_current_account(account) self.loaded.emit() class MainWindow(QMainWindow, Ui_MainWindow): - ''' classdocs ''' def __init__(self, app): - ''' - Constructor - ''' + """ + Init + :param ..core.app.Application app: + """ # Set up the user interface from Designer. super().__init__() self.setupUi(self) self.app = app + """:type: cutecoin.core.app.Application""" self.password_asker = None self.initialized = False @@ -86,6 +79,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.combo_referential.currentTextChanged.connect(self.referential_changed) self.status_label = QLabel("", self) + self.status_label.setTextFormat(Qt.RichText) self.label_time = QLabel("", self) @@ -109,7 +103,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.open_ucoin_info = lambda: QDesktopServices.openUrl(QUrl("http://ucoin.io/theoretical/")) self.homescreen.button_info.clicked.connect(self.open_ucoin_info) - #TODO: There are too much refresh() calls on startup + # TODO: There are too much refresh() calls on startup self.refresh() def open_add_account_dialog(self): @@ -118,20 +112,11 @@ class MainWindow(QMainWindow, Ui_MainWindow): if result == QDialog.Accepted: self.action_change_account(self.app.current_account.name) - @pyqtSlot() - def loader_finished(self): - logging.debug("Finished loading") - self.refresh() - self.busybar.hide() - QApplication.restoreOverrideCursor() - self.app.disconnect() - self.app.monitor.start_watching() - @pyqtSlot(str) def display_error(self, error): QMessageBox.critical(self, ":(", - error, - QMessageBox.Ok) + error, + QMessageBox.Ok) @pyqtSlot(str) def referential_changed(self, text): @@ -170,7 +155,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): logging.debug("Busybar : {:} : {:}".format(value, maximum)) self.busybar.setValue(value) self.busybar.setMaximum(maximum) - + if self.app.current_account: self.app.save_cache(self.app.current_account) @@ -188,13 +173,23 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.homescreen.button_new.hide() self.homescreen.button_import.hide() + @pyqtSlot() + def loader_finished(self): + logging.debug("Finished loading") + self.refresh() + self.busybar.hide() + QApplication.setOverrideCursor(Qt.ArrowCursor) + self.app.disconnect() + self.app.monitor.start_network_watchers() + QApplication.processEvents() + def open_transfer_money_dialog(self): dialog = TransferMoneyDialog(self.app.current_account, self.password_asker) dialog.accepted.connect(self.refresh_wallets) if dialog.exec_() == QDialog.Accepted: currency_tab = self.currencies_tabwidget.currentWidget() - currency_tab.table_history.model().invalidate() + currency_tab.tab_history.table_history.model().invalidate() def open_certification_dialog(self): dialog = CertificationDialog(self.app.current_account, @@ -211,7 +206,10 @@ class MainWindow(QMainWindow, Ui_MainWindow): dialog = ProcessConfigureAccount(self.app, self.app.current_account) result = dialog.exec_() if result == QDialog.Accepted: - self.action_change_account(self.app.current_account.name) + if self.app.current_account: + self.action_change_account(self.app.current_account.name) + else: + self.refresh() def open_about_popup(self): """ @@ -221,12 +219,12 @@ class MainWindow(QMainWindow, Ui_MainWindow): aboutUi = Ui_AboutPopup() aboutUi.setupUi(aboutDialog) - latest = self.app.latest_version() + latest = self.app.available_version version_info = "" version_url = "" if not latest[0]: version_info = "Latest release : {version}" \ - .format(version='.'.join(latest[1])) + .format(version='.'.join(latest[1])) version_url = latest[2] new_version_text = """ @@ -264,23 +262,13 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.currencies_tabwidget.clear() if self.app.current_account: for community in self.app.current_account.communities: - try: - tab_currency = CurrencyTabWidget(self.app, community, - self.password_asker, - self.status_label) - tab_currency.refresh() - self.currencies_tabwidget.addTab(tab_currency, - QIcon(":/icons/currency_icon"), - community.name) - except NoPeerAvailable as e: - QMessageBox.critical(self, "Could not join {0}".format(community.currency), - str(e), - QMessageBox.Ok) - continue - except requests.exceptions.RequestException as e: - QMessageBox.critical(self, ":(", - str(e), - QMessageBox.Ok) + tab_currency = CurrencyTabWidget(self.app, community, + self.password_asker, + self.status_label) + tab_currency.refresh() + self.currencies_tabwidget.addTab(tab_currency, + QIcon(":/icons/currency_icon"), + community.name) def refresh_accounts(self): self.menu_change_account.clear() @@ -350,7 +338,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.action_configure_parameters.setEnabled(True) self.menu_actions.setEnabled(True) self.setWindowTitle("CuteCoin {0} - Account : {1}".format(__version__, - self.app.current_account.name)) + self.app.current_account.name)) self.refresh_communities() self.refresh_wallets() @@ -363,9 +351,9 @@ class MainWindow(QMainWindow, Ui_MainWindow): def export_account(self): selected_file = QFileDialog.getSaveFileName(self, - "Export an account", - "", - "All account files (*.acc)") + "Export an account", + "", + "All account files (*.acc)") path = "" if selected_file[0][-4:] == ".acc": path = selected_file[0] diff --git a/src/cutecoin/gui/network_tab.py b/src/cutecoin/gui/network_tab.py index f30d5ce7402183df63efdd86a585b96cd579d2e1..f1c127ea8d98cf962920a396bcb12321872fc230 100644 --- a/src/cutecoin/gui/network_tab.py +++ b/src/cutecoin/gui/network_tab.py @@ -6,8 +6,7 @@ Created on 20 févr. 2015 import logging from PyQt5.QtWidgets import QWidget -from PyQt5.QtCore import Qt, QThread -from cutecoin.core.watching.network import NetworkWatcher +from PyQt5.QtCore import Qt, QThread, pyqtSlot from ..models.network import NetworkTableModel, NetworkFilterProxyModel from ..gen_resources.network_tab_uic import Ui_NetworkTabWidget @@ -31,5 +30,7 @@ class NetworkTabWidget(QWidget, Ui_NetworkTabWidget): self.table_network.resizeColumnsToContents() community.network.nodes_changed.connect(self.refresh_nodes) + @pyqtSlot() def refresh_nodes(self): + logging.debug("Refresh nodes") self.table_network.model().sourceModel().modelReset.emit() diff --git a/src/cutecoin/gui/process_cfg_community.py b/src/cutecoin/gui/process_cfg_community.py index 4f115ec673180d88b60d7ac8f21edfa9cfedd762..14fcd58ecd240b3f4c9769e9a082b17c55af7109 100644 --- a/src/cutecoin/gui/process_cfg_community.py +++ b/src/cutecoin/gui/process_cfg_community.py @@ -12,6 +12,7 @@ from ucoinpy.api.bma import ConnectionHandler from ucoinpy.documents.peer import Peer from PyQt5.QtWidgets import QDialog, QMenu, QMessageBox +from PyQt5.QtGui import QCursor from ..gen_resources.community_cfg_uic import Ui_CommunityConfigurationDialog from ..models.peering import PeeringTreeModel @@ -77,7 +78,7 @@ class StepPageAddpeers(Step): def display_page(self): # We add already known peers to the displayed list - self.config_dialog.nodes = self.config_dialog.community.nodes + self.config_dialog.nodes = self.config_dialog.community.network.root_nodes try: tree_model = PeeringTreeModel(self.config_dialog.community) except requests.exceptions.RequestException: @@ -151,8 +152,8 @@ class ProcessConfigureCommunity(QDialog, Ui_CommunityConfigurationDialog): ''' Add node slot ''' - server = self.lineedit_server.text() - port = self.spinbox_port.value() + server = self.lineedit_add_address.text() + port = self.spinbox_add_port.value() try: node = Node.from_address(self.community.currency, server, port) @@ -162,14 +163,34 @@ class ProcessConfigureCommunity(QDialog, Ui_CommunityConfigurationDialog): str(e)) self.tree_peers.setModel(PeeringTreeModel(self.community)) + def remove_node(self): + ''' + Remove node slot + ''' + logging.debug("Remove node") + index = self.sender().data() + self.community.remove_node(index) + self.tree_peers.setModel(PeeringTreeModel(self.community)) + + @property + def nb_steps(self): + s = self.step + nb_steps = 1 + while s.next_step != None: + s = s.next_step + nb_steps = nb_steps + 1 + return nb_steps + def showContextMenu(self, point): - if self.stacked_pages.currentIndex() == 1: + if self.stacked_pages.currentIndex() == self.nb_steps - 1: menu = QMenu() - action = menu.addAction("Delete", self.removeNode) + index = self.tree_peers.indexAt(point) + action = menu.addAction("Delete", self.remove_node) + action.setData(index.row()) if self.community is not None: if len(self.nodes) == 1: action.setEnabled(False) - menu.exec_(self.mapToGlobal(point)) + menu.exec_(QCursor.pos()) def accept(self): try: diff --git a/src/cutecoin/gui/transactions_tab.py b/src/cutecoin/gui/transactions_tab.py index 46324b5fa6dbf598e56297d6b9b8bc75b44be67e..a7291a8ac617b6e66d8c78e59de1939508067a37 100644 --- a/src/cutecoin/gui/transactions_tab.py +++ b/src/cutecoin/gui/transactions_tab.py @@ -9,6 +9,7 @@ from ..core.wallet import Wallet from ..core.person import Person from .transfer import TransferMoneyDialog +import logging class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget): """ @@ -60,7 +61,7 @@ class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget): self.table_history.setModel(proxy) self.table_history.setSelectionBehavior(QAbstractItemView.SelectRows) self.table_history.setSortingEnabled(True) - self.table_history.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) + self.table_history.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive) self.refresh_balance() @@ -190,3 +191,13 @@ QMessageBox.Ok | QMessageBox.Cancel) transfer = self.sender().data() transfer.drop() self.table_history.model().invalidate() + + def dates_changed(self): + logging.debug("Changed dates") + if self.table_history.model(): + ts_from = self.date_from.dateTime().toTime_t() + ts_to = self.date_to.dateTime().toTime_t() + + self.table_history.model().set_period(ts_from, ts_to) + + diff --git a/src/cutecoin/gui/transfer.py b/src/cutecoin/gui/transfer.py index 5ea7c494e28e192b2cf08f174ec11887ee49b35c..aa4009954ad60c70dbd46b8f042162c59a0c1439 100644 --- a/src/cutecoin/gui/transfer.py +++ b/src/cutecoin/gui/transfer.py @@ -73,6 +73,7 @@ class TransferMoneyDialog(QDialog, Ui_TransferMoneyDialog): try: QApplication.setOverrideCursor(Qt.WaitCursor) + QApplication.processEvents() self.wallet.send_money(self.account.salt, password, self.community, recipient, amount, comment) QMessageBox.information(self, "Money transfer", @@ -100,6 +101,7 @@ Please try again later""") return finally: QApplication.restoreOverrideCursor() + QApplication.processEvents() super().accept() diff --git a/src/cutecoin/gui/wallets_tab.py b/src/cutecoin/gui/wallets_tab.py index 6ae29fc7ad5e7c84f26d16f1787ba9d9e40159b1..f0d1d7a7f1c2cd8880a7be78e043ffe250ebae11 100644 --- a/src/cutecoin/gui/wallets_tab.py +++ b/src/cutecoin/gui/wallets_tab.py @@ -108,7 +108,7 @@ class WalletsTabWidget(QWidget, Ui_WalletsTab): <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> <tr><td align="right"><b>{:}</b></td><td>{:}</td></tr> </table> - """.format("Your money share : ", "{:.2f}%".format(amount / maximum * 100), + """.format("Your money share : ", "{:.2f}%".format(amount / maximum * 100) if maximum != 0 else "0%", "Your part : ", "{:} {:} in [{:.2f} - {:}] {:}" .format( localized_amount, @@ -202,4 +202,4 @@ class WalletsTabWidget(QWidget, Ui_WalletsTab): dialog.radio_pubkey.setChecked(True) if dialog.exec_() == QDialog.Accepted: currency_tab = self.window().currencies_tabwidget.currentWidget() - currency_tab.table_history.model().invalidate() + currency_tab.tab_history.table_history.model().invalidate() diff --git a/src/cutecoin/gui/wot_tab.py b/src/cutecoin/gui/wot_tab.py index ccecdef97d549014471d948c1ad32a4fdfb611ed..f08eefb3ba14edd5afae3646a05df3aadee2518c 100644 --- a/src/cutecoin/gui/wot_tab.py +++ b/src/cutecoin/gui/wot_tab.py @@ -3,6 +3,7 @@ import logging from cutecoin.core.graph import Graph from PyQt5.QtWidgets import QWidget, QComboBox +from PyQt5.QtCore import pyqtSlot 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 @@ -10,7 +11,7 @@ from cutecoin.core.person import Person class WotTabWidget(QWidget, Ui_WotTabWidget): - def __init__(self, account, community, password_asker, parent=None): + def __init__(self, app, account, community, password_asker, parent=None): """ :param cutecoin.core.account.Account account: @@ -37,6 +38,7 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): self.graphicsView.scene().node_contact.connect(self.add_node_as_contact) self.graphicsView.scene().node_member.connect(self.member_informations) + app.monitor.persons_watcher(community).person_changed.connect(self.handle_person_change) self.account = account self.community = community self.password_asker = password_asker @@ -45,8 +47,8 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): self.nodes = list() # create node metadata from account - metadata = {'text': self.account.name, 'id': self.account.pubkey} - self.draw_graph(metadata) + self._current_metadata = {'text': self.account.name, 'id': self.account.pubkey} + self.refresh() def draw_graph(self, metadata): """ @@ -55,11 +57,12 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): :param dict metadata: Graph node metadata of the identity """ logging.debug("Draw graph - " + metadata['text']) + self._current_metadata = metadata # create Person from node metadata person = Person.from_metadata(metadata) - person_account = Person.from_metadata({'text':self.account.name, - 'id':self.account.pubkey}) + person_account = Person.from_metadata({'text': self.account.name, + 'id': self.account.pubkey}) certifier_list = person.certifiers_of(self.community) certified_list = person.certified_by(self.community) @@ -99,6 +102,17 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): metadata ) + def refresh(self): + """ + Refresh graph scene to current metadata + """ + self.draw_graph(self._current_metadata) + + @pyqtSlot(str) + def handle_person_change(self, pubkey): + if pubkey == self._current_metadata['id']: + self.refresh() + def search(self): """ Search nodes when return is pressed in combobox lineEdit @@ -152,10 +166,11 @@ class WotTabWidget(QWidget, Ui_WotTabWidget): def add_node_as_contact(self, metadata): # check if contact already exists... - if metadata['id'] == self.account.pubkey or metadata['id'] in [contact.pubkey for contact in self.account.contacts]: + if metadata['id'] == self.account.pubkey \ + or metadata['id'] in [contact['pubkey'] for contact in self.account.contacts]: return False - person = Person.from_metadata(metadata) - self.parent.add_member_as_contact(person) + self.parent.add_member_as_contact({'name': metadata['text'], + 'pubkey': metadata['id']}) def get_block_mediantime(self, number): try: diff --git a/src/cutecoin/models/network.py b/src/cutecoin/models/network.py index 01153efd77071f12d4023bb540901b98106979be..60597f8a546a3ec18c76413d2e50ff5983e217cd 100644 --- a/src/cutecoin/models/network.py +++ b/src/cutecoin/models/network.py @@ -99,7 +99,7 @@ class NetworkTableModel(QAbstractTableModel): @property def nodes(self): - return self.community.nodes + return self.community.network.nodes def rowCount(self, parent): return len(self.nodes) diff --git a/src/cutecoin/models/peering.py b/src/cutecoin/models/peering.py index c3cc96f5d1162720fd14a2a29ecf12cd92f401a4..313c3c581210e52e426e33ede66d582b0629561a 100644 --- a/src/cutecoin/models/peering.py +++ b/src/cutecoin/models/peering.py @@ -96,7 +96,7 @@ class PeeringTreeModel(QAbstractItemModel): Constructor ''' super().__init__(None) - self.nodes = community.nodes + self.nodes = community._network.root_nodes self.root_item = RootItem(community.currency) self.refresh_tree() diff --git a/src/cutecoin/models/txhistory.py b/src/cutecoin/models/txhistory.py index cdb28b918a64660c1760366cbca61751cc6534a9..5a31fd8db4da7d5d1f451e90cae3c4ea4d2d18c7 100644 --- a/src/cutecoin/models/txhistory.py +++ b/src/cutecoin/models/txhistory.py @@ -31,6 +31,7 @@ class TxFilterProxyModel(QSortFilterProxyModel): logging.debug("Filtering from {0} to {1}".format(ts_from, ts_to)) self.ts_from = ts_from self.ts_to = ts_to + self.modelReset.emit() def filterAcceptsRow(self, sourceRow, sourceParent): def in_period(date_ts): @@ -75,10 +76,6 @@ class TxFilterProxyModel(QSortFilterProxyModel): return self.sortOrder() == Qt.DescendingOrder elif right_data == "": return self.sortOrder() == Qt.AscendingOrder - if left_data.__class__ is Person: - left_data = left_data.uid - if right_data.__class__ is Person: - right_data = right_data.uid return (left_data < right_data) @@ -90,11 +87,6 @@ class TxFilterProxyModel(QSortFilterProxyModel): state_data = self.sourceModel().data(state_index, Qt.DisplayRole) if role == Qt.DisplayRole: if source_index.column() == self.sourceModel().column_types.index('uid'): - if source_data.__class__ == Person: - tx_person = source_data.uid - else: - tx_person = "pub:{0}".format(source_data[:5]) - source_data = tx_person return source_data if source_index.column() == self.sourceModel().column_types.index('date'): date = QDateTime.fromTime_t(source_data) @@ -198,11 +190,10 @@ class HistoryTableModel(QAbstractTableModel): comment = "" if transfer.txdoc: comment = transfer.txdoc.comment - pubkey = transfer.metadata['issuer'] - try: - sender = Person.lookup(pubkey, self.community) - except PersonNotFoundError: - sender = pubkey + if transfer.metadata['issuer_uid'] != "": + sender = transfer.metadata['issuer_uid'] + else: + sender = "pub:{0}".format(transfer.metadata['issuer'][:5]) date_ts = transfer.metadata['time'] @@ -214,12 +205,11 @@ class HistoryTableModel(QAbstractTableModel): comment = "" if transfer.txdoc: comment = transfer.txdoc.comment - pubkey = transfer.metadata['receiver'] - try: - receiver = Person.lookup(pubkey, self.community) - except PersonNotFoundError: - # receiver = "pub:{0}".format(pubkey[:5]) - receiver = pubkey + if transfer.metadata['receiver_uid'] != "": + receiver = transfer.metadata['receiver_uid'] + else: + receiver = "pub:{0}".format(transfer.metadata['receiver'][:5]) + date_ts = transfer.metadata['time'] diff --git a/src/cutecoin/tests/MainWindowTest.py b/src/cutecoin/tests/MainWindowTest.py new file mode 100644 index 0000000000000000000000000000000000000000..deca0f8876dee2725af54c298839b66a475b38c5 --- /dev/null +++ b/src/cutecoin/tests/MainWindowTest.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- + +import sys +import unittest +import gc +import PyQt5 +from PyQt5.QtWidgets import QApplication, QMenu +from PyQt5.QtCore import QLocale +from cutecoin.gui.mainwindow import MainWindow +from cutecoin.core.app import Application + +# Qapplication cause a core dumped when re-run in setup +# set it as global var +qapplication = QApplication(sys.argv) + + +class MainWindowTest(unittest.TestCase): + def setUp(self): + QLocale.setDefault(QLocale("en_GB")) + self.application = Application(sys.argv) + self.main_window = MainWindow(self.application) + + def tearDown(self): + # delete all top widgets from main QApplication + lw = qapplication.topLevelWidgets() + for w in lw: + del w + gc.collect() + + def test_menubar(self): + children = self.main_window.menubar.children() + menus = [] + """:type: list[QMenu]""" + for child in children: + if isinstance(child, QMenu): + menus.append(child) + self.assertEqual(len(menus), 3) + self.assertEqual(menus[0].objectName(), 'menu_account') + self.assertEqual(menus[1].objectName(), 'menu_contacts') + self.assertEqual(menus[2].objectName(), 'menu_actions') + + def test_menu_account(self): + actions = self.main_window.menu_account.actions() + """:type: list[QAction]""" + self.assertEqual(len(actions), 10) + self.assertEqual(actions[0].objectName(), 'action_add_account') + self.assertEqual(actions[2].objectName(), 'action_configure_parameters') + self.assertEqual(actions[3].objectName(), 'action_set_as_default') + self.assertEqual(actions[5].objectName(), 'action_export') + self.assertEqual(actions[6].objectName(), 'action_import') + self.assertEqual(actions[8].objectName(), 'actionAbout') + self.assertEqual(actions[9].objectName(), 'action_quit') + + def test_menu_contacts(self): + actions = self.main_window.menu_contacts.actions() + """:type: list[QAction]""" + self.assertEqual(len(actions), 3) + self.assertEqual(actions[1].objectName(), 'action_add_a_contact') + + def test_menu_actions(self): + actions = self.main_window.menu_actions.actions() + """:type: list[QAction]""" + self.assertEqual(len(actions), 2) + self.assertEqual(actions[0].objectName(), 'actionTransfer_money') + self.assertEqual(actions[1].objectName(), 'actionCertification') + + def test_action_about(self): + # select about menu + self.main_window.actionAbout.trigger() + widgets = qapplication.topLevelWidgets() + dialog = None + for widget in widgets: + if isinstance(widget, PyQt5.QtWidgets.QDialog): + dialog = widget + break + self.assertEqual(dialog.objectName(), 'AboutPopup') + self.assertEqual(dialog.isVisible(), True) + +if __name__ == '__main__': + main_window_suite = unittest.TestLoader().loadTestsFromTestCase(MainWindowTest) + runner = unittest.TextTestRunner() + runner.run(main_window_suite)