electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit c3a0c9dd360ba801f20947ff5e57b48aceb10865
parent e4586ee59a3d35fde4b26cba2a7aee0e6bcae98b
Author: ThomasV <thomasv@gitorious>
Date:   Fri,  1 Feb 2013 18:22:36 +0100

transform the wall into a python console

Diffstat:
Mlib/gui_qt.py | 17+++++++++--------
Alib/qt_console.py | 179+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/wallet.py | 3+--
3 files changed, 189 insertions(+), 10 deletions(-)

diff --git a/lib/gui_qt.py b/lib/gui_qt.py @@ -395,7 +395,7 @@ class ElectrumWindow(QMainWindow): self.wallet = wallet self.config = config self.wallet.interface.register_callback('updated', self.update_callback) - self.wallet.interface.register_callback('connected', self.update_callback) + self.wallet.interface.register_callback('banner', lambda: self.emit(QtCore.SIGNAL('banner_signal')) ) self.wallet.interface.register_callback('disconnected', self.update_callback) self.wallet.interface.register_callback('disconnecting', self.update_callback) @@ -412,7 +412,7 @@ class ElectrumWindow(QMainWindow): tabs.addTab(self.create_send_tab(), _('Send') ) tabs.addTab(self.create_receive_tab(), _('Receive') ) tabs.addTab(self.create_contacts_tab(), _('Contacts') ) - tabs.addTab(self.create_wall_tab(), _('Wall') ) + tabs.addTab(self.create_wall_tab(), _('Console') ) tabs.setMinimumSize(600, 400) tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setCentralWidget(tabs) @@ -430,7 +430,7 @@ class ElectrumWindow(QMainWindow): QShortcut(QKeySequence("Ctrl+PgDown"), self, lambda: tabs.setCurrentIndex( (tabs.currentIndex() + 1 )%tabs.count() )) self.connect(self, QtCore.SIGNAL('updatesignal'), self.update_wallet) - #self.connect(self, SIGNAL('editamount'), self.edit_amount) + self.connect(self, QtCore.SIGNAL('banner_signal'), lambda: self.console.showMessage(self.wallet.banner) ) self.history_list.setFocus(True) self.exchanger = exchange_rate.Exchanger(self) @@ -496,12 +496,12 @@ class ElectrumWindow(QMainWindow): self.status_button.setIcon( icon ) if self.wallet.up_to_date or not self.wallet.interface.is_connected: - self.textbox.setText( self.wallet.banner ) self.update_history_tab() self.update_receive_tab() self.update_contacts_tab() self.update_completions() + def create_quote_text(self, btc_balance): quote_currency = self.config.get("currency", "None") quote_balance = self.exchanger.exchange(btc_balance, quote_currency) @@ -1244,11 +1244,12 @@ class ElectrumWindow(QMainWindow): l.setCurrentItem(l.topLevelItem(0)) + def create_wall_tab(self): - self.textbox = textbox = QTextEdit(self) - textbox.setFont(QFont(MONOSPACE_FONT)) - textbox.setReadOnly(True) - return textbox + from qt_console import Console + self.console = console = Console(startup_message=self.wallet.banner) + console.updateNamespace({'wallet' : self.wallet, 'interface' : self.wallet.interface}) + return console def create_status_bar(self): diff --git a/lib/qt_console.py b/lib/qt_console.py @@ -0,0 +1,179 @@ +# source: http://stackoverflow.com/questions/2758159/how-to-embed-a-python-interpreter-in-a-pyqt-widget + +import sys, os +import traceback +from PyQt4 import QtCore +from PyQt4 import QtGui + +class Console(QtGui.QPlainTextEdit): + def __init__(self, prompt='>> ', startup_message='', parent=None): + QtGui.QPlainTextEdit.__init__(self, parent) + self.prompt = prompt + self.history = [] + self.namespace = {} + self.construct = [] + + self.setGeometry(50, 75, 600, 400) + self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere) + self.setUndoRedoEnabled(False) + self.document().setDefaultFont(QtGui.QFont("monospace", 10, QtGui.QFont.Normal)) + self.showMessage(startup_message) + + def updateNamespace(self, namespace): + self.namespace.update(namespace) + + def showMessage(self, message): + self.appendPlainText(message) + self.newPrompt() + + def newPrompt(self): + if self.construct: + prompt = '.' * len(self.prompt) + else: + prompt = self.prompt + self.appendPlainText(prompt) + self.moveCursor(QtGui.QTextCursor.End) + + def getCommand(self): + doc = self.document() + curr_line = unicode(doc.findBlockByLineNumber(doc.lineCount() - 1).text()) + curr_line = curr_line.rstrip() + curr_line = curr_line[len(self.prompt):] + return curr_line + + def setCommand(self, command): + if self.getCommand() == command: + return + self.moveCursor(QtGui.QTextCursor.End) + self.moveCursor(QtGui.QTextCursor.StartOfLine, QtGui.QTextCursor.KeepAnchor) + for i in range(len(self.prompt)): + self.moveCursor(QtGui.QTextCursor.Right, QtGui.QTextCursor.KeepAnchor) + self.textCursor().removeSelectedText() + self.textCursor().insertText(command) + self.moveCursor(QtGui.QTextCursor.End) + + def getConstruct(self, command): + if self.construct: + prev_command = self.construct[-1] + self.construct.append(command) + if not prev_command and not command: + ret_val = '\n'.join(self.construct) + self.construct = [] + return ret_val + else: + return '' + else: + if command and command[-1] == (':'): + self.construct.append(command) + return '' + else: + return command + + def getHistory(self): + return self.history + + def setHisory(self, history): + self.history = history + + def addToHistory(self, command): + if command and (not self.history or self.history[-1] != command): + self.history.append(command) + self.history_index = len(self.history) + + def getPrevHistoryEntry(self): + if self.history: + self.history_index = max(0, self.history_index - 1) + return self.history[self.history_index] + return '' + + def getNextHistoryEntry(self): + if self.history: + hist_len = len(self.history) + self.history_index = min(hist_len, self.history_index + 1) + if self.history_index < hist_len: + return self.history[self.history_index] + return '' + + def getCursorPosition(self): + return self.textCursor().columnNumber() - len(self.prompt) + + def setCursorPosition(self, position): + self.moveCursor(QtGui.QTextCursor.StartOfLine) + for i in range(len(self.prompt) + position): + self.moveCursor(QtGui.QTextCursor.Right) + + def runCommand(self): + command = self.getCommand() + self.addToHistory(command) + + command = self.getConstruct(command) + + if command: + tmp_stdout = sys.stdout + + class stdoutProxy(): + def __init__(self, write_func): + self.write_func = write_func + self.skip = False + + def write(self, text): + if not self.skip: + stripped_text = text.rstrip('\n') + self.write_func(stripped_text) + QtCore.QCoreApplication.processEvents() + self.skip = not self.skip + + sys.stdout = stdoutProxy(self.appendPlainText) + try: + try: + result = eval(command, self.namespace, self.namespace) + if result != None: + self.appendPlainText(repr(result)) + except SyntaxError: + exec command in self.namespace + except SystemExit: + self.close() + except: + traceback_lines = traceback.format_exc().split('\n') + # Remove traceback mentioning this file, and a linebreak + for i in (3,2,1,-1): + traceback_lines.pop(i) + self.appendPlainText('\n'.join(traceback_lines)) + sys.stdout = tmp_stdout + self.newPrompt() + + def keyPressEvent(self, event): + if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return): + self.runCommand() + return + if event.key() == QtCore.Qt.Key_Home: + self.setCursorPosition(0) + return + if event.key() == QtCore.Qt.Key_PageUp: + return + elif event.key() in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Backspace): + if self.getCursorPosition() == 0: + return + elif event.key() == QtCore.Qt.Key_Up: + self.setCommand(self.getPrevHistoryEntry()) + return + elif event.key() == QtCore.Qt.Key_Down: + self.setCommand(self.getNextHistoryEntry()) + return + #elif event.key() == QtCore.Qt.Key_D and event.modifiers() == QtCore.Qt.ControlModifier: + # self.close() + super(Console, self).keyPressEvent(event) + + +welcome_message = ''' + --------------------------------------------------------------- + Welcome to a primitive Python interpreter. + --------------------------------------------------------------- +''' + +if __name__ == '__main__': + app = QtGui.QApplication(sys.argv) + console = Console(startup_message=welcome_message) + console.updateNamespace({'myVar1' : app, 'myVar2' : 1234}) + console.show(); + sys.exit(app.exec_()) diff --git a/lib/wallet.py b/lib/wallet.py @@ -1355,8 +1355,7 @@ class WalletSynchronizer(threading.Thread): elif method == 'server.banner': self.wallet.banner = result - self.was_updated = True - + self.interface.trigger_callback('banner') else: print_error("Error: Unknown message:" + method + ", " + repr(params) + ", " + repr(result) )