diff --git a/buildall-nix.sh b/buildall-nix.sh new file mode 100755 index 0000000000000..d00eb4867cf81 --- /dev/null +++ b/buildall-nix.sh @@ -0,0 +1,14 @@ +#!/bin/bash +threads=$1 + +if ! [[ -n "$threads" ]]; then + echo "Usage: ./buildall-nix.sh threadcount" + echo + echo "Usually, specify 1 more thread than you have CPU cores." + echo "example with 8 CPU cores: ./buildall-nix.sh 9" + exit +fi + +./autogen.sh +./configure --with-incompatible-bdb +make -j $threads diff --git a/doc/notes_blockchain.txt b/doc/notes_blockchain.txt index 3e200a4726d2c..07a9a010f0d9a 100644 --- a/doc/notes_blockchain.txt +++ b/doc/notes_blockchain.txt @@ -9,29 +9,29 @@ The bitcoin block-chain format is: blockhdr hdr varint ntxs {tx}+ transaction array - + blockhdr ::= uint32 version_number (0x00000001 or 0x00000002) uint256 prev_block_hash - uint256 merkle_root + uint256 merkle_root uint32 time_stamp uint32 difficulty_bits uint32 nonce - + tx ::= uint32 version_number varint ninputs {input}+ input array varint noutputs {output}+ output array uint32 lock_time - + input ::= uint256 prev_hash uint32 prev_index script input_script uint32 sequence - + output ::= uint64 amount script output_script - + Input scripts generally just push data (e.g., a signature as proof of possessing the private key) onto the stack which when used with the previous output script evaluates to true (e.g., OP_CHECKSIG). @@ -43,11 +43,11 @@ of the merkle tree of all hashes of the transactions. Example output scripts: Standard Generation Transaction (pay-to-pubkey): - script = OP_PUSHx41 publickey_uncompressed OP_CHECKSIG + script = OP_PUSHx41 publickey_uncompressed OP_CHECKSIG | OP_PUSHx21 publickey_compressed OP_CHECKSIG Standard Transaction to Bitcoin address (pay-to-pubkey-hash) - script = OP_DUP OP_HASH160 OP_PUSHx14 pubkey_hash + script = OP_DUP OP_HASH160 OP_PUSHx14 pubkey_hash OP_EQUALVERIFY OP_CHECKSIG | OP_HASH160 OP_PUSHx14 pubkey_hash OP_EQUAL @@ -57,14 +57,14 @@ Example output scripts: Example input scripts: - Standard Signature: + Standard Signature: script = OP_PUSHxXX {DER_sig SIGHASH_ALL} OP_PUSHx41 publickey_uncompressed | OP_PUSHxXX {DER_sig SIGHASH_ALL} OP_PUSHx21 publickey_compressed - DER_sig ::= uint8 DER_type (sequence: 0x30) - uint8 DER_length (nbytes of sequence) + DER_sig ::= uint8 DER_type (sequence: 0x30) + uint8 DER_length (nbytes of sequence) uint8 DER_type (integer 0x02) uint8 DER_length (nbytes of the integer) {uint8}+ r @@ -73,7 +73,7 @@ Example input scripts: {uint8}+ s DER_sig is the standard DER format of a pair of integers. - The signature values (r,s) are the ECDSA values to sign the + The signature values (r,s) are the ECDSA values to sign the two-round hash of the current tx (except that the previous transaction's input script is used and the SIGHASH_ALL tag is added to the end): @@ -98,7 +98,7 @@ Hivemind Blockchain Bitcoin's block chain can be viewed as a ledger of actions on a dataset. The dataset is the set of all coin allocations to addresses and the actions are -the transfers of coins from a subset of addresses to other addresses. +the transfers of coins from a subset of addresses to other addresses. Hivemind is a generalization of both the dataset and the set of actions. @@ -124,27 +124,27 @@ Hivemind's actions consists of: 7. creation of steal votes 8. creation of reveal votes 9. publishing outcomes with transfers of bitcoins. - 10. redistributions of votecoin allocations + 10. redistributions of votecoin allocations Anyone with bitcoins may initiate any of the actions 1,3,4,5. Anyone with votecoins will be obligated to initiate actions 6,8. The miners will initiate 9 and 10. -Each hivemind-specific action is a bitcoin-like transaction where the output +Each hivemind-specific action is a bitcoin-like transaction where the output script designates one of the actions to be taken. The format of the output script is simply: - + output_script = OP_PUSHxXX number of bytes char action_type {uint8}+ action_data OP_MARKET 0xc0 -If viewed as a stack operation, action_type and action_data are simply pushed -onto the stack and then OP_MARKET acts as an operation to (1) do the action -specified by the action_type using action_data as inputs and (2) clear the -stack with a TRUE result. The action_type byte will specify one of the -hivemind-specific actions 2-8 above. The specific format for action_data is +If viewed as a stack operation, action_type and action_data are simply pushed +onto the stack and then OP_MARKET acts as an operation to (1) do the action +specified by the action_type using action_data as inputs and (2) clear the +stack with a TRUE result. The action_type byte will specify one of the +hivemind-specific actions 2-8 above. The specific format for action_data is as follows. @@ -173,18 +173,18 @@ Create Branch longer be a part of their previous branches and the output votecoins will now be a part of the new branch. - Note 2: Each block number ending in a multiple of tau denotes the start of a + Note 2: Each block number ending in a multiple of tau denotes the start of a voting period for the branch's recently ended decisions. The schedule is block number / range ----------------------------------- ----------------------------------- - n*tau ballots available for all decisions - ending ((n-1)*tau, n*tau] + n*tau ballots available for all decisions + ending ((n-1)*tau, n*tau] (n*tau, n*tau+ballotTime] sealed ballots may be submitted (n*tau, n*tau+ballotTime+unsealTime) unsealed ballots may be submitted n*tau + ballotTime + unsealTime miner runs outcome algorithm - - We must have ballotTime + unsealTime less than tau so that the change of + + We must have ballotTime + unsealTime less than tau so that the change of votecoins in an outcome is set before the next run of the outcome algorithm. It is desireable to have tau correspond to approximately two weeks (for 10 @@ -192,10 +192,10 @@ Create Branch Note 3: The outcome algorithm is best when there are many decisions on a ballot, but not too many. The cost to create a decision for a ballot is thus - structured to depend on how many decisions have already been created for - that specific ballot. The parameters + structured to depend on how many decisions have already been created for + that specific ballot. The parameters freeDecisions <= targetDecisions <= maxDecisions. - are required. For the N-th decision ending in (n-1)*tau, n*tau], the + are required. For the N-th decision ending in (n-1)*tau, n*tau], the "listing fee" cost to create another decision in that interval will be cost N @@ -204,13 +204,13 @@ Create Branch baseListingFee [freeDecisions, targetDecisions) (N - targetDecisions)*baseListingFee [targetDecisions, maxDecisions) impossible [maxDecisions,infty) - + Note 4: TODO: consensusThreshold requirement for the outcome algorithm Note 5: TODO: minTradingFee Note 6: TODO: The creation of a new branch is a controlled process. - + Create Decision ------------------ @@ -225,20 +225,20 @@ Create Decision uint64 if scaled, maximum uint8 answer optionality (0=not optional, 1=optional) - Note 1: The creator of the decision pays a listing fee according to the + Note 1: The creator of the decision pays a listing fee according to the branch parameters and will receive a portion of the trading fees of all - markets on that decision. The outcome algorithm will allocate 25% of - each market's trading fees across the bitcoin public keys the market's + markets on that decision. The outcome algorithm will allocate 25% of + each market's trading fees across the bitcoin public keys in the market's decision list. Create Market ------------------ - + action_type = char 'M' (createmarket) action_data = uint160 bitcoin public key uint64 B (liquidity parameter) - uint64 tradingFee + uint64 tradingFee uint64 maxCommission string title string description @@ -250,17 +250,17 @@ Create Market {uint8}+ decisionFunctionids uint32 txPoWh transaction proof-of-work hashid uint32 txPoWd transaction proof-of-work difficulty level - + Note 1: The market will be dependent on the outcome of each decision - in the list. The maturation is set to be the maximum of the decision's + in the list. The maturation is set to be the maximum of the decision's eventOverBy numbers. - + Note 2: The market may depend on a function of the scaled decisions. The initial list of functions are id f(X) - ---------------------- ------------------ + ---------------------- ------------------ X1 [default] X X2 X*X X3 X*X*X @@ -302,7 +302,7 @@ Create Trade Create Reveal Vote ------------------ - + action_type = char 'R' (createrevealvote) action_data = uint256 branchid uint32 height @@ -314,7 +314,7 @@ Create Reveal Vote Note 1: The voteid is a previously submitted sealed vote. - Note 2: voteid must match the hash of the outcome with zeros in + Note 2: voteid must match the hash of the outcome with zeros in place of the voteid. @@ -339,16 +339,16 @@ Create Steal Vote uint256 voteid Note 1: The voteid is a previously submitted sealed vote. - + Create Outcome ------------------ action_type = char 'O' (createoutcomes) - action_data = + action_data = TODO - + action_type = char 'R' (redistribution of votecoins) action_data = varint noutputs {output}+ output array (pay-to-pubkey-hash) - + diff --git a/hivemind.pro b/hivemind.pro index ff8c4ee828e31..b669b9d93a03a 100644 --- a/hivemind.pro +++ b/hivemind.pro @@ -1,17 +1,15 @@ ###################################################################### -# Automatically generated by qmake (3.0) Fri Dec 11 22:09:58 2015 +# Automatically generated by qmake (3.0) Thu Jan 14 12:02:26 2016 ###################################################################### TEMPLATE = app TARGET = hivemind INCLUDEPATH += . \ src \ - src/config \ src/leveldb/port/win \ src/crypto \ src/primitives \ src/script \ - src/obj \ src/univalue \ src/json \ src/compat \ @@ -19,8 +17,6 @@ INCLUDEPATH += . \ src/leveldb/helpers/memenv \ src/linalg/src \ src/qt \ - src/qt/forms \ - src/test/data \ src/test \ src/fdlibm/src \ src/qt/test \ @@ -91,7 +87,6 @@ HEADERS += src/addrman.h \ src/wallet_ismine.h \ src/walletdb.h \ src/compat/sanity.h \ - src/config/hivemind-config.h \ src/crypto/common.h \ src/crypto/hmac_sha256.h \ src/crypto/hmac_sha512.h \ @@ -109,13 +104,14 @@ HEADERS += src/addrman.h \ src/json/json_spirit_value.h \ src/json/json_spirit_writer.h \ src/json/json_spirit_writer_template.h \ - src/obj/build.h \ src/primitives/block.h \ src/primitives/market.h \ src/primitives/transaction.h \ src/qt/addressbookpage.h \ src/qt/addresstablemodel.h \ src/qt/askpassphrasedialog.h \ + src/qt/authorpendingtablemodel.h \ + src/qt/authorview.h \ src/qt/ballotballotfilterproxymodel.h \ src/qt/ballotballottablemodel.h \ src/qt/ballotballotwindow.h \ @@ -133,16 +129,21 @@ HEADERS += src/addrman.h \ src/qt/clientmodel.h \ src/qt/coincontroldialog.h \ src/qt/coincontroltreewidget.h \ + src/qt/combocreationwidget.h \ src/qt/csvmodelwriter.h \ src/qt/decisionbranchfilterproxymodel.h \ src/qt/decisionbranchtablemodel.h \ src/qt/decisionbranchwindow.h \ + src/qt/decisioncreationwidget.h \ src/qt/decisiondecisionfilterproxymodel.h \ src/qt/decisiondecisiontablemodel.h \ src/qt/decisiondecisionwindow.h \ + src/qt/decisionmarketcreationwidget.h \ src/qt/decisionmarketfilterproxymodel.h \ src/qt/decisionmarkettablemodel.h \ src/qt/decisionmarketwindow.h \ + src/qt/decisionselectionmodel.h \ + src/qt/decisionselectionview.h \ src/qt/decisiontradefilterproxymodel.h \ src/qt/decisiontradetablemodel.h \ src/qt/decisiontradewindow.h \ @@ -166,7 +167,6 @@ HEADERS += src/addrman.h \ src/qt/optionsdialog.h \ src/qt/optionsmodel.h \ src/qt/overviewpage.h \ - src/qt/paymentrequest.pb.h \ src/qt/paymentrequestplus.h \ src/qt/paymentserver.h \ src/qt/peertablemodel.h \ @@ -250,22 +250,6 @@ HEADERS += src/addrman.h \ src/leveldb/util/testharness.h \ src/leveldb/util/testutil.h \ src/linalg/src/tc_mat.h \ - src/qt/forms/ui_addressbookpage.h \ - src/qt/forms/ui_askpassphrasedialog.h \ - src/qt/forms/ui_coincontroldialog.h \ - src/qt/forms/ui_editaddressdialog.h \ - src/qt/forms/ui_helpmessagedialog.h \ - src/qt/forms/ui_intro.h \ - src/qt/forms/ui_openuridialog.h \ - src/qt/forms/ui_optionsdialog.h \ - src/qt/forms/ui_overviewpage.h \ - src/qt/forms/ui_receivecoinsdialog.h \ - src/qt/forms/ui_receiverequestdialog.h \ - src/qt/forms/ui_rpcconsole.h \ - src/qt/forms/ui_sendcoinsdialog.h \ - src/qt/forms/ui_sendcoinsentry.h \ - src/qt/forms/ui_signverifymessagedialog.h \ - src/qt/forms/ui_transactiondescdialog.h \ src/qt/test/paymentrequestdata.h \ src/qt/test/paymentservertests.h \ src/qt/test/uritests.h \ @@ -291,7 +275,6 @@ HEADERS += src/addrman.h \ src/secp256k1/src/field_impl.h \ src/secp256k1/src/group.h \ src/secp256k1/src/group_impl.h \ - src/secp256k1/src/libsecp256k1-config.h \ src/secp256k1/src/num.h \ src/secp256k1/src/num_gmp.h \ src/secp256k1/src/num_gmp_impl.h \ @@ -305,17 +288,6 @@ HEADERS += src/addrman.h \ src/secp256k1/src/testrand.h \ src/secp256k1/src/testrand_impl.h \ src/secp256k1/src/util.h \ - src/test/data/alertTests.raw.h \ - src/test/data/base58_encode_decode.json.h \ - src/test/data/base58_keys_invalid.json.h \ - src/test/data/base58_keys_valid.json.h \ - src/test/data/script_invalid.json.h \ - src/test/data/script_valid.json.h \ - src/test/data/sig_canonical.json.h \ - src/test/data/sig_noncanonical.json.h \ - src/test/data/sighash.json.h \ - src/test/data/tx_invalid.json.h \ - src/test/data/tx_valid.json.h \ src/leveldb/helpers/memenv/memenv.h \ src/leveldb/include/leveldb/c.h \ src/leveldb/include/leveldb/cache.h \ @@ -334,15 +306,15 @@ HEADERS += src/addrman.h \ src/leveldb/port/win/stdint.h \ src/secp256k1/src/java/org_hivemind_NativeSecp256k1.h \ src/linalg/src/tc_mat.c \ - src/qt/hivemind.moc \ - src/qt/hivemindamountfield.moc \ - src/qt/intro.moc \ - src/qt/overviewpage.moc \ - src/qt/rpcconsole.moc \ src/secp256k1/src/secp256k1.c FORMS += src/qt/forms/addressbookpage.ui \ src/qt/forms/askpassphrasedialog.ui \ + src/qt/forms/authorview.ui \ src/qt/forms/coincontroldialog.ui \ + src/qt/forms/combocreationwidget.ui \ + src/qt/forms/decisioncreationwidget.ui \ + src/qt/forms/decisionmarketcreationwidget.ui \ + src/qt/forms/decisionselectionview.ui \ src/qt/forms/editaddressdialog.ui \ src/qt/forms/helpmessagedialog.ui \ src/qt/forms/intro.ui \ @@ -438,6 +410,8 @@ SOURCES += src/addrman.cpp \ src/qt/addressbookpage.cpp \ src/qt/addresstablemodel.cpp \ src/qt/askpassphrasedialog.cpp \ + src/qt/authorpendingtablemodel.cpp \ + src/qt/authorview.cpp \ src/qt/ballotballotfilterproxymodel.cpp \ src/qt/ballotballottablemodel.cpp \ src/qt/ballotballotwindow.cpp \ @@ -455,16 +429,21 @@ SOURCES += src/addrman.cpp \ src/qt/clientmodel.cpp \ src/qt/coincontroldialog.cpp \ src/qt/coincontroltreewidget.cpp \ + src/qt/combocreationwidget.cpp \ src/qt/csvmodelwriter.cpp \ src/qt/decisionbranchfilterproxymodel.cpp \ src/qt/decisionbranchtablemodel.cpp \ src/qt/decisionbranchwindow.cpp \ + src/qt/decisioncreationwidget.cpp \ src/qt/decisiondecisionfilterproxymodel.cpp \ src/qt/decisiondecisiontablemodel.cpp \ src/qt/decisiondecisionwindow.cpp \ + src/qt/decisionmarketcreationwidget.cpp \ src/qt/decisionmarketfilterproxymodel.cpp \ src/qt/decisionmarkettablemodel.cpp \ src/qt/decisionmarketwindow.cpp \ + src/qt/decisionselectionmodel.cpp \ + src/qt/decisionselectionview.cpp \ src/qt/decisiontradefilterproxymodel.cpp \ src/qt/decisiontradetablemodel.cpp \ src/qt/decisiontradewindow.cpp \ @@ -487,12 +466,9 @@ SOURCES += src/addrman.cpp \ src/qt/optionsdialog.cpp \ src/qt/optionsmodel.cpp \ src/qt/overviewpage.cpp \ - src/qt/paymentrequest.pb.cc \ src/qt/paymentrequestplus.cpp \ src/qt/paymentserver.cpp \ src/qt/peertablemodel.cpp \ - src/qt/qrc_hivemind.cpp \ - src/qt/qrc_hivemind_locale.cpp \ src/qt/qvalidatedlineedit.cpp \ src/qt/qvaluecombobox.cpp \ src/qt/receivecoinsdialog.cpp \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index dab4c9c4ae6ca..6a74ccb50ecf9 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -78,7 +78,12 @@ QT_TS = \ QT_FORMS_UI = \ qt/forms/addressbookpage.ui \ qt/forms/askpassphrasedialog.ui \ + qt/forms/authorview.ui \ qt/forms/coincontroldialog.ui \ + qt/forms/combocreationwidget.ui \ + qt/forms/decisioncreationwidget.ui \ + qt/forms/decisionmarketcreationwidget.ui \ + qt/forms/decisionselectionview.ui \ qt/forms/editaddressdialog.ui \ qt/forms/helpmessagedialog.ui \ qt/forms/intro.ui \ @@ -97,6 +102,8 @@ QT_MOC_CPP = \ qt/moc_addressbookpage.cpp \ qt/moc_addresstablemodel.cpp \ qt/moc_askpassphrasedialog.cpp \ + qt/moc_authorview.cpp \ + qt/moc_authorpendingtablemodel.cpp \ qt/moc_hivemindaddressvalidator.cpp \ qt/moc_hivemindamountfield.cpp \ qt/moc_hivemindgui.cpp \ @@ -104,7 +111,12 @@ QT_MOC_CPP = \ qt/moc_clientmodel.cpp \ qt/moc_coincontroldialog.cpp \ qt/moc_coincontroltreewidget.cpp \ + qt/moc_combocreationwidget.cpp \ qt/moc_csvmodelwriter.cpp \ + qt/moc_decisioncreationwidget.cpp \ + qt/moc_decisionmarketcreationwidget.cpp \ + qt/moc_decisionselectionview.cpp \ + qt/moc_decisionselectionmodel.cpp \ qt/moc_editaddressdialog.cpp \ qt/moc_guiutil.cpp \ qt/moc_intro.cpp \ @@ -197,6 +209,8 @@ HIVEMIND_QT_H = \ qt/addressbookpage.h \ qt/addresstablemodel.h \ qt/askpassphrasedialog.h \ + qt/authorview.h \ + qt/authorpendingtablemodel.h \ qt/hivemindaddressvalidator.h \ qt/hivemindamountfield.h \ qt/hivemindgui.h \ @@ -204,7 +218,10 @@ HIVEMIND_QT_H = \ qt/clientmodel.h \ qt/coincontroldialog.h \ qt/coincontroltreewidget.h \ + qt/combocreationwidget.h \ qt/csvmodelwriter.h \ + qt/decisioncreationwidget.h \ + qt/decisionmarketcreationwidget.h \ qt/editaddressdialog.h \ qt/guiconstants.h \ qt/guiutil.h \ @@ -234,6 +251,8 @@ HIVEMIND_QT_H = \ qt/decisionmarketfilterproxymodel.h \ qt/decisionmarkettablemodel.h \ qt/decisionmarketwindow.h \ + qt/decisionselectionview.h \ + qt/decisionselectionmodel.h \ qt/decisiontradefilterproxymodel.h \ qt/decisiontradetablemodel.h \ qt/decisiontradewindow.h \ @@ -285,6 +304,7 @@ RES_ICONS = \ qt/res/icons/address-book.png \ qt/res/icons/about.png \ qt/res/icons/about_qt.png \ + qt/res/icons/author.png \ qt/res/icons/hivemind.ico \ qt/res/icons/hivemind.png \ qt/res/icons/clock1.png \ @@ -360,11 +380,16 @@ endif if ENABLE_WALLET HIVEMIND_QT_CPP += \ + qt/authorview.cpp \ + qt/authorpendingtablemodel.cpp \ qt/addressbookpage.cpp \ qt/addresstablemodel.cpp \ qt/askpassphrasedialog.cpp \ qt/coincontroldialog.cpp \ qt/coincontroltreewidget.cpp \ + qt/combocreationwidget.cpp \ + qt/decisioncreationwidget.cpp \ + qt/decisionmarketcreationwidget.cpp \ qt/editaddressdialog.cpp \ qt/ballotview.cpp \ qt/ballotballotfilterproxymodel.cpp \ @@ -389,6 +414,8 @@ HIVEMIND_QT_CPP += \ qt/decisionmarketfilterproxymodel.cpp \ qt/decisionmarkettablemodel.cpp \ qt/decisionmarketwindow.cpp \ + qt/decisionselectionview.cpp \ + qt/decisionselectionmodel.cpp \ qt/decisiontradefilterproxymodel.cpp \ qt/decisiontradetablemodel.cpp \ qt/decisiontradewindow.cpp \ @@ -423,7 +450,7 @@ HIVEMIND_QT_CPP += \ qt/walletview.cpp endif -RES_IMAGES = +RES_IMAGES = RES_MOVIES = $(wildcard qt/res/movies/spinner-*.png) diff --git a/src/miner.cpp b/src/miner.cpp index 4212dc2b3011c..4e5c9e990ae1b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -74,7 +74,6 @@ CTransaction getOutcomeTx(marketBranch *branch, uint32_t height) /* outcomes: needed by both calc_rep_tx and calc_coin_tx */ vector outcomes = pmarkettree->GetOutcomes(branch->GetHash()); - /* outcome for this height */ struct marketOutcome *outcome = NULL; @@ -116,6 +115,8 @@ CTransaction getOutcomeTx(marketBranch *branch, uint32_t height) outcome->NA = defaultNA; /* if conflicts, to be changed (TODO) */ outcome->alpha = branch->alpha; outcome->tol = branch->tol; + outcome->nVoters = 0; + for(size_t i=0; i < decisions.size(); i++) { const marketDecision *decision = decisions[i]; if (decision->eventOverBy <= minDecisionHeight) @@ -130,6 +131,7 @@ CTransaction getOutcomeTx(marketBranch *branch, uint32_t height) goto end_rep_tx; outcome->voteMatrix.clear(); outcome->voteMatrix.resize(votes.size()*outcome->nDecisions, outcome->NA); + for(uint32_t i=0; i < preptx.vout.size(); i++) { uint160 u; vector > vSolutions; @@ -175,7 +177,8 @@ CTransaction getOutcomeTx(marketBranch *branch, uint32_t height) } outcome->nVoters++; } - if (!outcome->nVoters) /* if a branch is dead */ + + if (outcome->nVoters == 0 || (preptx.vout.size() == 0)) /* if a branch is dead */ goto end_rep_tx; /* calculate the new reputations */ @@ -198,7 +201,6 @@ CTransaction getOutcomeTx(marketBranch *branch, uint32_t height) delete revealvotes[i]; } - calc_coin_tx: { /* find which markets have just ended */ @@ -430,6 +432,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Create branches outcome txs uint32_t height = chainActive.Height() + 1; + vector branches = pmarkettree->GetBranches(); for(size_t i=0; i < branches.size(); i++) { CTransaction btx = getOutcomeTx(branches[i], height); diff --git a/src/primitives/market.h b/src/primitives/market.h index 1c63c27db4a1e..b16ff894c4439 100644 --- a/src/primitives/market.h +++ b/src/primitives/market.h @@ -76,7 +76,7 @@ struct marketTrade : public marketObj { marketTrade(void) : marketObj() { marketop = 'T'; } virtual ~marketTrade(void) { } - ADD_SERIALIZE_METHODS; + ADD_SERIALIZE_METHODS template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { @@ -176,7 +176,7 @@ struct marketRevealVote : public marketObj { marketRevealVote(void) : marketObj() { marketop = 'R'; } virtual ~marketRevealVote(void) { } - ADD_SERIALIZE_METHODS; + ADD_SERIALIZE_METHODS template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { @@ -200,7 +200,7 @@ struct marketSealedVote : public marketObj { marketSealedVote(void) : marketObj() { marketop = 'S'; } virtual ~marketSealedVote(void) { } - ADD_SERIALIZE_METHODS; + ADD_SERIALIZE_METHODS template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { @@ -221,7 +221,7 @@ struct marketStealVote : public marketObj { marketStealVote(void) : marketObj() { marketop = 'L'; } virtual ~marketStealVote(void) { } - ADD_SERIALIZE_METHODS; + ADD_SERIALIZE_METHODS template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { @@ -266,9 +266,9 @@ struct marketOutcome : public marketObj { CTransaction tx; /* transaction */ marketOutcome(void) : marketObj() { marketop = 'O'; } - virtual ~marketOutcome(void) { }; + virtual ~marketOutcome(void) { } - ADD_SERIALIZE_METHODS; + ADD_SERIALIZE_METHODS template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { @@ -329,7 +329,7 @@ struct marketBranch : public marketObj { marketBranch(void) : marketObj() { marketop = 'B'; } virtual ~marketBranch(void) { } - ADD_SERIALIZE_METHODS; + ADD_SERIALIZE_METHODS template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { diff --git a/src/qt/authorpendingtablemodel.cpp b/src/qt/authorpendingtablemodel.cpp new file mode 100644 index 0000000000000..d500d97006b27 --- /dev/null +++ b/src/qt/authorpendingtablemodel.cpp @@ -0,0 +1,677 @@ +#include "authorpendingtablemodel.h" + +#include +#include +#include + +AuthorPendingTableModel::AuthorPendingTableModel(QObject *parent) : + QAbstractTableModel(parent) +{ +} + +int AuthorPendingTableModel::rowCount(const QModelIndex & /*parent*/) const +{ + return pending.size(); +} + +int AuthorPendingTableModel::columnCount(const QModelIndex & /*parent*/) const +{ + return 18; +} + +QVariant AuthorPendingTableModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return false; + } + + int row = index.row(); + int col = index.column(); + + switch(role) { + case Qt::DisplayRole: + { + json_spirit::Array pendingCreation = pending.at(row); + + /* Display data shared between decisions and markets */ + + // Type + std::string type = json_spirit::write_string(pendingCreation.back(), true); + if (col == 0) { + return QString::fromStdString(type); + } + + // Address + if (col == 1) { + std::string address = json_spirit::write_string(pendingCreation.front(), true); + return QString::fromStdString(address); + } + + // Fee + if (col == 2) { + return "0.02"; // Dummy temp + } + + /* Display data unique to decisions */ + + if (type == "\"decision\"") { + // Fill blank spots (columns 8 - 17) + if (col >= 8 && col <= 17) { + return ("NA"); + } + + // Branch ID + if (col == 3) { + std::string branchID = json_spirit::write_string(pendingCreation.at(1), true); + return QString::fromStdString(branchID); + } + + // Prompt + if (col == 4) { + std::string prompt = json_spirit::write_string(pendingCreation.at(2), true); + return QString::fromStdString(prompt); + } + + // Event Over By + if (col == 5) { + int eventOverBy = pendingCreation.at(3).get_int(); + return eventOverBy; + } + + // Answer Optionality + if (col == 6) { + bool answerOptionality = pendingCreation.at(4).get_bool(); + return answerOptionality; + } + + // Is Scaled? + if (col == 7) { + bool scaled = pendingCreation.at(5).get_bool(); + return scaled; + } + } + + /* Display data unique to markets */ + + if (type == "\"market\"") { + // Fill blank spots (3 - 7) + if (col >= 3 && col <= 7) { + return QString("NA"); + } + + // Decision ID + if (col == 8) { + std::string decisionID = json_spirit::write_string(pendingCreation.at(1), true); + return QString::fromStdString(decisionID); + } + + // Liquidity Factor / B + if (col == 9) { + double B = pendingCreation.at(2).get_real(); + return B; + } + + // Trading Fee + if (col == 10) { + double tradingFee = pendingCreation.at(3).get_real(); + return tradingFee; + } + + // Max Commission + if (col == 11) { + double maxCommission = pendingCreation.at(4).get_real(); + return maxCommission; + } + + // Title + if (col == 12) { + std::string title = json_spirit::write_string(pendingCreation.at(5), true); + return QString::fromStdString(title); + } + + // Description + if (col == 13) { + std::string description = json_spirit::write_string(pendingCreation.at(6), true); + return QString::fromStdString(description); + } + + // Tags + if (col == 14) { + std::string tags = json_spirit::write_string(pendingCreation.at(7), true); + return QString::fromStdString(tags); + } + + // Maturation + if (col == 15) { + int maturation = pendingCreation.at(8).get_int(); + return maturation; + } + + // txPoWh + if (col == 16) { + int txPoWh = pendingCreation.at(9).get_int(); + return txPoWh; + } + + // txPoWd + if (col == 17) { + int txPoWd = pendingCreation.at(10).get_int(); + return txPoWd; + } + } + + break; + } + case Qt::FontRole: + if (col == 0) // Type is bold + { + QFont boldFont; + boldFont.setBold(true); + return boldFont; + } + break; + case Qt::BackgroundRole: + break; + case Qt::TextAlignmentRole: + break; + case Qt::CheckStateRole: + break; + } + + return QVariant(); +} + +QVariant AuthorPendingTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role == Qt::DisplayRole) + { + if (orientation == Qt::Horizontal) { + switch (section) + { + case 0: + return QString("Type"); + case 1: + return QString("Address"); + case 2: + return QString("Fee"); + case 3: + return QString("Branch"); + case 4: + return QString("Prompt"); + case 5: + return QString("eventOverBy"); + case 6: + return QString("Answer Optional"); + case 7: + return QString("Scaled"); + case 8: + return QString("Decision"); + case 9: + return QString("B"); + case 10: + return QString("Trading Fee"); + case 11: + return QString("Max Commission"); + case 12: + return QString("Title"); + case 13: + return QString("Description"); + case 14: + return QString("Tags"); + case 15: + return QString("Maturation"); + case 16: + return QString("txPoWh"); + case 17: + return QString("txPoWh"); + } + } + } + return QVariant(); +} + +void AuthorPendingTableModel::editCombo(const QModelIndex &index) +{ + ComboCreationWidget *comboCreationWidget = new ComboCreationWidget; + QHBoxLayout *hbox = new QHBoxLayout; + hbox->addWidget(comboCreationWidget); + + connect(comboCreationWidget, SIGNAL(updatedComboArray(json_spirit::Array)), + this, SLOT(receiveUpdatedCombo(json_spirit::Array))); + + json_spirit::Array comboToEdit = pending.at(index.row()); + comboToEdit.push_back(index.row()); + comboCreationWidget->editArray(comboToEdit); + + QDialog *dialog = new QDialog; + dialog->setLayout(hbox); + dialog->setWindowTitle("Edit Combo"); + dialog->show(); +} + +void AuthorPendingTableModel::editDecision(const QModelIndex &index) +{ + DecisionCreationWidget *decisionCreationWidget = new DecisionCreationWidget; + QHBoxLayout *hbox = new QHBoxLayout; + hbox->addWidget(decisionCreationWidget); + + connect(decisionCreationWidget, SIGNAL(updatedDecisionArray(json_spirit::Array)), + this, SLOT(receiveUpdatedDecision(json_spirit::Array))); + + json_spirit::Array decisionToEdit = pending.at(index.row()); + decisionToEdit.push_back(index.row()); + decisionCreationWidget->editArray(decisionToEdit); + + QDialog *dialog = new QDialog; + dialog->setLayout(hbox); + dialog->setWindowTitle("Edit Decision"); + dialog->show(); +} + +void AuthorPendingTableModel::editDecisionMarket(const QModelIndex &index) +{ + DecisionMarketCreationWidget *marketCreationWidget = new DecisionMarketCreationWidget; + QHBoxLayout *hbox = new QHBoxLayout; + hbox->addWidget(marketCreationWidget); + + connect(marketCreationWidget, SIGNAL(updatedDecisionMarketArray(json_spirit::Array)), + this, SLOT(receiveUpdatedDecisionMarket(json_spirit::Array))); + + json_spirit::Array marketToEdit = pending.at(index.row()); + marketToEdit.push_back(index.row()); + marketCreationWidget->editArray(marketToEdit); + + QDialog *dialog = new QDialog; + dialog->setLayout(hbox); + dialog->setWindowTitle("Edit Market"); + dialog->show(); +} + +void AuthorPendingTableModel::on_tableView_doubleClicked(const QModelIndex &index) +{ + // Figure out what we are editing, and open proper dialog + json_spirit::Array itemClicked = pending.at(index.row()); + std::string itemType = json_spirit::write_string(itemClicked.back(), true); + + if (itemType == "\"combo\"") { + editCombo(index); + } else if (itemType == "\"decision\"") { + editDecision(index); + } else if (itemType == "\"market\"") { + editDecisionMarket(index); + } else { + return; + } +} + +void AuthorPendingTableModel::receivePendingCombo(json_spirit::Array array) +{ + int row = pending.size(); + beginInsertRows(QModelIndex(), row, row+1); + + pending.push_back(array); + + endInsertRows(); +} + +void AuthorPendingTableModel::receivePendingDecision(json_spirit::Array array) +{ + int row = pending.size(); + beginInsertRows(QModelIndex(), row, row); + + pending.push_back(array); + + endInsertRows(); +} + +void AuthorPendingTableModel::receivePendingDecisionMarket(json_spirit::Array array) +{ + int row = pending.size(); + beginInsertRows(QModelIndex(), row, row); + + pending.push_back(array); + + endInsertRows(); +} + +void AuthorPendingTableModel::finalize() +{ + if (pending.empty()) { + QString error = "There is nothing to finalize, create some decisions or markets!\n"; + emit finalizeError(error); + } + + // Finalize the pending creations + for (int i = pending.size(); i > 0; i--) { + // Grab creation parameters and type + json_spirit::Array params = pending.at(i-1); + std::string type = json_spirit::write_string(params.back(), true); + + // Try to finalize combos + if (type == "\"combo\"") { + finalizeCombo(params, i); + continue; + } + + // Remove type from parameters + params.pop_back(); + + extern json_spirit::Value createdecision(const json_spirit::Array ¶ms, bool fHelp); + extern json_spirit::Value createmarket(const json_spirit::Array ¶ms, bool fHelp); + + json_spirit::Value result; + + // Try to finalize pending creations containing markets or decisions + try { + if (type == "\"decision\"") { + result = createdecision(params, false); + } else if (type == "\"market\"") { + result = createmarket(params, false); + } + } catch (const std::runtime_error &error) { + QString errorText = QString::fromStdString(error.what()); + emit finalizeError(errorText); + } catch (const std::exception &exception) { + QString exceptionText = QString::fromStdString(exception.what()); + emit finalizeError(exceptionText); + } catch (json_spirit::Object &object) { + result = object; + } + + // Check the result + try { + // Get result pairs + json_spirit::Object resultObject = result.get_obj(); + json_spirit::Pair codePair = resultObject[0]; + json_spirit::Pair messagePair = resultObject[1]; + + // If error, get error code and message + if (codePair.name_ == "code") { + int code = codePair.value_.get_int(); + if (code < 0) { + QString messageText = "Error creating #"; + messageText.append(QString::number(i)); // row # + messageText.append("\n"); + messageText.append(QString::fromStdString(messagePair.value_.get_str())); + emit finalizeError(messageText); + } + } + + // If success, get txid and decision or market id + if (codePair.name_ == "txid" ) { + std::string txid = codePair.value_.get_str(); + // Decision or market? + if (messagePair.name_ == "decisionid") { + // Remove finalized decisions from the pending model + beginRemoveRows(QModelIndex(), pending.size()-1, pending.size()-1); + pending.removeAt(i-1); + endRemoveRows(); + } else if (messagePair.name_ == "marketid") { + // Remove finalized markets from the pending model + beginRemoveRows(QModelIndex(), pending.size()-1, pending.size()-1); + pending.removeAt(i-1); + endRemoveRows(); + } + } + } catch (const std::runtime_error &error) { + QString errorText = QString::fromStdString(error.what()); + emit finalizeError(errorText); + } catch (const std::exception &exception) { + QString exceptionText = QString::fromStdString(exception.what()); + emit finalizeError(exceptionText); + } + } +} + +void AuthorPendingTableModel::finalizeCombo(json_spirit::Array params, unsigned int index) +{ + std::string type = json_spirit::write_string(params.back(), true); + + if (type != "\"combo\"") return; + + // Remove type from parameters + params.pop_back(); + + extern json_spirit::Value createdecision(const json_spirit::Array ¶ms, bool fHelp); + extern json_spirit::Value createmarket(const json_spirit::Array ¶ms, bool fHelp); + + // Split the combo into respective decision and market arrays + json_spirit::Array decisionParams; + json_spirit::Array marketParams; + + // Binary Decision & Market + if (params.size() == 19) { + // Perform checks + std::string marketType = json_spirit::write_string(params.back(), true); + if (marketType != "\"market\"") return; + + std::string decisionType = json_spirit::write_string(params.at(6), true); + if (decisionType != "\"decision\"") return; + + for (unsigned int i = 0; i < params.size(); i++) { + // Get decision params + if (i < 7) { + decisionParams.push_back(params.at(i)); + } + // Get market params + if (i >= 7 && i < 19) { + marketParams.push_back(params.at(i)); + } + } + } + + // Scaled Decision & Market + if (params.size() == 21) { + // Perform checks + std::string marketType = json_spirit::write_string(params.back(), true); + if (marketType != "\"market\"") return; + + std::string decisionType = json_spirit::write_string(params.at(8), true); + if (decisionType != "\"decision\"") return; + + for (unsigned int i = 0; i < params.size(); i++) { + // Get decision params + if (i < 9) { + decisionParams.push_back(params.at(i)); + } + // Get market params + if (i >= 9 && i < 21) { + marketParams.push_back(params.at(i)); + } + } + } + + json_spirit::Value decisionResult; + std::string decisionID = ""; + + try { + decisionParams.pop_back(); + decisionResult = createdecision(decisionParams, false); + } catch (const std::runtime_error &error) { + QString errorText = QString::fromStdString(error.what()); + emit finalizeError(errorText); + } catch (const std::exception &exception) { + QString exceptionText = QString::fromStdString(exception.what()); + emit finalizeError(exceptionText); + } catch (json_spirit::Object &object) { + decisionResult = object; + } + + // Check decision results: + try { + // Get result pairs + json_spirit::Object resultObject = decisionResult.get_obj(); + json_spirit::Pair codePair = resultObject[0]; + json_spirit::Pair messagePair = resultObject[1]; + // If error, get error code and message + if (codePair.name_ == "code") { + int code = codePair.value_.get_int(); + if (code < 0) { + QString messageText = "Error creating decision for #"; + messageText.append(QString::number(index)); // row # + messageText.append("\n"); + messageText.append(QString::fromStdString(messagePair.value_.get_str())); + emit finalizeError(messageText); + } + } + + // If success, get txid and decision id + if (codePair.name_ == "txid" ) { + std::string txid = codePair.value_.get_str(); + // Decision? + if (messagePair.name_ == "decisionid") { + decisionID = messagePair.value_.get_str(); + } + } + } catch (const std::runtime_error &error) { + QString errorText = QString::fromStdString(error.what()); + emit finalizeError(errorText); + } catch (const std::exception &exception) { + QString exceptionText = QString::fromStdString(exception.what()); + emit finalizeError(exceptionText); + } + + // If decision creation worked, create a market from the decision + if (!decisionID.empty()) { + marketParams.pop_back(); + + // Get author address + std::string authorAddress = decisionParams.at(0).get_str(); + json_spirit::Array filledMarketParams; + + // Create filledMarketParams array with decision and author addr + for (unsigned int i = 0; i < marketParams.size(); i++) { + if (i == 0) { + // Insert author address + filledMarketParams.push_back(authorAddress); + } else if (i == 1) { + // Insert decision ID and function type + decisionID.append(":X1"); + filledMarketParams.push_back(decisionID); + } else { + filledMarketParams.push_back(marketParams.at(i)); + } + } + + // Add decisions in mempool to the market tree + if (mempool.size()) { + std::map mapTx = mempool.mapTx; + map::iterator it; + + // Vector to store all market objects in the mempool + std::vector > vMarketObj; + + for (it = mapTx.begin(); it != mapTx.end(); it++) { + CTransaction tx = it->second.GetTx(); + + // Check transaction ouputs for OP_MARKET + BOOST_FOREACH(const CTxOut& txout, tx.vout) { + const CScript& scriptPubKey = txout.scriptPubKey; + size_t script_sz = scriptPubKey.size(); + if ((script_sz < 2) || + (scriptPubKey[script_sz-1] != OP_MARKET)) + continue; + + // Create market object + marketObj *obj = marketObjCtr(scriptPubKey); + if (!obj) + continue; + obj->txid = tx.GetHash(); + vMarketObj.push_back(std::make_pair(obj->GetHash(), obj)); + } + } + + /* write market objects to tx db */ + if (vMarketObj.size()) { + bool ret = pmarkettree->WriteMarketIndex(vMarketObj); + if (!ret) + for (size_t i=0; i < vMarketObj.size(); i++) { + delete vMarketObj[i].second; + } + } + } else { + QString errorText = "No pending decisions found for combo creation!"; + emit finalizeError(errorText); + } + + // Try to create the market + json_spirit::Value result; + try { + result = createmarket(filledMarketParams, false); + } catch (const std::runtime_error &error) { + QString errorText = QString::fromStdString(error.what()); + emit finalizeError(errorText); + } catch (const std::exception &exception) { + QString exceptionText = QString::fromStdString(exception.what()); + emit finalizeError(exceptionText); + } catch (json_spirit::Object &object) { + result = object; + } + + // Check the result + try { + // Get result pairs + json_spirit::Object resultObject = result.get_obj(); + json_spirit::Pair codePair = resultObject[0]; + json_spirit::Pair messagePair = resultObject[1]; + + // If error, get error code and message + if (codePair.name_ == "code") { + int code = codePair.value_.get_int(); + if (code < 0) { + QString messageText = "Error creating market at #"; + messageText.append(QString::number(index)); // row # + messageText.append("\n"); + messageText.append(QString::fromStdString(messagePair.value_.get_str())); + emit finalizeError(messageText); + } + } + + // If success, get txid and market id + if (codePair.name_ == "txid" ) { + std::string txid = codePair.value_.get_str(); + // Market? + if (messagePair.name_ == "marketid") { + // Remove finalized combos from the pending model + beginRemoveRows(QModelIndex(), pending.size()-1, pending.size()-1); + pending.removeAt(index-1); + endRemoveRows(); + } + } + } catch (const std::runtime_error &error) { + QString errorText = QString::fromStdString(error.what()); + emit finalizeError(errorText); + } catch (const std::exception &exception) { + QString exceptionText = QString::fromStdString(exception.what()); + emit finalizeError(exceptionText); + } + } +} + + +void AuthorPendingTableModel::receiveUpdatedCombo(json_spirit::Array array) +{ + if (!array.size() >= 19) return; + int index = array.back().get_int(); + array.pop_back(); + + pending.replace(index, array); +} + +void AuthorPendingTableModel::receiveUpdatedDecision(json_spirit::Array array) +{ + if (!array.size() >= 8) return; + int index = array.back().get_int(); + array.pop_back(); + + pending.replace(index, array); +} + +void AuthorPendingTableModel::receiveUpdatedDecisionMarket(json_spirit::Array array) +{ + if(!array.size() == 13) return; + int index = array.back().get_int(); + array.pop_back(); + + pending.replace(index, array); +} diff --git a/src/qt/authorpendingtablemodel.h b/src/qt/authorpendingtablemodel.h new file mode 100644 index 0000000000000..6d7bb0ca08bf7 --- /dev/null +++ b/src/qt/authorpendingtablemodel.h @@ -0,0 +1,60 @@ +#ifndef AUTHORPENDINGTABLEMODEL_H +#define AUTHORPENDINGTABLEMODEL_H + +#include "combocreationwidget.h" +#include "decisioncreationwidget.h" +#include "decisionmarketcreationwidget.h" +#include "json/json_spirit_writer_template.h" +#include "txdb.h" +#include "txmempool.h" + +#include +#include + +extern CTxMemPool mempool; +extern CMarketTreeDB *pmarkettree; + +class AuthorPendingTableModel : public QAbstractTableModel +{ + Q_OBJECT +public: + explicit AuthorPendingTableModel(QObject *parent = 0); + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + void finalize(); + void finalizeCombo(json_spirit::Array params, unsigned int index); + +signals: + void finalizeError(const QString &errorMessage); + void finalizeComplete(); + +public slots: + void on_tableView_doubleClicked(const QModelIndex &index); + + // Edit on double click + void editCombo(const QModelIndex &index); + void editDecision(const QModelIndex &index); + void editDecisionMarket(const QModelIndex &index); + + // Receive new arrays + void receivePendingCombo(json_spirit::Array array); + void receivePendingDecision(json_spirit::Array array); + void receivePendingDecisionMarket(json_spirit::Array array); + + // Receive array updates + void receiveUpdatedCombo(json_spirit::Array array); + void receiveUpdatedDecision(json_spirit::Array array); + void receiveUpdatedDecisionMarket(json_spirit::Array array); + +private: + QList pending; + + ComboCreationWidget *comboCreationWidget; + DecisionCreationWidget *decisionCreationWidget; + DecisionMarketCreationWidget *decisionMarketCreationWidget; + +}; + +#endif // AUTHORPENDINGTABLEMODEL_H diff --git a/src/qt/authorview.cpp b/src/qt/authorview.cpp new file mode 100644 index 0000000000000..4d644af3e0592 --- /dev/null +++ b/src/qt/authorview.cpp @@ -0,0 +1,123 @@ +#include "authorview.h" +#include "ui_authorview.h" + +#include +#include +#include + +AuthorView::AuthorView(QWidget *parent) : + QWidget(parent), + ui(new Ui::AuthorView) +{ + ui->setupUi(this); + + // Setup model & author pending table + pendingTableView = new QTableView(this); + pendingTableView->horizontalHeader()->setStretchLastSection(true); + pendingTableView->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents); + pendingTableModel = new AuthorPendingTableModel(this); + pendingTableView->setModel(pendingTableModel); + ui->frameLeft->layout()->addWidget(pendingTableView); + + // Setup signals + connect(this, SIGNAL(newPendingCombo(json_spirit::Array)), + pendingTableModel, SLOT(receivePendingCombo(json_spirit::Array))); + + connect(this, SIGNAL(newPendingDecision(json_spirit::Array)), + pendingTableModel, SLOT(receivePendingDecision(json_spirit::Array))); + + connect(this, SIGNAL(newPendingDecisionMarket(json_spirit::Array)), + pendingTableModel, SLOT(receivePendingDecisionMarket(json_spirit::Array))); + + connect(pendingTableView, SIGNAL(doubleClicked(QModelIndex)), + pendingTableModel, SLOT(on_tableView_doubleClicked(QModelIndex))); + + connect(pendingTableModel, SIGNAL(finalizeError(QString)), + this, SLOT(on_finalizeError(QString))); + + connect(pendingTableModel, SIGNAL(finalizeComplete()), + this, SLOT(on_finalizeComplete())); + + connect(pendingTableModel, SIGNAL(rowsInserted(QModelIndex,int,int)), + this, SLOT(calculateFees())); +} + +AuthorView::~AuthorView() +{ + delete ui; +} + +void AuthorView::on_pushButtonCreateCombo_clicked() +{ + comboCreationWidget = new ComboCreationWidget(this); + + QHBoxLayout *hbox = new QHBoxLayout(this); + hbox->addWidget(comboCreationWidget); + + // Pass arrays to model + connect(comboCreationWidget, SIGNAL(newComboArray(json_spirit::Array)), + this, SIGNAL(newPendingCombo(json_spirit::Array))); + + QDialog *dialog = new QDialog(this); + dialog->setWindowTitle("Create Combo (Decision & Market)"); + dialog->setLayout(hbox); + dialog->show(); +} + +void AuthorView::on_pushButtonCreateDecision_clicked() +{ + decisionCreationWidget = new DecisionCreationWidget(this); + QHBoxLayout *hbox = new QHBoxLayout(this); + hbox->addWidget(decisionCreationWidget); + + // Pass array to model + connect(decisionCreationWidget, SIGNAL(newDecisionArray(json_spirit::Array)), + this, SIGNAL(newPendingDecision(json_spirit::Array))); + + QDialog *dialog = new QDialog(this); + dialog->setWindowTitle("Create Decision"); + dialog->setLayout(hbox); + dialog->show(); +} + +void AuthorView::on_pushButtonCreateMarket_clicked() +{ + decisionMarketCreationWidget = new DecisionMarketCreationWidget(this); + QHBoxLayout *hbox = new QHBoxLayout(this); + hbox->addWidget(decisionMarketCreationWidget); + + // Pass array to model + connect(decisionMarketCreationWidget, SIGNAL(newDecisionMarketArray(json_spirit::Array)), + this, SIGNAL(newPendingDecisionMarket(json_spirit::Array))); + + QDialog *dialog = new QDialog(this); + dialog->setWindowTitle("Create Market"); + dialog->setLayout(hbox); + dialog->show(); +} + +void AuthorView::on_pushButtonFinalize_clicked() +{ + pendingTableModel->finalize(); + calculateFees(); +} + +void AuthorView::on_finalizeError(const QString &errorMessage) +{ + QMessageBox errorMessageBox; + errorMessageBox.setWindowTitle("Error finalizing creations!"); + errorMessageBox.setText(errorMessage); + errorMessageBox.setStandardButtons(QMessageBox::Ok); + errorMessageBox.setDefaultButton(QMessageBox::Ok); + errorMessageBox.exec(); +} + +void AuthorView::calculateFees() +{ + double fees = 0.0; + for (int i = 0; i < pendingTableModel->rowCount(); i++) { + fees += 0.02; + } + + ui->labelTotalValue->setText(QString::number(fees)); +} diff --git a/src/qt/authorview.h b/src/qt/authorview.h new file mode 100644 index 0000000000000..224c26ead0faa --- /dev/null +++ b/src/qt/authorview.h @@ -0,0 +1,50 @@ +#ifndef AUTHORVIEW_H +#define AUTHORVIEW_H + +#include "authorpendingtablemodel.h" +#include "combocreationwidget.h" +#include "decisioncreationwidget.h" +#include "decisionmarketcreationwidget.h" + +#include +#include +#include + +namespace Ui { +class AuthorView; +} + +class AuthorView : public QWidget +{ + Q_OBJECT + +public: + explicit AuthorView(QWidget *parent = 0); + ~AuthorView(); + +private slots: + void on_pushButtonCreateCombo_clicked(); + void on_pushButtonCreateDecision_clicked(); + void on_pushButtonCreateMarket_clicked(); + void on_pushButtonFinalize_clicked(); + void on_finalizeError(const QString &errorMessage); + void calculateFees(); + +signals: + void newPendingCombo(const json_spirit::Array array); + void newPendingDecision(const json_spirit::Array array); + void newPendingDecisionMarket(const json_spirit::Array array); + +private: + Ui::AuthorView *ui; + + ComboCreationWidget *comboCreationWidget; + DecisionCreationWidget *decisionCreationWidget; + DecisionMarketCreationWidget *decisionMarketCreationWidget; + + AuthorPendingTableModel *pendingTableModel; + QTableView *pendingTableView; + +}; + +#endif // AUTHORVIEW_H diff --git a/src/qt/ballotballotfilterproxymodel.h b/src/qt/ballotballotfilterproxymodel.h index 082f09d859485..ac5b791a6231c 100644 --- a/src/qt/ballotballotfilterproxymodel.h +++ b/src/qt/ballotballotfilterproxymodel.h @@ -10,8 +10,6 @@ #include #include - - class BallotBallotFilterProxyModel : public QSortFilterProxyModel { @@ -26,5 +24,4 @@ class BallotBallotFilterProxyModel private: }; - #endif // HIVEMIND_QT_BALLOTBALLOTFILTERPROXYMODEL_H diff --git a/src/qt/combocreationwidget.cpp b/src/qt/combocreationwidget.cpp new file mode 100644 index 0000000000000..30bb4ef07f78a --- /dev/null +++ b/src/qt/combocreationwidget.cpp @@ -0,0 +1,137 @@ +#include "combocreationwidget.h" +#include "ui_combocreationwidget.h" + +#include "decisioncreationwidget.h" + +ComboCreationWidget::ComboCreationWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::ComboCreationWidget) +{ + ui->setupUi(this); + + decisionCreationWidget = new DecisionCreationWidget(this); + decisionCreationWidget->comboCreationUI(); + + marketCreationWidget = new DecisionMarketCreationWidget(this); + marketCreationWidget->comboCreationUI(); + + ui->frameDecision->layout()->addWidget(decisionCreationWidget); + ui->frameMarket->layout()->addWidget(marketCreationWidget); + + updateIndex = -1; + ui->pushButtonUpdateCombo->hide(); +} + +ComboCreationWidget::~ComboCreationWidget() +{ + delete ui; +} + +json_spirit::Array ComboCreationWidget::createComboArray() +{ + json_spirit::Array decision = this->decisionCreationWidget->createDecisionArray(); + json_spirit::Array market = this->marketCreationWidget->createDecisionMarketArray(); + json_spirit::Array combo; + + // Add decision array to combo array + for (unsigned int i = 0; i < decision.size(); i++) { + combo.push_back(decision.at(i)); + } + + // Add market to combo array + for (unsigned int i = 0; i < market.size(); i++) { + combo.push_back(market.at(i)); + } + + // Type of array + combo.push_back("combo"); + + return combo; +} + +void ComboCreationWidget::on_pushButtonCreateCombo_clicked() +{ + json_spirit::Array comboArray = createComboArray(); + if (!comboArray.empty()) { + emit newComboArray(comboArray); + } +} + +void ComboCreationWidget::editArray(json_spirit::Array array) +{ + if (array.size() < 19) { + return; + } + + // Check for update index from model + updateIndex = array.back().get_int(); + array.pop_back(); + + // Confirm type + std::string type = json_spirit::write_string(array.back(), true); + if (type != "\"combo\"") return; + array.pop_back(); + + // Split the combo into respective decision and market arrays + json_spirit::Array decisionParams; + json_spirit::Array marketParams; + + // Binary Decision & Market + if (array.size() == 19) { + // Perform checks + std::string marketType = json_spirit::write_string(array.back(), true); + if (marketType != "\"market\"") return; + + std::string decisionType = json_spirit::write_string(array.at(6), true); + if (decisionType != "\"decision\"") return; + + for (unsigned int i = 0; i < array.size(); i++) { + // Get decision params + if (i < 7) { + decisionParams.push_back(array.at(i)); + } + // Get market params + if (i >= 7 && i < 19) { + marketParams.push_back(array.at(i)); + } + } + } + + // Scaled Decision & Market + if (array.size() == 21) { + // Perform checks + std::string marketType = json_spirit::write_string(array.back(), true); + if (marketType != "\"market\"") return; + + std::string decisionType = json_spirit::write_string(array.at(8), true); + if (decisionType != "\"decision\"") return; + + for (unsigned int i = 0; i < array.size(); i++) { + // Get decision params + if (i < 9) { + decisionParams.push_back(array.at(i)); + } + // Get market params + if (i >= 9 && i < 21) { + marketParams.push_back(array.at(i)); + } + } + } + + if (updateIndex >= 0) { + // Load the arrays in their respective widgets for editing + decisionCreationWidget->editArray(decisionParams); + marketCreationWidget->editArray(marketParams); + ui->pushButtonCreateCombo->hide(); + ui->pushButtonUpdateCombo->show(); + } +} + +void ComboCreationWidget::on_pushButtonUpdateCombo_clicked() +{ + json_spirit::Array updatedCombo = createComboArray(); + if (!updatedCombo.empty() && updateIndex >= 0) { + updatedCombo.push_back(updateIndex); + emit updatedComboArray(updatedCombo); + } +} diff --git a/src/qt/combocreationwidget.h b/src/qt/combocreationwidget.h new file mode 100644 index 0000000000000..e64cacd8896d7 --- /dev/null +++ b/src/qt/combocreationwidget.h @@ -0,0 +1,51 @@ +#ifndef COMBOCREATIONWIDGET_H +#define COMBOCREATIONWIDGET_H + +#include "decisioncreationwidget.h" +#include "decisionmarketcreationwidget.h" +#include "json/json_spirit_writer_template.h" + +#include +#include + +namespace Ui { +class ComboCreationWidget; +} + +class ComboCreationWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ComboCreationWidget(QWidget *parent = 0); + ~ComboCreationWidget(); + +private: + Ui::ComboCreationWidget *ui; + + DecisionCreationWidget *decisionCreationWidget; + DecisionMarketCreationWidget *marketCreationWidget; + + json_spirit::Array createComboArray(); + int updateIndex; + +signals: + /** Signal raised when json_spirit::Array for new Combo (Market & Decision) is created */ + void newComboArray(const json_spirit::Array &array); + + /** Signal raised for user input errors on combo creation widget */ + void inputError(const QString &error); + + /** Signal raised when user updates a decision array */ + void updatedComboArray(const json_spirit::Array array); + +public slots: + // Load a json_spirit array for editing + void editArray(json_spirit::Array array); + +private slots: + void on_pushButtonCreateCombo_clicked(); + void on_pushButtonUpdateCombo_clicked(); +}; + +#endif // COMBOCREATIONWIDGET_H diff --git a/src/qt/decisioncreationwidget.cpp b/src/qt/decisioncreationwidget.cpp new file mode 100644 index 0000000000000..e74b0d1a195c0 --- /dev/null +++ b/src/qt/decisioncreationwidget.cpp @@ -0,0 +1,218 @@ +#include "decisioncreationwidget.h" +#include "ui_decisioncreationwidget.h" + +#include + +DecisionCreationWidget::DecisionCreationWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::DecisionCreationWidget) +{ + ui->setupUi(this); + + ui->pushButtonUpdateDecision->hide(); + updateIndex = -1; + + connect(this, SIGNAL(inputError(QString)), + this, SLOT(on_inputError(QString))); +} + +DecisionCreationWidget::~DecisionCreationWidget() +{ + delete ui; +} + +json_spirit::Array DecisionCreationWidget::createDecisionArray() +{ + // Main branch ID + QString branchID; + if (ui->comboBoxBranch->currentText() == "Main") { + branchID = "0f894a25c5e0318ee148fe54600ebbf50782f0a1df1eb2aab06321a8ccec270d"; + } else if (ui->comboBoxBranch->currentText() == "Sports") { + branchID = "419cd87761f45c108a976ca6d93d4929c7c4d1ff4386f5089fc2f7ff7ae21ddf"; + } else if (ui->comboBoxBranch->currentText() == "Econ") { + branchID = "3277b5057ac9cda54e9edfbb45fd8bab38be1b5afc3cd6c587f6d17779f34f74"; + } + + // Grab user input from ui + QString address = ui->lineEditOwnerAddr->text(); + QString prompt = ui->plainTextEditPrompt->toPlainText(); + int eventOverBy = 1; // Temporary placeholder + bool answerOptionality = false; + if (ui->checkBoxVoteMandatory->isChecked()) { + answerOptionality = false; + } else { + answerOptionality = true; + } + bool scaled = ui->radioButtonScaled->isChecked(); + double scaledMin = ui->doubleSpinBoxScaledMin->value(); + double scaledMax = ui->doubleSpinBoxScaledMax->value(); + + bool error = false; + + // Perform basic checks and avoid wasting json calls + if (branchID.isEmpty()) { + emit inputError("You must select a branch!"); + error = true; + } + + if (address.isEmpty()) { + emit inputError("You must enter a valid Hivemind address!"); + error = true; + } + + if (prompt.isEmpty()) { + emit inputError("You must enter a valid prompt!"); + error = true; + } + + if (eventOverBy == 0) { + emit inputError("You must enter a valid ending date!"); + error = true; + } + + if (scaled && (scaledMax == scaledMin)) { + emit inputError("You must enter valid scaled values!"); + error = true; + } + + // Setup json_spirit array + json_spirit::Array params; + + // Return empty array if there was an input error + if (error) return params; + + // Add parmeters to array + params.push_back(address.toStdString()); + params.push_back(branchID.toStdString()); + params.push_back(prompt.toStdString()); + params.push_back(eventOverBy); + params.push_back(answerOptionality); + params.push_back(scaled); + if (scaled) { + params.push_back(scaledMin); + params.push_back(scaledMax); + } + // Type of array + params.push_back("decision"); + + return params; +} + +void DecisionCreationWidget::on_pushButtonCreateDecision_clicked() +{ + json_spirit::Array decisionArray = createDecisionArray(); + if (!decisionArray.empty()) { + emit newDecisionArray(decisionArray); + } +} + +void DecisionCreationWidget::on_radioButtonBinary_clicked(bool checked) +{ + // Enable scale doublespinbox widgets for binary decision + if (checked) { + ui->doubleSpinBoxScaledMin->setEnabled(false); + ui->doubleSpinBoxScaledMax->setEnabled(false); + } else { + ui->doubleSpinBoxScaledMin->setEnabled(true); + ui->doubleSpinBoxScaledMax->setEnabled(true); + } +} + +void DecisionCreationWidget::on_radioButtonScaled_clicked(bool checked) +{ + // Enable scale doublespinbox widgets for scaled decision + if (checked) { + ui->doubleSpinBoxScaledMin->setEnabled(true); + ui->doubleSpinBoxScaledMax->setEnabled(true); + } else { + ui->doubleSpinBoxScaledMin->setEnabled(false); + ui->doubleSpinBoxScaledMax->setEnabled(false); + } +} + +void DecisionCreationWidget::on_inputError(const QString &errorMessage) +{ + QMessageBox errorMessageBox; + errorMessageBox.setWindowTitle("Input error!"); + errorMessageBox.setText(errorMessage); + errorMessageBox.setStandardButtons(QMessageBox::Ok); + errorMessageBox.setDefaultButton(QMessageBox::Ok); + errorMessageBox.exec(); +} + +void DecisionCreationWidget::editArray(json_spirit::Array array) +{ + if (array.size() < 6) { + return; + } + + // Load owner address + json_spirit::Value ownerAddr = array.at(0); + ui->lineEditOwnerAddr->setText(QString::fromStdString(ownerAddr.get_str())); + + // Load branchID + json_spirit::Value branch = array.at(1); + QString branchLabel = "Branch: "; + QString branchID = QString::fromStdString(branch.get_str()); + branchLabel.append(branchID.left(12)); + branchLabel.append("..."); + ui->labelBranch->setText(branchLabel); + if (branchID == "0f894a25c5e0318ee148fe54600ebbf50782f0a1df1eb2aab06321a8ccec270d") { + ui->comboBoxBranch->setCurrentIndex(0); // Main + } else if (branchID == "419cd87761f45c108a976ca6d93d4929c7c4d1ff4386f5089fc2f7ff7ae21ddf") { + ui->comboBoxBranch->setCurrentIndex(1); // Sports + } else if (branchID == "3277b5057ac9cda54e9edfbb45fd8bab38be1b5afc3cd6c587f6d17779f34f74") { + ui->comboBoxBranch->setCurrentIndex(2); // Econ + } + + // Load prompt + json_spirit::Value prompt = array.at(2); + ui->plainTextEditPrompt->setPlainText(QString::fromStdString(prompt.get_str())); + + // Load event over by +// TODO: Replace with nLockTime +// json_spirit::Value eventOverBy = array.at(3); +// int overBy = eventOverBy.get_int(); + + // Load voteMandatory + json_spirit::Value voteMandatory = array.at(4); + ui->checkBoxVoteMandatory->setChecked(voteMandatory.get_bool()); + + // Load scaled + json_spirit::Value scaled = array.at(5); + bool isScaled = scaled.get_bool(); + ui->radioButtonScaled->setChecked(isScaled); + if (isScaled) { + // Load scale values + json_spirit::Value scaledMin = array.at(6); + ui->doubleSpinBoxScaledMin->setValue(scaledMin.get_real()); + json_spirit::Value scaledMax = array.at(7); + ui->doubleSpinBoxScaledMax->setValue(scaledMax.get_real()); + } + + // Check for update index from model + if (isScaled && array.size() == 10) { + ui->pushButtonCreateDecision->hide(); + ui->pushButtonUpdateDecision->show(); + updateIndex = array.at(9).get_int(); + } else if (!isScaled && array.size() == 8) { + ui->pushButtonCreateDecision->hide(); + ui->pushButtonUpdateDecision->show(); + updateIndex = array.at(7).get_int(); + } +} + +void DecisionCreationWidget::on_pushButtonUpdateDecision_clicked() +{ + json_spirit::Array updatedDecision = createDecisionArray(); + if (!updatedDecision.empty() && updateIndex >= 0) { + updatedDecision.push_back(updateIndex); + emit updatedDecisionArray(updatedDecision); + } +} + +// Setup the UI for the combo creation widget +void DecisionCreationWidget::comboCreationUI() +{ + ui->pushButtonCreateDecision->hide(); +} diff --git a/src/qt/decisioncreationwidget.h b/src/qt/decisioncreationwidget.h new file mode 100644 index 0000000000000..c9aaeccad3456 --- /dev/null +++ b/src/qt/decisioncreationwidget.h @@ -0,0 +1,59 @@ +#ifndef DECISIONCREATIONWIDGET_H +#define DECISIONCREATIONWIDGET_H + +#include "json/json_spirit_writer_template.h" + +#include + +class marketBranch; +class marketDecision; + +namespace Ui { +class DecisionCreationWidget; +} + +class DecisionCreationWidget : public QWidget +{ + Q_OBJECT + +public: + explicit DecisionCreationWidget(QWidget *parent = 0); + ~DecisionCreationWidget(); + + json_spirit::Array createDecisionArray(); + +signals: + /** Signal raised when json_spirit::Array for new Decision is created */ + void newDecisionArray(const json_spirit::Array array); + + /** Signal raised for user input errors on decision creation widget */ + void inputError(const QString &error); + + /** Signal raised when user updates a decision array */ + void updatedDecisionArray(const json_spirit::Array array); + +public slots: + // Load a json_spirit array for editing + void editArray(json_spirit::Array array); + + // Setup the UI for the combo creation widget + void comboCreationUI(); + +private slots: + void on_pushButtonCreateDecision_clicked(); + + void on_radioButtonBinary_clicked(bool checked); + + void on_radioButtonScaled_clicked(bool checked); + + void on_inputError(const QString &errorMessage); + + void on_pushButtonUpdateDecision_clicked(); + +private: + Ui::DecisionCreationWidget *ui; + const marketBranch *branch; + int updateIndex; +}; + +#endif // DECISIONCREATIONWIDGET_H diff --git a/src/qt/decisionmarketcreationwidget.cpp b/src/qt/decisionmarketcreationwidget.cpp new file mode 100644 index 0000000000000..3fde29771b507 --- /dev/null +++ b/src/qt/decisionmarketcreationwidget.cpp @@ -0,0 +1,273 @@ +#include "decisionmarketcreationwidget.h" +#include "ui_decisionmarketcreationwidget.h" + +#include "json/json_spirit_writer_template.h" +#include "txdb.h" + +#include +#include +#include + +extern CMarketTreeDB *pmarkettree; + +DecisionMarketCreationWidget::DecisionMarketCreationWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::DecisionMarketCreationWidget) +{ + ui->setupUi(this); + + ui->pushButtonUpdateMarket->hide(); + + updateIndex = -1; + + connect(this, SIGNAL(inputError(QString)), + this, SLOT(on_inputError(QString))); +} + +DecisionMarketCreationWidget::~DecisionMarketCreationWidget() +{ + delete ui; +} + +json_spirit::Array DecisionMarketCreationWidget::createDecisionMarketArray() +{ + // Grab user input from the ui + QString address = ui->lineEditAuthorAddress->text(); + std::string decisionID = ui->lineEditDecisions->text().toStdString(); + decisionID += ":"; + decisionID += ui->comboBoxFunctions->currentText().toStdString(); + double B = ui->doubleSpinBoxB->value(); + double tradingFee = ui->doubleSpinBoxTradeFee->value(); + double maxCommission = ui->doubleSpinBoxMaxCommission->value(); + QString title = ui->lineEditTitle->text(); + QString description = ui->plainTextEditDescription->toPlainText(); + QString tags = ui->lineEditTags->text(); + int maturation = 1; + int txPoWh = ui->comboBoxHashFunction->currentIndex(); + int txPoWd = ui->doubleSpinBoxDifficulty->value(); + + bool error = false; + + // Perform basic checks and avoid wasting json calls + if (address.isEmpty()) { + emit inputError("You must enter a valid Hivemind address!"); + error = true; + } + + if (decisionID.size() == 0) { + emit inputError("You must enter a decision ID!"); + error = true; + } + + if (B == 0) { + emit inputError("You must enter a valid B value!"); + error = true; + } + + if (tradingFee == 0) { + emit inputError("You must enter a valid trading fee!"); + error = true; + } + + if (maxCommission == 0) { + emit inputError("You must enter a valid max commission!"); + error = true; + } + + if (title.isEmpty()) { + emit inputError("You must enter a valid title!"); + error = true; + } + + if (description.isEmpty()) { + emit inputError("You must enter a valid Hivemind description!"); + error = true; + } + + if (tags.isEmpty()) { + emit inputError("You must enter valid tags!"); + error = true; + } + + if (maturation == 0) { + emit inputError("You must enter a valid maturation date!"); + error = true; + } + + if (txPoWd == 0) { + emit inputError("You must enter a valid PoW difficulty!"); + error = true; + } + + // Setup json_spirit array + json_spirit::Array params; + + // Return empty array if there was an input error + if (error) return params; + + params.push_back(address.toStdString()); + params.push_back(decisionID); + params.push_back(B); + params.push_back(tradingFee); + params.push_back(maxCommission); + params.push_back(title.toStdString()); + params.push_back(description.toStdString()); + params.push_back(tags.toStdString()); + params.push_back(maturation); + params.push_back(txPoWh); + params.push_back(txPoWd); + // Array type + params.push_back("market"); + + return params; +} + +void DecisionMarketCreationWidget::on_pushButtonCreateMarket_clicked() +{ + json_spirit::Array decisionMarketArray = createDecisionMarketArray(); + if (!decisionMarketArray.empty()) { + emit newDecisionMarketArray(decisionMarketArray); + } +} + +void DecisionMarketCreationWidget::on_pushButtonSelectDecision_clicked() +{ + // Grab the ID of the user selected branch + QString branchID; + if (ui->comboBoxBranch->currentText() == "Main") { + branchID = "0f894a25c5e0318ee148fe54600ebbf50782f0a1df1eb2aab06321a8ccec270d"; + } else if (ui->comboBoxBranch->currentText() == "Sports") { + branchID = "419cd87761f45c108a976ca6d93d4929c7c4d1ff4386f5089fc2f7ff7ae21ddf"; + } else if (ui->comboBoxBranch->currentText() == "Econ") { + branchID = "3277b5057ac9cda54e9edfbb45fd8bab38be1b5afc3cd6c587f6d17779f34f74"; + } + + // Exit if no branch is selected (technically impossible via the UI) + if (branchID.isEmpty()) return; + + // Grab the branch + uint256 uBranch; + uBranch.SetHex(branchID.toStdString()); + const marketBranch *branch = pmarkettree->GetBranch(uBranch); + + if (!branch) return; + + // Grab decisions on the branch + vector decisions = pmarkettree->GetDecisions(uBranch); + + // Setup the decision selection widget + decisionSelection = new DecisionSelectionView(this); + QVector qvDecisions = QVector::fromStdVector(decisions); + QList qlDecisions = QList::fromVector(qvDecisions); + decisionSelection->loadDecisions(qlDecisions); + + // Connect signals + connect(decisionSelection, SIGNAL(decisionSelected(QString)), + this, SLOT(decisionSelected(QString))); + + // Display the decision selection widget + QHBoxLayout *hbox = new QHBoxLayout(this); + hbox->addWidget(decisionSelection); + QDialog *dialog = new QDialog(this); + + connect(decisionSelection, SIGNAL(done()), + dialog, SLOT(close())); + + dialog->setWindowTitle("Select Decision"); + dialog->setLayout(hbox); + dialog->exec(); +} + +void DecisionMarketCreationWidget::on_inputError(const QString &errorMessage) +{ + QMessageBox errorMessageBox; + errorMessageBox.setWindowTitle("Input error!"); + errorMessageBox.setText(errorMessage); + errorMessageBox.setStandardButtons(QMessageBox::Ok); + errorMessageBox.setDefaultButton(QMessageBox::Ok); + errorMessageBox.exec(); +} + +void DecisionMarketCreationWidget::editArray(json_spirit::Array array) +{ + if (array.size() < 12) { + return; + } + + // Load address + json_spirit::Value address = array.at(0); + ui->lineEditAuthorAddress->setText(QString::fromStdString(address.get_str())); + + // Load decisionID & Function option + json_spirit::Value decisionID = array.at(1); + ui->lineEditDecisions->setText(QString::fromStdString(decisionID.get_str())); + + // Load B + json_spirit::Value B = array.at(2); + ui->doubleSpinBoxB->setValue(B.get_real()); + + // Load tradingFee + json_spirit::Value tradingFee = array.at(3); + ui->doubleSpinBoxTradeFee->setValue(tradingFee.get_real()); + + // Load maxCommission + json_spirit::Value maxCommission = array.at(4); + ui->doubleSpinBoxMaxCommission->setValue(maxCommission.get_real()); + + // Load title + json_spirit::Value title = array.at(5); + ui->lineEditTitle->setText(QString::fromStdString(title.get_str())); + + // Load description + json_spirit::Value description = array.at(6); + ui->plainTextEditDescription->setPlainText(QString::fromStdString(description.get_str())); + + // Load tags + json_spirit::Value tags = array.at(7); + ui->lineEditTags->setText(QString::fromStdString(tags.get_str())); + + // Load maturation + json_spirit::Value maturation = array.at(8); + ui->spinBoxMaturation->setValue(maturation.get_int()); + + // Load txPoWh + json_spirit::Value txPoWh = array.at(9); + ui->comboBoxHashFunction->setCurrentIndex(txPoWh.get_int()); + + // Load txPoWd + json_spirit::Value txPoWd = array.at(10); + ui->doubleSpinBoxDifficulty->setValue(txPoWd.get_real()); + + if (array.size() == 13) { + // Show update button and set index + ui->pushButtonCreateMarket->hide(); + ui->pushButtonUpdateMarket->show(); + updateIndex = array.at(12).get_int(); + } +} + +void DecisionMarketCreationWidget::on_pushButtonUpdateMarket_clicked() +{ + json_spirit::Array updatedMarket = createDecisionMarketArray(); + if (!updatedMarket.empty() && updateIndex >= 0) { + updatedMarket.push_back(updateIndex); + emit updatedDecisionMarketArray(updatedMarket); + } +} + +void DecisionMarketCreationWidget::comboCreationUI() +{ + ui->groupBoxDecision->hide(); + ui->pushButtonCreateMarket->hide(); + + ui->lineEditAuthorAddress->setText("Temp"); + ui->lineEditDecisions->setText("Temp"); + + ui->lineEditAuthorAddress->hide(); + ui->labelAuthorAddress->hide(); +} + +void DecisionMarketCreationWidget::decisionSelected(QString decisionHex) +{ + ui->lineEditDecisions->setText(decisionHex); +} diff --git a/src/qt/decisionmarketcreationwidget.h b/src/qt/decisionmarketcreationwidget.h new file mode 100644 index 0000000000000..40a1022554ed3 --- /dev/null +++ b/src/qt/decisionmarketcreationwidget.h @@ -0,0 +1,57 @@ +#ifndef DECISIONMARKETCREATIONWIDGET_H +#define DECISIONMARKETCREATIONWIDGET_H + +#include "json/json_spirit_writer_template.h" +#include "decisionselectionview.h" + +#include + +namespace Ui { +class DecisionMarketCreationWidget; +} + +class DecisionMarketCreationWidget : public QWidget +{ + Q_OBJECT + +public: + explicit DecisionMarketCreationWidget(QWidget *parent = 0); + ~DecisionMarketCreationWidget(); + + json_spirit::Array createDecisionMarketArray(); + +private slots: + void on_pushButtonCreateMarket_clicked(); + + void on_pushButtonSelectDecision_clicked(); + + void on_inputError(const QString &errorMessage); + + void on_pushButtonUpdateMarket_clicked(); + +public slots: + // Load json_spirit array for editing + void editArray(json_spirit::Array array); + + // Setup the UI for the combo creation widget + void comboCreationUI(); + + void decisionSelected(QString decisionHex); + +signals: + /** Signal raised when json_spirit::Array for new Decision Market is created */ + void newDecisionMarketArray(const json_spirit::Array array); + + /** Signal raised when user updates a decision array */ + void updatedDecisionMarketArray(const json_spirit::Array array); + + /** Signal raised for user input errors on market creation widget */ + void inputError(const QString &error); + +private: + Ui::DecisionMarketCreationWidget *ui; + int updateIndex; + DecisionSelectionView *decisionSelection; +}; + +#endif // DECISIONMARKETCREATIONWIDGET_H diff --git a/src/qt/decisionselectionmodel.cpp b/src/qt/decisionselectionmodel.cpp new file mode 100644 index 0000000000000..9cba44adbc84b --- /dev/null +++ b/src/qt/decisionselectionmodel.cpp @@ -0,0 +1,84 @@ +#include "decisionselectionmodel.h" + +DecisionSelectionModel::DecisionSelectionModel(QObject *parent) : + QAbstractTableModel(parent) +{ +} + +int DecisionSelectionModel::rowCount(const QModelIndex &parent) const +{ + return model.size(); +} + +int DecisionSelectionModel::columnCount(const QModelIndex &parent) const +{ + return 2; +} + +QVariant DecisionSelectionModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) { + return false; + } + + int row = index.row(); + int col = index.column(); + + switch(role) { + case Qt::DisplayRole: + { + // Decision prompt + if (col == 0) { + QString decisionPrompt = QString::fromStdString(model.at(row)->prompt); + + return decisionPrompt; + } + // Decision ID + if (col == 1) { + QString decisionID = QString::fromStdString(model.at(row)->GetHash().GetHex()); + + return decisionID; + } + break; + } + } + + return QVariant(); + +} + +QVariant DecisionSelectionModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role == Qt::DisplayRole) + { + if (orientation == Qt::Horizontal) { + switch (section) + { + case 0: + return QString("Prompt"); + break; + case 1: + return QString("ID"); + } + } + } + return QVariant(); +} + +void DecisionSelectionModel::on_tableView_doubleClicked(const QModelIndex &index) +{ + +} + +void DecisionSelectionModel::loadDecisions(QList decisions) +{ + if (decisions.isEmpty()) return; + + beginInsertRows(QModelIndex(), 0, decisions.size()); + + for (int i = 0; i < decisions.size(); i++) { + model.push_back(decisions.at(i)); + } + + endInsertRows(); +} diff --git a/src/qt/decisionselectionmodel.h b/src/qt/decisionselectionmodel.h new file mode 100644 index 0000000000000..70f93e2098207 --- /dev/null +++ b/src/qt/decisionselectionmodel.h @@ -0,0 +1,31 @@ +#ifndef DECISIONSELECTIONMODEL_H +#define DECISIONSELECTIONMODEL_H + +#include "primitives/market.h" + +#include +#include +#include + +class DecisionSelectionModel : public QAbstractTableModel +{ + Q_OBJECT +public: + explicit DecisionSelectionModel(QObject *parent = 0); + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + +signals: + +public slots: + void on_tableView_doubleClicked(const QModelIndex &index); + void loadDecisions(QList decisions); + +private: + QList model; + +}; + +#endif // DECISIONSELECTIONMODEL_H diff --git a/src/qt/decisionselectionview.cpp b/src/qt/decisionselectionview.cpp new file mode 100644 index 0000000000000..544f885320e86 --- /dev/null +++ b/src/qt/decisionselectionview.cpp @@ -0,0 +1,44 @@ +#include "decisionselectionview.h" +#include "ui_decisionselectionview.h" + +DecisionSelectionView::DecisionSelectionView(QWidget *parent) : + QWidget(parent), + ui(new Ui::DecisionSelectionView) +{ + ui->setupUi(this); + + // Setup model and decision selection table + decisionSelectionTable = new QTableView(this); + decisionSelectionTable->horizontalHeader()->setStretchLastSection(true); + decisionSelectionTable->horizontalHeader()->setResizeMode(QHeaderView::Stretch); + decisionSelectionModel = new DecisionSelectionModel(this); + decisionSelectionTable->setModel(decisionSelectionModel); + + ui->frame->layout()->addWidget(decisionSelectionTable); + + // Setup signals + connect(decisionSelectionTable, SIGNAL(doubleClicked(QModelIndex)), + this, SLOT(on_table_doubleClicked(QModelIndex))); +} + +DecisionSelectionView::~DecisionSelectionView() +{ + delete ui; +} + +void DecisionSelectionView::loadDecisions(QList decisions) +{ + decisionSelectionModel->loadDecisions(decisions); +} + +void DecisionSelectionView::on_table_doubleClicked(QModelIndex index) +{ + QString hex = decisionSelectionTable->model()->data(decisionSelectionTable->model()->index(index.row(), 1)).toString(); + emit decisionSelected(hex); + emit done(); +} + +void DecisionSelectionView::on_pushButtonDone_clicked() +{ + emit done(); +} diff --git a/src/qt/decisionselectionview.h b/src/qt/decisionselectionview.h new file mode 100644 index 0000000000000..3748e6e777085 --- /dev/null +++ b/src/qt/decisionselectionview.h @@ -0,0 +1,39 @@ +#ifndef DECISIONSELECTIONVIEW_H +#define DECISIONSELECTIONVIEW_H + +#include "decisionselectionmodel.h" + +#include +#include + +namespace Ui { +class DecisionSelectionView; +} + +class DecisionSelectionView : public QWidget +{ + Q_OBJECT + +public: + explicit DecisionSelectionView(QWidget *parent = 0); + ~DecisionSelectionView(); + +public slots: + void loadDecisions(QList decisions); + void on_table_doubleClicked(QModelIndex index); + +signals: + void decisionSelected(QString decisionHex); + void done(); + +private slots: + void on_pushButtonDone_clicked(); + +private: + Ui::DecisionSelectionView *ui; + + DecisionSelectionModel *decisionSelectionModel; + QTableView *decisionSelectionTable; +}; + +#endif // DECISIONSELECTIONVIEW_H diff --git a/src/qt/decisionview.cpp b/src/qt/decisionview.cpp index b49762bc806ef..acb170c32c16a 100644 --- a/src/qt/decisionview.cpp +++ b/src/qt/decisionview.cpp @@ -999,7 +999,7 @@ void DecisionView::showTradeWindow(void) void DecisionView::setModel(WalletModel *model) { this->model = model; - /* branch is last. it populate decisions and market */ + /* branch is last as it populates decisions and market */ tradeWindow->setModel(model); marketWindow->setModel(model); decisionWindow->setModel(model); diff --git a/src/qt/decisionview.h b/src/qt/decisionview.h index 60752e0a09ff0..e3647c5476fa7 100644 --- a/src/qt/decisionview.h +++ b/src/qt/decisionview.h @@ -32,7 +32,6 @@ QT_END_NAMESPACE #define DECISIONMARKET_NLABLES 12 #define DECISIONTRADE_NLABLES 8 - class DecisionView : public QWidget { diff --git a/src/qt/forms/authorview.ui b/src/qt/forms/authorview.ui new file mode 100644 index 0000000000000..7e9b30a77299b --- /dev/null +++ b/src/qt/forms/authorview.ui @@ -0,0 +1,191 @@ + + + AuthorView + + + + 0 + 0 + 1033 + 518 + + + + Form + + + + :/icons/hivemind:/icons/hivemind + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 40 + + + + Create Decision and Market + + + + + + + + 0 + 40 + + + + Create Decision + + + + + + + + 0 + 40 + + + + Create Market + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Info: + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Total: + + + + + + + Qt::Horizontal + + + + + + + Fees: + + + + + + + 0.0 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 100 + 40 + + + + Finalize + + + + :/icons/synced:/icons/synced + + + + + + + + + + + + + diff --git a/src/qt/forms/combocreationwidget.ui b/src/qt/forms/combocreationwidget.ui new file mode 100644 index 0000000000000..12d8028b69141 --- /dev/null +++ b/src/qt/forms/combocreationwidget.ui @@ -0,0 +1,91 @@ + + + ComboCreationWidget + + + + 0 + 0 + 848 + 569 + + + + Form + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + Step 1: Create Decision + + + + + + + + + + true + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + true + + + Step 2: Create Market + + + + + + + + + + + + + Create Combo + + + + + + + Update Combo + + + + + + + + diff --git a/src/qt/forms/decisioncreationwidget.ui b/src/qt/forms/decisioncreationwidget.ui new file mode 100644 index 0000000000000..6cf3a16c83ab7 --- /dev/null +++ b/src/qt/forms/decisioncreationwidget.ui @@ -0,0 +1,279 @@ + + + DecisionCreationWidget + + + + 0 + 0 + 892 + 459 + + + + + 0 + 0 + + + + Form + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + 0 + 0 + + + + + Main + + + + + Sports + + + + + Econ + + + + + + + + Branch + + + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + Slot Type + + + + + + + Standard + + + true + + + + + + + Overflow + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Decision Type: + + + + + + + Binary + + + true + + + + + + + Scaled + + + + + + + Qt::Vertical + + + + + + + false + + + + + + + false + + + + + + + Over By: + + + + + + + + + + + + + + + 0 + 0 + 0 + 2016 + 1 + 12 + + + + true + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Owner Address: + + + + + + + Owner Address + + + + + + + Prompt: + + + + + + + + + + Voting Mandatory + + + true + + + + + + + + + + + 0 + 40 + + + + Create Decision + + + + + + + + 0 + 40 + + + + Update Decision + + + + + + + + diff --git a/src/qt/forms/decisionmarketcreationwidget.ui b/src/qt/forms/decisionmarketcreationwidget.ui new file mode 100644 index 0000000000000..610d806c961b5 --- /dev/null +++ b/src/qt/forms/decisionmarketcreationwidget.ui @@ -0,0 +1,341 @@ + + + DecisionMarketCreationWidget + + + + 0 + 0 + 650 + 882 + + + + + 650 + 0 + + + + Form + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Market Type: + + + + + + + Standard + + + true + + + + + + + DAC (Selling Disabled) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Select Decision + + + + + + + 0 + 0 + + + + Branch: + + + + + + + + Main + + + + + Sports + + + + + Econ + + + + + + + + + 0 + 60 + + + + Select Decision + + + + + + + Decisions: + + + + + + + + + + + + + Market Setup + + + + + + Title: + + + + + + + + + + Description: + + + + + + + + + + Tags (comma seperated) + + + + + + + + + + Author Address: + + + + + + + + + + Maturation + + + + + + + 1 + + + + + + + + + + Advanced + + + + + + Liquidity Factor: + + + + + + + Max Commission: + + + + + + + 0.100000000000000 + + + + + + + 0.100000000000000 + + + + + + + Trading Fee: + + + + + + + Function: + + + + + + + 0.100000000000000 + + + + + + + + X1 + + + + + X2 + + + + + X3 + + + + + LNX1 + + + + + + + + Hash Function: + + + + + + + Difficulty + + + + + + + + SHA-2 + + + + + + + + 1.000000000000000 + + + + + + + + + + + 0 + 40 + + + + Create Market + + + + + + + + 0 + 40 + + + + Update Market + + + + + + + + diff --git a/src/qt/forms/decisionselectionview.ui b/src/qt/forms/decisionselectionview.ui new file mode 100644 index 0000000000000..1de44ca283a52 --- /dev/null +++ b/src/qt/forms/decisionselectionview.ui @@ -0,0 +1,59 @@ + + + DecisionSelectionView + + + + 0 + 0 + 800 + 400 + + + + + 800 + 400 + + + + Form + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + Select Decision by double clicking, or select multiple and click "Done": + + + + + + + + + + Done + + + + + + + + diff --git a/src/qt/hivemind.qrc b/src/qt/hivemind.qrc index d0833d4f06e3b..f16b3907573e7 100644 --- a/src/qt/hivemind.qrc +++ b/src/qt/hivemind.qrc @@ -1,4 +1,4 @@ - + res/icons/hivemind.png res/icons/address-book.png @@ -49,6 +49,7 @@ res/icons/about.png res/icons/about_qt.png res/icons/verify.png + res/icons/author.png res/movies/spinner-000.png diff --git a/src/qt/hivemindgui.cpp b/src/qt/hivemindgui.cpp index 1ba214cf245cd..ad3c8709ecfa0 100644 --- a/src/qt/hivemindgui.cpp +++ b/src/qt/hivemindgui.cpp @@ -75,6 +75,7 @@ HivemindGUI::HivemindGUI(const NetworkStyle *networkStyle, QWidget *parent) : appMenuBar(0), overviewAction(0), historyAction(0), + authorAction(0), ballotAction(0), decisionAction(0), marketAction(0), @@ -299,6 +300,13 @@ void HivemindGUI::createActions(const NetworkStyle *networkStyle) decisionAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_6)); tabGroup->addAction(decisionAction); + authorAction = new QAction(SingleColorIcon(":/icons/author"), tr("&Author"), this); + authorAction->setStatusTip(tr("Create decisions and markets")); + authorAction->setToolTip(authorAction->statusTip()); + authorAction->setCheckable(true); + authorAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_8)); + tabGroup->addAction(authorAction); + ballotAction = new QAction(SingleColorIcon(":/icons/ballot"), tr("&Ballot"), this); ballotAction->setStatusTip(tr("See votes")); ballotAction->setToolTip(ballotAction->statusTip()); @@ -306,7 +314,6 @@ void HivemindGUI::createActions(const NetworkStyle *networkStyle) ballotAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_7)); tabGroup->addAction(ballotAction); - #ifdef ENABLE_WALLET // These showNormalIfMinimized are needed because Send Coins and Receive Coins // can be triggered from the tray menu, and need to show the GUI to be useful. @@ -324,6 +331,8 @@ void HivemindGUI::createActions(const NetworkStyle *networkStyle) connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage())); connect(ballotAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(ballotAction, SIGNAL(triggered()), this, SLOT(gotoBallotPage())); + connect(authorAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); + connect(authorAction, SIGNAL(triggered()), this, SLOT(gotoAuthorView())); connect(decisionAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); connect(decisionAction, SIGNAL(triggered()), this, SLOT(gotoDecisionPage())); connect(marketAction, SIGNAL(triggered()), this, SLOT(showNormalIfMinimized())); @@ -454,6 +463,7 @@ void HivemindGUI::createToolBars() toolbar->addAction(historyAction); toolbar->addAction(marketAction); toolbar->addAction(decisionAction); + toolbar->addAction(authorAction); toolbar->addAction(ballotAction); overviewAction->setChecked(true); } @@ -533,6 +543,7 @@ void HivemindGUI::setWalletActionsEnabled(bool enabled) receiveCoinsAction->setEnabled(enabled); receiveCoinsMenuAction->setEnabled(enabled); historyAction->setEnabled(enabled); + authorAction->setEnabled(enabled); ballotAction->setEnabled(enabled); decisionAction->setEnabled(enabled); marketAction->setEnabled(enabled); @@ -656,6 +667,12 @@ void HivemindGUI::gotoHistoryPage() if (walletFrame) walletFrame->gotoHistoryPage(); } +void HivemindGUI::gotoAuthorView() +{ + authorAction->setChecked(true); + if (walletFrame) walletFrame->gotoAuthorView(); +} + void HivemindGUI::gotoBallotPage() { ballotAction->setChecked(true); diff --git a/src/qt/hivemindgui.h b/src/qt/hivemindgui.h index 63a44a42c54cc..e3e6fb3cf0012 100644 --- a/src/qt/hivemindgui.h +++ b/src/qt/hivemindgui.h @@ -89,6 +89,7 @@ class HivemindGUI : public QMainWindow QMenuBar *appMenuBar; QAction *overviewAction; QAction *historyAction; + QAction *authorAction; QAction *ballotAction; QAction *decisionAction; QAction *marketAction; @@ -179,6 +180,8 @@ private slots: void gotoOverviewPage(); /** Switch to history (transactions) page */ void gotoHistoryPage(); + /** Switch to author page */ + void gotoAuthorView(); /** Switch to ballot page */ void gotoBallotPage(); /** Switch to decision page */ diff --git a/src/qt/res/icons/author.png b/src/qt/res/icons/author.png new file mode 100644 index 0000000000000..ed0e1c58ec4ce Binary files /dev/null and b/src/qt/res/icons/author.png differ diff --git a/src/qt/res/icons/decisions.png b/src/qt/res/icons/decisions.png deleted file mode 100644 index 83acef6b4caa7..0000000000000 Binary files a/src/qt/res/icons/decisions.png and /dev/null differ diff --git a/src/qt/res/icons/truthcoin.icns b/src/qt/res/icons/truthcoin.icns deleted file mode 100644 index 54d02d34dd9f1..0000000000000 Binary files a/src/qt/res/icons/truthcoin.icns and /dev/null differ diff --git a/src/qt/res/icons/truthcoin.ico b/src/qt/res/icons/truthcoin.ico deleted file mode 100644 index 48a32666492f6..0000000000000 Binary files a/src/qt/res/icons/truthcoin.ico and /dev/null differ diff --git a/src/qt/res/icons/truthcoin.png b/src/qt/res/icons/truthcoin.png deleted file mode 100644 index 7cde85fbcc163..0000000000000 Binary files a/src/qt/res/icons/truthcoin.png and /dev/null differ diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index cb44a86eb16b9..084c8df47a171 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -120,6 +120,13 @@ void WalletFrame::gotoHistoryPage() i.value()->gotoHistoryPage(); } +void WalletFrame::gotoAuthorView() +{ + QMap::const_iterator i; + for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) + i.value()->gotoAuthorView(); +} + void WalletFrame::gotoBallotPage() { QMap::const_iterator i; diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 020be289eed75..e94870d705c96 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -53,6 +53,8 @@ public slots: void gotoOverviewPage(); /** Switch to history (transactions) page */ void gotoHistoryPage(); + /** Switch to author page */ + void gotoAuthorView(); /** Switch to ballot page */ void gotoBallotPage(); /** Switch to decision page */ diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index f3a79c51e333c..77921bd6066d5 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -43,6 +43,7 @@ WalletView::WalletView(QWidget *parent): // Create tabs overviewPage = new OverviewPage(); + // Transactions tab transactionsPage = new QWidget(this); QVBoxLayout *vbox = new QVBoxLayout(); QHBoxLayout *hbox_buttons = new QHBoxLayout(); @@ -58,6 +59,10 @@ WalletView::WalletView(QWidget *parent): vbox->addLayout(hbox_buttons); transactionsPage->setLayout(vbox); + // Author tab + authorView = new AuthorView(this); + + // Ballot tab ballotPage = new QWidget(this); QVBoxLayout *bvbox = new QVBoxLayout(); QHBoxLayout *bhbox_buttons = new QHBoxLayout(); @@ -67,6 +72,7 @@ WalletView::WalletView(QWidget *parent): bvbox->addLayout(bhbox_buttons); ballotPage->setLayout(bvbox); + // Decision tab decisionPage = new QWidget(this); QVBoxLayout *dvbox = new QVBoxLayout(); QHBoxLayout *dhbox_buttons = new QHBoxLayout(); @@ -76,6 +82,7 @@ WalletView::WalletView(QWidget *parent): dvbox->addLayout(dhbox_buttons); decisionPage->setLayout(dvbox); + // Market tab marketPage = new QWidget(this); QVBoxLayout *mvbox = new QVBoxLayout(); QHBoxLayout *mhbox_buttons = new QHBoxLayout(); @@ -85,9 +92,13 @@ WalletView::WalletView(QWidget *parent): mvbox->addLayout(mhbox_buttons); marketPage->setLayout(mvbox); + // Receive tab receiveCoinsPage = new ReceiveCoinsDialog(); + + // Send tab sendCoinsPage = new SendCoinsDialog(); + addWidget(authorView); addWidget(overviewPage); addWidget(transactionsPage); addWidget(marketPage); @@ -203,6 +214,11 @@ void WalletView::gotoHistoryPage() setCurrentWidget(transactionsPage); } +void WalletView::gotoAuthorView() +{ + setCurrentWidget(authorView); +} + void WalletView::gotoBallotPage() { setCurrentWidget(ballotPage); diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 123bdbd79a9ba..f112f45a63319 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -7,6 +7,7 @@ #define HIVEMIND_QT_WALLETVIEW_H #include "amount.h" +#include "authorview.h" #include @@ -67,6 +68,7 @@ class WalletView : public QStackedWidget QWidget *marketPage; ReceiveCoinsDialog *receiveCoinsPage; SendCoinsDialog *sendCoinsPage; + AuthorView *authorView; BallotView *ballotView; DecisionView *decisionView; @@ -80,6 +82,8 @@ public slots: void gotoOverviewPage(); /** Switch to history (transactions) page */ void gotoHistoryPage(); + /** Switch to author view */ + void gotoAuthorView(); /** Switch to ballot page */ void gotoBallotPage(); /** Switch to decision page */