Commits

Henning Schröder committed f542619

moved unused code to contrib

Comments (0)

Files changed (5)

codeaide/modes/htmledit.py

-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-# http://qt.gitorious.org/qt-labs/graphics-dojo/blobs/master/htmleditor/htmleditor.cpp
-# http://www.w3.org/TR/html5/editing.html#execCommand
-from PyQt4.QtCore import SIGNAL, QString
-from PyQt4.QtGui import (
-    QApplication, QVBoxLayout, QWidget, QFont, QLabel, QColor)
-from PyQt4.QtWebKit import QWebView, QWebPage
-
-
-js_helpers = """
-function getSelectionStart(){
-    var node = document.getSelection().anchorNode;
-    var startNode = (node.nodeName == "#text" ? node.parentNode : node);
-    return startNode;
-}
-"""
-
-class Editor(QWidget):
-
-
-    def __init__(self, parent):
-        QWidget.__init__(self)
-        self.vblayout = QVBoxLayout(self)
-        self.view = QWebView(self)
-        self.layout().addWidget(self.view)
-        self.sbar = QLabel(self)
-        self.layout().addWidget(self.sbar)
-        self.load("/usr/share/doc/ubuntu-artwork/html/home/firefox-index.html")
-
-
-    def set_html(self, html):
-        self.view.setContent(html, "text/html")
-        self.page = self.view.page()
-        self.page.setContentEditable(True)
-        self.page.setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
-        self.connect(self.page, SIGNAL("linkClicked(QUrl)"), self.on_link_clicked)
-        self.frame = self.page.mainFrame()
-        self.frame.evaluateJavaScript(js_helpers)
-
-        self.connect(self.page, SIGNAL("selectionChanged()"), self.on_selection_changed)
-        self.connect(self.page, SIGNAL("contentsChanged()"), self.on_contents_changed)
-
-
-    def convert_hashmap(self, d):
-        r = {}
-        for name, value in d.items():
-            if isinstance(value, QString):
-                value = unicode(value)
-            elif isinstance(value, dict):
-                value = self.convert_hashmap(value)
-            r[unicode(name)] = value
-        return r
-
-
-    def on_selection_changed(self):
-        r = self.frame.evaluateJavaScript("getSelectionStart()")
-        d = self.convert_hashmap(r.toPyObject())
-        print d
-
-
-
-    def on_contents_changed(self):
-        pass
-
-
-    def load(self, filename):
-        data = open(filename).read()
-        self.set_html(data)
-        
-
-
-    def on_link_clicked(self, url):
-        pass
-
-
-    def exec_command(self, cmd, arg=None):
-        if arg is None:
-            arg = "null"
-        else:
-            arg = repr(arg)
-        js = "document.execCommand(%r, false, %s)" % (
-            cmd, arg
-            )
-        self.frame.evaluateJavaScript(js)
-
-
-    
-
-
-    def query_command(self, cmd):
-        result = self.frame.evaluateJavaScript(js)
-        return unicode(result.toString())
-
-
-    def query_state(self, cmd):
-        result = self.query_command(cmd)
-        return result.lower() == "true"
-
-
-
-    def insert_html(self, html):
-        self.exec_command("insertHTML", html)
-
-
-    def insert_image(self, html):
-        self.exec_command("insertImage", html)
-
-
-    def create_link(self, link):
-        self.exec_command("createLink", link)
-
-
-    def format_block(self, paragraph_tag):
-        self.exec_command(paragraph_tag)
-
-
-    def align_left(self):
-        self.exec_command("justifyLeft")
-
-
-    def align_right(self):
-        self.exec_command("justifyRight")
-
-
-    def align_center(self):
-        self.exec_command("justifyCenter")
-
-
-    def align_justify(self):
-        self.exec_command("justifyFull")
-
-
-    def bold(self):
-        self.exec_command("bold")
-
-
-    def italic(self):
-        self.exec_command("italic")
-
-
-    def underline(self):
-        self.exec_command("underline")
-
-
-    def strike_through(self):
-        self.exec_command("strikeThrough")
-
-
-    def is_strike_through(self):
-        return self.query_state("strikeThrough")
-
-
-    def is_ordered_list(self):
-        return self.query_state("insertOrderedList")
-
-
-    def is_unordered_list(self):
-        return self.query_state("insertUnorderedList")
-
-
-    def indent(self):
-        self.exec_command("indent")
-
-
-    def dedent(self):
-        self.exec_command("outdent")
-
-
-    def insert_ordered_list(self):
-        self.exec_command("insertOrderedList")
-
-
-    def insert_unordered_list(self):
-        self.exec_command("insertUnorderedList")
-
-
-    def set_font_name(self, font):
-        if isinstance(font, QFont):
-            font = unicode(font.family())
-        self.exec_command("fontName", font)
-
-
-    def set_font_size(self, size):
-        size_list = ["xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large"]
-        if isinstance(size, basestring):
-            size = size_list.index(size)
-        self.exec_command("fontSize", size)
-
-
-    def set_font_color(self, color):
-        if not isinstance(color, QColor):
-            if instance(color, tuple):
-                color = QColor(*color)
-            else:
-                color = QColor(color)
-        self.exec_command("foreColor", unicode(color.name()))
-
-
-    def set_background_color(self, color):
-        if not isinstance(color, QColor):
-            if instance(color, tuple):
-                color = QColor(*color)
-            else:
-                color = QColor(color)
-        self.exec_command("hiliteColor", unicode(color.name()))
-
-
-
-def main():
-    import sys
-    app = QApplication(sys.argv)
-    edit = Editor(None)
-    edit.resize(640, 480)
-    edit.show()
-    app.exec_()
-
-if __name__ == "__main__":
-    main()

codeaide/modes/wysiwym.py

