/*************************************************************************** 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 TQT_TEXT_BUG // TQt includes #include #include #include // for DSREPLACE #include "sqltables.h" /* EXAMPLE TEXT: "" "

A little bit formated " "richtext which should be printed to a TQPrinter with TQSimpleRichText.

" "

Printing should work in ScreenResolution as well as in HighResolution, but as you can see it will only work in ScreenResolution.

" ""; Another example

Text test label

Resolution formated 108dpi. This text & text should now overlap with the first line. 4 < 6a

A 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. Some text "in" a bigger courier font. Also this paragraph should be justified as blockquote. I hope it works and KBarcodes text redering will be better than the one found in TQt.

*/ DSRichText::DSRichText( const TQString & t ) : text( t ) { if( text.find("") == -1 ) text = "

" + t + "

"; //tqDebug( text ); start = end = pos = 0; x = y = 0; sx = sy = 1.0; m_base = TQFont(); TQString tmp = parse( text, "", 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( "text = TQString(); f->line = false; f->alignment = alignment; f->font = m_base; f->color = m_color; } void DSRichText::initLine( TQValueList* 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( TQValueList* l, TQFontMetrics* 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; TQFontMetrics 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( TQPainter* 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), TQPainter::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 == TQt::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( TQPen( f.color ) ); int a = f.alignment; if( a == TQt::AlignRight ) { a = TQt::AlignLeft; if( !x ) x = w - l.width; } else if( a == TQt::AlignHCenter ) { a = TQt::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(); TQFontMetrics 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( TQPen( 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), TQt::AlignAuto, line->formats[z].text ); x += tw; x += space; } } bool DSRichText::parseParagraph() { int alignment = 0; formated_word f; TQString d = parse( text, "", pos ); //tqDebug("D=" + d ); //tqDebug("POS=%i", pos ); pos += d.length(); if( d.isNull() ) return false; d = parseParagraphTag( d, &alignment ); WordList words; TQString 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 = TQString(); // bail out now, otherwise there is // and endless loop for e.g.

a

if( i == (d.length() - 1) ) break; if( d[i] == '<' ) { TQString span = d.mid( i, d.find( ">", i ) - i + 1 ); i += span.length(); if( span.startsWith( "setNamedColor( s.right( s.length() - 6 ) ); } else if( s.startsWith("text-decoration:") ) { if( s.endsWith( "underline" ) ) f.setUnderline( true ); /*#if [[[TQT_VERSION IS DEPRECATED]]] >= 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 TQt values } } return f; } TQString DSRichText::parse( const TQString & t, const TQString & find, const TQString & find2, int start ) { int s = t.find( find, start ); if( s == -1 || s < start ) return TQString(); int pend = t.find( find2, s + find.length() ); if( pend == -1 || pend < (signed int)(s + find.length()) ) return TQString(); TQString 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 TQString & align ) { TQString a = TQString( 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 TQt::AlignLeft; else if( a == "center" ) return TQt::AlignHCenter; else if( a == "right" ) return TQt::AlignRight; else if( a == "justify" ) return TQt::AlignJustify; return 0; } void DSRichText::parseWords( const TQString & 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; } } TQString DSRichText::replaceEscapeSequences( const TQString & t ) { TQString tmp = TQString( t ); tmp = tmp.replace( DSREPLACE( "<" ), "<" ); tmp = tmp.replace( DSREPLACE( ">" ), ">" ); tmp = tmp.replace( DSREPLACE( "&" ), "&" ); tmp = tmp.replace( DSREPLACE( """ ), "\"" ); return tmp; } TQString DSRichText::parseParagraphTag( const TQString &t, int* alignment ) { TQString d = TQString( t ); if( d.startsWith("

") ) { d = d.mid( 3, d.length() - 3 ); } else if( d.startsWith("

" ) ) { int x = d.find(">" ) + 1; d = d.mid( x, d.length() - x ); } } if( d.endsWith("

") ) d = d.left( d.length() - 4 ); // strlen("

"); return d; } #endif // TQT_TEXT_BUG