def __init__(self, parent): super(QWidget, self).__init__(parent) self.parent = parent self.tree = ProposalsTreeWidget(parent) # Proposals that have been paid for but not submitted. self.unsubmitted_proposals = [] description = ''.join([ 'You can create a budget proposal below. ', 'Proposals require 5 AXE to create. ', 'Your proposal can be submitted once the collateral transaction has enough confirmations.' ]) description = QLabel(_(description)) description.setWordWrap(True) self.name_edit = QLineEdit() self.name_edit.setPlaceholderText(_('Name of your proposal')) self.url_edit = QLineEdit() self.url_edit.setPlaceholderText( _('URL that your proposal can be found at')) self.payments_count_edit = QSpinBox() self.payments_count_edit.setRange(1, 1000000) self.start_block_edit = QSpinBox() self.start_block_edit.setRange(0, 1000000) self.address_edit = QLineEdit() self.address_edit.setPlaceholderText( _('Address that will receive payments')) self.amount_edit = BTCAmountEdit(self.parent.get_decimal_point) self.create_proposal_button = QPushButton(_('Create Proposal')) self.create_proposal_button.clicked.connect(self.create_proposal) self.submit_ready_proposals_button = QPushButton( _('Submit Confirmed Proposals')) self.submit_ready_proposals_button.clicked.connect( self.submit_waiting_proposals) self.submit_ready_proposals_button.setEnabled(False) self.ready_proposals = QLabel() self.ready_proposals.setVisible(False) form = QFormLayout() form.addRow(_('Proposal Name:'), self.name_edit) form.addRow(_('Proposal URL:'), self.url_edit) form.addRow(_('Number of Payments:'), self.payments_count_edit) form.addRow(_('Starting Block:'), self.start_block_edit) form.addRow(_('Payment Address:'), self.address_edit) form.addRow(_('Monthly AXE Payment:'), self.amount_edit) vbox = QVBoxLayout() vbox.addWidget(self.tree) vbox.addWidget(description) vbox.addLayout(form) vbox.addLayout(util.Buttons(self.create_proposal_button)) vbox.addLayout( util.Buttons(self.ready_proposals, self.submit_ready_proposals_button)) self.setLayout(vbox)
def add_paytoedit(self): w = QWidget() grid = QGridLayout() grid.setSpacing(8) grid.setColumnMinimumWidth(1, 300) grid.setColumnStretch(1, 2) pay_edit = PayToEdit(self.parent, BTCAmountEdit(self.parent.get_decimal_point)) self.payto_widgets.append((w, pay_edit)) current_widget_index = len(self.payto_widgets) - 1 completer = QCompleter() completer.setCaseSensitivity(False) pay_edit.setCompleter(completer) completer.setModel(self.parent.completions) if current_widget_index == 0: grid.addWidget(QLabel(_('Pay to')), 0, 0, 1, 1) grid.addWidget(QLabel(_('Amount')), 0, 3, 1, 1) grid.addWidget(self.payto_help, 0, 1) grid.addWidget(self.amount_help, 0, 4) grid.addWidget(pay_edit, 1, 0, 1, 3) grid.addWidget(pay_edit.amount_edit, 1, 3, 1, 3) w.setLayout(grid) self.vbox.addWidget(w) pay_edit.amount_edit.shortcut.connect( functools.partial(self.on_shortcut, current_widget_index)) pay_edit.textChanged.connect( functools.partial(self.on_textChanged, current_widget_index)) pay_edit.amount_edit.textEdited.connect( functools.partial(self.on_textChanged, current_widget_index)) return w
def create_chain_options(self): rows = [] gui = self.gui # Number of Zeroes nz_label = QLabel(_('Zeros after decimal point') + ':') nz_help = HelpButton(_('Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"')) nz = QSpinBox() nz.setMinimum(0) nz.setMaximum(gui.decimal_point) nz.setValue(gui.num_zeros) if not self.config.is_modifiable('num_zeros'): for w in [nz, nz_label]: w.setEnabled(False) def on_nz(): value = nz.value() if gui.num_zeros != value: gui.num_zeros = value self.config.set_key('num_zeros', value, True) gui.update_history_tab() gui.update_address_tab() nz.valueChanged.connect(on_nz) rows.append(SettingsRow(self,'combobox', (nz_label, nz, nz_help))) # Fee # fee_label = QLabel(_('Transaction fee per kb') + ':') fee_help = HelpButton(_('Fee per kilobyte of transaction.') + '\n' \ + _('Recommended value') + ': ' + gui.format_amount(gui.active_chain.RECOMMENDED_FEE) + ' ' + gui.base_unit()) fee_e = BTCAmountEdit(gui.get_decimal_point) fee_e.setAmount(gui.wallet.fee_per_kb) if not self.config.is_modifiable('fee_per_kb'): for w in [fee_e, fee_label]: w.setEnabled(False) def on_fee(): fee = fee_e.get_amount() gui.wallet.set_fee(fee) fee_e.editingFinished.connect(on_fee) rows.append(SettingsRow(self,'combobox', (fee_label, fee_e, fee_help))) # Base Unit # units = gui.base_units.keys() unit_label = QLabel(_('Base unit') + ':') unit_combo = QComboBox() unit_combo.addItems(units) unit_combo.setCurrentIndex(units.index(gui.base_unit())) msg = _('Base unit of your wallet.')\ + '\n1BTC=1000mBTC.\n' \ + _(' These settings affects the fields in the Send tab')+' ' unit_help = HelpButton(msg) def on_unit(x): unit_result = units[unit_combo.currentIndex()] if gui.base_unit() == unit_result: return gui.decimal_point = gui.base_units[unit_result] self.config.set_key('decimal_point', gui.decimal_point, True) gui.update_history_tab() gui.update_receive_tab() gui.update_address_tab() gui.update_invoices_tab() fee_e.setAmount(gui.wallet.fee_per_kb) gui.update_status() unit_combo.currentIndexChanged.connect(on_unit) rows.append(SettingsRow(self,'combobox', (unit_label, unit_combo, unit_help))) # Block Explorers # block_explorers = gui.block_explorers.keys() block_ex_label = QLabel(_('Online Block Explorer') + ':') block_ex_combo = QComboBox() block_ex_combo.addItems(block_explorers) block_ex_combo.setCurrentIndex(block_explorers.index(self.config.get('block_explorer', block_explorers[0]))) block_ex_help = HelpButton(_('Choose which online block explorer to use for functions that open a web browser')) def on_be(x): be_result = block_explorers[block_ex_combo.currentIndex()] self.config.set_key('block_explorer', be_result, True) block_ex_combo.currentIndexChanged.connect(on_be) rows.append(SettingsRow(self,'combobox', (block_ex_label, block_ex_combo, block_ex_help))) # Use Change Addresses # usechange_cb = QCheckBox(_('Use change addresses')) usechange_cb.setChecked(gui.wallet.use_change) usechange_help = HelpButton(_('Using change addresses makes it more difficult for other people to track your transactions.')) if not self.config.is_modifiable('use_change'): usechange_cb.setEnabled(False) def on_usechange(x): usechange_result = x == Qt.Checked if gui.wallet.use_change != usechange_result: gui.wallet.use_change = usechange_result gui.wallet.storage.put('use_change', gui.wallet.use_change) usechange_cb.stateChanged.connect(on_usechange) rows.append(SettingsRow(self,'toggle', (usechange_cb, usechange_help))) # Show Tx Before Broadcast # showtx_cb = QCheckBox(_('Show transaction before broadcast')) showtx_cb.setChecked(self.config.get('show_before_broadcast', False)) showtx_cb.stateChanged.connect(lambda x: self.config.set_key('show_before_broadcast', showtx_cb.isChecked())) showtx_help = HelpButton(_('Display the details of your transactions before broadcasting it.')) rows.append(SettingsRow(self,'toggle', (showtx_cb, showtx_help))) # Set Fees Manually # can_edit_fees_cb = QCheckBox(_('Set transaction fees manually')) can_edit_fees_cb.setChecked(self.config.get('can_edit_fees', False)) def on_editfees(x): self.config.set_key('can_edit_fees', x == Qt.Checked) gui.update_fee_edit() can_edit_fees_cb.stateChanged.connect(on_editfees) can_edit_fees_help = HelpButton(_('This option lets you edit fees in the send tab.')) rows.append(SettingsRow(self,'toggle', (can_edit_fees_cb, can_edit_fees_help))) return rows
class ProposalsTab(QWidget): """Wallet tab for budget proposals.""" def __init__(self, parent): super(QWidget, self).__init__(parent) self.parent = parent self.tree = ProposalsTreeWidget(parent) # Proposals that have been paid for but not submitted. self.unsubmitted_proposals = [] description = ''.join([ 'You can create a budget proposal below. ', 'Proposals require 5 AXE to create. ', 'Your proposal can be submitted once the collateral transaction has enough confirmations.' ]) description = QLabel(_(description)) description.setWordWrap(True) self.name_edit = QLineEdit() self.name_edit.setPlaceholderText(_('Name of your proposal')) self.url_edit = QLineEdit() self.url_edit.setPlaceholderText( _('URL that your proposal can be found at')) self.payments_count_edit = QSpinBox() self.payments_count_edit.setRange(1, 1000000) self.start_block_edit = QSpinBox() self.start_block_edit.setRange(0, 1000000) self.address_edit = QLineEdit() self.address_edit.setPlaceholderText( _('Address that will receive payments')) self.amount_edit = BTCAmountEdit(self.parent.get_decimal_point) self.create_proposal_button = QPushButton(_('Create Proposal')) self.create_proposal_button.clicked.connect(self.create_proposal) self.submit_ready_proposals_button = QPushButton( _('Submit Confirmed Proposals')) self.submit_ready_proposals_button.clicked.connect( self.submit_waiting_proposals) self.submit_ready_proposals_button.setEnabled(False) self.ready_proposals = QLabel() self.ready_proposals.setVisible(False) form = QFormLayout() form.addRow(_('Proposal Name:'), self.name_edit) form.addRow(_('Proposal URL:'), self.url_edit) form.addRow(_('Number of Payments:'), self.payments_count_edit) form.addRow(_('Starting Block:'), self.start_block_edit) form.addRow(_('Payment Address:'), self.address_edit) form.addRow(_('Monthly AXE Payment:'), self.amount_edit) vbox = QVBoxLayout() vbox.addWidget(self.tree) vbox.addWidget(description) vbox.addLayout(form) vbox.addLayout(util.Buttons(self.create_proposal_button)) vbox.addLayout( util.Buttons(self.ready_proposals, self.submit_ready_proposals_button)) self.setLayout(vbox) def get_model(self): """Get the model so that other widgets can display proposals.""" return self.tree.model def update(self, proposals): self.tree.update(proposals, self.parent) self.start_block_edit.setMinimum( self.parent.network.get_local_height()) # Check if we have unsubmitted proposals. self.update_unsubmitted_proposals() def update_unsubmitted_proposals(self): """Update the list of unsubmitted proposals.""" self.unsubmitted_proposals = [] for p in self.parent.masternode_manager.proposals: if p.fee_txid and not p.submitted and not p.rejected: confirmations, timestamp = self.parent.wallet.get_confirmations( p.fee_txid) if confirmations < BUDGET_FEE_CONFIRMATIONS: continue item = (p.proposal_name, p.fee_txid) if item not in self.unsubmitted_proposals: self.unsubmitted_proposals.append(item) can_submit = len(self.unsubmitted_proposals) > 0 self.submit_ready_proposals_button.setEnabled(can_submit) num = len(self.unsubmitted_proposals) noun = 'proposal%s' % ('' if num == 1 else 's') article = 'is' if num == 1 else 'are' self.ready_proposals.setText( str(num) + _(' %s %s ready to be submitted.' % (noun, article))) self.ready_proposals.setVisible(can_submit) def create_proposal_from_widgets(self): """Get BudgetProposal keyword arguments from our widgets and instantiate one.""" kwargs = {} kwargs['proposal_name'] = str(self.name_edit.text()) kwargs['proposal_url'] = str(self.url_edit.text()) kwargs['start_block'] = self.start_block_edit.value() kwargs['address'] = str(self.address_edit.text()) kwargs['payment_amount'] = self.amount_edit.get_amount() proposal = BudgetProposal(**kwargs) # Assign end_block using the number of payments. proposal.set_payments_count(self.payments_count_edit.value()) # Raise if proposal is invalid. proposal.check_valid() return proposal def create_proposal(self): manager = self.parent.masternode_manager try: proposal = self.create_proposal_from_widgets() except Exception as e: return QMessageBox.critical(self, _('Error'), _(str(e))) pw = None if manager.wallet.use_encryption: pw = self.parent.password_dialog(msg=_( 'Please enter your password to create a budget proposal.')) if pw is None: return manager.add_proposal(proposal) def sign_done(proposal, tx): print_error('proposal tx sign done: %s' % proposal.proposal_name) if tx: label = _('Budget Proposal Tx: ') + proposal.proposal_name self.parent.broadcast_transaction(tx, label) self.parent.masternode_manager.save() self.create_proposal_tx(proposal, pw, sign_done) def create_proposal_tx(self, proposal, pw, callback): """Create and sign the proposal fee transaction.""" result = [False] def tx_thread(): return self.parent.masternode_manager.create_proposal_tx( proposal.proposal_name, pw, save=False) def on_tx_made(tx): result[0] = tx def on_done(): callback(proposal, result[0]) self.waiting_dialog = util.WaitingDialog(self, _('Creating Transaction...'), tx_thread, on_tx_made, on_done) self.waiting_dialog.start() def submit_waiting_proposals(self): """Submit the proposals that are ready to the network.""" # Submit the proposals that are ready. results = [('', '', False)] * len(self.unsubmitted_proposals) def submit_thread(): for i, (proposal_name, txid) in enumerate(self.unsubmitted_proposals): errmsg, success = self.parent.masternode_manager.submit_proposal( proposal_name, save=False) results[i] = (proposal_name, errmsg, success) if success: print_error('Sucessfully submitted proposal "%s"' % proposal_name) else: print_error('Failed to submit proposal "%s": %s' % (proposal_name, errmsg)) return results def on_done(): msg = '' for proposal_name, errmsg, success in results: if success: msg += '<b>' + proposal_name + '</b>' + _( ': submitted successfully.') else: msg += '<b>' + proposal_name + '</b>' + _( ': failed! "%s"' % errmsg) msg += '\n' QMessageBox.information(self, _('Results'), msg) self.update_unsubmitted_proposals() self.parent.masternode_manager.save() self.waiting_dialog = util.WaitingDialog(self, _('Submitting Proposals...'), submit_thread, on_complete=on_done) self.waiting_dialog.start()