summaryrefslogtreecommitdiffstats
path: root/kopete/libkopete/private
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/libkopete/private')
-rw-r--r--kopete/libkopete/private/Makefile.am13
-rw-r--r--kopete/libkopete/private/kopetecommand.cpp142
-rw-r--r--kopete/libkopete/private/kopetecommand.h109
-rw-r--r--kopete/libkopete/private/kopeteemoticons.cpp559
-rw-r--r--kopete/libkopete/private/kopeteemoticons.h184
-rw-r--r--kopete/libkopete/private/kopeteutils_private.cpp85
-rw-r--r--kopete/libkopete/private/kopeteutils_private.h60
-rw-r--r--kopete/libkopete/private/kopeteviewmanager.cpp364
-rw-r--r--kopete/libkopete/private/kopeteviewmanager.h103
9 files changed, 1619 insertions, 0 deletions
diff --git a/kopete/libkopete/private/Makefile.am b/kopete/libkopete/private/Makefile.am
new file mode 100644
index 00000000..15e930df
--- /dev/null
+++ b/kopete/libkopete/private/Makefile.am
@@ -0,0 +1,13 @@
+METASOURCES = AUTO
+
+AM_CPPFLAGS = -DKDE_NO_COMPAT -DQT_NO_COMPAT -DQT_NO_CAST_ASCII -DQT_NO_ASCII_CAST \
+ $(KOPETE_INCLUDES) $(all_includes)
+
+noinst_LTLIBRARIES = libkopeteprivate.la
+
+libkopeteprivate_la_SOURCES = kopeteemoticons.cpp \
+ kopetecommand.cpp kopeteviewmanager.cpp kopeteutils_private.cpp
+libkopeteprivate_la_LDFLAGS = $(all_libraries)
+libkopeteprivate_la_LIBADD = $(LIB_KDEUI)
+# vim: set noet:
+
diff --git a/kopete/libkopete/private/kopetecommand.cpp b/kopete/libkopete/private/kopetecommand.cpp
new file mode 100644
index 00000000..52588f2e
--- /dev/null
+++ b/kopete/libkopete/private/kopetecommand.cpp
@@ -0,0 +1,142 @@
+/*
+ kopetecommand.cpp - Command
+
+ Copyright (c) 2003 by Jason Keirstead <[email protected]>
+
+ *************************************************************************
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <qstringlist.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kinputdialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "kopetechatsessionmanager.h"
+#include "kopeteview.h"
+#include "kopetecommand.h"
+#include "kopeteuiglobal.h"
+
+Kopete::Command::Command( QObject *parent, const QString &command, const char* handlerSlot,
+ const QString &help, Kopete::CommandHandler::CommandType type, const QString &formatString,
+ uint minArgs, int maxArgs, const KShortcut &cut, const QString &pix )
+ : KAction( command[0].upper() + command.right( command.length() - 1).lower(), pix, cut, parent,
+ ( command.lower() + QString::fromLatin1("_command") ).latin1() )
+{
+ init( command, handlerSlot, help, type, formatString, minArgs, maxArgs );
+}
+
+void Kopete::Command::init( const QString &command, const char* slot, const QString &help,
+ Kopete::CommandHandler::CommandType type, const QString &formatString, uint minArgs, int maxArgs )
+{
+ m_command = command;
+ m_help = help;
+ m_type = type;
+ m_formatString = formatString;
+ m_minArgs = minArgs;
+ m_maxArgs = maxArgs;
+ m_processing = false;
+
+ if( m_type == Kopete::CommandHandler::Normal )
+ {
+ QObject::connect( this, SIGNAL( handleCommand( const QString &, Kopete::ChatSession *) ),
+ parent(), slot );
+ }
+
+ QObject::connect( this, SIGNAL( activated() ), this, SLOT( slotAction() ) );
+}
+
+void Kopete::Command::slotAction()
+{
+ Kopete::ChatSession *manager = Kopete::ChatSessionManager::self()->activeView()->msgManager();
+
+ QString args;
+ if( m_minArgs > 0 )
+ {
+ args = KInputDialog::getText( i18n("Enter Arguments"), i18n("Enter the arguments to %1:").arg(m_command) );
+ if( args.isNull() )
+ return;
+ }
+
+ processCommand( args, manager, true );
+}
+
+void Kopete::Command::processCommand( const QString &args, Kopete::ChatSession *manager, bool gui )
+{
+ QStringList mArgs = Kopete::CommandHandler::parseArguments( args );
+ if( m_processing )
+ {
+ printError( i18n("Alias \"%1\" expands to itself.").arg( text() ), manager, gui );
+ }
+ else if( mArgs.count() < m_minArgs )
+ {
+ printError( i18n("\"%1\" requires at least %n argument.",
+ "\"%1\" requires at least %n arguments.", m_minArgs)
+ .arg( text() ), manager, gui );
+ }
+ else if( m_maxArgs > -1 && (int)mArgs.count() > m_maxArgs )
+ {
+ printError( i18n("\"%1\" has a maximum of %n argument.",
+ "\"%1\" has a maximum of %n arguments.", m_minArgs)
+ .arg( text() ), manager, gui );
+ }
+ else if( !KApplication::kApplication()->authorizeKAction( name() ) )
+ {
+ printError( i18n("You are not authorized to perform the command \"%1\".").arg(text()), manager, gui );
+ }
+ else
+ {
+ m_processing = true;
+ if( m_type == Kopete::CommandHandler::UserAlias ||
+ m_type == Kopete::CommandHandler::SystemAlias )
+ {
+ QString formatString = m_formatString;
+
+ // Translate %s to the whole string and %n to current nickname
+
+ formatString.replace( QString::fromLatin1("%n"), manager->myself()->nickName() );
+ formatString.replace( QString::fromLatin1("%s"), args );
+
+ // Translate %1..%N to word1..wordN
+
+ while( mArgs.count() > 0 )
+ {
+ formatString = formatString.arg( mArgs.front() );
+ mArgs.pop_front();
+ }
+
+ kdDebug(14010) << "New Command after processing alias: " << formatString << endl;
+
+ Kopete::CommandHandler::commandHandler()->processMessage( QString::fromLatin1("/") + formatString, manager );
+ }
+ else
+ {
+ emit( handleCommand( args, manager ) );
+ }
+ m_processing = false;
+ }
+}
+
+void Kopete::Command::printError( const QString &error, Kopete::ChatSession *manager, bool gui ) const
+{
+ if( gui )
+ {
+ KMessageBox::error( Kopete::UI::Global::mainWidget(), error, i18n("Command Error") );
+ }
+ else
+ {
+ Kopete::Message msg( manager->myself(), manager->members(), error,
+ Kopete::Message::Internal, Kopete::Message::PlainText );
+ manager->appendMessage( msg );
+ }
+}
+
+#include "kopetecommand.moc"
diff --git a/kopete/libkopete/private/kopetecommand.h b/kopete/libkopete/private/kopetecommand.h
new file mode 100644
index 00000000..298872db
--- /dev/null
+++ b/kopete/libkopete/private/kopetecommand.h
@@ -0,0 +1,109 @@
+
+/*
+ kopetecommand.h - Command
+
+ Copyright (c) 2003 by Jason Keirstead <[email protected]>
+ Kopete (c) 2002-2003 by the Kopete developers <[email protected]>
+
+ *************************************************************************
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef __KOPETECOMMAND_H__
+#define __KOPETECOMMAND_H__
+
+#include <qobject.h>
+#include <kaction.h>
+#include "kopetecommandhandler.h"
+
+namespace Kopete
+{
+
+class ChatSession;
+
+class Command : public KAction
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Creates a Kopete::Command object
+ *
+ * @param parent The plugin who owns this command
+ * @param command The command we want to handle, not including the '/'
+ * @param handlerSlot The slot used to handle the command. This slot must
+ * accept two parameters, a QString of arguments, and a Kopete::ChatSession
+ * pointer to the Manager under which the command was sent.
+ * @param help An optional help string to be shown when the user uses
+ * /help <i>command</i>
+ * @param type If this command is an alias, and what type
+ * @param formatString The formatString of the alias if any
+ * @param minArgs Minimum number of arguments
+ * @param maxArgs Maximum number of arguments
+ * @param cut The shortcut for the command
+ * @param pix The icon to use for the command
+ */
+ Command( QObject *parent, const QString &command, const char* handlerSlot,
+ const QString &help = QString::null, CommandHandler::CommandType type = CommandHandler::Normal, const QString &formatString = QString::null,
+ uint minArgs = 0, int maxArgs = -1, const KShortcut &cut = 0,
+ const QString &pix = QString::null );
+
+ /**
+ * Process this command
+ */
+ void processCommand( const QString &args, ChatSession *manager, bool gui = false );
+
+ /**
+ * Returns the command this object handles
+ */
+ const QString &command() const { return m_command; };
+
+ /**
+ * Returns the help string for this command
+ */
+ const QString &help() const { return m_help; };
+
+ /**
+ * Returns the type of the command
+ */
+ const CommandHandler::CommandType type() const { return m_type; };
+
+ signals:
+ /**
+ * Emitted whenever a command is handled by this object. When a command
+ * has been handled, all processing on it stops by the command handler
+ * (a command cannot be handled twice)
+ */
+ void handleCommand( const QString &args, Kopete::ChatSession *manager );
+
+ private slots:
+ /**
+ * Connected to our activated() signal
+ */
+ void slotAction();
+
+ private:
+ void init( const QString &command, const char* slot, const QString &help,
+ CommandHandler::CommandType type, const QString &formatString,
+ uint minArgs, int maxArgs );
+
+ void printError( const QString &error, ChatSession *manager, bool gui = false ) const;
+
+ QString m_command;
+ QString m_help;
+ QString m_formatString;
+ uint m_minArgs;
+ int m_maxArgs;
+ bool m_processing;
+ CommandHandler::CommandType m_type;
+};
+
+}
+
+#endif
diff --git a/kopete/libkopete/private/kopeteemoticons.cpp b/kopete/libkopete/private/kopeteemoticons.cpp
new file mode 100644
index 00000000..87da4cf7
--- /dev/null
+++ b/kopete/libkopete/private/kopeteemoticons.cpp
@@ -0,0 +1,559 @@
+/*
+ kopeteemoticons.cpp - Kopete Preferences Container-Class
+
+ Copyright (c) 2002 by Stefan Gehn <metz AT gehn.net>
+ Copyright (c) 2002-2006 by Olivier Goffart <ogoffart @ kde.org>
+ Copyright (c) 2005 by Engin AYDOGAN <[email protected]>
+
+ Kopete (c) 2002-2005 by the Kopete developers <[email protected]>
+
+ *************************************************************************
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include "kopeteemoticons.h"
+
+#include "kopeteprefs.h"
+
+#include <qdom.h>
+#include <qfile.h>
+#include <qstylesheet.h>
+#include <qimage.h>
+#include <qdatetime.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <kdeversion.h>
+
+#include <set>
+#include <algorithm>
+#include <iterator>
+
+
+/*
+ * Testcases can be found in the kopeteemoticontest app in the tests/ directory.
+ */
+
+
+namespace Kopete {
+
+
+struct Emoticons::Emoticon
+{
+ Emoticon(){}
+ /* sort by longest to shortest matchText */
+ bool operator< (const Emoticon &e){ return matchText.length() > e.matchText.length(); }
+ QString matchText;
+ QString matchTextEscaped;
+ QString picPath;
+ QString picHTMLCode;
+};
+
+/* This is the object we will store each emoticon match in */
+struct Emoticons::EmoticonNode {
+ const Emoticon emoticon;
+ int pos;
+ EmoticonNode() : emoticon(), pos( -1 ) {}
+ EmoticonNode( const Emoticon e, int p ) : emoticon( e ), pos( p ) {}
+};
+
+class Emoticons::Private
+{
+public:
+ QMap<QChar, QValueList<Emoticon> > emoticonMap;
+ QMap<QString, QStringList> emoticonAndPicList;
+
+ /**
+ * The current icon theme from KopetePrefs
+ */
+ QString theme;
+
+
+};
+
+
+Emoticons *Emoticons::s_self = 0L;
+
+Emoticons *Emoticons::self()
+{
+ if( !s_self )
+ s_self = new Emoticons;
+ return s_self;
+}
+
+
+QString Emoticons::parseEmoticons(const QString& message, ParseMode mode ) //static
+{
+ return self()->parse( message, mode );
+}
+
+QValueList<Emoticons::Token> Emoticons::tokenizeEmoticons( const QString& message, ParseMode mode ) // static
+{
+ return self()->tokenize( message, mode );
+}
+
+QValueList<Emoticons::Token> Emoticons::tokenize( const QString& message, uint mode )
+{
+ QValueList<Token> result;
+ if ( !KopetePrefs::prefs()->useEmoticons() )
+ {
+ result.append( Token( Text, message ) );
+ return result;
+ }
+
+ if( ! ( mode & (StrictParse|RelaxedParse) ) )
+ {
+ //if none of theses two mode are selected, use the mode from the config
+ mode |= KopetePrefs::prefs()->emoticonsRequireSpaces() ? StrictParse : RelaxedParse ;
+ }
+
+ /* previous char, in the firs iteration assume that it is space since we want
+ * to let emoticons at the beginning, the very first previous QChar must be a space. */
+ QChar p = ' ';
+ QChar c; /* current char */
+ QChar n; /* next character after a match candidate, if strict this should be QChar::null or space */
+
+ /* This is the EmoticonNode container, it will represent each matched emoticon */
+ QValueList<EmoticonNode> foundEmoticons;
+ QValueList<EmoticonNode>::const_iterator found;
+ /* First-pass, store the matched emoticon locations in foundEmoticons */
+ QValueList<Emoticon> emoticonList;
+ QValueList<Emoticon>::const_iterator it;
+ size_t pos;
+
+ bool inHTMLTag = false;
+ bool inHTMLLink = false;
+ bool inHTMLEntity = false;
+ QString needle; // search for this
+ for ( pos = 0; pos < message.length(); pos++ )
+ {
+ c = message[ pos ];
+
+ if ( mode & SkipHTML ) // Shall we skip HTML ?
+ {
+ if ( !inHTMLTag ) // Are we already in an HTML tag ?
+ {
+ if ( c == '<' ) { // If not check if are going into one
+ inHTMLTag = true; // If we are, change the state to inHTML
+ p = c;
+ continue;
+ }
+ }
+ else // We are already in a HTML tag
+ {
+ if ( c == '>' ) { // Check if it ends
+ inHTMLTag = false; // If so, change the state
+ if ( p == 'a' )
+ {
+ inHTMLLink = false;
+ }
+ }
+ else if ( c == 'a' && p == '<' ) // check if we just entered an achor tag
+ {
+ inHTMLLink = true; // don't put smileys in urls
+ }
+ p = c;
+ continue;
+ }
+
+ if( !inHTMLEntity )
+ { // are we
+ if( c == '&' )
+ {
+ inHTMLEntity = true;
+ }
+ }
+ }
+
+ if ( inHTMLLink ) // i can't think of any situation where a link adress might need emoticons
+ {
+ p = c;
+ continue;
+ }
+
+ if ( (mode & StrictParse) && !p.isSpace() && p != '>')
+ { // '>' may mark the end of an html tag
+ p = c;
+ continue;
+ } /* strict requires space before the emoticon */
+ if ( d->emoticonMap.contains( c ) )
+ {
+ emoticonList = d->emoticonMap[ c ];
+ bool found = false;
+ for ( it = emoticonList.begin(); it != emoticonList.end(); ++it )
+ {
+ // If this is an HTML, then search for the HTML form of the emoticon.
+ // For instance <o) => &gt;o)
+ needle = ( mode & SkipHTML ) ? (*it).matchTextEscaped : (*it).matchText;
+ if ( ( pos == (size_t)message.find( needle, pos ) ) )
+ {
+ if( mode & StrictParse )
+ {
+ /* check if the character after this match is space or end of string*/
+ n = message[ pos + needle.length() ];
+ //<br/> marks the end of a line
+ if( n != '<' && !n.isSpace() && !n.isNull() && n!= '&')
+ break;
+ }
+ /* Perfect match */
+ foundEmoticons.append( EmoticonNode( (*it), pos ) );
+ found = true;
+ /* Skip the matched emoticon's matchText */
+ pos += needle.length() - 1;
+ break;
+ }
+ }
+ if( !found )
+ {
+ if( inHTMLEntity ){
+ // If we are in an HTML entitiy such as &gt;
+ int htmlEnd = message.find( ';', pos );
+ // Search for where it ends
+ if( htmlEnd == -1 )
+ {
+ // Apparently this HTML entity isn't ended, something is wrong, try skip the '&'
+ // and continue
+ kdDebug( 14000 ) << k_funcinfo << "Broken HTML entity, trying to recover." << endl;
+ inHTMLEntity = false;
+ pos++;
+ }
+ else
+ {
+ pos = htmlEnd;
+ inHTMLEntity = false;
+ }
+ }
+ }
+ } /* else no emoticons begin with this character, so don't do anything */
+ p = c;
+ }
+
+ /* if no emoticons found just return the text */
+ if ( foundEmoticons.isEmpty() )
+ {
+ result.append( Token( Text, message ) );
+ return result;
+ }
+
+ /* Second-pass, generate tokens based on the matches */
+
+ pos = 0;
+ int length;
+
+ for ( found = foundEmoticons.begin(); found != foundEmoticons.end(); ++found )
+ {
+ needle = ( mode & SkipHTML ) ? (*found).emoticon.matchTextEscaped : (*found).emoticon.matchText;
+ if ( ( length = ( (*found).pos - pos ) ) )
+ {
+ result.append( Token( Text, message.mid( pos, length ) ) );
+ result.append( Token( Image, (*found).emoticon.matchTextEscaped, (*found).emoticon.picPath, (*found).emoticon.picHTMLCode ) );
+ pos += length + needle.length();
+ }
+ else
+ {
+ result.append( Token( Image, (*found).emoticon.matchTextEscaped, (*found).emoticon.picPath, (*found).emoticon.picHTMLCode ) );
+ pos += needle.length();
+ }
+ }
+
+ if ( message.length() - pos ) // if there is remaining regular text
+ {
+ result.append( Token( Text, message.mid( pos ) ) );
+ }
+
+ return result;
+}
+
+Emoticons::Emoticons( const QString &theme ) : QObject( kapp, "KopeteEmoticons" )
+{
+// kdDebug(14010) << "KopeteEmoticons::KopeteEmoticons" << endl;
+ d=new Private;
+ if(theme.isNull())
+ {
+ initEmoticons();
+ connect( KopetePrefs::prefs(), SIGNAL(saved()), this, SLOT(initEmoticons()) );
+ }
+ else
+ {
+ initEmoticons( theme );
+ }
+}
+
+
+Emoticons::~Emoticons( )
+{
+ delete d;
+}
+
+
+
+void Emoticons::addIfPossible( const QString& filenameNoExt, const QStringList &emoticons )
+{
+ KStandardDirs *dir = KGlobal::dirs();
+ QString pic;
+
+ //maybe an extension was given, so try to find the exact file
+ pic = dir->findResource( "emoticons", d->theme + QString::fromLatin1( "/" ) + filenameNoExt );
+
+ if( pic.isNull() )
+ pic = dir->findResource( "emoticons", d->theme + QString::fromLatin1( "/" ) + filenameNoExt + QString::fromLatin1( ".mng" ) );
+ if ( pic.isNull() )
+ pic = dir->findResource( "emoticons", d->theme + QString::fromLatin1( "/" ) + filenameNoExt + QString::fromLatin1( ".png" ) );
+ if ( pic.isNull() )
+ pic = dir->findResource( "emoticons", d->theme + QString::fromLatin1( "/" ) + filenameNoExt + QString::fromLatin1( ".gif" ) );
+
+ if( !pic.isNull() ) // only add if we found one file
+ {
+ QPixmap p;
+ QString result;
+
+ d->emoticonAndPicList.insert( pic, emoticons );
+
+ for ( QStringList::const_iterator it = emoticons.constBegin(), end = emoticons.constEnd();
+ it != end; ++it )
+ {
+ QString matchEscaped=QStyleSheet::escape(*it);
+
+ Emoticon e;
+ e.picPath = pic;
+
+ // We need to include size (width, height attributes) hints in the emoticon HTML code
+ // Unless we do so, ChatMessagePart::slotScrollView does not work properly and causing
+ // HTMLPart not to be scrolled to the very last message.
+ p.load( e.picPath );
+ result = QString::fromLatin1( "<img align=\"center\" src=\"" ) +
+ e.picPath +
+ QString::fromLatin1( "\" title=\"" ) +
+ matchEscaped +
+ QString::fromLatin1( "\" width=\"" ) +
+ QString::number( p.width() ) +
+ QString::fromLatin1( "\" height=\"" ) +
+ QString::number( p.height() ) +
+ QString::fromLatin1( "\" />" );
+
+ e.picHTMLCode = result;
+ e.matchTextEscaped = matchEscaped;
+ e.matchText = *it;
+ d->emoticonMap[ matchEscaped[0] ].append( e );
+ d->emoticonMap[ (*it)[0] ].append( e );
+ }
+ }
+}
+
+void Emoticons::initEmoticons( const QString &theme )
+{
+ if(theme.isNull())
+ {
+ if ( d->theme == KopetePrefs::prefs()->iconTheme() )
+ return;
+
+ d->theme = KopetePrefs::prefs()->iconTheme();
+ }
+ else
+ {
+ d->theme = theme;
+ }
+
+// kdDebug(14010) << k_funcinfo << "Called" << endl;
+ d->emoticonAndPicList.clear();
+ d->emoticonMap.clear();
+
+ QString filename= KGlobal::dirs()->findResource( "emoticons", d->theme + QString::fromLatin1( "/emoticons.xml" ) );
+ if(!filename.isEmpty())
+ return initEmoticon_emoticonsxml( filename );
+ filename= KGlobal::dirs()->findResource( "emoticons", d->theme + QString::fromLatin1( "/icondef.xml" ) );
+ if(!filename.isEmpty())
+ return initEmoticon_JEP0038( filename );
+ kdWarning(14010) << k_funcinfo << "emotiucon XML theme description not found" <<endl;
+}
+
+void Emoticons::initEmoticon_emoticonsxml( const QString & filename)
+{
+ QDomDocument emoticonMap( QString::fromLatin1( "messaging-emoticon-map" ) );
+
+ QFile mapFile( filename );
+ mapFile.open( IO_ReadOnly );
+ emoticonMap.setContent( &mapFile );
+
+ QDomElement list = emoticonMap.documentElement();
+ QDomNode node = list.firstChild();
+ while( !node.isNull() )
+ {
+ QDomElement element = node.toElement();
+ if( !element.isNull() )
+ {
+ if( element.tagName() == QString::fromLatin1( "emoticon" ) )
+ {
+ QString emoticon_file = element.attribute(
+ QString::fromLatin1( "file" ), QString::null );
+ QStringList items;
+
+ QDomNode emoticonNode = node.firstChild();
+ while( !emoticonNode.isNull() )
+ {
+ QDomElement emoticonElement = emoticonNode.toElement();
+ if( !emoticonElement.isNull() )
+ {
+ if( emoticonElement.tagName() == QString::fromLatin1( "string" ) )
+ {
+ items << emoticonElement.text();
+ }
+ else
+ {
+ kdDebug(14010) << k_funcinfo <<
+ "Warning: Unknown element '" << element.tagName() <<
+ "' in emoticon data" << endl;
+ }
+ }
+ emoticonNode = emoticonNode.nextSibling();
+ }
+
+ addIfPossible ( emoticon_file, items );
+ }
+ else
+ {
+ kdDebug(14010) << k_funcinfo << "Warning: Unknown element '" <<
+ element.tagName() << "' in map file" << endl;
+ }
+ }
+ node = node.nextSibling();
+ }
+ mapFile.close();
+ sortEmoticons();
+}
+
+
+void Emoticons::initEmoticon_JEP0038( const QString & filename)
+{
+ QDomDocument emoticonMap( QString::fromLatin1( "icondef" ) );
+
+ QFile mapFile( filename );
+ mapFile.open( IO_ReadOnly );
+ emoticonMap.setContent( &mapFile );
+
+ QDomElement list = emoticonMap.documentElement();
+ QDomNode node = list.firstChild();
+ while( !node.isNull() )
+ {
+ QDomElement element = node.toElement();
+ if( !element.isNull() )
+ {
+ if( element.tagName() == QString::fromLatin1( "icon" ) )
+ {
+ QStringList items;
+ QString emoticon_file;
+
+ QDomNode emoticonNode = node.firstChild();
+ while( !emoticonNode.isNull() )
+ {
+ QDomElement emoticonElement = emoticonNode.toElement();
+ if( !emoticonElement.isNull() )
+ {
+ if( emoticonElement.tagName() == QString::fromLatin1( "text" ) )
+ {
+ //TODO xml:lang
+ items << emoticonElement.text();
+ }
+ else if( emoticonElement.tagName() == QString::fromLatin1( "object" ) && emoticon_file.isEmpty() )
+ {
+ QString mime= emoticonElement.attribute(
+ QString::fromLatin1( "mime" ), QString::fromLatin1("image/*") );
+ if(mime.startsWith(QString::fromLatin1("image/")) && !mime.endsWith(QString::fromLatin1("/svg+xml")))
+ {
+ emoticon_file = emoticonElement.text();
+ }
+ else
+ {
+ kdDebug(14010) << k_funcinfo << "Warning: Unsupported format '" << mime << endl;
+ }
+ }
+ /*else
+ {
+ kdDebug(14010) << k_funcinfo <<
+ "Warning: Unknown element '" << element.tagName() <<
+ "' in emoticon data" << endl;
+ }*/
+ }
+ emoticonNode = emoticonNode.nextSibling();
+ }
+ if( !items.isEmpty() && !emoticon_file.isEmpty() )
+ addIfPossible ( emoticon_file, items );
+ }
+ else
+ {
+ kdDebug(14010) << k_funcinfo << "Warning: Unknown element '" <<
+ element.tagName() << "' in map file" << endl;
+ }
+ }
+ node = node.nextSibling();
+ }
+ mapFile.close();
+ sortEmoticons();
+}
+
+
+void Emoticons::sortEmoticons()
+{
+ /* sort strings in order of longest to shortest to provide convenient input for
+ greedy matching in the tokenizer */
+ QValueList<QChar> keys = d->emoticonMap.keys();
+ for ( QValueList<QChar>::const_iterator it = keys.begin(); it != keys.end(); ++it )
+ {
+ QChar key = (*it);
+ QValueList<Emoticon> keyValues = d->emoticonMap[key];
+ qHeapSort(keyValues.begin(), keyValues.end());
+ d->emoticonMap[key] = keyValues;
+ }
+}
+
+
+
+
+QMap<QString, QStringList> Emoticons::emoticonAndPicList()
+{
+ return d->emoticonAndPicList;
+}
+
+
+QString Emoticons::parse( const QString &message, ParseMode mode )
+{
+ if ( !KopetePrefs::prefs()->useEmoticons() )
+ return message;
+
+ QValueList<Token> tokens = tokenize( message, mode );
+ QValueList<Token>::const_iterator token;
+ QString result;
+ QPixmap p;
+ for ( token = tokens.begin(); token != tokens.end(); ++token )
+ {
+ switch ( (*token).type )
+ {
+ case Text:
+ result += (*token).text;
+ break;
+ case Image:
+ result += (*token).picHTMLCode;
+ kdDebug( 14010 ) << k_funcinfo << "Emoticon html code: " << result << endl;
+ break;
+ default:
+ kdDebug( 14010 ) << k_funcinfo << "Unknown token type. Something's broken." << endl;
+ }
+ }
+ return result;
+}
+
+} //END namesapce Kopete
+
+#include "kopeteemoticons.moc"
+
+
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/libkopete/private/kopeteemoticons.h b/kopete/libkopete/private/kopeteemoticons.h
new file mode 100644
index 00000000..848185e6
--- /dev/null
+++ b/kopete/libkopete/private/kopeteemoticons.h
@@ -0,0 +1,184 @@
+/*
+ kopeteemoticons.cpp - Kopete Preferences Container-Class
+
+ Copyright (c) 2002-2003 by Stefan Gehn <metz AT gehn.net>
+ Kopete (c) 2002-2004 by the Kopete developers <[email protected]>
+ Copyright (c) 2005 by Engin AYDOGAN <engin @ bzzzt.biz>
+
+ *************************************************************************
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef kopeteemoticons_h__
+#define kopeteemoticons_h__
+
+#include <qobject.h>
+#include <qvaluelist.h>
+#include <qregexp.h>
+
+#include "kopete_export.h"
+
+namespace Kopete {
+
+class KOPETE_EXPORT Emoticons : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor: DON'T use it if you want to use the emoticon theme
+ * chosen by the user.
+ * Instead, use @ref Kopete::Emoticons::self()
+ **/
+ Emoticons( const QString &theme = QString::null );
+
+ ~Emoticons( );
+
+ /**
+ * The emoticons container-class by default is a singleton object.
+ * Use this method to retrieve the instance.
+ */
+ static Emoticons *self();
+
+ /**
+ * The possible parse modes
+ */
+ enum ParseMode { DefaultParseMode = 0x0 , /** Use strict or relaxed according the config */
+ StrictParse = 0x1, /** Strict parsing requires a space between each emoticon */
+ RelaxedParse = 0x4, /** Parse mode where all possible emoticon matches are allowed */
+ SkipHTML = 0x2 /** Skip emoticons within HTML */
+ };
+
+ /**
+ * Use it to parse emoticons in a text.
+ * You don't need to use this for chat windows,
+ * There is a special class that abstract a chat view
+ * and uses emoticons parser.
+ * This function will use the selected emoticon theme.
+ * If nicks is provided, they will not be parsed if they
+ * exist in message.
+ */
+ static QString parseEmoticons( const QString &message, ParseMode = SkipHTML ) ;
+
+
+ QString parse( const QString &message, ParseMode = SkipHTML );
+
+ /**
+ * TokenType, a token might be an image ( emoticon ) or text.
+ */
+ enum TokenType { Undefined, /** Undefined, for completeness only */
+ Image, /** Token contains a path to an image */
+ Text /** Token contains test */
+ };
+
+ /**
+ * A token consists of a QString text which is either a regular text
+ * or a path to image depending on the type.
+ * If type is Image the text refers to an image path.
+ * If type is Text the text refers to a regular text.
+ */
+ struct Token {
+ Token() : type( Undefined ) {}
+ Token( TokenType t, const QString &m ) : type( t ), text(m) {}
+ Token( TokenType t, const QString &m, const QString &p, const QString &html )
+ : type( t ), text( m ), picPath( p ), picHTMLCode( html ) {}
+ TokenType type;
+ QString text;
+ QString picPath;
+ QString picHTMLCode;
+ };
+
+
+ /**
+ * Static function which will call tokenize
+ * @see tokenize( const QString& )
+ */
+ static QValueList<Token> tokenizeEmoticons( const QString &message, ParseMode mode = DefaultParseMode );
+
+ /**
+ * Tokenizes an message.
+ * For example;
+ * Assume :], (H), :-x are three emoticons.
+ * A text "(H)(H) foo bar john :] :-x" would be tokenized as follows (not strict):
+ * 1- /path/to/shades.png
+ * 2- /path/to/shades.png
+ * 3- " foo bar john "
+ * 4- /path/to/bat.png
+ * 5- " "
+ * 6- /path/to/kiss.png
+ *
+ * Strict tokenization (require spaces around emoticons):
+ * 1- "(H)(H) foo bar john "
+ * 2- /path/to/bat.png
+ * 3- " "
+ * 4- /path/to/kiss.png
+ * Note: quotation marks are used to emphasize white spaces.
+ * @param message is the message to tokenize
+ * @param mode is a bitmask of ParseMode enum
+ * @return a QValueList which consiste of ordered tokens of the text.
+ * @author Engin AYDOGAN < [email protected] >
+ * @since 23-03-05
+ */
+ QValueList<Token> tokenize( const QString &message, uint mode = DefaultParseMode );
+
+ /**
+ * Return all emoticons and the corresponding icon.
+ * (only one emoticon per image)
+ */
+ QMap<QString, QStringList> emoticonAndPicList();
+
+
+private:
+ /**
+ * Our instance
+ **/
+ static Emoticons *s_self;
+
+ /**
+ * add an emoticon to our mapping if
+ * an animation/pixmap has been found for it
+ **/
+ void addIfPossible( const QString& filenameNoExt, const QStringList &emoticons );
+
+ /**
+ * uses the kopete's emoticons.xml for the theme
+ * @see initEmoticons
+ */
+ void initEmoticon_emoticonsxml( const QString & filename);
+
+ /**
+ * uses the JEP-0038 xml description for the theme
+ * @see initEmoticons
+ */
+ void initEmoticon_JEP0038( const QString & filename);
+
+ /**
+ * sorts emoticons for convenient parsing, which yields greedy matching on
+ * matchText
+ */
+ void sortEmoticons();
+
+
+ struct Emoticon;
+ struct EmoticonNode;
+ class Private;
+ Private *d;
+private slots:
+
+ /**
+ * Fills the map with paths and emoticons
+ * This needs to be done on every emoticon-theme change
+ **/
+ void initEmoticons ( const QString &theme = QString::null );
+};
+
+
+} //END namespace Kopete
+
+#endif
+// vim: set noet ts=4 sts=4 sw=4:
diff --git a/kopete/libkopete/private/kopeteutils_private.cpp b/kopete/libkopete/private/kopeteutils_private.cpp
new file mode 100644
index 00000000..3746bcd3
--- /dev/null
+++ b/kopete/libkopete/private/kopeteutils_private.cpp
@@ -0,0 +1,85 @@
+/*
+ Kopete Utils.
+ Copyright (c) 2005 Duncan Mac-Vicar Prett <[email protected]>
+
+ Kopete (c) 2002-2005 by the Kopete developers <[email protected]>
+
+ *************************************************************************
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <qmap.h>
+
+#include <kmessagebox.h>
+
+#include <kdebug.h>
+
+#include "knotification.h"
+#include "kopeteutils_private.h"
+#include "kopeteuiglobal.h"
+
+namespace Kopete
+{
+namespace Utils
+{
+
+NotifyHelper* NotifyHelper::s_self = 0L;
+
+NotifyHelper::NotifyHelper()
+{
+}
+
+NotifyHelper::~NotifyHelper()
+{
+}
+
+NotifyHelper* NotifyHelper::self()
+{
+ if (!s_self)
+ s_self = new NotifyHelper();
+
+ return s_self;
+}
+
+void NotifyHelper::slotEventActivated(unsigned int action)
+{
+ const KNotification *n = dynamic_cast<const KNotification *>(QObject::sender());
+ if (n)
+ {
+ ErrorNotificationInfo info = m_events[n];
+ if ( info.debugInfo.isEmpty() )
+ KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Information, info.explanation, info.caption);
+ else
+ KMessageBox::queuedDetailedError( Kopete::UI::Global::mainWidget(), info.explanation, info.debugInfo, info.caption);
+
+ unregisterNotification(n);
+ }
+}
+
+void NotifyHelper::slotEventClosed()
+{
+ const KNotification *n = dynamic_cast<const KNotification *>(QObject::sender());
+ if (n)
+ unregisterNotification(n);
+}
+
+void NotifyHelper::registerNotification(const KNotification* event, ErrorNotificationInfo error)
+{
+ m_events.insert( event, error);
+}
+
+void NotifyHelper::unregisterNotification(const KNotification* event)
+{
+ m_events.remove(event);
+}
+
+} // end ns ErrorNotifier
+} // end ns Kopete
+
+#include "kopeteutils_private.moc"
diff --git a/kopete/libkopete/private/kopeteutils_private.h b/kopete/libkopete/private/kopeteutils_private.h
new file mode 100644
index 00000000..a684c965
--- /dev/null
+++ b/kopete/libkopete/private/kopeteutils_private.h
@@ -0,0 +1,60 @@
+/*
+ Kopete Utils.
+
+ Copyright (c) 2005 Duncan Mac-Vicar Prett <[email protected]>
+
+ Kopete (c) 2002-2005 by the Kopete developers <[email protected]>
+
+ *************************************************************************
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Lesser General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KOPETE_UTILS_PRIVATE_H
+#define KOPETE_UTILS_PRIVATE_H
+
+#include "qobject.h"
+#include "qstring.h"
+#include "qpixmap.h"
+
+class KNotification;
+
+namespace Kopete
+{
+
+namespace Utils
+{
+
+typedef struct
+{
+ QString caption;
+ QString explanation;
+ QString debugInfo;
+} ErrorNotificationInfo;
+
+class NotifyHelper : public QObject
+{
+Q_OBJECT
+public:
+ static NotifyHelper* self();
+ void registerNotification(const KNotification* event, ErrorNotificationInfo error);
+ void unregisterNotification(const KNotification* event);
+public slots:
+ void slotEventActivated(unsigned int action);
+ void slotEventClosed();
+private:
+ NotifyHelper();
+ ~NotifyHelper();
+ QMap<const KNotification*, ErrorNotificationInfo> m_events;
+ static NotifyHelper *s_self;
+};
+
+} // end ns Utils
+} // end ns Kopete
+
+#endif
diff --git a/kopete/libkopete/private/kopeteviewmanager.cpp b/kopete/libkopete/private/kopeteviewmanager.cpp
new file mode 100644
index 00000000..c6d295fd
--- /dev/null
+++ b/kopete/libkopete/private/kopeteviewmanager.cpp
@@ -0,0 +1,364 @@
+/*
+ kopeteviewmanager.cpp - View Manager
+
+ Copyright (c) 2003 by Jason Keirstead <[email protected]>
+ Kopete (c) 2002-2005 by the Kopete developers <[email protected]>
+
+ *************************************************************************
+ * *
+ * 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 <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <qptrlist.h>
+#include <qstylesheet.h>
+#include <kplugininfo.h>
+#include <knotification.h>
+#include <kglobal.h>
+#include <kwin.h>
+
+#include "kopeteprefs.h"
+#include "kopeteaccount.h"
+#include "kopetepluginmanager.h"
+#include "kopeteviewplugin.h"
+#include "kopetechatsessionmanager.h"
+#include "kopetemetacontact.h"
+#include "kopetenotifyevent.h"
+#include "kopetemessageevent.h"
+#include "kopeteview.h"
+//#include "systemtray.h"
+
+#include "kopeteviewmanager.h"
+
+typedef QMap<Kopete::ChatSession*,KopeteView*> ManagerMap;
+typedef QPtrList<Kopete::MessageEvent> EventList;
+
+struct KopeteViewManagerPrivate
+{
+ ManagerMap managerMap;
+ EventList eventList;
+ KopeteView *activeView;
+
+ bool useQueueOrStack;
+ bool raiseWindow;
+ bool queueUnreadMessages;
+ bool queueOnlyHighlightedMessagesInGroupChats;
+ bool queueOnlyMessagesOnAnotherDesktop;
+ bool balloonNotifyIgnoreClosesChatView;
+ bool foreignMessage;
+};
+
+KopeteViewManager *KopeteViewManager::s_viewManager = 0L;
+
+KopeteViewManager *KopeteViewManager::viewManager()
+{
+ if( !s_viewManager )
+ s_viewManager = new KopeteViewManager();
+ return s_viewManager;
+}
+
+KopeteViewManager::KopeteViewManager()
+{
+ s_viewManager=this;
+ d = new KopeteViewManagerPrivate;
+ d->activeView = 0L;
+ d->foreignMessage=false;
+
+ connect( KopetePrefs::prefs(), SIGNAL( saved() ), this, SLOT( slotPrefsChanged() ) );
+
+ connect( Kopete::ChatSessionManager::self() , SIGNAL( display( Kopete::Message &, Kopete::ChatSession *) ),
+ this, SLOT ( messageAppended( Kopete::Message &, Kopete::ChatSession *) ) );
+
+ connect( Kopete::ChatSessionManager::self() , SIGNAL( readMessage() ),
+ this, SLOT ( nextEvent() ) );
+
+ slotPrefsChanged();
+}
+
+KopeteViewManager::~KopeteViewManager()
+{
+// kdDebug(14000) << k_funcinfo << endl;
+
+ //delete all open chatwindow.
+ ManagerMap::Iterator it;
+ for ( it = d->managerMap.begin(); it != d->managerMap.end(); ++it )
+ it.data()->closeView( true ); //this does not clean the map, but we don't care
+
+ delete d;
+}
+
+void KopeteViewManager::slotPrefsChanged()
+{
+ d->useQueueOrStack = KopetePrefs::prefs()->useQueue() || KopetePrefs::prefs()->useStack();
+ d->raiseWindow = KopetePrefs::prefs()->raiseMsgWindow();
+ d->queueUnreadMessages = KopetePrefs::prefs()->queueUnreadMessages();
+ d->queueOnlyHighlightedMessagesInGroupChats = KopetePrefs::prefs()->queueOnlyHighlightedMessagesInGroupChats();
+ d->queueOnlyMessagesOnAnotherDesktop = KopetePrefs::prefs()->queueOnlyMessagesOnAnotherDesktop();
+ d->balloonNotifyIgnoreClosesChatView = KopetePrefs::prefs()->balloonNotifyIgnoreClosesChatView();
+}
+
+KopeteView *KopeteViewManager::view( Kopete::ChatSession* session, const QString &requestedPlugin )
+{
+// kdDebug(14000) << k_funcinfo << endl;
+
+ if( d->managerMap.contains( session ) && d->managerMap[ session ] )
+ {
+ return d->managerMap[ session ];
+ }
+ else
+ {
+ Kopete::PluginManager *pluginManager = Kopete::PluginManager::self();
+ Kopete::ViewPlugin *viewPlugin = 0L;
+
+ QString pluginName = requestedPlugin.isEmpty() ? KopetePrefs::prefs()->interfacePreference() : requestedPlugin;
+ if( !pluginName.isEmpty() )
+ {
+ viewPlugin = (Kopete::ViewPlugin*)pluginManager->loadPlugin( pluginName );
+
+ if( !viewPlugin )
+ {
+ kdWarning(14000) << "Requested view plugin, " << pluginName <<
+ ", was not found. Falling back to chat window plugin" << endl;
+ }
+ }
+
+ if( !viewPlugin )
+ viewPlugin = (Kopete::ViewPlugin*)pluginManager->loadPlugin( QString::fromLatin1("kopete_chatwindow") );
+
+ if( viewPlugin )
+ {
+ KopeteView *newView = viewPlugin->createView(session);
+
+ d->foreignMessage = false;
+ d->managerMap.insert( session, newView );
+
+ connect( session, SIGNAL( closing(Kopete::ChatSession *) ),
+ this, SLOT(slotChatSessionDestroyed(Kopete::ChatSession*)) );
+
+ return newView;
+ }
+ else
+ {
+ kdError(14000) << "Could not create a view, no plugins available!" << endl;
+ return 0L;
+ }
+ }
+}
+
+
+void KopeteViewManager::messageAppended( Kopete::Message &msg, Kopete::ChatSession *manager)
+{
+// kdDebug(14000) << k_funcinfo << endl;
+
+ bool outgoingMessage = ( msg.direction() == Kopete::Message::Outbound );
+
+ if( !outgoingMessage || d->managerMap.contains( manager ) )
+ {
+ d->foreignMessage=!outgoingMessage; //let know for the view we are about to create
+ manager->view(true,msg.requestedPlugin())->appendMessage( msg );
+ d->foreignMessage=false; //the view is created, reset the flag
+
+ bool appendMessageEvent = d->useQueueOrStack;
+
+ QWidget *w;
+ if( d->queueUnreadMessages && ( w = dynamic_cast<QWidget*>(view( manager )) ) )
+ {
+ // append msg event to queue if chat window is active but not the chat view in it...
+ appendMessageEvent = appendMessageEvent && !(w->isActiveWindow() && manager->view() == d->activeView);
+ // ...and chat window is on another desktop
+ appendMessageEvent = appendMessageEvent && (!d->queueOnlyMessagesOnAnotherDesktop || !KWin::windowInfo( w->topLevelWidget()->winId(), NET::WMDesktop ).isOnCurrentDesktop());
+ }
+ else
+ {
+ // append if no chat window exists already
+ appendMessageEvent = appendMessageEvent && !view( manager )->isVisible();
+ }
+
+ // in group chats always append highlighted messages to queue
+ appendMessageEvent = appendMessageEvent && (!d->queueOnlyHighlightedMessagesInGroupChats || manager->members().count() == 1 || msg.importance() == Kopete::Message::Highlight);
+
+ if( appendMessageEvent )
+ {
+ if ( !outgoingMessage )
+ {
+ Kopete::MessageEvent *event=new Kopete::MessageEvent(msg,manager);
+ d->eventList.append( event );
+ connect(event, SIGNAL(done(Kopete::MessageEvent *)), this, SLOT(slotEventDeleted(Kopete::MessageEvent *)));
+ Kopete::ChatSessionManager::self()->postNewEvent(event);
+ }
+ }
+ else if( d->eventList.isEmpty() )
+ {
+ readMessages( manager, outgoingMessage );
+ }
+
+ if ( !outgoingMessage && ( !manager->account()->isAway() || KopetePrefs::prefs()->soundIfAway() )
+ && msg.direction() != Kopete::Message::Internal )
+ {
+ QWidget *w=dynamic_cast<QWidget*>(manager->view(false));
+ KConfig *config = KGlobal::config();
+ config->setGroup("General");
+ if( (!manager->view(false) || !w || manager->view() != d->activeView ||
+ config->readBoolEntry("EventIfActive", true) || !w->isActiveWindow())
+ && msg.from())
+ {
+ QString msgFrom = QString::null;
+ if( msg.from()->metaContact() )
+ msgFrom = msg.from()->metaContact()->displayName();
+ else
+ msgFrom = msg.from()->contactId();
+
+ QString msgText = msg.plainBody();
+ if( msgText.length() > 90 )
+ msgText = msgText.left(88) + QString::fromLatin1("...");
+
+ QString event;
+ QString body =i18n( "<qt>Incoming message from %1<br>\"%2\"</qt>" );
+
+ switch( msg.importance() )
+ {
+ case Kopete::Message::Low:
+ event = QString::fromLatin1( "kopete_contact_lowpriority" );
+ break;
+ case Kopete::Message::Highlight:
+ event = QString::fromLatin1( "kopete_contact_highlight" );
+ body = i18n( "<qt>A highlighted message arrived from %1<br>\"%2\"</qt>" );
+ break;
+ default:
+ event = QString::fromLatin1( "kopete_contact_incoming" );
+ }
+ KNotification *notify=KNotification::event(msg.from()->metaContact() , event, body.arg( QStyleSheet::escape(msgFrom), QStyleSheet::escape(msgText) ), 0, /*msg.from()->metaContact(),*/
+ w , i18n("View") );
+
+ connect(notify,SIGNAL(activated(unsigned int )), manager , SLOT(raiseView()) );
+ }
+ }
+ }
+}
+
+void KopeteViewManager::readMessages( Kopete::ChatSession *manager, bool outgoingMessage, bool activate )
+{
+// kdDebug( 14000 ) << k_funcinfo << endl;
+ d->foreignMessage=!outgoingMessage; //let know for the view we are about to create
+ KopeteView *thisView = manager->view( true );
+ d->foreignMessage=false; //the view is created, reset the flag
+ if( ( outgoingMessage && !thisView->isVisible() ) || d->raiseWindow || activate )
+ thisView->raise( activate );
+ else if( !thisView->isVisible() )
+ thisView->makeVisible();
+
+ QPtrListIterator<Kopete::MessageEvent> it( d->eventList );
+ Kopete::MessageEvent* event;
+ while ( ( event = it.current() ) != 0 )
+ {
+ ++it;
+ if ( event->message().manager() == manager )
+ {
+ event->apply();
+ d->eventList.remove( event );
+ }
+ }
+}
+
+void KopeteViewManager::slotEventDeleted( Kopete::MessageEvent *event )
+{
+// kdDebug(14000) << k_funcinfo << endl;
+ Kopete::ChatSession *kmm=event->message().manager();
+ if(!kmm)
+ return;
+
+ d->eventList.remove( event );
+
+ if ( event->state() == Kopete::MessageEvent::Applied )
+ {
+ readMessages( kmm, false, true );
+ }
+ else if ( event->state() == Kopete::MessageEvent::Ignored && d->balloonNotifyIgnoreClosesChatView )
+ {
+ bool bAnotherWithThisManager = false;
+ for( QPtrListIterator<Kopete::MessageEvent> it( d->eventList ); it; ++it )
+ {
+ Kopete::MessageEvent *event = it.current();
+ if ( event->message().manager() == kmm )
+ bAnotherWithThisManager = true;
+ }
+ if ( !bAnotherWithThisManager && kmm->view( false ) )
+ kmm->view()->closeView( true );
+ }
+}
+
+void KopeteViewManager::nextEvent()
+{
+// kdDebug( 14000 ) << k_funcinfo << endl;
+
+ if( d->eventList.isEmpty() )
+ return;
+
+ Kopete::MessageEvent* event = d->eventList.first();
+
+ if ( event )
+ event->apply();
+}
+
+void KopeteViewManager::slotViewActivated( KopeteView *view )
+{
+// kdDebug( 14000 ) << k_funcinfo << endl;
+ d->activeView = view;
+
+ QPtrListIterator<Kopete::MessageEvent> it ( d->eventList );
+ Kopete::MessageEvent* event;
+ while ( ( event = it.current() ) != 0 )
+ {
+ ++it;
+ if ( event->message().manager() == view->msgManager() )
+ event->deleteLater();
+ }
+
+}
+
+void KopeteViewManager::slotViewDestroyed( KopeteView *closingView )
+{
+// kdDebug( 14000 ) << k_funcinfo << endl;
+
+ if( d->managerMap.contains( closingView->msgManager() ) )
+ {
+ d->managerMap.remove( closingView->msgManager() );
+// closingView->msgManager()->setCanBeDeleted( true );
+ }
+
+ if( closingView == d->activeView )
+ d->activeView = 0L;
+}
+
+void KopeteViewManager::slotChatSessionDestroyed( Kopete::ChatSession *manager )
+{
+// kdDebug( 14000 ) << k_funcinfo << endl;
+
+ if( d->managerMap.contains( manager ) )
+ {
+ KopeteView *v=d->managerMap[ manager ];
+ v->closeView( true );
+ delete v; //closeView call deleteLater, but in this case this is not enough, because some signal are called that case crash
+ d->managerMap.remove( manager );
+ }
+}
+
+KopeteView* KopeteViewManager::activeView() const
+{
+ return d->activeView;
+}
+
+
+#include "kopeteviewmanager.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
+
diff --git a/kopete/libkopete/private/kopeteviewmanager.h b/kopete/libkopete/private/kopeteviewmanager.h
new file mode 100644
index 00000000..b1706906
--- /dev/null
+++ b/kopete/libkopete/private/kopeteviewmanager.h
@@ -0,0 +1,103 @@
+/*
+ kopeteviewmanager.h - View Manager
+
+ Copyright (c) 2003 by Jason Keirstead
+ Kopete (c) 2002-2003 by the Kopete developers <[email protected]>
+
+ *************************************************************************
+ * *
+ * 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. *
+ * *
+ *************************************************************************
+*/
+
+#ifndef KOPETEVIEWMANAGER_H
+#define KOPETEVIEWMANAGER_H
+
+#include "kopetemessage.h"
+#include "kopete_export.h"
+
+namespace Kopete
+{
+ class ChatSession;
+ class Protocol;
+ class Contact;
+ class MessageEvent;
+}
+
+class KopeteView;
+class QTextEdit;
+
+struct KopeteViewManagerPrivate;
+
+/**
+ * Relates an actual chat to the means used to view it.
+ */
+class KOPETE_EXPORT KopeteViewManager : public QObject
+{
+ Q_OBJECT
+ public:
+ /** This is a singleton class. Call this method to get a pointer to
+ * a KopeteViewManager.
+ */
+ static KopeteViewManager *viewManager();
+
+ KopeteViewManager();
+ ~KopeteViewManager();
+
+ /**
+ * Return a view for the supplied Kopete::ChatSession. If one already
+ * exists, it will be returned, otherwise, a new view is created.
+ * @param session The Kopete::ChatSession we are viewing.
+ * @param requestedPlugin Specifies the view plugin to use.
+ */
+ KopeteView *view( Kopete::ChatSession *session, const QString &requestedPlugin = QString::null );
+
+ /**
+ * Provide access to the list of KopeteChatWindow the class maintains.
+ */
+ KopeteView *activeView() const;
+
+ private:
+
+
+ KopeteViewManagerPrivate *d;
+ static KopeteViewManager *s_viewManager;
+
+ public slots:
+ /**
+ * Make a view visible and on top.
+ * @param manager The originating Kopete::ChatSession.
+ * @param outgoingMessage Whether the message is inbound or outbound.
+ * @param activate Indicate whether the view should be activated
+ * @todo Document @p activate
+ */
+ void readMessages( Kopete::ChatSession* manager, bool outgoingMessage, bool activate = false );
+
+ /**
+ * Called when a new message has been appended to the given
+ * Kopete::ChatSession. Procures a view for the message, and generates any notification events or displays messages, as appropriate.
+ * @param msg The new message
+ * @param manager The originating Kopete::ChatSession
+ */
+ void messageAppended( Kopete::Message &msg, Kopete::ChatSession *manager);
+
+ void nextEvent();
+
+ private slots:
+ void slotViewDestroyed( KopeteView *);
+ void slotChatSessionDestroyed( Kopete::ChatSession * );
+
+ /**
+ * An event has been deleted.
+ */
+ void slotEventDeleted( Kopete::MessageEvent * );
+
+ void slotPrefsChanged();
+ void slotViewActivated( KopeteView * );
+};
+
+#endif