Source

codeaide / codeaide / widget.py

Full commit
from codeaide.base import *


class TextBlockUserData(QTextBlockUserData):
    
    def __init__(self):
        QTextBlockUserData.__init__(self)
        self.attrs = {}
        
        
    def __getitem__(self, name):
        return self.attrs[name]
        
        
    def get(self, name, default=None):
        return self.attrs.get(name, default)
        
        
    def __setitem__(self, name, value):
        self.attrs[name] = value



class CodeAide(QPlainTextEdit):



    def __init__(self, parent=None):
        QPlainTextEdit.__init__(self, parent)
        self.setFrameStyle(0)
        #self.setBackgroundVisible(True)
        self.set_font()
        self.state = 0
        self.keyboard_hooks = {}
        self.paint_hooks = {}
        self.resize_hooks = {}
        self.installed_modes = []
        self.idle_timer_id = self.startTimer(2000)


    def not_idle(self):
        self.killTimer(self.idle_timer_id)
        self.idle_timer_id = self.startTimer(2000)


    def timerEvent(self, event):
        self.killTimer(self.idle_timer_id)
        QTimer.singleShot(0, self._emit_idle)
        self.idle_timer_id = self.startTimer(2000)


    def _emit_idle(self):
        self.emit(SIGNAL("idle()"))


    def set_font(self, name="Monospace", size=10):
        font = self.document().defaultFont()
        font.setPointSize(10)
        font.setFamily("Monospace")
        font.setFixedPitch(True)
        self.document().setDefaultFont(font)
        self.setFont(font)


    def find_mode(self, cls):
        for mode in self.installed_modes:
            if isinstance(mode, cls):
                return mode


    def is_installed(self, mode):
        for installed in self.installed_modes:
            if installed.__class__ is mode:
                return True
        return False


    def install(self, *mode_args):
        for mode in mode_args:
            mode = ModeBase.find(mode)
            if not self.is_installed(mode):
                mode_instance = mode(self)
                self.installed_modes.append(mode_instance)


    @property
    def commands(self):
        c = {}
        for mode in self.installed_modes:
            for name in members(mode):
                if not name.startswith("_"):
                    obj = getattr(mode, name)
                    if getattr(obj, "is_command", False):
                        c[name] = obj
        return c


    def __call__(self, cmd, *args, **kwargs):
        method = self.commands.get(cmd)
        if not method:
            raise TypeError, "Method %r not found" % cmd
        return method(*args, **kwargs)


    def paintEvent(self, event):
        viewport = self.viewport()
        painter = QPainter(viewport)
        h = self.paint_hooks
        for callback in \
                h.get(self.state, []) + h.get(-1, []):
            if callback(event, painter, viewport):
                return
        painter.end()
        return QPlainTextEdit.paintEvent(self, event)

    
    def mousePressEvent(self, event):
        self.not_idle()
        return QPlainTextEdit.mousePressEvent(self, event)


    def keyPressEvent(self, event):
        key = event.key()
        text = event.text()
        modifiers = event.modifiers()
        h = self.keyboard_hooks.get(self.state, {})
        for callback in \
                h.get((key, int(modifiers)), []) + \
                h.get((key, -1), []):
            if callback(event, key, modifiers, text):
                return
        self.not_idle()
        return QPlainTextEdit.keyPressEvent(self, event)


    def resizeEvent(self, event):
        h = self.resize_hooks
        for callback in \
                h.get(self.state, []) + h.get(-1, []):
            if callback(event):
                return
        return QPlainTextEdit.resizeEvent(self, event)


    def user_data(self, block=None):
        if not block:
            block = self.textCursor().block()
        user_data = block.userData()
        if not user_data:
            user_data = TextBlockUserData()
            block.setUserData(user_data)
        return user_data

    
    def mark_unmodified(self):
        # XXX this should be done inside line status mode
        block = self.document().begin()
        while block and block.isValid():
            user_data = self.user_data(block)
            user_data["status"] = 0
            user_data["backup"] = block.text()
            block = block.next()


    def setText(self, text):
        self.setPlainText(text)
        #self.emit("newText")
        self.mark_unmodified()


    def remove_extra_selections(self, selections):
        l = []
        for sel in self.extraSelections():
            if not sel in selections:
                l.append(sel)
        self.setExtraSelections(l)
            

    def add_extra_selections(self, selections):
        self.setExtraSelections(self.extraSelections() + selections)