// -*- Mode: c++-mode; c-basic-offset: 2; indent-tabs-mode: t; tab-width: 2; -*- // // Copyright (C) 2004 Grzegorz Jaskiewicz // // gadurichtextformat.cpp // // 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. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301, USA. #include #include #include #include "gadurichtextformat.h" #include "gadusession.h" #include #include GaduRichTextFormat::GaduRichTextFormat() { } GaduRichTextFormat::~GaduRichTextFormat() { } TQString GaduRichTextFormat::convertToHtml( const TQString& msg, unsigned int formats, void* formatStructure) { TQString tmp, nb; gg_msg_richtext_format *format; char *pointer = (char*) formatStructure; unsigned int i,j; int r, g, b; r = g = b = 0; bool opened = false; if ( formatStructure == NULL || formats == 0 ) { tmp = msg; escapeBody( tmp ); return tmp; } for ( i = 0, j = 0 ; i < formats ; ) { format = (gg_msg_richtext_format*) pointer; unsigned int position = format->position; char font = format->font; TQString style; if ( position < j || position > msg.length() ) { break; } if ( font & GG_FONT_IMAGE ) { i += sizeof( gg_msg_richtext_image ); pointer += sizeof( gg_msg_richtext_image ); tmp += "[this should be a picture, not yet implemented]"; } else { nb = msg.mid( j, position - j ); tmp += escapeBody( nb ); j = position; // add message bit between formating if ( opened ) { tmp += formatClosingTag("span"); opened = false; } // set font attributes if ( font & GG_FONT_BOLD ) { style += (" font-weight:bold; "); } if ( font & GG_FONT_ITALIC ) { style += (" font-style:italic; "); } if ( font & GG_FONT_UNDERLINE ) { style += (" text-decoration:underline; "); } // add color if ( font & GG_FONT_COLOR ) { pointer += sizeof( gg_msg_richtext_format ); i += sizeof( gg_msg_richtext_format ); gg_msg_richtext_color *color = (gg_msg_richtext_color*)( pointer ); r = (int)color->red; g = (int)color->green; b = (int)color->blue; } style += TQString(" color: rgb( %1, %2, %3 ); ").arg( r ).arg( g ).arg( b ); tmp += formatOpeningTag( TQString::fromLatin1("span"), TQString::fromLatin1("style=\"%1\"").arg( style ) ); opened = true; } // advance to next structure in row pointer += sizeof( gg_msg_richtext_format ); i += sizeof( gg_msg_richtext_format ); } nb = msg.mid( j, msg.length() ); tmp += escapeBody( nb ); if ( opened ) { tmp += formatClosingTag("span"); } return tmp; } TQString GaduRichTextFormat::formatOpeningTag( const TQString& tag, const TQString& attributes ) { TQString res = "<" + tag; if(!attributes.isEmpty()) res.append(" " + attributes); return res + ">"; } TQString GaduRichTextFormat::formatClosingTag( const TQString& tag ) { return ""; } // the initial idea stolen from IRC plugin KGaduMessage* GaduRichTextFormat::convertToGaduMessage( const Kopete::Message& message ) { TQString htmlString = message.escapedBody(); KGaduMessage* output = new KGaduMessage; rtcs.blue = rtcs.green = rtcs.red = 0; color = TQColor(); int position = 0; rtf.resize( sizeof( gg_msg_richtext) ); output->rtf.resize(0); // test first if there is any HTML formating in it if( htmlString.find( TQString::fromLatin1(" -1 ) { TQRegExp findTags( TQString::fromLatin1("(.*)") ); findTags.setMinimal( true ); int pos = 0; int lastpos = 0; while ( pos >= 0 ){ pos = findTags.search( htmlString ); rtfs.font = 0; if ( pos != lastpos ) { TQString tmp; if ( pos < 0 ) { tmp = htmlString.mid( lastpos ); } else { tmp = htmlString.mid( lastpos, pos - lastpos ); } if ( !tmp.isEmpty() ) { color.setRgb( 0, 0, 0 ); if ( insertRtf( position ) == false ) { delete output; return NULL; } tmp = unescapeGaduMessage( tmp ); output->message += tmp; position += tmp.length(); } } if ( pos > -1 ) { TQString styleHTML = findTags.cap(1); TQString replacement = findTags.cap(2); TQStringList styleAttrs = TQStringList::split( ';', styleHTML ); rtfs.font = 0; lastpos = pos + replacement.length(); for( TQStringList::Iterator attrPair = styleAttrs.begin(); attrPair != styleAttrs.end(); ++attrPair ) { TQString attribute = (*attrPair).section(':',0,0); TQString value = (*attrPair).section(':',1); parseAttributes( attribute, value ); } if ( insertRtf( position ) == false ) { delete output; return NULL; } TQString rep = TQString("%2" ).arg( styleHTML ).arg( replacement ); htmlString.replace( findTags.pos( 0 ), rep.length(), replacement ); replacement = unescapeGaduMessage( replacement ); output->message += replacement; position += replacement.length(); } } output->rtf = rtf; // this is sick, but that's the way libgadu is designed // here I am adding network header !, should sit in libgadu IMO header = (gg_msg_richtext*) output->rtf.data(); header->length = output->rtf.size() - sizeof( gg_msg_richtext ); header->flag = 2; } else { output->message = message.escapedBody(); output->message = unescapeGaduMessage( output->message ); } return output; } void GaduRichTextFormat::parseAttributes( const TQString attribute, const TQString value ) { if( attribute == TQString::fromLatin1("color") ) { color.setNamedColor( value ); } if( attribute == TQString::fromLatin1("font-weight") && value == TQString::fromLatin1("600") ) { rtfs.font |= GG_FONT_BOLD; } if( attribute == TQString::fromLatin1("text-decoration") && value == TQString::fromLatin1("underline") ) { rtfs.font |= GG_FONT_UNDERLINE ; } if( attribute == TQString::fromLatin1("font-style") && value == TQString::fromLatin1("italic") ) { rtfs.font |= GG_FONT_ITALIC; } } TQString GaduRichTextFormat::unescapeGaduMessage( TQString& ns ) { TQString s; s = Kopete::Message::unescape( ns ); s.replace( TQString::fromAscii( "\n" ), TQString::fromAscii( "\r\n" ) ); return s; } bool GaduRichTextFormat::insertRtf( uint position) { if ( color != TQColor( rtcs.red, rtcs.green, rtcs.blue ) ) { rtcs.red = color.red(); rtcs.green = color.green(); rtcs.blue = color.blue(); rtfs.font |= GG_FONT_COLOR; } if ( rtfs.font ) { // append font description rtfs.position = position; uint csize = rtf.size(); if ( rtf.resize( csize + sizeof( gg_msg_richtext_format ) ) == FALSE ) { return false; }; memcpy( rtf.data() + csize, &rtfs, sizeof( rtfs ) ); // append color description, if color has changed if ( rtfs.font & GG_FONT_COLOR ) { csize = rtf.size(); if ( rtf.resize( csize + sizeof( gg_msg_richtext_color ) ) == FALSE ) { return false; }; memcpy( rtf.data() + csize, &rtcs, sizeof( rtcs ) ); } } return true; } TQString GaduRichTextFormat::escapeBody( TQString& input ) { input.replace( '<', TQString::fromLatin1("<") ); input.replace( '>', TQString::fromLatin1(">") ); input.replace( '\n', TQString::fromLatin1( "
" ) ); input.replace( '\t', TQString::fromLatin1( "    " ) ); input.replace( TQRegExp( TQString::fromLatin1( "\\s\\s" ) ), TQString::fromLatin1( "  " ) ); return input; }