You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
292 lines
7.8 KiB
292 lines
7.8 KiB
15 years ago
|
// -*- Mode: c++-mode; c-basic-offset: 2; indent-tabs-mode: t; tab-width: 2; -*-
|
||
|
//
|
||
|
// Copyright (C) 2004 Grzegorz Jaskiewicz <gj at pointblue.com.pl>
|
||
|
//
|
||
|
// 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., 59 Temple Place - Suite 330, Boston, MA
|
||
|
// 02111-1307, USA.
|
||
|
|
||
|
#include <knotifyclient.h>
|
||
|
#include <kdebug.h>
|
||
|
#include <kopetemessage.h>
|
||
|
|
||
|
#include "gadurichtextformat.h"
|
||
|
#include "gadusession.h"
|
||
|
|
||
|
#include <qstring.h>
|
||
|
#include <qregexp.h>
|
||
|
|
||
|
GaduRichTextFormat::GaduRichTextFormat()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
GaduRichTextFormat::~GaduRichTextFormat()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
QString
|
||
|
GaduRichTextFormat::convertToHtml( const QString& msg, unsigned int formats, void* formatStructure)
|
||
|
{
|
||
|
QString 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;
|
||
|
QString 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 += "<b>[this should be a picture, not yet implemented]</b>";
|
||
|
}
|
||
|
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 += QString(" color: rgb( %1, %2, %3 ); ").arg( r ).arg( g ).arg( b );
|
||
|
|
||
|
tmp += formatOpeningTag( QString::fromLatin1("span"), QString::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;
|
||
|
}
|
||
|
|
||
|
QString
|
||
|
GaduRichTextFormat::formatOpeningTag( const QString& tag, const QString& attributes )
|
||
|
{
|
||
|
QString res = "<" + tag;
|
||
|
if(!attributes.isEmpty())
|
||
|
res.append(" " + attributes);
|
||
|
return res + ">";
|
||
|
}
|
||
|
|
||
|
QString
|
||
|
GaduRichTextFormat::formatClosingTag( const QString& tag )
|
||
|
{
|
||
|
return "</" + tag + ">";
|
||
|
}
|
||
|
|
||
|
// the initial idea stolen from IRC plugin
|
||
|
KGaduMessage*
|
||
|
GaduRichTextFormat::convertToGaduMessage( const Kopete::Message& message )
|
||
|
{
|
||
|
QString htmlString = message.escapedBody();
|
||
|
KGaduMessage* output = new KGaduMessage;
|
||
|
rtcs.blue = rtcs.green = rtcs.red = 0;
|
||
|
color = QColor();
|
||
|
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( QString::fromLatin1("</span") ) > -1 ) {
|
||
|
QRegExp findTags( QString::fromLatin1("<span style=\"(.*)\">(.*)</span>") );
|
||
|
findTags.setMinimal( true );
|
||
|
int pos = 0;
|
||
|
int lastpos = 0;
|
||
|
|
||
|
while ( pos >= 0 ){
|
||
|
pos = findTags.search( htmlString );
|
||
|
rtfs.font = 0;
|
||
|
if ( pos != lastpos ) {
|
||
|
QString 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 ) {
|
||
|
QString styleHTML = findTags.cap(1);
|
||
|
QString replacement = findTags.cap(2);
|
||
|
QStringList styleAttrs = QStringList::split( ';', styleHTML );
|
||
|
rtfs.font = 0;
|
||
|
|
||
|
lastpos = pos + replacement.length();
|
||
|
|
||
|
for( QStringList::Iterator attrPair = styleAttrs.begin(); attrPair != styleAttrs.end(); ++attrPair ) {
|
||
|
QString attribute = (*attrPair).section(':',0,0);
|
||
|
QString value = (*attrPair).section(':',1);
|
||
|
parseAttributes( attribute, value );
|
||
|
}
|
||
|
|
||
|
if ( insertRtf( position ) == false ) {
|
||
|
delete output;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
QString rep = QString("<span style=\"%1\">%2</span>" ).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 QString attribute, const QString value )
|
||
|
{
|
||
|
if( attribute == QString::fromLatin1("color") ) {
|
||
|
color.setNamedColor( value );
|
||
|
}
|
||
|
if( attribute == QString::fromLatin1("font-weight") && value == QString::fromLatin1("600") ) {
|
||
|
rtfs.font |= GG_FONT_BOLD;
|
||
|
}
|
||
|
if( attribute == QString::fromLatin1("text-decoration") && value == QString::fromLatin1("underline") ) {
|
||
|
rtfs.font |= GG_FONT_UNDERLINE ;
|
||
|
}
|
||
|
if( attribute == QString::fromLatin1("font-style") && value == QString::fromLatin1("italic") ) {
|
||
|
rtfs.font |= GG_FONT_ITALIC;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QString
|
||
|
GaduRichTextFormat::unescapeGaduMessage( QString& ns )
|
||
|
{
|
||
|
QString s;
|
||
|
s = Kopete::Message::unescape( ns );
|
||
|
s.replace( QString::fromAscii( "\n" ), QString::fromAscii( "\r\n" ) );
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
GaduRichTextFormat::insertRtf( uint position)
|
||
|
{
|
||
|
if ( color != QColor( 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;
|
||
|
}
|
||
|
|
||
|
QString
|
||
|
GaduRichTextFormat::escapeBody( QString& input )
|
||
|
{
|
||
|
input.replace( '<', QString::fromLatin1("<") );
|
||
|
input.replace( '>', QString::fromLatin1(">") );
|
||
|
input.replace( '\n', QString::fromLatin1( "<br />" ) );
|
||
|
input.replace( '\t', QString::fromLatin1( " " ) );
|
||
|
input.replace( QRegExp( QString::fromLatin1( "\\s\\s" ) ), QString::fromLatin1( " " ) );
|
||
|
return input;
|
||
|
}
|