-# -*- coding: utf-8 -*-
-from PyQt4.QtCore import SIGNAL, QString, QVariant, Qt, QUrl
-from PyQt4.QtGui import (
-    QApplication, QToolBar, QComboBox, QFrame, QToolButton,
-    QFileDialog, QVBoxLayout, QBrush, QColor, QFont, QImage,
-    QTextFormat, QTextBlockFormat, QTextCharFormat, QTextImageFormat,
-    QTextFrameFormat, QTextDocument, QTextEdit, QTextCursor
-    )
-
-
-class jdict(dict):
-
-    def __getattr__(self, name):
-        return self.get(name, None)
-
-
-object_type_map = jdict(
-    text=QTextFormat.NoObject,
-    image=QTextFormat.ImageObject,
-    table=QTextFormat.TableObject,
-    cell=QTextFormat.TableCellObject,
-    link=QTextFormat.UserObject + 1,
-)
-reverse_object_type_map = dict(
-    [(v,k) for (k,v) in object_type_map.items()])
-
-
-property_format_map = dict(
-    name=QTextFormat.UserProperty + 1,
-    url=QTextFormat.UserProperty + 2
-)
-
-
-
-
-
-class FormatProperties(object):
-
-    property_format_map = property_format_map
-
-
-    def __init__(self, format):
-        self.format = format
-
-
-    def __getattr__(self, name):
-        return getattr(self.format, name)
-
-
-    def keys(self):
-        return self.property_format_map.keys()
-
-
-    def __getitem__(self, name):
-        prop_id = self.property_format_map.get(name)
-        if isinstance(prop_id, tuple):
-            getter, setter = prop_id
-            return getter(self, name)
-        variant = self.format.property(prop_id)
-        value = variant.toPyObject()
-        if isinstance(value, QString):
-            value = unicode(value)
-        return value
-
-
-    def __setitem__(self, name, value):
-        prop_id = self.property_format_map.get(name)
-        if not prop_id:
-            raise TypeError, "Unknown parameter %r" % name
-        elif isinstance(prop_id, tuple):
-            getter, setter = prop_id
-            setter(self, value)
-        else:
-            self.format.setProperty(prop_id, QVariant(value))
-
-
-
-class TextCharFormat(FormatProperties):
-
-
-    def get_bold(self):
-        return self.format.property(
-            QTextFormat.FontWeight).toPyObject() == QFont.Bold
-
-
-    def set_bold(self, flag):
-        if flag:
-            self.format.setProperty(
-                QTextFormat.FontWeight, QFont.Bold)
-        else:
-            self.format.setProperty(
-                QTextFormat.FontWeight, QFont.Normal)
-
-
-    def set_color(self, value):
-        self.format.setProperty(
-            QTextFormat.ForegroundBrush, QVariant(QBrush(QColor(value))))
-
-
-    def get_color(self):
-        return self.format.property(
-            QTextFormat.ForegroundBrush).toPyObject()
-
-
-
-    property_format_map = dict(property_format_map,
-      font_family=QTextFormat.FontFamily,
-      font_point_size=QTextFormat.FontPointSize,
-      font_pixel_size=QTextFormat.FontPixelSize,
-      font_weight=QTextFormat.FontWeight,
-      italic=QTextFormat.FontItalic,
-      underline=QTextFormat.FontUnderline,
-      bold=(get_bold, set_bold),
-      color=(get_color, set_color)
-    )
-
-
-class TextBlockFormat(FormatProperties):
-
-
-    def set_background(self, value):
-        self.format.setProperty(
-            QTextFormat.BackgroundBrush, QVariant(QBrush(QColor(value))))
-
-
-    def get_background(self):
-        return self.format.property(
-            QTextFormat.BackgroundBrush).toPyObject()
-
-
-
-    property_format_map = dict(property_format_map,
-      alignment=QTextFormat.BlockAlignment,
-      margin_left=QTextFormat.BlockLeftMargin,
-      margin_right=QTextFormat.BlockRightMargin,
-      margin_top=QTextFormat.BlockTopMargin,
-      margin_bottom=QTextFormat.BlockBottomMargin,
-      indent=QTextFormat.BlockIndent,
-      background=(get_background, set_background)
-    )
-
-
-
-class TextImageFormat(FormatProperties):
-
-    property_format_map = dict(property_format_map,
-      image_name=QTextFormat.ImageName,
-      image_width=QTextFormat.ImageWidth,
-      image_height=QTextFormat.ImageHeight
-    )
-
-
-
-class LinkCharFormat(TextCharFormat):
-
-
-    def __init__(self, cf):
-        TextCharFormat.__init__(self, cf)
-        cf.setFontUnderline(True)
-
-
-
-class Styles(object):
-
-
-    def __init__(self):
-        self.block_format_list = [
-            self.create_block_format("p", font_point_size=9),
-            self.create_block_format("h1", font_point_size=24,
-                                     alignment=Qt.AlignCenter),
-            self.create_block_format("h2", font_point_size=18),
-            self.create_block_format("h3", font_point_size=14, bold=True),
-            self.create_block_format("h4", font_point_size=12, bold=True),
-            self.create_block_format("h5", font_point_size=10, bold=True),
-            self.create_block_format("h6", font_point_size=8, bold=True),
-            self.create_block_format("code", font_family="monospace",
-                                     indent=1, background="lightyellow")
-        ]
-        self.char_format_list = [
-            self.create_char_format("normal"),
-            self.create_char_format("strong", bold=True),
-            self.create_char_format("emphasis", italic=True),
-            self.create_char_format("underline", underline=True),
-        ]
-
-
-    def format_name(self, format):
-        return FormatProperties(format)["name"]
-
-
-    def block_format(self, name):
-        for bf, bcf in self.block_format_list:
-            if self.format_name(bf) == name:
-                return bf, bcf
-
-
-    def char_format(self, name):
-        for f in self.char_format_list:
-            if self.format_name(f) == name:
-                return f
-
-
-    def create_char_format(self, name, **properties):
-        cf = TextCharFormat(QTextCharFormat())
-        cf["name"] = name
-        for pname, pvalue in properties.items():
-            cf[pname] = pvalue
-        return cf.format
-
-
-    def create_block_format(self, name, **properties):
-        bf = TextBlockFormat(QTextBlockFormat())
-        bf["name"] = name
-        cf = TextCharFormat(QTextCharFormat())
-        for pname, pvalue in properties.items():
-            if pname in bf.keys():
-                bf[pname] = pvalue
-            else:
-                cf[pname] = pvalue
-        return bf.format, cf.format
-
-
-
-
-class Document(QTextDocument):
-
-
-    def __init__(self, styles=None):
-        QTextDocument.__init__(self)
-        self.styles = styles or Styles()
-
-
-    def __iter__(self):
-        block = self.begin()
-        while block.isValid():
-            bf_name = self.styles.format_name(block.blockFormat())
-            parts = []
-            fragment_iterator = block.begin()
-            while not fragment_iterator.atEnd():
-                frag = fragment_iterator.fragment()
-                cf = frag.charFormat()
-                cf_name = self.styles.format_name(cf)
-                ot = reverse_object_type_map[cf.objectType()]
-                if ot == "image":
-                    data = TextImageFormat(cf)["image_name"]
-                elif ot == "link":
-                    data = LinkCharFormat(cf)["url"]
-                else:
-                    data = unicode(frag.text())
-                parts.append((cf_name, ot, data))
-                fragment_iterator += 1
-            yield bf_name, parts
-            block = block.next()
-
-
-    def dump(self):
-        for block_format, fragments in self:
-            print block_format, fragments
-
-
-
-
-class FormatSelectorWidget(QComboBox):
-
-    def setCurrentValue(self, text):
-        if text:
-            found = self.findText(text)
-            self.setCurrentIndex(found)
-
-
-class ParagaphFormatSelector(FormatSelectorWidget):
-    pass
-
-
-class CharFormatSelector(FormatSelectorWidget):
-    pass
-
-
-
-class WysiswymFormatToolbar(QToolBar):
-
-
-    def __init__(self, editor):
-        QToolBar.__init__(self, editor)
-        self.paragraph_formats = ParagaphFormatSelector(self)
-        self.view = editor.view
-        self.styles = editor.view.styles
-        for bf, bcf in self.styles.block_format_list:
-            self.paragraph_formats.addItem(
-                self.styles.format_name(bf))
-        self.connect(self.paragraph_formats,
-                     SIGNAL("activated(const QString&)"),
-                     self.on_change_paragraph_style)
-        self.addWidget(self.paragraph_formats)
-        self.char_formats = CharFormatSelector(self)
-        for f in self.styles.char_format_list:
-            self.char_formats.addItem(
-                self.styles.format_name(f))
-        self.connect(self.char_formats,
-                     SIGNAL("activated(const QString&)"),
-                     self.on_change_char_style)
-        self.addWidget(self.char_formats)
-        self.connect(editor.view,
-                     SIGNAL("cursorPositionChanged()"),
-                     self.cursor_pos_changed)
-        self.add_image_button = QToolButton(self)
-        self.add_image_button.setText("Add image...")
-        self.addWidget(self.add_image_button)
-        self.connect(self.add_image_button, SIGNAL("clicked()"),
-                     self.on_add_image)
-
-
-    def cursor_pos_changed(self):
-        cursor = self.view.textCursor()
-        bf_name = self.styles.format_name(
-            cursor.blockFormat())
-        self.paragraph_formats.setCurrentValue(bf_name)
-        cf_name = self.styles.format_name(
-            cursor.charFormat())
-        self.char_formats.setCurrentValue(cf_name)
-
-
-    def on_add_image(self):
-        filename = QFileDialog.getOpenFileName(
-            self, "Add image..", "", "Images (*.png *.jpg *.gif)")
-        if filename:
-            filename = unicode(filename)
-            self.view.textCursor().insert_image(filename)
-
-
-    def on_change_paragraph_style(self, name):
-        self.view.textCursor().change_paragraph_style(name)
-
-
-    def on_change_char_style(self, name):
-        self.view.textCursor().change_char_style(name)
-
-
-
-
-class TextCursor(QTextCursor):
-
-
-    def __init__(self, tc_or_doc_or_block):
-        QTextCursor.__init__(self, tc_or_doc_or_block)
-
-
-    def insert_image(self, filename, align=QTextFrameFormat.InFlow):
-        #QTextFrameFormat.FloatLeft, QTextFrameFormat.FloatRight
-        img = QImage(filename)
-        self.document().addResource(
-            QTextDocument.ImageResource, QUrl(filename), img)
-        tif = QTextImageFormat()
-        tif.setName(filename)
-        self.insertImage(tif, align)
-
-
-    def insert_text(self, text, cf_name=None):
-        styles = self.document().styles
-        bf_name = TextBlockFormat(self.blockFormat())["name"]
-        bf, bcf = styles.block_format(bf_name)
-        cf = styles.char_format(cf_name)
-        if cf:        
-            merged_cf = QTextCharFormat()
-            merged_cf.merge(cf)
-            merged_cf.merge(bcf)
-        else:
-            merged_cf = bcf
-        self.insertText(text, merged_cf)
-        return merged_cf
-
-
-    def insert_link(self, url):
-        cf = self.document().styles.create_char_format("_link", underline=True, color="blue")
-        LinkCharFormat(cf)["url"] = url
-        cf.setObjectType(object_type_map.link)
-        self.insertText(url, cf)
-
-
-
-    def change_paragraph_style(self, name):
-        bf, bcf = self.document().styles.block_format(unicode(name))
-        self.setBlockFormat(bf)
-        self.select(QTextCursor.BlockUnderCursor)
-        format = QTextCharFormat()
-        format.merge(self.charFormat())
-        format.merge(bcf)
-        self.setCharFormat(format)
-
-
-    def change_char_style(self, name):
-        styles = self.document().styles
-        cf = styles.char_format(unicode(name))
-        bf = TextBlockFormat(self.blockFormat())
-        bf, bcf = styles.block_format(bf["name"])
-        merged_cf = QTextCharFormat()
-        merged_cf.merge(bcf)
-        merged_cf.merge(cf)
-        self.setCharFormat(merged_cf)
-
-
-
-
-class WysiswymView(QTextEdit):
-
-
-    def __init__(self, parent=None, styles=None):
-        QTextEdit.__init__(self, parent)
-        self.doc = Document(styles)
-        self.styles = self.doc.styles
-        self.setDocument(self.doc)
-
-
-    def textCursor(self):
-        return TextCursor(QTextEdit.textCursor(self))
-
-
-
-
-class WysiswymEditor(QFrame):
-
-    def __init__(self, parent=None):
-        QFrame.__init__(self, parent)
-        self.view = WysiswymView(self)
-        self.toolbar = WysiswymFormatToolbar(self)
-        self.vboxlayout = QVBoxLayout(self)
-        self.setLayout(self.vboxlayout)
-        self.layout().addWidget(self.toolbar)
-        self.layout().addWidget(self.view)
-
-
-
-
-class Formatter(object):
-
-
-    def __init__(self, doc):
-        if isinstance(doc, QTextEdit):
-            doc = doc.document()
-        self.cursor = TextCursor(doc)
-        self.doc = doc
-
-
-    def new_paragraph(self, format):
-        bf, bcf = self.doc.styles.block_format(format)
-        self.cursor.insertBlock(bf)
-        self.cursor.setCharFormat(bcf)
-
-
-
-    def end_paragraph(self):
-        pass
-
-
-    def insert_text(self, text, cf_name):
-        self.cursor.insert_text(text, cf_name)
-
-
-
-    def insert_image(self, filename):
-        if filename.startswith("file://"):
-            filename = filename[7:]
-        self.cursor.insert_image(filename)
-
-
-    def insert_link(self, url):
-        self.cursor.insert_link(url)
-
-
-
-
-class Parser(object):
-
-
-    def __init__(self, formatter, data=None):
-        self.formatter = formatter
-        if data:
-            self.feed(data)
-
-
-    def feed(self, data):
-        pass
-
-
-
-
-
-import re
-
-
-
-
-class WikiParser(Parser):
-
-    paragraph_formats = [
-        "^= (?P<h1>.*) =$",
-        "^== (?P<h2>.*) ==$",
-        "^=== (?P<h3>.*) ===$",
-        "^==== (?P<h4>.*) ====$",
-        "^===== (?P<h5>.*) =====$",
-        "^====== (?P<h6>.*) ======$",
-        #" * (?P<_list>.*)",
-        "  (?P<code>.*)",
-        ]
-    char_formats = [
-        "\*\*(?P<strong>.*?)\*\*",
-        "''(?P<emphasis>.*?)''",
-        "__(?P<underline>.*)__",
-        "(?P<_image>(file|http)://[^ \t\n].*?\.(png|jpg|gif))",
-        "(?P<_link>http://[^ \t\n]+)",
-        ]
-
-
-    def feed(self, data):
-        self.parse(data)
-
-
-    def parse(self, data):
-        char_re = re.compile("|".join(self.char_formats))
-        paragraph_re = re.compile("|".join(self.paragraph_formats))
-        image_re = re.compile("file:/{}")
-        for line in data.split("\n"):
-            found = paragraph_re.match(line)
-            if found:
-                paragraph_format_name = found.lastgroup
-                paragraph_content = found.group(paragraph_format_name)
-            else:
-                paragraph_format_name = "p"
-                paragraph_content = line
-            if not paragraph_format_name.startswith("_"):
-                self.formatter.new_paragraph(paragraph_format_name)
-            last_pos = 0
-            for found in char_re.finditer(paragraph_content):
-                start, end = found.span()
-                if start > last_pos:
-                    self.formatter.insert_text(
-                        paragraph_content[last_pos:start], "normal")
-                last_pos = end
-                cf_name = found.lastgroup
-                char_content = found.group(cf_name)
-                if cf_name.startswith("_"):
-                    if cf_name == "_image":
-                        self.formatter.insert_image(char_content)
-                    elif cf_name == "_link":
-                        self.formatter.insert_link(char_content)
-                else:
-                    self.formatter.insert_text(char_content, cf_name)
-            if last_pos + 1 < len(paragraph_content):
-                self.formatter.insert_text(
-                    paragraph_content[last_pos:], "normal")
-            if not paragraph_format_name.startswith("_"):
-                self.formatter.end_paragraph()
-
-
-
-
-
-
-def main():
-    example = """\
-Sandbox
-
-= heading 1 =
-== heading 2 ==
-=== heading 3 ===
-
-This is a normal paragraph with **bold** and ''italic'' words.
-
-Here is an image:
-file:///usr/share/doc/ubuntu-artwork/html/img/headerlogo.png (Ubuntu Logo)
-
-
-Example code:
-
-  def hello():
-     print 'Hello, world'
-
-Now a list (TODO):
- * one
- * two
-
-
-Visit: http://programming.reddit.com
-"""
-
-    import sys
-    app = QApplication(sys.argv)
-    edit = WysiswymEditor()
-    edit.resize(640, 480)
-    parser = WikiParser(Formatter(edit.view), example)
-    edit.show()
-    app.exec_()
-    edit.view.document().dump()
-
-
-if __name__ == "__main__":
-    main()

