292 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			292 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import enum
 | |
| import json
 | |
| import urllib.request
 | |
| import urllib.parse
 | |
| 
 | |
| from . import qt_resources
 | |
| if qt_resources.QT_VERSION == 5:
 | |
|     from PyQt5.QtGui import QStandardItemModel, QStandardItem
 | |
|     from PyQt5.QtCore import Qt,QPersistentModelIndex, QModelIndex
 | |
|     from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,QMenu)
 | |
| else:
 | |
|     from PyQt6.QtGui import QStandardItemModel, QStandardItem
 | |
|     from PyQt6.QtCore import Qt,QPersistentModelIndex, QModelIndex
 | |
|     from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,QMenu)
 | |
| 
 | |
| 
 | |
| from electrum.i18n import _
 | |
| from electrum.gui.qt.util import (Buttons,read_QIcon, import_meta_gui, export_meta_gui,MessageBoxMixin)
 | |
| from electrum.util import write_json_file,read_json_file
 | |
| from electrum.gui.qt.my_treeview import MyTreeView
 | |
| 
 | |
| from ..bal import BalPlugin
 | |
| from .. import util as Util
 | |
| from .. import willexecutors as Willexecutors
 | |
| from .baldialog import BalDialog,BalBlockingWaitingDialog
 | |
| from electrum.logging import get_logger,Logger
 | |
| 
 | |
| _logger=get_logger(__name__)
 | |
| class WillExecutorList(MyTreeView):
 | |
|     class Columns(MyTreeView.BaseColumnsEnum):
 | |
|         SELECTED = enum.auto()
 | |
|         URL = enum.auto()
 | |
|         BASE_FEE = enum.auto()
 | |
|         INFO = enum.auto()
 | |
|         ADDRESS = enum.auto()
 | |
|         STATUS = enum.auto()
 | |
| 
 | |
|     headers = {
 | |
|         Columns.SELECTED:_(''),
 | |
|         Columns.URL: _('Url'),
 | |
|         Columns.BASE_FEE: _('Base fee'),
 | |
|         Columns.INFO:_('Info'),
 | |
|         Columns.ADDRESS:_('Default Address'),
 | |
|         Columns.STATUS: _('S'),
 | |
|     }
 | |
| 
 | |
|     ROLE_HEIR_KEY = Qt.ItemDataRole.UserRole + 2000
 | |
|     key_role = ROLE_HEIR_KEY
 | |
| 
 | |
|     def __init__(self, parent: 'WillExecutorDialog'):
 | |
|         super().__init__(
 | |
|             parent=parent,
 | |
|             stretch_column=self.Columns.ADDRESS,
 | |
|             editable_columns=[self.Columns.URL,self.Columns.BASE_FEE,self.Columns.ADDRESS,self.Columns.INFO],
 | |
| 
 | |
|         )
 | |
|         self.parent = parent
 | |
|         self.setModel(QStandardItemModel(self))
 | |
|         self.setSortingEnabled(True)
 | |
|         self.std_model = self.model()
 | |
|         self.config =parent.bal_plugin.config
 | |
|            
 | |
| 
 | |
|         self.update()
 | |
| 
 | |
| 
 | |
| 
 | |
|     def create_menu(self, position):
 | |
|         menu = QMenu()
 | |
|         idx = self.indexAt(position)
 | |
|         column = idx.column() or self.Columns.URL
 | |
|         selected_keys = []
 | |
|         for s_idx in self.selected_in_column(self.Columns.URL):
 | |
|             sel_key = self.model().itemFromIndex(s_idx).data(0)
 | |
|             selected_keys.append(sel_key)
 | |
|         if selected_keys and idx.isValid():
 | |
|             column_title = self.model().horizontalHeaderItem(column).text()
 | |
|             column_data = '\n'.join(self.model().itemFromIndex(s_idx).text()
 | |
|                                     for s_idx in self.selected_in_column(column))
 | |
|             if Willexecutors.is_selected(self.parent.willexecutors_list[sel_key]):
 | |
|                 menu.addAction(_("deselect").format(column_title), lambda: self.deselect(selected_keys))
 | |
|             else:
 | |
|                 menu.addAction(_("select").format(column_title), lambda: self.select(selected_keys))
 | |
|             if column in self.editable_columns:
 | |
|                 item = self.model().itemFromIndex(idx)
 | |
|                 if item.isEditable():
 | |
|                     persistent = QPersistentModelIndex(idx)
 | |
|                     menu.addAction(_("Edit {}").format(column_title), lambda p=persistent: self.edit(QModelIndex(p)))
 | |
| 
 | |
|             menu.addAction(_("Ping").format(column_title), lambda: self.ping_willexecutors(selected_keys))
 | |
|             menu.addSeparator()
 | |
|             menu.addAction(_("delete").format(column_title), lambda: self.delete(selected_keys))
 | |
| 
 | |
