/* This file is part of ksirc Copyright (c) 2001 Malte Starostik <malte@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Color parser code courtesy of ksirc <http://www.kde.org> Modified by Jason Keirstead <jason@keirstead.org> */ #include <knotifyclient.h> #include <kdebug.h> #include <tqbuffer.h> #include <tqdatastream.h> #include <tqstylesheet.h> #include "ksparser.h" #include <stdlib.h> KSParser KSParser::m_parser; const TQColor KSParser::IRC_Colors[17]= { TQt::white, TQt::black, TQt::darkBlue, TQt::darkGreen, TQt::red, TQt::darkRed, TQt::darkMagenta, TQt::darkYellow, TQt::yellow, TQt::green, TQt::darkCyan, TQt::cyan, TQt::blue, TQt::magenta, TQt::darkGray, TQt::gray, TQColor() // default invalid color, must be the last }; const TQRegExp KSParser::sm_colorsModeRegexp("(\\d{1,2})(?:,(\\d{1,2}))?"); template <typename _TYPE_> inline void swap(_TYPE_ &o1, _TYPE_ &o2) { _TYPE_ tmp = o1; o1 = o2; o2 = tmp; } KSParser::KSParser() { kdDebug(14120) << k_funcinfo << endl; } KSParser::~KSParser() { kdDebug(14120) << k_funcinfo << endl; } /* NOTE: If thread corruption are seen simply ad a qlock here */ TQCString KSParser::parse(const TQCString &message) { return m_parser._parse(message); } TQCString KSParser::_parse(const TQCString &message) { TQCString data( message.size() * 2 ); TQBuffer buff( data ); buff.open( IO_WriteOnly ); m_tags.clear(); m_attributes.clear(); TQRegExp colorsModeRegexp(sm_colorsModeRegexp); // should be set to the current default colors .... TQColor fgColor; /*KopeteMesage::fg().name()*/ TQColor bgColor; /*KopeteMesage::bg().name()*/ uint chars = 0; for(uint i = 0; i < message.length(); ++i) { const TQChar &cur = message[i]; TQString toAppend; switch (cur) { case 0x02: //Bold: ^B toAppend= toggleTag("b"); break; case 0x03: //Color code: ^C if (colorsModeRegexp.search(message, i+1) == (int)i+1) { i += colorsModeRegexp.matchedLength(); // + 1 will be added by ++ TQString tagStyle; fgColor = ircColor(colorsModeRegexp.cap(1)); bgColor = ircColor(colorsModeRegexp.cap(2)); toAppend = pushColorTag(fgColor, bgColor); } else { toAppend = popTag(TQString::fromLatin1("span")); } break; case 0x07: //System bell: ^G KNotifyClient::beep( TQString::fromLatin1("IRC beep event received in a message") ); break; case '\t': // 0x09 toAppend = TQString::fromLatin1(" "); break; case '\n': // 0x0D toAppend= TQString::fromLatin1("<br/>"); break; case 0x0D: // Italics: ^N toAppend = toggleTag("i"); break; case 0x0F: //Plain Text, close all tags: ^O toAppend = popAll(); break; // case 0x12: // Reverse original text colors: ^R // break; case 0x16: //Invert Colors: ^V swap(fgColor, bgColor); toAppend = pushColorTag(fgColor, bgColor); break; case 0x1F: //Underline toAppend = toggleTag("u"); break; case '<': toAppend = TQString::fromLatin1("<"); break; case '>': toAppend = TQString::fromLatin1(">"); break; default: if (cur < TQChar(' ')) // search for control characters toAppend = TQString::fromLatin1("<%1>").arg(cur, 2, 16).upper(); else toAppend = TQStyleSheet::escape(cur); } chars += toAppend.length(); buff.writeBlock( toAppend.latin1(), toAppend.length() ); } TQString toAppend = popAll(); chars += toAppend.length(); buff.writeBlock( toAppend.latin1(), toAppend.length() ); // Make sure we have enough room for NULL character. if (data.size() < chars+1) data.resize(chars+1); data[chars] = '\0'; return data; } TQString KSParser::pushTag(const TQString &tag, const TQString &attributes) { TQString res; m_tags.push(tag); if(!m_attributes.contains(tag)) m_attributes.insert(tag, attributes); else if(!attributes.isEmpty()) m_attributes.replace(tag, attributes); res.append("<" + tag); if(!m_attributes[tag].isEmpty()) res.append(" " + m_attributes[tag]); return res + ">"; } TQString KSParser::pushColorTag(const TQColor &fgColor, const TQColor &bgColor) { TQString tagStyle; if (fgColor.isValid()) tagStyle += TQString::fromLatin1("color:%1;").arg(fgColor.name()); if (bgColor.isValid()) tagStyle += TQString::fromLatin1("background-color:%1;").arg(bgColor.name()); if(!tagStyle.isEmpty()) tagStyle = TQString::fromLatin1("style=\"%1\"").arg(tagStyle); return pushTag(TQString::fromLatin1("span"), tagStyle);; } TQString KSParser::popTag(const TQString &tag) { if (!m_tags.contains(tag)) return TQString(); TQString res; TQValueStack<TQString> savedTags; while(m_tags.top() != tag) { savedTags.push(m_tags.pop()); res.append("</" + savedTags.top() + ">"); } res.append("</" + m_tags.pop() + ">"); m_attributes.remove(tag); while(!savedTags.isEmpty()) res.append(pushTag(savedTags.pop())); return res; } TQString KSParser::toggleTag(const TQString &tag) { return m_attributes.contains(tag)?popTag(tag):pushTag(tag); } TQString KSParser::popAll() { TQString res; while(!m_tags.isEmpty()) res.append("</" + m_tags.pop() + ">"); m_attributes.clear(); return res; } TQColor KSParser::ircColor(const TQString &color) { bool success; unsigned int intColor = color.toUInt(&success); if (success) return ircColor(intColor); else return TQColor(); } TQColor KSParser::ircColor(unsigned int color) { unsigned int maxcolor = sizeof(IRC_Colors)/sizeof(TQColor); return color<=maxcolor?IRC_Colors[color]:IRC_Colors[maxcolor]; } int KSParser::colorForHTML(const TQString &html) { TQColor color(html); for(uint i=0; i<sizeof(IRC_Colors)/sizeof(TQColor); i++) { if(IRC_Colors[i] == color) return i; } return -1; }