diff options
Diffstat (limited to 'kbarcode/dsrichtext.cpp')
-rw-r--r-- | kbarcode/dsrichtext.cpp | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/kbarcode/dsrichtext.cpp b/kbarcode/dsrichtext.cpp new file mode 100644 index 0000000..01f7182 --- /dev/null +++ b/kbarcode/dsrichtext.cpp @@ -0,0 +1,427 @@ +/*************************************************************************** + dsrichtext.cpp - description + ------------------- + begin : Fre Okt 17 2003 + copyright : (C) 2003 by Dominik Seichter + email : domseichter@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "dsrichtext.h" + +#ifdef QT_TEXT_BUG + +// Qt includes +#include <qfontmetrics.h> +#include <qpainter.h> +#include <qregexp.h> + +// for DSREPLACE +#include "sqltables.h" + +/* +EXAMPLE TEXT: + "<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body style=\"font-size:10pt;font-family:Nimbus Sans l\">" + "<p>A little bit <span style=\"font-style:italic;font-weight:600\">formated</span><span style=\"color:#4400ff\"> " + "richtext</span> which should be printed to a <span style=\"font-weight:600\">QPrinter</span> with <span style=\"text-decoration:underline\">QSimpleRichText</span>. </p>" + "<p><span style=\"font-family:Times New Roman;font-size:16pt\">Printing should work in ScreenResolution as well as in HighResolution, but as you can see it will only work in ScreenResolution.</span></p>" + "</body></html>"; + +Another example +<html><head><meta name="qrichtext" content="1" /></head><body style="font-size:10pt;font-family:Nimbus Sans l"> +<p align="center"><span style="font-size:12pt;font-weight:600;text-decoration:underline">Text test </span><span style="font-size:12pt;font-weight:600;text-decoration:underline;color:#ff0000">label</span></p> +<p>Resolution <span style="font-weight:600">formated</span> 108dpi. This text & text should now overlap with the first line. 4 < 6a</p> +<p><span style="font-family:Nimbus Sans L;font-weight:600">A</span><span style="font-family:Nimbus Sans L"> longer paragraph with some text, so that I can test wether wordwrap is working. Another "line" to test line spacing without a bigger font (like the one found in the next sentence) messing up the spacing.</span><span style="font-family:Courier [Adobe];font-size:16pt"> Some text "in" a bigger courier font.</span><span style="font-family:Nimbus Sans L"> Also this paragraph should be justified as blockquote.</span><span style="font-family:Nimbus Sans L;color:#ff0004"> I hope it works</span><span style="font-family:Nimbus Sans L"> and KBarcodes text redering will be better than the one found in Qt.</span></p> +</body></html> + +*/ + +DSRichText::DSRichText( const QString & t ) + : text( t ) +{ + if( text.find("<html>") == -1 ) + text = "<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body style=\"font-size:10pt;font-family:Nimbus Sans l\"><p>" + + t + "</p></body></html>"; + + //qDebug( text ); + + start = end = pos = 0; + x = y = 0; + sx = sy = 1.0; + m_base = QFont(); + + QString tmp = parse( text, "<body ", ">", 0 ); + if( !tmp.isNull() ) { + pos += tmp.length(); + tmp = tmp.left( tmp.length() - 1 ); + tmp = tmp.mid( 5, tmp.length() - 5 ); + m_base = parseStyle( parse( tmp, "style=\"", "\"", pos ), &m_color ); + } + + pos = text.find( "<p", 0 ); // initalize pos correctly + while( parseParagraph() ); // empty while loop +} + +DSRichText::~DSRichText() +{ +} + +void DSRichText::initFormat( formated_word* f, int alignment ) +{ + f->text = QString::null; + f->line = false; + f->alignment = alignment; + f->font = m_base; + f->color = m_color; +} + +void DSRichText::initLine( QValueList<formated_line>* l ) +{ + formated_line li; + li.width = 0; + li.ascent = 0; + li.leading = 0; + li.lineSpacing = 0; + li.line = false; + l->append( li ); +} + +void DSRichText::updateSpacing( QValueList<formated_line>* l, QFontMetrics* fm ) +{ + l->last().lineSpacing = (l->last().lineSpacing < fm->lineSpacing()) ? fm->lineSpacing() : l->last().lineSpacing; + l->last().ascent = (l->last().ascent < fm->ascent()) ? fm->ascent() : l->last().ascent; + l->last().leading = (l->last().leading < fm->leading()) ? fm->leading() : l->last().leading; +} + +void DSRichText::fillLines() +{ + for( unsigned int z = 0; z < word_p.count(); z++ ) { + WordList words = word_p[z]; + LineList lines; + initLine( &lines ); + for( unsigned int i = 0; i < words.count(); i++ ) { + formated_word word = words[i]; + lines.last().line = lines.last().line | word.line; + + QFontMetrics fm( word.font ); + updateSpacing( &lines, &fm ); + + int tw = fm.width( word.text ); + // word does not fit in the current line, create a new one + if( lines.last().width + tw >= w ) + initLine( &lines ); + + // TODO: check here for words longer than one line + lines.last().formats.append( word ); + lines.last().width += tw; + } + line_p.append( lines ); + } +} + +void DSRichText::draw( QPainter* p ) +{ + /* don't try to draw if there is no space to draw */ + if( !w || !h ) + return; + + fillLines(); + + painter = p; + painter->save(); + painter->setClipRect( xpos, ypos, int(w*sx), int(h*sy), QPainter::CoordPainter ); + + for( unsigned int z = 0; z < line_p.count(); z++ ) { + LineList lines = line_p[z]; + if( lines.count() && z ) + y += int( lines[0].lineSpacing * 0.5); + + for( unsigned int i = 0; i < lines.count(); i++ ) { + formated_line l = lines[i]; + + if( l.formats.count() && l.formats[0].alignment == Qt::AlignJustify && i != lines.count() - 1 ) { + // last line in a paragraph is not justified (in blocksatz mode)! + drawJustified( &l ); + } else { + for( unsigned int z = 0; z < l.formats.count(); z++ ) { + formated_word f = l.formats[z]; + + painter->setFont( f.font ); + painter->setPen( QPen( f.color ) ); + + int a = f.alignment; + if( a == Qt::AlignRight ) { + a = Qt::AlignLeft; + if( !x ) + x = w - l.width; + } else if( a == Qt::AlignHCenter ) { + a = Qt::AlignLeft; + if( !x ) + x = ( w - l.width ) / 2; + } + + int ya = yDeviation( &l ); + painter->drawText( xpos + int(x*sx), ypos + int((y+ya)*sy), int(l.width*sx), int(l.lineSpacing * sy), a, f.text ); + x += painter->fontMetrics().width( f.text ); + } + } + + x = 0; + y += l.lineSpacing; + } + } + + painter->restore(); +} + +void DSRichText::drawJustified( formated_line* line ) +{ + int all = 0; + for( unsigned int z = 0; z < line->formats.count(); z++ ) { + line->formats[z].text = line->formats[z].text.stripWhiteSpace(); + QFontMetrics fm( line->formats[z].font ); + all += fm.width( line->formats[z].text ); + } + + int x = 0; + int space = (w - all) / (line->formats.count() - 1); + for( unsigned int z = 0; z < line->formats.count(); z++ ) { + painter->setFont( line->formats[z].font ); + painter->setPen( QPen( line->formats[z].color ) ); + + int ya = yDeviation( line ); + int tw = painter->fontMetrics().width(line->formats[z].text); + painter->drawText( int(x*sx), int((y+ya)*sy), int(tw*sx), int(line->lineSpacing * sy), Qt::AlignAuto, line->formats[z].text ); + x += tw; + x += space; + } + +} + +bool DSRichText::parseParagraph() +{ + int alignment = 0; + formated_word f; + QString d = parse( text, "<p", "</p>", pos ); + //qDebug("D=" + d ); + //qDebug("POS=%i", pos ); + + pos += d.length(); + if( d.isNull() ) + return false; + + d = parseParagraphTag( d, &alignment ); + + WordList words; + QString data; + initFormat( &f, alignment ); + + if( d.isEmpty() ) { + // found empty paragraph + words.append( f ); + word_p.append( words ); + return true; + } + + for( unsigned int i = 0; i < d.length(); ) { + if( d[i] == '<' || i == (d.length() - 1) ) { + if( i == (d.length() - 1) ) + data.append( d[i] ); + + parseWords( data, &f, &words ); + initFormat( &f, alignment ); + data = QString::null; + + // bail out now, otherwise there is + // and endless loop for e.g. <p>a</p> + if( i == (d.length() - 1) ) + break; + + if( d[i] == '<' ) { + QString span = d.mid( i, d.find( ">", i ) - i + 1 ); + i += span.length(); + + if( span.startsWith( "<span " ) ) { + initFormat( &f, alignment ); + f.font = parseStyle( parse( span, "style=\"", "\"", 0 ), &f.color ); + } + } + } else { + data.append( d[i] ); + i++; + } + } + + word_p.append( words ); + return true; +} + +QFont DSRichText::parseStyle( const QString & s, QColor* color ) +{ + QString style = QString( s ); + + style = style.left( style.length() - 1 ); + if( style.startsWith("style=\"" ) ) + style = style.mid( 7, style.length() - 7 ); + + QFont f = m_base; + *color = m_color; + + for ( int i = 0; i < style.contains(';')+1; i++ ) { + QString s = style.section( ';', i, i ); + if( s.isEmpty() ) + continue; + + if ( s.startsWith("font-size:" ) ) { + f.setPointSize( s.mid(10, s.length() - 12).toInt() ); + } else if ( s.startsWith("font-family:" ) ) { + f.setFamily( s.right( s.length() - 12 ) ); + } else if( s.startsWith( "color:" ) ) { + color->setNamedColor( s.right( s.length() - 6 ) ); + } else if( s.startsWith("text-decoration:") ) { + if( s.endsWith( "underline" ) ) + f.setUnderline( true ); +/*#if QT_VERSION >= 0x030200 + else if( s.endsWith( "overline" ) ) + f.setOverline( true ); +#endif */ + else if( s.endsWith( "line-through" ) ) + f.setStrikeOut( true ); + } else if( s.startsWith( "font-style:") ) { + if( s.endsWith( "italic" ) || s.endsWith( "oblique" ) ) + f.setItalic( true ); + } else if( s.startsWith( "font-weight:" ) ) { + bool ok = false; + int n = s.right( s.length() - 12 ).toInt( &ok ); + if( s.endsWith( "bold" ) ) + f.setBold( true ); + else if( ok ) + f.setWeight( n / 8 ); // convert CSS values to Qt values + } + } + + return f; +} + +QString DSRichText::parse( const QString & t, const QString & find, const QString & find2, int start ) +{ + int s = t.find( find, start ); + if( s == -1 || s < start ) + return QString::null; + + int pend = t.find( find2, s + find.length() ); + if( pend == -1 || pend < (signed int)(s + find.length()) ) + return QString::null; + + QString text = t.mid( s, pend - s + find2.length() ); + return text; +} + +void DSRichText::setX( int x ) +{ + xpos = x; +} + +void DSRichText::setY( int y ) +{ + ypos = y; +} + +void DSRichText::setWidth( int width ) +{ + w = width; +} + +void DSRichText::setHeight( int height ) +{ + h = height; +} + +int DSRichText::parseAlignment( const QString & align ) +{ + QString a = QString( align ); + if( a.endsWith("\"") ) + a = a.left( a.length() - 1 ); + + if( a.startsWith("align=\"") ) + a = a.mid( 7, a.length() - 7 ); + + if( a == "left" ) + return Qt::AlignLeft; + else if( a == "center" ) + return Qt::AlignHCenter; + else if( a == "right" ) + return Qt::AlignRight; + else if( a == "justify" ) + return Qt::AlignJustify; + + return 0; +} + +void DSRichText::parseWords( const QString & t, formated_word* w, WordList* words ) +{ + unsigned int p = 0; + for( unsigned int i = 0; i < t.length(); i++ ) { + if( (t[i].isSpace() && p != i) || i == t.length() - 1 ) { + formated_word word = *w; + + word.text = replaceEscapeSequences( t.mid( p, i + 1 - p ) ); + + p = i + 1; + words->append( word ); + } + } +} + +inline int DSRichText::yDeviation( const formated_line* line ) +{ + // leading = 1 (almost ever) + // linespacing = leading + height + // height = ascent + descent + 1 + if( line->lineSpacing != painter->fontMetrics().lineSpacing() ) { + return line->ascent + line->leading - painter->fontMetrics().ascent() - painter->fontMetrics().leading(); + } else { + return 0; + } +} + +QString DSRichText::replaceEscapeSequences( const QString & t ) +{ + QString tmp = QString( t ); + tmp = tmp.replace( DSREPLACE( "<" ), "<" ); + tmp = tmp.replace( DSREPLACE( ">" ), ">" ); + tmp = tmp.replace( DSREPLACE( "&" ), "&" ); + tmp = tmp.replace( DSREPLACE( """ ), "\"" ); + return tmp; +} + +QString DSRichText::parseParagraphTag( const QString &t, int* alignment ) +{ + QString d = QString( t ); + if( d.startsWith("<p>") ) { + d = d.mid( 3, d.length() - 3 ); + } else if( d.startsWith("<p ") ) { + *alignment = parseAlignment( parse( d, "align=\"", "\"", 0 ) ); + if( d.contains( ">" ) ) { + int x = d.find(">" ) + 1; + d = d.mid( x, d.length() - x ); + } + } + + if( d.endsWith("</p>") ) + d = d.left( d.length() - 4 ); // strlen("</p>"); + + return d; +} + +#endif // QT_TEXT_BUG + + |