|         menu.exec(self.viewport().mapToGlobal(position))
 | |
| 
 | |
|     def ping_willexecutors(self,selected_keys):
 | |
|         wout={}
 | |
|         for k in selected_keys:
 | |
|             wout[k]=self.parent.willexecutors_list[k]
 | |
|         self.parent.update_willexecutors(wout)
 | |
|         self.update()
 | |
| 
 | |
|     def get_edit_key_from_coordinate(self, row, col):
 | |
|         a= self.get_role_data_from_coordinate(row, col, role=self.ROLE_HEIR_KEY+col)
 | |
|         return a
 | |
| 
 | |
|     def delete(self,selected_keys):
 | |
|         for key in selected_keys:
 | |
|             del self.parent.willexecutors_list[key]
 | |
|         self.update()
 | |
| 
 | |
|     def select(self,selected_keys):
 | |
|         for wid,w in self.parent.willexecutors_list.items():
 | |
|             if wid in selected_keys:
 | |
|                 w['selected']=True
 | |
|         self.update()
 | |
| 
 | |
|     def deselect(self,selected_keys):
 | |
|         for wid,w in self.parent.willexecutors_list.items():
 | |
|             if wid in selected_keys:
 | |
|                 w['selected']=False
 | |
|         self.update()
 | |
| 
 | |
|     def on_edited(self, idx, edit_key, *, text):
 | |
|         prior_name = self.parent.willexecutors_list[edit_key]
 | |
|         col = idx.column()
 | |
|         try:
 | |
|             if col == self.Columns.URL:
 | |
|                 self.parent.willexecutors_list[text]=self.parent.willexecutors_list[edit_key]
 | |
|                 del self.parent.willexecutors_list[edit_key]
 | |
|             if col == self.Columns.BASE_FEE:
 | |
|                 self.parent.willexecutors_list[edit_key]["base_fee"] = Util.encode_amount(text,self.config.get_decimal_point())
 | |
|             if col == self.Columns.ADDRESS:
 | |
|                 self.parent.willexecutors_list[edit_key]["address"] = text
 | |
|             if col == self.Columns.INFO:
 | |
|                 self.parent.willexecutors_list[edit_key]["info"] = text
 | |
|             self.update()
 | |
|         except Exception as e:
 | |
|             pass
 | |
| 
 | |
|     def update(self):
 | |
|         if self.parent.willexecutors_list is None:
 | |
|             return
 | |
|         try: 
 | |
|             current_key = self.get_role_data_for_current_item(col=self.Columns.URL, role=self.ROLE_HEIR_KEY)
 | |
|             self.model().clear()
 | |
|             self.update_headers(self.__class__.headers)
 | |
| 
 | |
|             set_current = None
 | |
| 
 | |
|             for url, value in self.parent.willexecutors_list.items():
 | |
|                 labels = [""] * len(self.Columns)
 | |
|                 labels[self.Columns.URL] = url 
 | |
|                 if Willexecutors.is_selected(value):
 | |
|                     labels[self.Columns.SELECTED] = [read_QIcon('confirmed.png'),'']
 | |
|                 else:
 | |
|                     labels[self.Columns.SELECTED] = ''
 | |
|                 labels[self.Columns.BASE_FEE] = Util.decode_amount(value.get('base_fee',0),self.config.get_decimal_point())
 | |
|                 if str(value.get('status',0)) == "200":
 | |
|                     labels[self.Columns.STATUS] = [read_QIcon('status_connected.png'),'']
 | |
|                 else:
 | |
|                     labels[self.Columns.STATUS] = [read_QIcon('unconfirmed.png'),'']
 | |
|                 labels[self.Columns.ADDRESS] = str(value.get('address',''))
 | |
|                 labels[self.Columns.INFO] = str(value.get('info',''))
 | |
|                 
 | |
|                 items=[]
 | |
|                 for e in labels:
 | |
|                     if type(e)== list:
 | |
|                         try:
 | |
|                             items.append(QStandardItem(*e))
 | |
|                         except Exception as e:
 | |
|                             pass
 | |
|                     else:
 | |
|                         items.append(QStandardItem(e))
 | |
|                 items[self.Columns.SELECTED].setEditable(False)
 | |
|                 items[self.Columns.URL].setEditable(True)
 | |
|                 items[self.Columns.ADDRESS].setEditable(True)
 | |
|                 items[self.Columns.INFO].setEditable(True)
 | |
|                 items[self.Columns.BASE_FEE].setEditable(True)
 | |
|                 items[self.Columns.STATUS].setEditable(False)
 | |
| 
 | |
|                 items[self.Columns.URL].setData(url, self.ROLE_HEIR_KEY+1)
 | |
|                 items[self.Columns.BASE_FEE].setData(url, self.ROLE_HEIR_KEY+2)
 | |
|                 items[self.Columns.INFO].setData(url, self.ROLE_HEIR_KEY+3)
 | |
