URI: 
       ttransform the wall into a python console - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit c3a0c9dd360ba801f20947ff5e57b48aceb10865
   DIR parent e4586ee59a3d35fde4b26cba2a7aee0e6bcae98b
  HTML Author: ThomasV <thomasv@gitorious>
       Date:   Fri,  1 Feb 2013 18:22:36 +0100
       
       ttransform the wall into a python console
       
       Diffstat:
         M lib/gui_qt.py                       |      17 +++++++++--------
         A lib/qt_console.py                   |     179 +++++++++++++++++++++++++++++++
         M lib/wallet.py                       |       3 +--
       
       3 files changed, 189 insertions(+), 10 deletions(-)
       ---
   DIR diff --git a/lib/gui_qt.py b/lib/gui_qt.py
       t@@ -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)
        
       t@@ -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)
       t@@ -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)
       t@@ -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)
       t@@ -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):
   DIR diff --git a/lib/qt_console.py b/lib/qt_console.py
       t@@ -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_())
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -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) )