contrib/htmledit.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# http://qt.gitorious.org/qt-labs/graphics-dojo/blobs/master/htmleditor/htmleditor.cpp
+# http://www.w3.org/TR/html5/editing.html#execCommand
+from PyQt4.QtCore import SIGNAL, QString
+from PyQt4.QtGui import (
+    QApplication, QVBoxLayout, QWidget, QFont, QLabel, QColor)
+from PyQt4.QtWebKit import QWebView, QWebPage
+
+
+js_helpers = """
+function getSelectionStart(){
+    var node = document.getSelection().anchorNode;
+    var startNode = (node.nodeName == "#text" ? node.parentNode : node);
+    return startNode;
+}
+"""
+
+class Editor(QWidget):
+
+
+    def __init__(self, parent):
+        QWidget.__init__(self)
+        self.vblayout = QVBoxLayout(self)
+        self.view = QWebView(self)
+        self.layout().addWidget(self.view)
+        self.sbar = QLabel(self)
+        self.layout().addWidget(self.sbar)
+        self.load("/usr/share/doc/ubuntu-artwork/html/home/firefox-index.html")
+
+
+    def set_html(self, html):
+        self.view.setContent(html, "text/html")
+        self.page = self.view.page()
+        self.page.setContentEditable(True)
+        self.page.setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
+        self.connect(self.page, SIGNAL("linkClicked(QUrl)"), self.on_link_clicked)
+        self.frame = self.page.mainFrame()
+        self.frame.evaluateJavaScript(js_helpers)
+
+        self.connect(self.page, SIGNAL("selectionChanged()"), self.on_selection_changed)
+        self.connect(self.page, SIGNAL("contentsChanged()"), self.on_contents_changed)
+
+
+    def convert_hashmap(self, d):
+        r = {}
+        for name, value in d.items():
+            if isinstance(value, QString):
+                value = unicode(value)
+            elif isinstance(value, dict):
+                value = self.convert_hashmap(value)
+            r[unicode(name)] = value
+        return r
+
+
+    def on_selection_changed(self):
+        r = self.frame.evaluateJavaScript("getSelectionStart()")
+        d = self.convert_hashmap(r.toPyObject())
+        print d
+
+
+
+    def on_contents_changed(self):
+        pass
+
+
+    def load(self, filename):
+        data = open(filename).read()
+        self.set_html(data)
+        
+
+
+    def on_link_clicked(self, url):
+        pass
+
+
+    def exec_command(self, cmd, arg=None):
+        if arg is None:
+            arg = "null"
+        else:
+            arg = repr(arg)
+        js = "document.execCommand(%r, false, %s)" % (
+            cmd, arg
+            )
+        self.frame.evaluateJavaScript(js)
+
+
+    
+
+
+    def query_command(self, cmd):
+        result = self.frame.evaluateJavaScript(js)
+        return unicode(result.toString())
+
+
+    def query_state(self, cmd):
+        result = self.query_command(cmd)
+        return result.lower() == "true"
+
+
+
+    def insert_html(self, html):
+        self.exec_command("insertHTML", html)
+
+
+    def insert_image(self, html):
+        self.exec_command("insertImage", html)
+
+
+    def create_link(self, link):
+        self.exec_command("createLink", link)
+
+
+    def format_block(self, paragraph_tag):
+        self.exec_command(paragraph_tag)
+
+
+    def align_left(self):
+        self.exec_command("justifyLeft")
+
+
+    def align_right(self):
+        self.exec_command("justifyRight")
+
+
+    def align_center(self):
+        self.exec_command("justifyCenter")
+
+
+    def align_justify(self):
+        self.exec_command("justifyFull")
+
+
+    def bold(self):
+        self.exec_command("bold")
+
+
+    def italic(self):
+        self.exec_command("italic")
+
+
+    def underline(self):
+        self.exec_command("underline")
+
+
+    def strike_through(self):
+        self.exec_command("strikeThrough")
+
+
+    def is_strike_through(self):
+        return self.query_state("strikeThrough")
+
+
+    def is_ordered_list(self):
+        return self.query_state("insertOrderedList")
+
+
+    def is_unordered_list(self):
+        return self.query_state("insertUnorderedList")
+
+
+    def indent(self):
+        self.exec_command("indent")
+
+
+    def dedent(self):
+        self.exec_command("outdent")
+
+
+    def insert_ordered_list(self):
+        self.exec_command("insertOrderedList")
+
+
+    def insert_unordered_list(self):
+        self.exec_command("insertUnorderedList")
+
+
+    def set_font_name(self, font):
+        if isinstance(font, QFont):
+            font = unicode(font.family())
+        self.exec_command("fontName", font)
+
+
+    def set_font_size(self, size):
+        size_list = ["xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large"]
+        if isinstance(size, basestring):
+            size = size_list.index(size)
+        self.exec_command("fontSize", size)
+
+
+    def set_font_color(self, color):
+        if not isinstance(color, QColor):
+            if instance(color, tuple):
+                color = QColor(*color)
+            else:
+                color = QColor(color)
+        self.exec_command("foreColor", unicode(color.name()))
+
+
+    def set_background_color(self, color):
+        if not isinstance(color, QColor):
+            if instance(color, tuple):
+                color = QColor(*color)
+            else:
+                color = QColor(color)
+        self.exec_command("hiliteColor", unicode(color.name()))
+
+
+
+def main():
+    import sys
+    app = QApplication(sys.argv)
+    edit = Editor(None)
+    edit.resize(640, 480)
+    edit.show()
+    app.exec_()
+
+if __name__ == "__main__":
+    main()