|                 items[self.Columns.ADDRESS].setData(url, self.ROLE_HEIR_KEY+4)
 | |
| 
 | |
| 
 | |
|                 self.model().insertRow(self.model().rowCount(), items)
 | |
|                 if url == current_key:
 | |
|                     idx = self.model().index(row_count, self.Columns.NAME)
 | |
|                     set_current = QPersistentModelIndex(idx)
 | |
|                 self.set_current_idx(set_current)
 | |
|             self.parent.save_willexecutors()
 | |
|         except Exception as e:
 | |
|             _logger.error(e)
 | |
| 
 | |
| 
 | |
| class WillExecutorDialog(BalDialog,MessageBoxMixin):
 | |
|     def __init__(self, bal_window):
 | |
|         BalDialog.__init__(self,bal_window.window)
 | |
|         self.bal_plugin = bal_window.bal_plugin
 | |
|         self.config = self.bal_plugin.config
 | |
|         self.window = bal_window.window
 | |
|         self.bal_window = bal_window
 | |
|         self.willexecutors_list = Willexecutors.get_willexecutors(self.bal_plugin)
 | |
| 
 | |
|         self.setWindowTitle(_('Will-Executor Service List'))
 | |
|         self.setMinimumSize(1000, 200)
 | |
|         self.size_label = QLabel()
 | |
|         self.willexecutor_list = WillExecutorList(self)
 | |
| 
 | |
|         vbox = QVBoxLayout(self)
 | |
|         vbox.addWidget(self.size_label)
 | |
|         vbox.addWidget(self.willexecutor_list)
 | |
|         buttonbox = QHBoxLayout()
 | |
| 
 | |
|         b = QPushButton(_('Ping'))
 | |
|         b.clicked.connect(self.update_willexecutors)
 | |
|         buttonbox.addWidget(b)
 | |
| 
 | |
|         b = QPushButton(_('Import'))
 | |
|         b.clicked.connect(self.import_file)
 | |
|         buttonbox.addWidget(b)
 | |
| 
 | |
|         b = QPushButton(_('Export'))
 | |
|         b.clicked.connect(self.export_file)
 | |
|         buttonbox.addWidget(b)
 | |
| 
 | |
|         b = QPushButton(_('Add'))
 | |
|         b.clicked.connect(self.add)
 | |
|         buttonbox.addWidget(b)
 | |
|         
 | |
|         b = QPushButton(_('Close'))
 | |
|         b.clicked.connect(self.close)
 | |
|         buttonbox.addWidget(b)
 | |
| 
 | |
|         vbox.addLayout(buttonbox)
 | |
| 
 | |
|         self.willexecutor_list.update()
 | |
| 
 | |
|     def add(self):
 | |
|         self.willexecutors_list["http://localhost:8080"]={"info":"New Will Executor","base_fee":0,"status":"-1"}
 | |
|         self.willexecutor_list.update()     
 | |
| 
 | |
|     def import_file(self):
 | |
|         import_meta_gui(self, _('willexecutors.json'), self.import_json_file, self.willexecutors_list.update)
 | |
| 
 | |
|     def export_file(self, path):
 | |
|         Util.export_meta_gui(self, _('willexecutors.json'), self.export_json_file)
 | |
| 
 | |
|     def export_json_file(self,path):
 | |
|         write_json_file(path, self.willexecutors_list)
 | |
| 
 | |
|     def update_willexecutors(self,wes=None):
 | |
|         if not wes:
 | |
|             self.willexecutors_list = Willexecutors.get_willexecutors(self.bal_plugin, update = True, bal_window = self.bal_window,force=True)
 | |
|         else:
 | |
|             self.bal_window.ping_willexecutors(wes)
 | |
|             self.willexecutors_list.update(wes)
 | |
|             self.willexecutor_list.update()
 | |
| 
 | |
|         
 | |
|     def import_json_file(self, path):
 | |
|         data = read_json_file(path)
 | |
|         data = self._validate(data)
 | |
|         self.willexecutors_list.update(data)
 | |
|         self.willexecutor_list.update()
 | |
| 
 | |
|     #TODO validate willexecutor json import file
 | |
|     def _validate(self,data):
 | |
|         return data
 | |
| 
 | |
|     def is_hidden(self):
 | |
|         return self.isMinimized() or self.isHidden()
 | |
| 
 | |
|     def show_or_hide(self):
 | |
|         if self.is_hidden():
 | |
|             self.bring_to_top()
 | |
|         else:
 | |
|             self.hide()
 | |
| 
 | |
|     def bring_to_top(self):
 | |
|         self.show()
 | |
|         self.raise_()
 | |
| 
 | |
|     def closeEvent(self, event):
 | |
|         event.accept()
 | |
| 
 | |
|     def save_willexecutors(self):
 | |
|         self.bal_plugin.config.set_key(self.bal_plugin.WILLEXECUTORS,self.willexecutors_list,save=True)
 | |
|     
 |