diff --git a/electrum/gui/qt/contact_list.py b/electrum/gui/qt/contact_list.py index e1915b1b6..5c167f3ec 100644 --- a/electrum/gui/qt/contact_list.py +++ b/electrum/gui/qt/contact_list.py @@ -49,12 +49,8 @@ class ContactList(MyTreeView): def on_edited(self, idx, user_role, text): _type, prior_name = self.parent.contacts.pop(user_role) - - # TODO when min Qt >= 5.11, use siblingAtColumn - col_1_sibling = idx.sibling(idx.row(), 1) - col_1_item = self.model().itemFromIndex(col_1_sibling) - - self.parent.set_contact(text, col_1_item.text()) + self.parent.set_contact(text, user_role) + self.update() def import_contacts(self): import_meta_gui(self.parent, _('contacts'), self.parent.contacts.import_file, self.update) diff --git a/electrum/gui/qt/history_list.py b/electrum/gui/qt/history_list.py index 1a2fb30af..b50aaa7d9 100644 --- a/electrum/gui/qt/history_list.py +++ b/electrum/gui/qt/history_list.py @@ -67,9 +67,6 @@ class HistorySortModel(QSortFilterProxyModel): return False return item1.value() < item2.value() -# requires PyQt5 5.11 -indexIsValid = QAbstractItemModel.CheckIndexOptions(QAbstractItemModel.CheckIndexOption.IndexIsValid.value) - class HistoryModel(QAbstractItemModel): def __init__(self, parent): super().__init__(parent) @@ -80,14 +77,15 @@ class HistoryModel(QAbstractItemModel): return 8 def rowCount(self, parent: QModelIndex): - l = len(self.transactions) - return l + return len(self.transactions) def index(self, row: int, column: int, parent : QModelIndex): return self.createIndex(row,column) def data(self, index: QModelIndex, role: Qt.ItemDataRole): - assert self.checkIndex(index, indexIsValid) + # requires PyQt5 5.11 + # indexIsValid = QAbstractItemModel.CheckIndexOptions(QAbstractItemModel.CheckIndexOption.IndexIsValid.value) + # assert self.checkIndex(index, indexIsValid) assert index.isValid() tx_item = self.transactions[index.row()] tx_hash = tx_item['txid'] @@ -169,6 +167,10 @@ class HistoryModel(QAbstractItemModel): return self.parent.wallet.get_addresses() def refresh(self, reason: str): + selected = self.parent.history_list.selectionModel().currentIndex() + selected_row = None + if selected: + selected_row = selected.row() fx = self.parent.fx if fx: fx.history_used_spot = False r = self.parent.wallet.get_full_history(domain=self.get_domain(), from_timestamp=None, to_timestamp=None, fx=fx) @@ -182,6 +184,8 @@ class HistoryModel(QAbstractItemModel): self.beginInsertRows(QModelIndex(), 0, len(r['transactions'])-1) self.transactions = r['transactions'] self.endInsertRows() + if selected_row: + self.parent.history_list.selectionModel().select(self.createIndex(selected_row, 0), QItemSelectionModel.Rows | QItemSelectionModel.SelectCurrent) f = self.parent.history_list.current_filter if f: self.parent.history_list.filter(f) @@ -279,7 +283,6 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): self.proxy.setSourceModel(model) self.setModel(self.proxy) - self.summary = {} self.config = parent.config AcceptFileDragDrop.__init__(self, ".txn") self.setSortingEnabled(True) @@ -374,7 +377,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): return datetime.datetime(date.year, date.month, date.day) def show_summary(self): - h = self.summary + h = self.model().sourceModel().summary if not h: self.parent.show_message(_("Nothing to summarize.")) return @@ -425,7 +428,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): self.parent.show_message(str(e)) def on_edited(self, index, user_role, text): - print("on_edited") + index = self.model().mapToSource(index) row, column = index.row(), index.column() tx_item = self.hm.transactions[row] key = tx_item['txid'] @@ -438,7 +441,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): self.wallet.set_fiat_value(key, self.parent.fx.ccy, text, self.parent.fx, tx_item['value'].value) value = tx_item['value'].value if value is not None: - self.hm.update_fiat(row, self.model().mapToSource(index)) + self.hm.update_fiat(row, index) else: assert False @@ -472,7 +475,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): column_data = tx_item['txid'] else: column_title = self.hm.headerData(column, Qt.Horizontal, Qt.DisplayRole) - column_data = str(self.hm.data(idx, Qt.DisplayRole)) + column_data = self.hm.data(idx, Qt.DisplayRole).value() tx_hash = tx_item['txid'] tx = self.wallet.transactions[tx_hash] tx_URL = block_explorer_URL(self.config, 'tx', tx_hash) @@ -595,4 +598,4 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): def text_txid_from_coordinate(self, row, col): idx = self.model().mapToSource(self.model().index(row, col)) tx_item = self.hm.transactions[idx.row()] - return str(self.hm.data(idx, Qt.DisplayRole)), tx_item['txid'] + return self.hm.data(idx, Qt.DisplayRole).value(), tx_item['txid'] diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py index 7fba7ce67..c88b9e333 100644 --- a/electrum/gui/qt/util.py +++ b/electrum/gui/qt/util.py @@ -398,8 +398,23 @@ def filename_field(parent, config, defaultname, select_msg): return vbox, filename_e, b1 class ElectrumItemDelegate(QStyledItemDelegate): - def createEditor(self, parent, option, index): - return self.parent().createEditor(parent, option, index) + def __init__(self, tv): + super().__init__(tv) + self.tv = tv + self.opened = None + def on_closeEditor(editor: QLineEdit, hint): + self.opened = None + def on_commitData(editor: QLineEdit): + new_text = editor.text() + idx = QModelIndex(self.opened) + _prior_text, user_role = self.tv.text_txid_from_coordinate(idx.row(), idx.column()) + self.tv.on_edited(idx, user_role, new_text) + self.closeEditor.connect(on_closeEditor) + self.commitData.connect(on_commitData) + + def createEditor(self, parent, option, idx): + self.opened = QPersistentModelIndex(idx) + return super().createEditor(parent, option, idx) class MyTreeView(QTreeView): @@ -415,8 +430,6 @@ class MyTreeView(QTreeView): self.icon_cache = IconCache() # Control which columns are editable - self.editor = None - self.pending_update = False if editable_columns is None: editable_columns = {stretch_column} else: @@ -458,7 +471,9 @@ class MyTreeView(QTreeView): self.header().setSectionResizeMode(col, sm) def keyPressEvent(self, event): - if event.key() in [ Qt.Key_F2, Qt.Key_Return ] and self.editor is None: + if self.itemDelegate().opened: + return + if event.key() in [ Qt.Key_F2, Qt.Key_Return ]: self.on_activated(self.selectionModel().currentIndex()) return super().keyPressEvent(event) @@ -469,36 +484,6 @@ class MyTreeView(QTreeView): pt.setX(50) self.customContextMenuRequested.emit(pt) - def createEditor(self, parent, option, idx): - self.editor = QStyledItemDelegate.createEditor(self.itemDelegate(), - parent, option, idx) - prior_text, user_role = self.text_txid_from_coordinate(idx.row(), idx.column()) - def editing_finished(): - print("editing finished") - # Long-time QT bug - pressing Enter to finish editing signals - # editingFinished twice. If the item changed the sequence is - # Enter key: editingFinished, on_change, editingFinished - # Mouse: on_change, editingFinished - # This mess is the cleanest way to ensure we make the - # on_edited callback with the updated item - if self.editor is None: - return - if self.editor.text() == prior_text: - print("unchanged ignore any 2nd call") - self.editor = None # Unchanged - ignore any 2nd call - return - if not idx.isValid(): - print("idx not valid") - return - new_text, _ = self.text_txid_from_coordinate(idx.row(), idx.column()) - if new_text == prior_text: - print("buggy first call", new_text, prior_text) - return # Buggy first call on Enter key, item not yet updated - self.on_edited(idx, user_role, self.editor.text()) - self.editor = None - self.editor.editingFinished.connect(editing_finished) - return self.editor - def edit(self, idx, trigger=QAbstractItemView.AllEditTriggers, event=None): """ this is to prevent: @@ -509,7 +494,7 @@ class MyTreeView(QTreeView): def on_edited(self, idx: QModelIndex, user_role, text): self.parent.wallet.set_label(user_role, text) - self.parent.history_list.update_labels() + self.parent.history_model.refresh('on_edited in MyTreeView') self.parent.update_completions() def should_hide(self, row): @@ -523,7 +508,10 @@ class MyTreeView(QTreeView): assert not isinstance(self.model(), QSortFilterProxyModel) idx = self.model().index(row_num, column) item = self.model().itemFromIndex(idx) - return item.text(), item.data(Qt.UserRole) + user_role = item.data(Qt.UserRole) + # check that we didn't forget to set UserRole on an editable field + assert user_role is not None, (row_num, column) + return item.text(), user_role def hide_row(self, row_num): """ diff --git a/electrum/gui/qt/utxo_list.py b/electrum/gui/qt/utxo_list.py index 0b9d85508..046f30fc4 100644 --- a/electrum/gui/qt/utxo_list.py +++ b/electrum/gui/qt/utxo_list.py @@ -33,7 +33,7 @@ class UTXOList(MyTreeView): filter_columns = [0, 1] # Address, Label def __init__(self, parent=None): - super().__init__(parent, self.create_menu, 1) + super().__init__(parent, self.create_menu, 1, editable_columns=[]) self.setModel(QStandardItemModel(self)) self.setSelectionMode(QAbstractItemView.ExtendedSelection) self.setSortingEnabled(True) diff --git a/electrum/wallet.py b/electrum/wallet.py index a32888cf2..746f25cac 100644 --- a/electrum/wallet.py +++ b/electrum/wallet.py @@ -239,7 +239,7 @@ class Abstract_Wallet(AddressSynchronizer): self.labels[name] = text changed = True else: - if old_text: + if old_text is not None: self.labels.pop(name) changed = True if changed: