class LineNumbering(DocumentListener): """Pane containing line numbers. Listens to changes in a textpane to update itself automatically. """ def __init__(self, textpane): self.component = JTextPane( font=textpane.font, border=BorderFactory.createEmptyBorder(5, 5, 5, 5), editable=False, background=awtColor(220, 220, 220), ) self.doc = self.component.document self.component.setParagraphAttributes( textpane.paragraphAttributes, True ) self.linecount = 0 self.style = new_style(self.doc, "default", foreground=awtColor(100, 100, 100), ) self.reset(1) textpane.document.addDocumentListener(self) def reset(self, lc): self.linecount = lc self.doc.remove(0, self.doc.length) self.doc.insertString(0, make_line_numbers(1, lc), self.style) def resize(self, lc): if not lc: self.reset(1) elif len(str(lc)) != len(str(self.linecount)): self.reset(lc) elif lc > self.linecount: self.doc.insertString(self.doc.length, "\n", self.style) self.doc.insertString(self.doc.length, make_line_numbers(self.linecount + 1, lc), self.style ) self.linecount = lc elif lc < self.linecount: root = self.doc.defaultRootElement offset = root.getElement(lc).startOffset - 1 self.doc.remove(offset, self.doc.length - offset) self.linecount = lc # Implementation of DocumentListener def changedUpdate(self, evt): pass def insertUpdate(self, evt): self.resize(document_linecount(evt.document)) def removeUpdate(self, evt): self.resize(document_linecount(evt.document))
class OutputPane(object): """Pane for outpout of interactive session""" def __init__(self): self.textpane = JTextPane() self.doc = self.textpane.getStyledDocument() self.textpane.editable = False style_context = StyleContext.getDefaultStyleContext() default_style = style_context.getStyle(StyleContext.DEFAULT_STYLE) parent_style = self.doc.addStyle("parent", default_style) StyleConstants.setFontFamily(parent_style, "Monospaced") input_style = self.doc.addStyle("input", parent_style) output_style = self.doc.addStyle("output", parent_style) StyleConstants.setForeground(output_style, awtColor.BLUE) error_style = self.doc.addStyle("error", parent_style) StyleConstants.setForeground(error_style, awtColor.RED) # Do a dance to set tab size font = Font("Monospaced", Font.PLAIN, 12) self.textpane.setFont(font) fm = self.textpane.getFontMetrics(font) tabw = float(fm.stringWidth(" "*4)) tabs = [ TabStop(tabw*i, TabStop.ALIGN_LEFT, TabStop.LEAD_NONE) for i in xrange(1, 51) ] attr_set = style_context.addAttribute( SimpleAttributeSet.EMPTY, StyleConstants.TabSet, TabSet(tabs) ) self.textpane.setParagraphAttributes(attr_set, False) #Dance done! def addtext(self, text, style="input", ensure_newline=False): doclen = self.doc.length if ensure_newline and doclen: if self.doc.getText(doclen - 1, 1) != '\n': text = '\n' + text self.doc.insertString(self.doc.length, text, self.doc.getStyle(style)) # Scroll down self.textpane.setCaretPosition(self.doc.length) def clear(self): """Remove all text""" self.doc.remove(0, self.doc.length)