QScintilla/Exporters/ExporterHTML.py

changeset 0
de9c2efb9d02
child 12
1d8dd9706f46
diff -r 000000000000 -r de9c2efb9d02 QScintilla/Exporters/ExporterHTML.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QScintilla/Exporters/ExporterHTML.py	Mon Dec 28 16:03:33 2009 +0000
@@ -0,0 +1,364 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2007 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing an exporter for HTML.
+"""
+
+# This code is a port of the C++ code found in SciTE 1.74
+# Original code: Copyright 1998-2006 by Neil Hodgson <neilh@scintilla.org>
+
+import os
+
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+from PyQt4.Qsci import QsciScintilla
+
+from ExporterBase import ExporterBase
+
+import Preferences
+import Utilities
+
+class ExporterHTML(ExporterBase):
+    """
+    Class implementing an exporter for HTML.
+    """
+    def __init__(self, editor, parent = None):
+        """
+        Constructor
+        
+        @param editor reference to the editor object (QScintilla.Editor.Editor)
+        @param parent parent object of the exporter (QObject)
+        """
+        ExporterBase.__init__(self, editor, parent)
+    
+    def exportSource(self):
+        """
+        Public method performing the export.
+        """
+        filename = self._getFileName(self.trUtf8("HTML Files (*.html)"))
+        if not filename:
+            return
+        
+        try:
+            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
+            QApplication.processEvents()
+            
+            self.editor.recolor(0, -1)
+            
+            tabSize = Preferences.getEditor("TabWidth")
+            if tabSize == 0:
+                tabSize = 4
+            wysiwyg = Preferences.getEditorExporter("HTML/WYSIWYG")
+            folding = Preferences.getEditorExporter("HTML/Folding")
+            onlyStylesUsed = Preferences.getEditorExporter("HTML/OnlyStylesUsed")
+            titleFullPath = Preferences.getEditorExporter("HTML/FullPathAsTitle")
+            tabs = Preferences.getEditorExporter("HTML/UseTabs")
+            
+            lengthDoc = self.editor.length()
+            styleIsUsed = {}
+            if onlyStylesUsed:
+                for index in range(QsciScintilla.STYLE_MAX + 1):
+                    styleIsUsed[index] = False
+                # check the used styles
+                pos = 0
+                while pos < lengthDoc:
+                    styleIsUsed[self.editor.styleAt(pos) & 0x7F] = True
+                    pos += 1
+            else:
+                for index in range(QsciScintilla.STYLE_MAX + 1):
+                    styleIsUsed[index] = True
+            styleIsUsed[QsciScintilla.STYLE_DEFAULT] = True
+            
+            try:
+                f = open(filename, "wb")
+                
+                f.write(
+                    '''<!DOCTYPE html PUBLIC "-//W3C//DTD'''
+                    ''' XHTML 1.0 Transitional//EN"\n''')
+                f.write(
+                    ''' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n''')
+                f.write('''<html xmlns="http://www.w3.org/1999/xhtml">\n''')
+                f.write('''<head>\n''')
+                if titleFullPath:
+                    f.write('''<title>%s</title>\n''' % self.editor.getFileName())
+                else:
+                    f.write('''<title>%s</title>\n''' % \
+                        os.path.basename(self.editor.getFileName()))
+                f.write('''<meta name="Generator" content="eric4" />\n''')
+                f.write('''<meta http-equiv="Content-Type" '''
+                        '''content="text/html; charset=utf-8" />\n''')
+                if folding:
+                    f.write('''<script language="JavaScript" type="text/javascript">\n'''
+                            '''<!--\n'''
+                            '''function symbol(id, sym) {\n'''
+                            '''  if (id.textContent == undefined) {\n'''
+                            '''    id.innerText = sym;\n'''
+                            '''  } else {\n'''
+                            '''    id.textContent = sym;\n'''
+                            '''  }\n'''
+                            '''}\n'''
+                            '''function toggle(id) {\n'''
+                            '''  var thislayer = document.getElementById('ln' + id);\n'''
+                            '''  id -= 1;\n'''
+                            '''  var togline = document.getElementById('hd' + id);\n'''
+                            '''  var togsym = document.getElementById('bt' + id);\n'''
+                            '''  if (thislayer.style.display == 'none') {\n'''
+                            '''    thislayer.style.display = 'block';\n'''
+                            '''    togline.style.textDecoration = 'none';\n'''
+                            '''    symbol(togsym, '- ');\n'''
+                            '''  } else {\n'''
+                            '''    thislayer.style.display = 'none';\n'''
+                            '''    togline.style.textDecoration = 'underline';\n'''
+                            '''    symbol(togsym, '+ ');\n'''
+                            '''  }\n'''
+                            '''}\n'''
+                            '''//-->\n'''
+                            '''</script>\n'''
+                    )
+                
+                lex = self.editor.getLexer()
+                if lex:
+                    bgColour = lex.paper(QsciScintilla.STYLE_DEFAULT).name()
+                else:
+                    bgColour = self.editor.paper().name()
+                
+                f.write('''<style type="text/css">\n''')
+                if lex:
+                    istyle = 0
+                    while istyle <= QsciScintilla.STYLE_MAX:
+                        if (istyle <= QsciScintilla.STYLE_DEFAULT or \
+                            istyle > QsciScintilla.STYLE_LASTPREDEFINED) and \
+                           styleIsUsed[istyle]:
+                            if lex.description(istyle) or \
+                               istyle == QsciScintilla.STYLE_DEFAULT:
+                                font = lex.font(istyle)
+                                colour = lex.color(istyle)
+                                paper = lex.paper(istyle)
+                                if istyle == QsciScintilla.STYLE_DEFAULT:
+                                    f.write('''span {\n''')
+                                else:
+                                    f.write('''.S%d {\n''' % istyle)
+                                if font.italic():
+                                    f.write('''    font-style: italic;\n''')
+                                if font.bold():
+                                    f.write('''    font-weight: bold;\n''')
+                                if wysiwyg:
+                                    f.write('''    font-family: '%s';\n''' % \
+                                            font.family())
+                                f.write('''    color: %s;\n''' % colour.name())
+                                if istyle != QsciScintilla.STYLE_DEFAULT and \
+                                   bgColour != paper.name():
+                                    f.write('''    background: %s;\n''' % paper.name())
+                                    f.write('''    text-decoration: inherit;\n''')
+                                if wysiwyg:
+                                    f.write('''    font-size: %dpt;\n''' % \
+                                            QFontInfo(font).pointSize())
+                                f.write('''}\n''')
+                            else:
+                                styleIsUsed[istyle] = False
+                        istyle += 1
+                else:
+                    colour = self.editor.color()
+                    paper = self.editor.paper()
+                    font = Preferences.getEditorOtherFonts("DefaultFont")
+                    f.write('''.S0 {\n''')
+                    if font.italic():
+                        f.write('''    font-style: italic;\n''')
+                    if font.bold():
+                        f.write('''    font-weight: bold;\n''')
+                    if wysiwyg:
+                        f.write('''    font-family: '%s';\n''' % font.family())
+                    f.write('''    color: %s;\n''' % colour.name())
+                    if bgColour != paper.name():
+                        f.write('''    background: %s;\n''' % paper.name())
+                        f.write('''    text-decoration: inherit;\n''')
+                    if wysiwyg:
+                        f.write('''    font-size: %dpt;\n''' % \
+                                QFontInfo(font).pointSize())
+                    f.write('''}\n''')
+                f.write('''</style>\n''')
+                f.write('''</head>\n''')
+                
+                f.write('''<body bgcolor="%s">\n''' % bgColour)
+                line = self.editor.lineAt(0)
+                level = self.editor.foldLevelAt(line) - QsciScintilla.SC_FOLDLEVELBASE
+                levelStack = [level]
+                styleCurrent = self.editor.styleAt(0)
+                inStyleSpan = False
+                inFoldSpan = False
+                # Global span for default attributes
+                if wysiwyg:
+                    f.write('''<span>''')
+                else:
+                    f.write('''<pre>''')
+                
+                if folding:
+                    if self.editor.foldFlagsAt(line) & \
+                       QsciScintilla.SC_FOLDLEVELHEADERFLAG:
+                        f.write('''<span id="hd%d" onclick="toggle('%d')">''' % \
+                                (line, line + 1))
+                        f.write('''<span id="bt%d">- </span>''' % line)
+                        inFoldSpan = True
+                    else:
+                        f.write('''&nbsp; ''')
+                
+                if styleIsUsed[styleCurrent]:
+                    f.write('''<span class="S%0d">''' % styleCurrent)
+                    inStyleSpan = True
+                
+                column = 0
+                pos = 0
+                utf8 = self.editor.isUtf8()
+                utf8Ch = ""
+                utf8Len = 0
+                
+                while pos < lengthDoc:
+                    ch = self.editor.rawCharAt(pos)
+                    style = self.editor.styleAt(pos)
+                    if style != styleCurrent:
+                        if inStyleSpan:
+                            f.write('''</span>''')
+                            inStyleSpan = False
+                        if ch not in ['\r', '\n']: # no need of a span for the EOL
+                            if styleIsUsed[style]:
+                                f.write('''<span class="S%d">''' % style)
+                                inStyleSpan = True
+                            styleCurrent = style
+                    
+                    if ch == ' ':
+                        if wysiwyg:
+                            prevCh = ''
+                            if column == 0: 
+                                # at start of line, must put a &nbsp; 
+                                # because regular space will be collapsed
+                                prevCh = ' '
+                            while pos < lengthDoc and self.editor.rawCharAt(pos) == ' ':
+                                if prevCh != ' ':
+                                    f.write(' ')
+                                else:
+                                    f.write('''&nbsp;''')
+                                prevCh = self.editor.rawCharAt(pos)
+                                pos += 1
+                                column += 1
+                            pos -= 1 
+                            # the last incrementation will be done by the outer loop
+                        else:
+                            f.write(' ')
+                            column += 1
+                    elif ch == '\t':
+                        ts = tabSize - (column % tabSize)
+                        if wysiwyg:
+                            f.write('''&nbsp;''' * ts)
+                            column += ts
+                        else:
+                            if tabs:
+                                f.write(ch)
+                                column += 1
+                            else:
+                                f.write(' ' * ts)
+                                column += ts
+                    elif ch in ['\r', '\n']:
+                        if inStyleSpan:
+                            f.write('''</span>''')
+                            inStyleSpan = False
+                        if inFoldSpan:
+                            f.write('''</span>''')
+                            inFoldSpan = False
+                        if ch == '\r' and self.editor.rawCharAt(pos + 1) == '\n':
+                            pos += 1 # CR+LF line ending, skip the "extra" EOL char
+                        column = 0
+                        if wysiwyg:
+                            f.write('''<br />''')
+                        
+                        styleCurrent = self.editor.styleAt(pos + 1)
+                        if folding:
+                            line = self.editor.lineAt(pos + 1)
+                            newLevel = self.editor.foldLevelAt(line)
+                            
+                            if newLevel < level:
+                                while levelStack[-1] > newLevel:
+                                    f.write('''</span>''')
+                                    levelStack.pop()
+                            f.write('\n') # here to get clean code
+                            if newLevel > level:
+                                f.write('''<span id="ln%d">''' % line)
+                                levelStack.append(newLevel)
+                            if self.editor.foldFlagsAt(line) & \
+                               QsciScintilla.SC_FOLDLEVELHEADERFLAG:
+                                f.write('''<span id="hd%d" onclick="toggle('%d')">''' % \
+                                        (line, line + 1))
+                                f.write('''<span id="bt%d">- </span>''' % line)
+                                inFoldSpan = True
+                            else:
+                                f.write('''&nbsp; ''')
+                            level = newLevel
+                        else:
+                            f.write('\n')
+                        
+                        if styleIsUsed[styleCurrent] and \
+                           self.editor.rawCharAt(pos + 1) not in ['\r', '\n']:
+                            # We know it's the correct next style,
+                            # but no (empty) span for an empty line
+                            f.write('''<span class="S%0d">''' % styleCurrent)
+                            inStyleSpan = True
+                    else:
+                        if ch == '<':
+                            f.write('''&lt;''')
+                        elif ch == '>':
+                            f.write('''&gt''')
+                        elif ch == '&':
+                            f.write('''&amp;''')
+                        else:
+                            if ord(ch) > 127 and utf8:
+                                utf8Ch += ch
+                                if utf8Len == 0:
+                                    if (ord(utf8Ch[0]) & 0xF0) == 0xF0:
+                                        utf8Len = 4
+                                    elif (ord(utf8Ch[0]) & 0xE0) == 0xE0:
+                                        utf8Len = 3
+                                    elif (ord(utf8Ch[0]) & 0xC0) == 0xC0:
+                                        utf8Len = 2
+                                    column -= 1 # will be incremented again later
+                                elif len(utf8Ch) == utf8Len:
+                                    ch = utf8Ch.decode('utf8')
+                                    f.write(Utilities.html_encode(ch))
+                                    utf8Ch = ""
+                                    utf8Len = 0
+                                else:
+                                    column -= 1 # will be incremented again later
+                            else:
+                                f.write(ch)
+                        column += 1
+                    
+                    pos += 1
+                
+                if inStyleSpan:
+                    f.write('''</span>''')
+                
+                if folding:
+                    while levelStack:
+                        f.write('''</span>''')
+                        levelStack.pop()
+                
+                if wysiwyg:
+                    f.write('''</span>''')
+                else:
+                    f.write('''</pre>''')
+                
+                f.write('''</body>\n</html>\n''')
+                f.close()
+            except IOError, err:
+                QApplication.restoreOverrideCursor()
+                QMessageBox.critical(self.editor,
+                    self.trUtf8("Export source"),
+                    self.trUtf8(\
+                        """<p>The source could not be exported to <b>{0}</b>.</p>"""
+                        """<p>Reason: {1}</p>""")\
+                        .format(filename, unicode(err)),
+                    QMessageBox.StandardButtons(\
+                        QMessageBox.Ok))
+        finally:
+            QApplication.restoreOverrideCursor()

eric ide

mercurial