contrib/wysiwym.py

+# -*- coding: utf-8 -*-
+from PyQt4.QtCore import SIGNAL, QString, QVariant, Qt, QUrl
+from PyQt4.QtGui import (
+    QApplication, QToolBar, QComboBox, QFrame, QToolButton,
+    QFileDialog, QVBoxLayout, QBrush, QColor, QFont, QImage,
+    QTextFormat, QTextBlockFormat, QTextCharFormat, QTextImageFormat,
+    QTextFrameFormat, QTextDocument, QTextEdit, QTextCursor
+    )
+
+
+class jdict(dict):
+
+    def __getattr__(self, name):
+        return self.get(name, None)
+
+
+object_type_map = jdict(
+    text=QTextFormat.NoObject,
+    image=QTextFormat.ImageObject,
+    table=QTextFormat.TableObject,
+    cell=QTextFormat.TableCellObject,
+    link=QTextFormat.UserObject + 1,
+)
+reverse_object_type_map = dict(
+    [(v,k) for (k,v) in object_type_map.items()])
+
+
+property_format_map = dict(
+    name=QTextFormat.UserProperty + 1,
+    url=QTextFormat.UserProperty + 2
+)
+
+
+
+
+
+class FormatProperties(object):
+
+    property_format_map = property_format_map
+
+
+    def __init__(self, format):
+        self.format = format
+
+
+    def __getattr__(self, name):
+        return getattr(self.format, name)
+
+
+    def keys(self):
+        return self.property_format_map.keys()
+
+
+    def __getitem__(self, name):
+        prop_id = self.property_format_map.get(name)
+        if isinstance(prop_id, tuple):
+            getter, setter = prop_id
+            return getter(self, name)
+        variant = self.format.property(prop_id)
+        value = variant.toPyObject()
+        if isinstance(value, QString):
+            value = unicode(value)
+        return value
+
+
+    def __setitem__(self, name, value):
+        prop_id = self.property_format_map.get(name)
+        if not prop_id:
+            raise TypeError, "Unknown parameter %r" % name
+        elif isinstance(prop_id, tuple):
+            getter, setter = prop_id
+            setter(self, value)
+        else:
+            self.format.setProperty(prop_id, QVariant(value))
+
+
+
+class TextCharFormat(FormatProperties):
+
+
+    def get_bold(self):
+        return self.format.property(
+            QTextFormat.FontWeight).toPyObject() == QFont.Bold
+
+
+    def set_bold(self, flag):
+        if flag:
+            self.format.setProperty(
+                QTextFormat.FontWeight, QFont.Bold)
+        else:
+            self.format.setProperty(
+                QTextFormat.FontWeight, QFont.Normal)
+
+
+    def set_color(self, value):
+        self.format.setProperty(
+            QTextFormat.ForegroundBrush, QVariant(QBrush(QColor(value))))
+
+
+    def get_color(self):
+        return self.format.property(
+            QTextFormat.ForegroundBrush).toPyObject()
+
+
+
+    property_format_map = dict(property_format_map,
+      font_family=QTextFormat.FontFamily,
+      font_point_size=QTextFormat.FontPointSize,
+      font_pixel_size=QTextFormat.FontPixelSize,
+      font_weight=QTextFormat.FontWeight,
+      italic=QTextFormat.FontItalic,
+      underline=QTextFormat.FontUnderline,
+      bold=(get_bold, set_bold),
+      color=(get_color, set_color)
+    )
+
+
+class TextBlockFormat(FormatProperties):
+
+
+    def set_background(self, value):
+        self.format.setProperty(
+            QTextFormat.BackgroundBrush, QVariant(QBrush(QColor(value))))
+
+
+    def get_background(self):
+        return self.format.property(
+            QTextFormat.BackgroundBrush).toPyObject()
+
+
+
+    property_format_map = dict(property_format_map,
+      alignment=QTextFormat.BlockAlignment,
+      margin_left=QTextFormat.BlockLeftMargin,
+      margin_right=QTextFormat.BlockRightMargin,
+      margin_top=QTextFormat.BlockTopMargin,
+      margin_bottom=QTextFormat.BlockBottomMargin,
+      indent=QTextFormat.BlockIndent,
+      background=(get_background, set_background)
+    )
+
+
+
+class TextImageFormat(FormatProperties):
+
+    property_format_map = dict(property_format_map,
+      image_name=QTextFormat.ImageName,
+      image_width=QTextFormat.ImageWidth,
+      image_height=QTextFormat.ImageHeight
+    )
+
+
+
+class LinkCharFormat(TextCharFormat):
+
+
+    def __init__(self, cf):
+        TextCharFormat.__init__(self, cf)
+        cf.setFontUnderline(True)
+
+
+
+class Styles(object):
+
+
+    def __init__(self):
+        self.block_format_list = [
+            self.create_block_format("p", font_point_size=9),
+            self.create_block_format("h1", font_point_size=24,
+                                     alignment=Qt.AlignCenter),
+            self.create_block_format("h2", font_point_size=18),
+            self.create_block_format("h3", font_point_size=14, bold=True),
+            self.create_block_format("h4", font_point_size=12, bold=True),
+            self.create_block_format("h5", font_point_size=10, bold=True),
+            self.create_block_format("h6", font_point_size=8, bold=True),
+            self.create_block_format("code", font_family="monospace",
+                                     indent=1, background="lightyellow")
+        ]
+        self.char_format_list = [
+            self.create_char_format("normal"),
+            self.create_char_format("strong", bold=True),
+            self.create_char_format("emphasis", italic=True),
+            self.create_char_format("underline", underline=True),
+        ]
+
+
+    def format_name(self, format):
+        return FormatProperties(format)["name"]
+
+
+    def block_format(self, name):
+        for bf, bcf in self.block_format_list:
+            if self.format_name(bf) == name:
+                return bf, bcf
+
+
+    def char_format(self, name):
+        for f in self.char_format_list:
+            if self.format_name(f) == name:
+                return f
+
+
+    def create_char_format(self, name, **properties):
+        cf = TextCharFormat(QTextCharFormat())
+        cf["name"] = name
+        for pname, pvalue in properties.items():
+            cf[pname] = pvalue
+        return cf.format
+
+
+    def create_block_format(self, name, **properties):
+        bf = TextBlockFormat(QTextBlockFormat())
+        bf["name"] = name
+        cf = TextCharFormat(QTextCharFormat())
+        for pname, pvalue in properties.items():
+            if pname in bf.keys():
+                bf[pname] = pvalue
+            else:
+                cf[pname] = pvalue
+        return bf.format, cf.format
+
+
+
+
+class Document(QTextDocument):
+
+
+    def __init__(self, styles=None):
+        QTextDocument.__init__(self)
+        self.styles = styles or Styles()
+
+
+    def __iter__(self):
+        block = self.begin()
+        while block.isValid():
+            bf_name = self.styles.format_name(block.blockFormat())
+            parts = []
+            fragment_iterator = block.begin()
+            while not fragment_iterator.atEnd():
+                frag = fragment_iterator.fragment()
+                cf = frag.charFormat()
+                cf_name = self.styles.format_name(cf)
+                ot = reverse_object_type_map[cf.objectType()]
+                if ot == "image":
+                    data = TextImageFormat(cf)["image_name"]
+                elif ot == "link":
+                    data = LinkCharFormat(cf)["url"]
+                else:
+                    data = unicode(frag.text())
+                parts.append((cf_name, ot, data))
+                fragment_iterator += 1
+            yield bf_name, parts
+            block = block.next()
+
+
+    def dump(self):
+        for block_format, fragments in self:
+            print block_format, fragments
+
+
+
+
+class FormatSelectorWidget(QComboBox):
+
+    def setCurrentValue(self, text):
+        if text:
+            found = self.findText(text)
+            self.setCurrentIndex(found)
+
+
+class ParagaphFormatSelector(FormatSelectorWidget):
+    pass
+
+
+class CharFormatSelector(FormatSelectorWidget):
+    pass
+
+
+
+class WysiswymFormatToolbar(QToolBar):
+
+
+    def __init__(self, editor):
+        QToolBar.__init__(self, editor)
+        self.paragraph_formats = ParagaphFormatSelector(self)
+        self.view = editor.view
+        self.styles = editor.view.styles
+        for bf, bcf in self.styles.block_format_list:
+            self.paragraph_formats.addItem(
+                self.styles.format_name(bf))
+        self.connect(self.paragraph_formats,
+                     SIGNAL("activated(const QString&)"),
+                     self.on_change_paragraph_style)
+        self.addWidget(self.paragraph_formats)
+        self.char_formats = CharFormatSelector(self)
+        for f in self.styles.char_format_list:
+            self.char_formats.addItem(
+                self.styles.format_name(f))
+        self.connect(self.char_formats,
+                     SIGNAL("activated(const QString&)"),
+                     self.on_change_char_style)
+        self.addWidget(self.char_formats)
+        self.connect(editor.view,
+                     SIGNAL("cursorPositionChanged()"),
+                     self.cursor_pos_changed)
+        self.add_image_button = QToolButton(self)
+        self.add_image_button.setText("Add image...")
+        self.addWidget(self.add_image_button)
+        self.connect(self.add_image_button, SIGNAL("clicked()"),
+                     self.on_add_image)
+
+
+    def cursor_pos_changed(self):
+        cursor = self.view.textCursor()
+        bf_name = self.styles.format_name(
+            cursor.blockFormat())
+        self.paragraph_formats.setCurrentValue(bf_name)
+        cf_name = self.styles.format_name(
+            cursor.charFormat())
+        self.char_formats.setCurrentValue(cf_name)
+
+
+    def on_add_image(self):
+        filename = QFileDialog.getOpenFileName(
+            self, "Add image..", "", "Images (*.png *.jpg *.gif)")
+        if filename:
+            filename = unicode(filename)
+            self.view.textCursor().insert_image(filename)
+
+
+    def on_change_paragraph_style(self, name):
+        self.view.textCursor().change_paragraph_style(name)
+
+
+    def on_change_char_style(self, name):
+        self.view.textCursor().change_char_style(name)
+
+
+
+
+class TextCursor(QTextCursor):
+
+
+    def __init__(self, tc_or_doc_or_block):
+        QTextCursor.__init__(self, tc_or_doc_or_block)
+
+
+    def insert_image(self, filename, align=QTextFrameFormat.InFlow):
+        #QTextFrameFormat.FloatLeft, QTextFrameFormat.FloatRight
+        img = QImage(filename)
+        self.document().addResource(
+            QTextDocument.ImageResource, QUrl(filename), img)
+        tif = QTextImageFormat()
+        tif.setName(filename)
+        self.insertImage(tif, align)
+
+
+    def insert_text(self, text, cf_name=None):
+        styles = self.document().styles
+        bf_name = TextBlockFormat(self.blockFormat())["name"]
+        bf, bcf = styles.block_format(bf_name)
+        cf = styles.char_format(cf_name)
+        if cf:        
+            merged_cf = QTextCharFormat()
+            merged_cf.merge(cf)
+            merged_cf.merge(bcf)
+        else:
+            merged_cf = bcf
+        self.insertText(text, merged_cf)
+        return merged_cf
+
+
+    def insert_link(self, url):
+        cf = self.document().styles.create_char_format("_link", underline=True, color="blue")
+        LinkCharFormat(cf)["url"] = url
+        cf.setObjectType(object_type_map.link)
+        self.insertText(url, cf)
+
+
+
+    def change_paragraph_style(self, name):
+        bf, bcf = self.document().styles.block_format(unicode(name))
+        self.setBlockFormat(bf)
+        self.select(QTextCursor.BlockUnderCursor)
+        format = QTextCharFormat()
+        format.merge(self.charFormat())
+        format.merge(bcf)
+        self.setCharFormat(format)
+
+
+    def change_char_style(self, name):
+        styles = self.document().styles
+        cf = styles.char_format(unicode(name))
+        bf = TextBlockFormat(self.blockFormat())
+        bf, bcf = styles.block_format(bf["name"])
+        merged_cf = QTextCharFormat()
+        merged_cf.merge(bcf)
+        merged_cf.merge(cf)
+        self.setCharFormat(merged_cf)
+
+
+
+
+class WysiswymView(QTextEdit):
+
+
+    def __init__(self, parent=None, styles=None):
+        QTextEdit.__init__(self, parent)
+        self.doc = Document(styles)
+        self.styles = self.doc.styles
+        self.setDocument(self.doc)
+
+
+    def textCursor(self):
+        return TextCursor(QTextEdit.textCursor(self))
+
+
+
+
+class WysiswymEditor(QFrame):
+
+    def __init__(self, parent=None):
+        QFrame.__init__(self, parent)
+        self.view = WysiswymView(self)
+        self.toolbar = WysiswymFormatToolbar(self)
+        self.vboxlayout = QVBoxLayout(self)
+        self.setLayout(self.vboxlayout)
+        self.layout().addWidget(self.toolbar)
+        self.layout().addWidget(self.view)
+
+
+
+
+class Formatter(object):
+
+
+    def __init__(self, doc):
+        if isinstance(doc, QTextEdit):
+            doc = doc.document()
+        self.cursor = TextCursor(doc)
+        self.doc = doc
+
+
+    def new_paragraph(self, format):
+        bf, bcf = self.doc.styles.block_format(format)
+        self.cursor.insertBlock(bf)
+        self.cursor.setCharFormat(bcf)
+
+
+
+    def end_paragraph(self):
+        pass
+
+
+    def insert_text(self, text, cf_name):
+        self.cursor.insert_text(text, cf_name)
+
+
+
+    def insert_image(self, filename):
+        if filename.startswith("file://"):
+            filename = filename[7:]
+        self.cursor.insert_image(filename)
+
+
+    def insert_link(self, url):
+        self.cursor.insert_link(url)
+
+
+
+
+class Parser(object):
+
+
+    def __init__(self, formatter, data=None):
+        self.formatter = formatter
+        if data:
+            self.feed(data)
+
+
+    def feed(self, data):
+        pass
+
+
+
+
+
+import re
+
+
+
+
+class WikiParser(Parser):
+
+    paragraph_formats = [
+        "^= (?P<h1>.*) =$",
+        "^== (?P<h2>.*) ==$",
+        "^=== (?P<h3>.*) ===$",
+        "^==== (?P<h4>.*) ====$",
+        "^===== (?P<h5>.*) =====$",
+        "^====== (?P<h6>.*) ======$",
+        #" * (?P<_list>.*)",
+        "  (?P<code>.*)",
+        ]
+    char_formats = [
+        "\*\*(?P<strong>.*?)\*\*",
+        "''(?P<emphasis>.*?)''",
+        "__(?P<underline>.*)__",
+        "(?P<_image>(file|http)://[^ \t\n].*?\.(png|jpg|gif))",
+        "(?P<_link>http://[^ \t\n]+)",
+        ]
+
+
+    def feed(self, data):
+        self.parse(data)
+
+
+    def parse(self, data):
+        char_re = re.compile("|".join(self.char_formats))
+        paragraph_re = re.compile("|".join(self.paragraph_formats))
+        image_re = re.compile("file:/{}")
+        for line in data.split("\n"):
+            found = paragraph_re.match(line)
+            if found:
+                paragraph_format_name = found.lastgroup
+                paragraph_content = found.group(paragraph_format_name)
+            else:
+                paragraph_format_name = "p"
+                paragraph_content = line
+            if not paragraph_format_name.startswith("_"):
+                self.formatter.new_paragraph(paragraph_format_name)
+            last_pos = 0
+            for found in char_re.finditer(paragraph_content):
+                start, end = found.span()
+                if start > last_pos:
+                    self.formatter.insert_text(
+                        paragraph_content[last_pos:start], "normal")
+                last_pos = end
+                cf_name = found.lastgroup
+                char_content = found.group(cf_name)
+                if cf_name.startswith("_"):
+                    if cf_name == "_image":
+                        self.formatter.insert_image(char_content)
+                    elif cf_name == "_link":
+                        self.formatter.insert_link(char_content)
+                else:
+                    self.formatter.insert_text(char_content, cf_name)
+            if last_pos + 1 < len(paragraph_content):
+                self.formatter.insert_text(
+                    paragraph_content[last_pos:], "normal")
+            if not paragraph_format_name.startswith("_"):
+                self.formatter.end_paragraph()
+
+
+
+
+
+
+def main():
+    example = """\
+Sandbox
+
+= heading 1 =
+== heading 2 ==
+=== heading 3 ===
+
+This is a normal paragraph with **bold** and ''italic'' words.
+
+Here is an image:
+file:///usr/share/doc/ubuntu-artwork/html/img/headerlogo.png (Ubuntu Logo)
+
+
+Example code:
+
+  def hello():
+     print 'Hello, world'
+
+Now a list (TODO):
+ * one
+ * two
+
+
+Visit: http://programming.reddit.com
+"""
+
+    import sys
+    app = QApplication(sys.argv)
+    edit = WysiswymEditor()
+    edit.resize(640, 480)
+    parser = WikiParser(Formatter(edit.view), example)
+    edit.show()
+    app.exec_()
+    edit.view.document().dump()
+
+
+if __name__ == "__main__":
+    main()

