def switch_to(self, mode, wallet_name, recipient_wallet, time, password): window = self.wallet_windows[wallet_name] try: l = mode(window, self, wallet_name, recipient_wallet, time, password=password) tab = window.create_list_tab(l) destroyed_print_error(tab) # track object lifecycle finalization_print_error(tab) # track object lifecycle old_tab = self.lw_tabs.get(wallet_name) i = window.tabs.indexOf(old_tab) self.lw_tabs[wallet_name] = tab self.lw_tab[wallet_name] = l window.tabs.addTab(tab, self.icon(), _('Bitcoin Bileto')) if old_tab: window.tabs.removeTab(i) old_tab.searchable_list.deleteLater() old_tab.deleteLater( ) # Qt (and Python) will proceed to delete this widget except Exception as e: self.print_error(repr(e)) return
def create_window_for_wallet(self, wallet): w = ElectrumWindow(self, wallet) self.windows.append(w) finalization_print_error(w, "[{}] finalized".format(w.diagnostic_name())) self.build_tray_menu() run_hook('on_new_window', w) return w
def __init__(self, config, app, plugins, storage, partial_title='Install Wizard'): BaseWizard.__init__(self, config, storage) QDialog.__init__(self, None) self.setWindowTitle('Electron Cash SLP Edition - ' + _(partial_title)) self.app = app self.config = config # Set for base base class self.plugins = plugins self.setMinimumSize(600, 450) self.accept_signal.connect(self.accept) self.title = QLabel() self.main_widget = QWidget() self.back_button = QPushButton(_("Back"), self) self.back_button.setText( _('Back') if self.can_go_back() else _('Cancel')) self.next_button = QPushButton(_("Next"), self) self.next_button.setDefault(True) self.logo = QLabel() self.please_wait = QLabel(_("Please wait...")) self.please_wait.setAlignment(Qt.AlignCenter) self.icon_filename = None self.loop = QEventLoop() self.rejected.connect(lambda: self.loop.exit(0)) self.back_button.clicked.connect(lambda: self.loop.exit(1)) self.next_button.clicked.connect(lambda: self.loop.exit(2)) outer_vbox = QVBoxLayout(self) inner_vbox = QVBoxLayout() inner_vbox.addWidget(self.title) inner_vbox.addWidget(self.main_widget) inner_vbox.addStretch(1) inner_vbox.addWidget(self.please_wait) inner_vbox.addStretch(1) scroll_widget = QWidget() scroll_widget.setLayout(inner_vbox) scroll = QScrollArea() scroll.setWidget(scroll_widget) scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) scroll.setWidgetResizable(True) icon_vbox = QVBoxLayout() icon_vbox.addWidget(self.logo) icon_vbox.addStretch(1) hbox = QHBoxLayout() hbox.addLayout(icon_vbox) hbox.addSpacing(5) hbox.addWidget(scroll) hbox.setStretchFactor(scroll, 1) outer_vbox.addLayout(hbox) outer_vbox.addLayout(Buttons(self.back_button, self.next_button)) self.set_icon(':icons/electron-cash.svg') self.show() self.raise_() # Track object lifecycle finalization_print_error(self)
def __init__(self, config): super().__init__(None) # Top-level Object if Exception_Hook._instance: return # This is ok, we will be GC'd later. Exception_Hook._instance = self # strong reference to self should keep us alive until uninstall() is called self.config = config sys.excepthook = self.handler # yet another strong reference. We really won't die unless uninstall() is called self._report_exception.connect(_show_window) print_error("[{}] Installed.".format(__class__.__qualname__)) finalization_print_error(self, "[{}] Finalized.".format(__class__.__qualname__)) destroyed_print_error(self)
def _cleanup_keystore_extra(self, keystore): # awkward cleanup code for the keystore 'thread' object (qt.util.TaskThread object) # we have to do it this way so as to avoid relying on and/or importing gui.qt finalization_print_error(keystore) # track object lifecycle thread = getattr(keystore, 'thread', None) if thread and all( hasattr(thread, attr) for attr in ('isRunning', 'stop')) and thread.isRunning(): # was a Qt TaskThread, kill it, and wait up to 5 seconds for it to stop thread.stop(waitTime=5.0)
def __init__( self, bip38_keys, *, parent=None, title=None, message=None, # The message to display as a label up top show_count=True, # If false, don't show 'Key 1/n:' in UI instead just say: 'Key: ' on_success=None, # Callback will be called with a dict of bip38key -> (decoded_wif_str, Address) objects on_cancel=None): # Callback will be called if user hits cancel ''' bip38_keys should be a list of '6P' strings, representing bip38 keys. The user will be prompted for each key to enter a password and will be shown the decoded address and WIF key. Note that this method will raise RuntimeError if not bitcion.is_bip38_available(). on_success: if specified, will be called after the window has closed (exec_ has finished) with a single argument: a dict of bip38key -> (decoded_wif, Address). on_cancel: if specified, will be called after the window was closed (exec_ has finished) with no arguments. If you don't specify any callbacks, results are still available in the self.decoded_keys dict. The dialog will always terminate with either all keys successfully decrypted or a user cancel. ''' if not title: title = f'{PROJECT_NAME} - ' + _('BIP38 Import') WindowModalDialog.__init__(self, parent=parent, title=title) if not bitcoin.is_bip38_available(): raise RuntimeError( 'Bip38Importer: bip38 decoding is not available') self.bip38_keys = tuple(bip38_keys) assert self.bip38_keys and all( bitcoin.is_bip38_key(k) for k in self.bip38_keys) if not parent: self.setWindowModality(Qt.ApplicationModal) self.decoded_keys = dict() # results are placed here on success self.success_cb, self.cancel_cb = on_success, on_cancel self.cur, self.decoded_wif, self.decoded_address = 0, None, None self.decrypter = None self.show_count = show_count self.decrypted_sig.connect(self.on_decrypted) self._setup_ui(message) util.finalization_print_error(self)
def __init__(self, config): super().__init__() self.dialog: Optional[ExceptionDialog] = None if ExceptionHook._instance is not None: # This is ok, we will be GC'd later. return # strong reference to self keeps us alive until uninstall() is called ExceptionHook._instance = self self.config = config sys.excepthook = self.handler self._report_exception.connect(self._show_window) print_error(f"[{__class__.__qualname__}] Installed.") finalization_print_error(self, f"[{__class__.__qualname__}] Finalized.") destroyed_print_error(self)
def ShowPopupLabel(text, target, timeout, name="Global", pointer_position=PopupWidget.RightSide, opacity=0.9, onClick=None, onRightClick=None, activation_hides=True, track_target=True, dark_mode=False): assert isinstance(name, str) and isinstance(text, str) and isinstance(target, QWidget) and isinstance(timeout, (float, int)), "Invalid parameters" window = target.window() if not window.isActiveWindow(): return False KillPopupLabel(name) popup = PopupLabel(text, window, timeout=timeout, delete_on_hide=True, activation_hides=activation_hides, dark_mode=dark_mode) popup.setPointerPosition(pointer_position) popup.final_opacity = opacity popup.setObjectName(str(id(popup))) def onDestroyed(x): # NB: even though x and popup are the same object, they will have different id() at this point (I think this is because Qt destructed the python object stub and is passing us a reference to the QWidget base here.) xid = None try: xid = int(x.objectName()) except (ValueError,TypeError): pass if xid == id(_extant_popups.get(name, None)): # Clean up the dict entry _extant_popups.pop(name, None) #print("----> Destroyed and cleaned up:",name) else: # Stale object or already removed from dict. No need to clean up the dict entry pass #print("----> Not found!!") if track_target: class MyEventFilter(QObject): ''' Traps target move events and moves the popup to line up with the target ''' def eventFilter(self, obj, e): lbl = self.parent() if e.type() in (QEvent.Move, QEvent.Resize) and isinstance(lbl, PopupLabel): # track the target, moving us along with it if its geometry changes lbl.moveRelativeTo(obj) return False popup.my_e_filter = MyEventFilter(popup) target.installEventFilter(popup.my_e_filter) popup.destroyed.connect(onDestroyed) destroyed_print_error(popup, "[PopupLabel/{}] destroyed".format(name)) finalization_print_error(popup, "[PopupLabel/{}] finalized".format(name)) _extant_popups[name] = popup if onClick: popup.onClick.connect(onClick, Qt.QueuedConnection) if onRightClick: popup.onRightClick.connect(onRightClick, Qt.QueuedConnection) popup.showRelativeTo(target) return True
def ShowPopupLabel(text, target, timeout, name="Global", pointer_position=PopupWidget.RightSide, opacity=0.9, onClick=None, onRightClick=None): assert isinstance(name, str) and isinstance(text, str) and isinstance( target, QWidget) and isinstance(timeout, (float, int)), "Invalid parameters" window = target.window() if not window.isActiveWindow(): return False KillPopupLabel(name) popup = PopupLabel(text, window, timeout=timeout, delete_on_hide=True) popup.setPointerPosition(pointer_position) popup.final_opacity = opacity popup.setObjectName(str(id(popup))) def onDestroyed(x): # NB: even though x and popup are the same object, they will have different id() at this point (I think this is because Qt destructed the python object stub and is passing us a reference to the QWidget base here.) xid = None try: xid = int(x.objectName()) except (ValueError, TypeError): pass if xid == id(_extant_popups.get(name, None)): # Clean up the dict entry _extant_popups.pop(name, None) #print("----> Destroyed and cleaned up:",name) else: # Stale object or already removed from dict. No need to clean up the dict entry pass #print("----> Not found!!") popup.destroyed.connect(onDestroyed) destroyed_print_error(popup, "[PopupLabel/{}] destroyed".format(name)) finalization_print_error(popup, "[PopupLabel/{}] finalized".format(name)) _extant_popups[name] = popup if onClick: popup.onClick.connect(onClick, Qt.QueuedConnection) if onRightClick: popup.onRightClick.connect(onRightClick, Qt.QueuedConnection) popup.showRelativeTo(target) return True
def multiple_result_picker(parent, results, wallet=None, msg=None, title=None, gbtext=None): ''' Pops up a modal dialog telling you to pick a results. Used by the Contacts tab edit function, etc. ''' assert parent from .main_window import ElectrumWindow if isinstance(parent, ElectrumWindow) and not wallet: wallet = parent.wallet assert isinstance(wallet, Abstract_Wallet) msg = msg or _( 'Multiple results were found, please select an option from the items below:' ) title = title or _("Select Cash Account") d = WindowModalDialog(parent, title) util.finalization_print_error(d) # track object lifecycle destroyed_print_error(d) vbox = QVBoxLayout(d) lbl = WWLabel(msg) vbox.addWidget(lbl) gb = InfoGroupBox(d, parent, results) vbox.addWidget(gb) ok_but = OkButton(d) buts = Buttons(CancelButton(d), ok_but) vbox.addLayout(buts) ok_but.setEnabled(False) but_grp = gb.buttonGroup() but_grp.buttonClicked.connect( lambda x=None: ok_but.setEnabled(gb.selectedItem() is not None)) code = d.exec_() if code == QDialog.Accepted: item = gb.selectedItem() if item: return item[:-1]
def __init__(self, parent, message, task, on_success=None, on_error=None, auto_cleanup=True, *, auto_show=True, auto_exec=False, title=None, disable_escape_key=False): assert parent if isinstance(parent, MessageBoxMixin): parent = parent.top_level_window() WindowModalDialog.__init__(self, parent, title or _("Please wait")) self.auto_cleanup = auto_cleanup self.disable_escape_key = disable_escape_key self._vbox = vbox = QVBoxLayout(self) self._label = label = QLabel(message) vbox.addWidget(label) self.accepted.connect(self.on_accepted) self.rejected.connect(self.on_rejected) if auto_show and not auto_exec: self.open() self.thread = TaskThread(self) self.thread.add(task, on_success, self.accept, on_error) if auto_exec: self.exec_() finalization_print_error(self) # track object lifecycle
def switch_to(self, mode, wallet_name, password, manager): window=self.wallet_windows[wallet_name] try: l = mode(window, self, wallet_name, password=password, manager=manager) tab = window.create_list_tab(l) destroyed_print_error(tab) # track object lifecycle finalization_print_error(tab) # track object lifecycle old_tab = self.mecenas_tabs.get(wallet_name, None) i = window.tabs.indexOf(old_tab) self.mecenas_tabs[wallet_name] = tab self.mecenas_tab[wallet_name] = l if old_tab: window.tabs.removeTab(i) old_tab.searchable_list.deleteLater() old_tab.deleteLater() window.tabs.insertTab(i,tab, self._get_icon(), _('Mecenas')) window.tabs.setCurrentIndex(i) except Exception as e: self.print_error(repr(e)) return
def __init__(self, main_window, token_id_hex=None, token_name=None, allow_overwrite=False): # We want to be a top-level window QDialog.__init__(self, parent=None) from .main_window import ElectrumWindow assert isinstance(main_window, ElectrumWindow) main_window._slp_dialogs.add(self) finalization_print_error(self) # Track object lifecycle self.provided_token_name = token_name self.allow_overwrite = allow_overwrite self.main_window = main_window self.wallet = main_window.wallet self.network = main_window.network self.app = main_window.app if self.main_window.gui_object.warn_if_no_network(self.main_window): return if self.provided_token_name: self.setWindowTitle(_("SLP Token Details")) else: self.setWindowTitle(_("Add SLP Token")) vbox = QVBoxLayout() self.setLayout(vbox) vbox.addWidget(QLabel(_('Token ID:'))) self.token_id_e = ButtonsLineEdit() if token_id_hex is not None: self.token_id_e.addCopyButton() vbox.addWidget(self.token_id_e) hbox = QHBoxLayout() vbox.addLayout(hbox) hbox.addWidget(QLabel(_('Genesis transaction information:'))) self.get_info_button = b = QPushButton(_("Download")) b.clicked.connect(self.download_info) hbox.addWidget(b) self.load_tx_menu_button = b = QPushButton(_("Load...")) menu = QMenu() menu.addAction(_("&From file"), self.do_process_from_file) menu.addAction(_("&From text"), self.do_process_from_text) menu.addAction(_("&From QR code"), self.read_tx_from_qrcode) b.setMenu(menu) hbox.addWidget(b) self.view_tx_button = b = QPushButton(_("View Tx")) b.clicked.connect(self.view_tx) b.setDisabled(True) hbox.addWidget(b) hbox.addStretch(1) self.token_info_e = QTextBrowser() self.token_info_e.setOpenExternalLinks(True) self.token_info_e.setMinimumHeight(100) vbox.addWidget(self.token_info_e) hbox = QHBoxLayout() vbox.addLayout(hbox) warnpm = QIcon(":icons/warning.png").pixmap(20, 20) l = QLabel() l.setPixmap(warnpm) hbox.addWidget(l) hbox.addWidget( QLabel( _('Avoid counterfeits—carefully compare the token ID with a trusted source.' ))) l = QLabel() l.setPixmap(warnpm) hbox.addWidget(l) if self.provided_token_name is None: namelabel = QLabel( _('To use tokens with this ID, assign it a name.')) namelabel.setAlignment(Qt.AlignRight) vbox.addWidget(namelabel) hbox = QHBoxLayout() vbox.addLayout(hbox) self.cancel_button = b = QPushButton(_("Cancel")) self.cancel_button.setAutoDefault(False) self.cancel_button.setDefault(False) b.clicked.connect(self.close) b.setDefault(True) hbox.addWidget(self.cancel_button) hbox.addStretch(1) hbox.addWidget(QLabel(_('Name in wallet:'))) self.token_name_e = QLineEdit() self.token_name_e.setFixedWidth(200) if self.provided_token_name is not None: self.token_name_e.setText(self.provided_token_name) hbox.addWidget(self.token_name_e) self.add_button = b = QPushButton( _("Add") if self.provided_token_name is None else _("Change")) b.clicked.connect(self.add_token) self.add_button.setAutoDefault(True) self.add_button.setDefault(True) b.setDisabled(True) hbox.addWidget(self.add_button) if token_id_hex is not None: self.token_id_e.setText(token_id_hex) self.download_info() self.got_network_response_sig.connect(self.got_network_response_slot, Qt.QueuedConnection) self.update() dialogs.append(self) self.show() self.token_name_e.setFocus()
def _cleanup_keystore_extra(self, keystore): # awkward cleanup code for the keystore 'thread' object (see qt.py) finalization_print_error(keystore) # track object lifecycle if callable(getattr(keystore.thread, 'stop', None)): keystore.thread.stop()
def __init__(self, main_window, token_id_hex, token_name): QDialog.__init__(self, parent=None) from .main_window import ElectrumWindow assert isinstance(main_window, ElectrumWindow) main_window._slp_dialogs.add(self) finalization_print_error(self) # Track object lifecycle self.main_window = main_window self.wallet = main_window.wallet self.network = main_window.network self.app = main_window.app if self.main_window.gui_object.warn_if_no_network(self.main_window): return self.baton_txo = None try: self.baton_txo = self.main_window.wallet.get_slp_token_baton(token_id_hex) except SlpNoMintingBatonFound: pass self.setWindowTitle(_("Burn Tokens")) vbox = QVBoxLayout() self.setLayout(vbox) grid = QGridLayout() grid.setColumnStretch(1, 1) vbox.addLayout(grid) row = 0 grid.addWidget(QLabel(_('Name:')), row, 0) self.token_name = QLineEdit() self.token_name.setFixedWidth(490) self.token_name.setText(token_name) self.token_name.setDisabled(True) grid.addWidget(self.token_name, row, 1) row += 1 msg = _('Unique identifier for the token.') grid.addWidget(HelpLabel(_('Token ID:'), msg), row, 0) self.token_id_e = QLineEdit() self.token_id_e.setFixedWidth(490) self.token_id_e.setText(token_id_hex) self.token_id_e.setDisabled(True) grid.addWidget(self.token_id_e, row, 1) row += 1 msg = _('The number of decimal places used in the token quantity.') grid.addWidget(HelpLabel(_('Decimals:'), msg), row, 0) self.token_dec = QDoubleSpinBox() decimals = self.main_window.wallet.token_types.get(token_id_hex)['decimals'] self.token_dec.setRange(0, 9) self.token_dec.setValue(decimals) self.token_dec.setDecimals(0) self.token_dec.setFixedWidth(50) self.token_dec.setDisabled(True) grid.addWidget(self.token_dec, row, 1) row += 1 hbox = QHBoxLayout() msg = _('The number of tokens to be destroyed for this token.') grid.addWidget(HelpLabel(_('Burn Amount:'), msg), row, 0) name = self.main_window.wallet.token_types.get(token_id_hex)['name'] self.token_qty_e = SLPAmountEdit(name, int(decimals)) self.token_qty_e.setFixedWidth(200) #self.token_qty_e.textChanged.connect(self.check_token_qty) hbox.addWidget(self.token_qty_e) self.max_button = EnterButton(_("Max"), self.burn_max) self.max_button.setFixedWidth(140) #self.max_button.setCheckable(True) hbox.addWidget(self.max_button) hbox.addStretch(1) grid.addLayout(hbox, row, 1) row += 1 hbox = QHBoxLayout() vbox.addLayout(hbox) self.token_burn_baton_cb = cb = QCheckBox(_("Burn Minting Baton")) self.token_burn_baton_cb.setChecked(False) self.token_burn_baton_cb.setDisabled(True) grid.addWidget(self.token_burn_baton_cb, row, 0) if self.baton_txo != None: self.token_burn_baton_cb.setDisabled(False) self.token_burn_invalid_cb = cb = QCheckBox(_("Burn invalid SLP transactions for this token")) self.token_burn_invalid_cb.setChecked(True) grid.addWidget(self.token_burn_invalid_cb, row, 1) row += 1 self.cancel_button = b = QPushButton(_("Cancel")) self.cancel_button.setAutoDefault(True) self.cancel_button.setDefault(True) b.clicked.connect(self.close) b.setDefault(True) hbox.addWidget(self.cancel_button) hbox.addStretch(1) self.preview_button = EnterButton(_("Preview"), self.do_preview) self.burn_button = b = QPushButton(_("Burn Tokens")) b.clicked.connect(self.burn_token) self.burn_button.setAutoDefault(False) self.burn_button.setDefault(False) hbox.addWidget(self.preview_button) hbox.addWidget(self.burn_button) dialogs.append(self) self.show() self.token_qty_e.setFocus()
def __init__(self, parent): super().__init__(parent) util.finalization_print_error(self) warning_fmt = '<h1 align="center">{0}</h1><p align=center><font size=-1>{1} {2}</font></p><p align=center><font size=-1><a href="{3}" {5}>{3}</a></font></p><p align="center">{4}</p>' warning_text = warning_fmt.format( _('WARNING'), _('Do not enter code here that you don\'t understand. Executing the wrong code could ' 'lead to your coins being irreversibly lost.'), _("If someone you do not trust wants you to enter something here, that person might " "be attempting a social engineering / phishing attack on you."), 'https://en.wikipedia.org/wiki/Social_engineering_(security)', _("Type: '{}' below to proceed").format('<b>' + self.CONFIRM_TEXT + '</b>'), 'style="color: #3399ff;"' if ColorScheme.dark_scheme else '', ) style_sheet = self.STYLESHEET_DARK if ColorScheme.dark_scheme else self.STYLESHEET style_sheet = style_sheet + self.STYLESHEET_COMMON style_sheet = style_sheet + self.STYLESHEET_BORDER_RADIUS self.setStyleSheet(style_sheet) layout = QtWidgets.QVBoxLayout() layout.setContentsMargins(35,35,35,35) self.setLayout(layout) warning_label = QtWidgets.QLabel(warning_text) warning_label.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) warning_label.setWordWrap(True) warning_label.setOpenExternalLinks(True) layoutLbl = QtWidgets.QVBoxLayout() layoutLbl.addWidget(warning_label) layout.addLayout(layoutLbl, 1) if not ColorScheme.dark_scheme: drop_shadow_effect = QtWidgets.QGraphicsDropShadowEffect() drop_shadow_effect.setBlurRadius(5.0) drop_shadow_effect.setOffset(2.0, 2.0) drop_shadow_effect.setColor(QtGui.QColor(63,63,63,100)) warning_label.setGraphicsEffect(drop_shadow_effect) hbox_layout = QtWidgets.QHBoxLayout() layout.addLayout(hbox_layout) fixed = QtWidgets.QSizePolicy.Fixed hbox_layout.addSpacerItem(QtWidgets.QSpacerItem(self.BORDER_RADIUS, 0, fixed, fixed)) self.input_edit = QtWidgets.QLineEdit() self.input_edit.textChanged.connect(self.on_text_changed) self.input_edit.returnPressed.connect(self.on_confirm) hbox_layout.addWidget(self.input_edit) self.confirm_btn = QtWidgets.QPushButton(_("&Confirm")) self.confirm_btn.setEnabled(False) self.confirm_btn.clicked.connect(self.on_confirm) hbox_layout.addWidget(self.confirm_btn) self.dontaskagain_cbx = QtWidgets.QCheckBox(_("&Don't ask again")) hbox_layout.addWidget(self.dontaskagain_cbx) hbox_layout.addSpacerItem(QtWidgets.QSpacerItem(self.BORDER_RADIUS, 0, fixed, fixed))
def __init__(self, main_window, token_id_hex): # We want to be a top-level window QDialog.__init__(self, parent=None) from .main_window import ElectrumWindow assert isinstance(main_window, ElectrumWindow) main_window._slp_dialogs.add(self) finalization_print_error(self) # Track object lifecycle self.main_window = main_window self.wallet = main_window.wallet self.network = main_window.network self.app = main_window.app if self.main_window.gui_object.warn_if_no_network(self.main_window): return self.setWindowTitle(_("Mint Additional Tokens")) vbox = QVBoxLayout() self.setLayout(vbox) grid = QGridLayout() grid.setColumnStretch(1, 1) vbox.addLayout(grid) row = 0 msg = _('Unique identifier for the token.') grid.addWidget(HelpLabel(_('Token ID:'), msg), row, 0) self.token_id_e = QLineEdit() self.token_id_e.setFixedWidth(490) self.token_id_e.setText(token_id_hex) self.token_id_e.setDisabled(True) grid.addWidget(self.token_id_e, row, 1) row += 1 msg = _('The number of decimal places used in the token quantity.') grid.addWidget(HelpLabel(_('Decimals:'), msg), row, 0) self.token_dec = QDoubleSpinBox() decimals = self.main_window.wallet.token_types.get( token_id_hex)['decimals'] self.token_dec.setRange(0, 9) self.token_dec.setValue(decimals) self.token_dec.setDecimals(0) self.token_dec.setFixedWidth(50) self.token_dec.setDisabled(True) grid.addWidget(self.token_dec, row, 1) row += 1 msg = _( 'The number of tokens created during token minting transaction, send to the receiver address provided below.' ) grid.addWidget(HelpLabel(_('Additional Token Quantity:'), msg), row, 0) name = self.main_window.wallet.token_types.get(token_id_hex)['name'] self.token_qty_e = SLPAmountEdit(name, int(decimals)) self.token_qty_e.setFixedWidth(200) self.token_qty_e.textChanged.connect(self.check_token_qty) grid.addWidget(self.token_qty_e, row, 1) row += 1 msg = _( 'The simpleledger formatted bitcoin address for the genesis receiver of all genesis tokens.' ) grid.addWidget(HelpLabel(_('Token Receiver Address:'), msg), row, 0) self.token_pay_to_e = ButtonsLineEdit() self.token_pay_to_e.setFixedWidth(490) grid.addWidget(self.token_pay_to_e, row, 1) row += 1 msg = _( 'The simpleledger formatted bitcoin address for the genesis baton receiver.' ) self.token_baton_label = HelpLabel(_('Mint Baton Address:'), msg) grid.addWidget(self.token_baton_label, row, 0) self.token_baton_to_e = ButtonsLineEdit() self.token_baton_to_e.setFixedWidth(490) grid.addWidget(self.token_baton_to_e, row, 1) row += 1 try: slpAddr = self.wallet.get_unused_address().to_slpaddr() self.token_pay_to_e.setText( Address.prefix_from_address_string(slpAddr) + ":" + slpAddr) self.token_baton_to_e.setText( Address.prefix_from_address_string(slpAddr) + ":" + slpAddr) except Exception as e: pass self.token_fixed_supply_cb = cb = QCheckBox( _('Permanently end issuance')) self.token_fixed_supply_cb.setChecked(False) grid.addWidget(self.token_fixed_supply_cb, row, 0) cb.clicked.connect(self.show_mint_baton_address) row += 1 hbox = QHBoxLayout() vbox.addLayout(hbox) self.cancel_button = b = QPushButton(_("Cancel")) self.cancel_button.setAutoDefault(False) self.cancel_button.setDefault(False) b.clicked.connect(self.close) b.setDefault(True) hbox.addWidget(self.cancel_button) hbox.addStretch(1) self.preview_button = EnterButton(_("Preview"), self.do_preview) self.mint_button = b = QPushButton(_("Create Additional Tokens")) b.clicked.connect(self.mint_token) self.mint_button.setAutoDefault(True) self.mint_button.setDefault(True) hbox.addWidget(self.preview_button) hbox.addWidget(self.mint_button) dialogs.append(self) self.show() self.token_qty_e.setFocus()
def __init__(self, main_window, *, nft_parent_id=None): #self.provided_token_name = token_name # We want to be a top-level window QDialog.__init__(self, parent=None) from .main_window import ElectrumWindow assert isinstance(main_window, ElectrumWindow) main_window._slp_dialogs.add(self) finalization_print_error(self) # track object lifecycle self.main_window = main_window self.wallet = main_window.wallet self.config = main_window.config self.network = main_window.network self.app = main_window.app self.nft_parent_id = nft_parent_id if nft_parent_id != None: self.token_type = 65 else: self.token_type = 1 if self.main_window.gui_object.warn_if_no_network(self.main_window): return self.setWindowTitle(_("Create a New Token")) vbox = QVBoxLayout() self.setLayout(vbox) grid = QGridLayout() grid.setColumnStretch(1, 1) vbox.addLayout(grid) row = 0 msg = _( 'An optional name string embedded in the token genesis transaction.' ) grid.addWidget(HelpLabel(_('Token Name (optional):'), msg), row, 0) self.token_name_e = QLineEdit() grid.addWidget(self.token_name_e, row, 1) row += 1 msg = _( 'An optional ticker symbol string embedded into the token genesis transaction.' ) grid.addWidget(HelpLabel(_('Ticker Symbol (optional):'), msg), row, 0) self.token_ticker_e = QLineEdit() self.token_ticker_e.setFixedWidth(110) self.token_ticker_e.textChanged.connect(self.upd_token) grid.addWidget(self.token_ticker_e, row, 1) row += 1 msg = _( 'An optional URL string embedded into the token genesis transaction.' ) grid.addWidget(HelpLabel(_('Document URL (optional):'), msg), row, 0) self.token_url_e = QLineEdit() self.token_url_e.setFixedWidth(560) self.token_url_e.textChanged.connect(self.upd_token) grid.addWidget(self.token_url_e, row, 1) row += 1 msg = _('An optional hash hexidecimal bytes embedded into the token genesis transaction for hashing') \ + 'the document file contents at the URL provided above.' grid.addWidget(HelpLabel(_('Document Hash (optional):'), msg), row, 0) self.token_dochash_e = QLineEdit() self.token_dochash_e.setInputMask( "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH") self.token_dochash_e.setFixedWidth(560) self.token_dochash_e.textChanged.connect(self.upd_token) grid.addWidget(self.token_dochash_e, row, 1) row += 1 msg = _('Sets the number of decimals of divisibility for this token (embedded into genesis).') \ + '\n\n' \ + _('Each 1 token is divisible into 10^(decimals) base units, and internally in the protocol') \ + _('the token amounts are represented as 64-bit integers measured in these base units.') grid.addWidget(HelpLabel(_('Decimal Places:'), msg), row, 0) self.token_ds_e = QDoubleSpinBox() self.token_ds_e.setRange(0, 9) self.token_ds_e.setDecimals(0) self.token_ds_e.setFixedWidth(50) self.token_ds_e.valueChanged.connect(self.upd_token) grid.addWidget(self.token_ds_e, row, 1) row += 1 msg = _('The number of tokens created during token genesis transaction,') \ + _('send to the receiver address provided below.') if nft_parent_id == None: self.token_qty_label = HelpLabel(_('Token Quantity:'), msg) else: self.token_qty_label = HelpLabel(_('Number of Child NFTs:'), msg) grid.addWidget(self.token_qty_label, row, 0) self.token_qty_e = SLPAmountEdit('', 0) self.token_qty_e.setFixedWidth(200) self.token_qty_e.textChanged.connect(self.check_token_qty) grid.addWidget(self.token_qty_e, row, 1) row += 1 msg = _( 'The \'simpleledger:\' formatted bitcoin address for the genesis receiver of all genesis tokens.' ) grid.addWidget(HelpLabel(_('Token Receiver Address:'), msg), row, 0) self.token_pay_to_e = ButtonsLineEdit() self.token_pay_to_e.setFixedWidth(560) grid.addWidget(self.token_pay_to_e, row, 1) row += 1 self.token_fixed_supply_cb = cb = QCheckBox(_('Fixed Supply')) self.token_fixed_supply_cb.setChecked(True) grid.addWidget(self.token_fixed_supply_cb, row, 1) cb.clicked.connect(self.show_mint_baton_address) row += 1 self.token_nft_parent_cb = cb = QCheckBox(_('Is NFT Parent?')) self.token_nft_parent_cb.setChecked(False) grid.addWidget(self.token_nft_parent_cb, row, 1) cb.clicked.connect(self.token_nft_parent_cb_update) row += 1 if self.nft_parent_id: self.token_nft_parent_cb.setDisabled(True) self.token_fixed_supply_cb.setDisabled(True) self.token_qty_e.setAmount(1) self.token_qty_e.setDisabled(True) self.token_ds_e.setDisabled(True) msg = _('The \'simpleledger:\' formatted bitcoin address for the "minting baton" receiver.') + '\n\n' \ + _('After the genesis transaction, further unlimited minting operations can be performed by the owner of') \ + ' the "minting baton" transaction output. This baton can be repeatedly used for minting operations but' \ + ' it cannot be duplicated.' self.token_baton_label = HelpLabel(_('Address for Baton:'), msg) self.token_baton_label.setHidden(True) grid.addWidget(self.token_baton_label, row, 0) self.token_baton_to_e = ButtonsLineEdit() self.token_baton_to_e.setFixedWidth(560) self.token_baton_to_e.setHidden(True) grid.addWidget(self.token_baton_to_e, row, 1) row += 1 try: slpAddr = self.wallet.get_unused_address().to_slpaddr() self.token_pay_to_e.setText( Address.prefix_from_address_string(slpAddr) + ":" + slpAddr) self.token_baton_to_e.setText( Address.prefix_from_address_string(slpAddr) + ":" + slpAddr) except Exception as e: pass if nft_parent_id: nft_parent_coin = get_nft_parent_coin(nft_parent_id, main_window) if not get_nft_parent_coin(nft_parent_id, main_window): hbox2 = QHBoxLayout() vbox.addLayout(hbox2) warnpm = QIcon(":icons/warning.png").pixmap(20, 20) self.warn1 = l = QLabel() l.setPixmap(warnpm) hbox2.addWidget(l) self.warn_msg = msg = QLabel( _(" NOTE: The parent token needs to be split before a new NFT can be created, click 'Prepare Group Parent'." )) hbox2.addWidget(msg) self.warn2 = l = QLabel() l.setPixmap(warnpm) hbox2.addStretch(1) hbox2.addWidget(l) hbox = QHBoxLayout() vbox.addLayout(hbox) self.cancel_button = b = QPushButton(_("Cancel")) self.cancel_button.setAutoDefault(False) self.cancel_button.setDefault(False) b.clicked.connect(self.close) hbox.addWidget(self.cancel_button) hbox.addStretch(1) # self.hash_button = b = QPushButton(_("Compute Document Hash...")) # self.hash_button.setAutoDefault(False) # self.hash_button.setDefault(False) # b.clicked.connect(self.hash_file) # b.setDefault(True) # hbox.addWidget(self.hash_button) self.tok_doc_button = b = QPushButton(_("Upload a Token Document...")) self.tok_doc_button.setAutoDefault(False) self.tok_doc_button.setDefault(False) b.clicked.connect(self.show_upload) b.setDefault(True) hbox.addWidget(self.tok_doc_button) if nft_parent_id: self.import_burn_tx_file_button = EnterButton( _("Import file..."), self.do_process_from_file) self.import_burn_tx_text_button = EnterButton( _("Import hex..."), self.do_process_from_text) hbox.addWidget(self.import_burn_tx_file_button) hbox.addWidget(self.import_burn_tx_text_button) self.preview_button = EnterButton(_("Preview"), self.do_preview) hbox.addWidget(self.preview_button) self.create_button = b = QPushButton( _("Create New Token" )) #if self.provided_token_name is None else _("Change")) b.clicked.connect(self.create_token) self.create_button.setAutoDefault(True) self.create_button.setDefault(True) hbox.addWidget(self.create_button) if nft_parent_id: self.create_button.setText("Create NFT") if not nft_parent_coin: self.create_button.setHidden(True) self.prepare_parent_bttn = QPushButton( _("Prepare Group Parent")) self.prepare_parent_bttn.clicked.connect( self.prepare_nft_parent) self.prepare_parent_bttn.setAutoDefault(True) self.prepare_parent_bttn.setDefault(True) hbox.addWidget(self.prepare_parent_bttn) self.token_name_e.setDisabled(True) self.token_ticker_e.setDisabled(True) self.token_url_e.setDisabled(True) self.token_dochash_e.setDisabled(True) self.token_pay_to_e.setDisabled(True) self.token_baton_to_e.setDisabled(True) dialogs.append(self) self.show() self.token_name_e.setFocus()