contrib/wysiwym2.py

+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+try:
+   # This is only needed for Python v2 but is harmless for Python v3.
+   import sip
+   sip.setapi('QVariant', 2)
+except ImportError:
+   pass
+
+from PyQt4 import QtCore, QtGui
+
+
+
+
+class WysiwymWidgetEditor(QtGui.QWidget):
+
+   TEXT_OBJECT_WRAPPER = QtGui.QTextFormat.UserObject + 1001
+
+
+   def __init__(self):
+       super(WysiwymWidgetEditor, self).__init__()
+
+       self.setWindowTitle('WysiwymWidgetEditor')
+
+       self.textEdit = QtGui.QTextEdit()
+       widget = QtGui.QLineEdit()
+       widget.setText('I am here!')
+       self.text_object_wrapper(self.textEdit, widget)
+
+       layout = _vertical( self.textEdit )
+
+       self.setLayout(layout)
+
+       cursor = self.textEdit.textCursor()
+       cursor.insertText('previously\n')
+
+       self.insertTextObject(cursor)
+
+       cursor.insertText('subsequently')
+       self.textEdit.setTextCursor(cursor)
+
+   def text_object_wrapper(self, editor, widget):
+       class _TextObject(QtGui.QPyTextObject):
+        
+           def intrinsicSize(self, doc, posInDocument, format):
+        
+               size = widget.sizeHint()
+               return QtCore.QSizeF(size)
+        
+           def drawObject(self, painter, rect, doc, posInDocument, format):
+               widget.resize(widget.sizeHint())
+               widget.render(painter, QtCore.QPoint(int(rect.x()), int(rect.y())))
+
+
+       interface = _TextObject(self)
+       editor.document().documentLayout().registerHandler(WysiwymWidgetEditor.TEXT_OBJECT_WRAPPER, interface)
+
+   def insertTextObject(self, cursor):
+
+       charFormat = QtGui.QTextCharFormat()
+       charFormat.setObjectType(WysiwymWidgetEditor.TEXT_OBJECT_WRAPPER)
+
+       try:
+           # Python v2.
+           orc = unichr(0xfffc)
+       except NameError:
+           # Python v3.
+           orc = chr(0xfffc)
+
+       cursor.insertText(orc, charFormat)
+
+
+def _vertical(*things):
+   return _lay_out(QtGui.QVBoxLayout, *things)
+
+def _lay_out(LayoutClass, *things):
+   layout = LayoutClass()
+
+   for thing in things:
+       if hasattr(thing, 'BottomToTop'):
+           layout.addLayout(thing)
+       else:
+           layout.addWidget(thing)
+
+   return layout
+
+
+
+if __name__ == '__main__':
+
+   import sys
+
+   app = QtGui.QApplication(sys.argv)
+   window = WysiwymWidgetEditor()
+   window.show()
+   sys.exit(app.exec_())