diff -Nurp ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/chatmessagepart.cpp kopete-3.4.0/kopete/kopete/chatwindow/chatmessagepart.cpp --- ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/chatmessagepart.cpp 2005-05-18 15:23:36.000000000 +0600 +++ kopete-3.4.0/kopete/kopete/chatwindow/chatmessagepart.cpp 2005-05-18 15:25:24.000000000 +0600 @@ -23,9 +23,11 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -162,7 +164,7 @@ ChatMessagePart::ChatMessagePart( Kopete { d->xsltParser = new Kopete::XSLT( KopetePrefs::prefs()->styleContents() ); d->transformAllMessages = ( d->xsltParser->flags() & Kopete::XSLT::TransformAllMessages ); - + codepage="Unicode"; backgroundFile = 0; root = 0; messageId = 0; @@ -176,12 +178,11 @@ ChatMessagePart::ChatMessagePart( Kopete setMetaRefreshEnabled( false ); begin(); - write( QString::fromLatin1( "\n" - "\n") ); + write( QString::fromLatin1( "\n" + "\n") ); end(); - view()->setFocusPolicy( QWidget::NoFocus ); new ToolTip( this ); @@ -338,7 +339,7 @@ void ChatMessagePart::slotAppearanceChan slotRefreshNodes(); } -void ChatMessagePart::appendMessage( Kopete::Message &message ) +void ChatMessagePart::appendMessage( Kopete::Message &message,bool encode) { //parse emoticons and URL now. message.setBody( message.parsedBody() , Kopete::Message::ParsedHTML ); @@ -348,7 +349,6 @@ void ChatMessagePart::appendMessage( Kop message.setRtfOverride( d->rtfOverride ); messageMap.append( message.asXML().toString() ); - uint bufferLen = (uint)KopetePrefs::prefs()->chatViewBufferSize(); // transform all messages every time. needed for Adium style. @@ -364,7 +364,13 @@ void ChatMessagePart::appendMessage( Kop QDomDocument domMessage = message.asXML(); domMessage.documentElement().setAttribute( QString::fromLatin1( "id" ), QString::number( messageId ) ); QString resultHTML = addNickLinks( d->xsltParser->transform( domMessage.toString() ) ); - + if(encode && (codepage != "Unicode")) + { + QCString locallyEncoded = resultHTML.ascii(); + QTextCodec *codec = QTextCodec::codecForName(codepage.ascii()); + if(codec) + resultHTML = codec->toUnicode( locallyEncoded ); + } QString direction = ( message.plainBody().isRightToLeft() ? QString::fromLatin1("rtl") : QString::fromLatin1("ltr") ); DOM::HTMLElement newNode = document().createElement( QString::fromLatin1("span") ); newNode.setAttribute( QString::fromLatin1("dir"), direction ); @@ -891,3 +897,52 @@ void ChatMessagePart::emitTooltipEvent( // vim: set noet ts=4 sts=4 sw=4: +void ChatMessagePart::slotConvert(const QString& string) +{ + + + DOM::DOMString text=htmlDocument().body().innerHTML(); + if(codepage!="Unicode") + { + QCString locallyEncoded; + QTextCodec *codec = QTextCodec::codecForName(codepage.ascii()); + if(!codec) + { + kdDebug()<<"codec for this name not exisit\n"; + return; + } + locallyEncoded=codec->fromUnicode(text.string()); + if(string!="Unicode") + { + QTextCodec *codec = QTextCodec::codecForName(string.ascii()); + if(!codec) + { + kdDebug()<<"codec for this name not exisit\n"; + return; + } + text=codec->toUnicode(locallyEncoded); + } + else + text=QString(locallyEncoded); + } + else + { + if(string!="Unicode") + { + QTextCodec *codec = QTextCodec::codecForName(string.ascii()); + if(!codec) + { + kdDebug()<<"codec for this name not exisit\n"; + return; + } + text=codec->toUnicode(text.string().ascii()); + } + } + htmlDocument().body().setInnerHTML(text); + setCodepage(string); +} + +void ChatMessagePart::setCodepage(const QString& page) +{ + codepage=page; +} diff -Nurp ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/chatmessagepart.h kopete-3.4.0/kopete/kopete/chatwindow/chatmessagepart.h --- ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/chatmessagepart.h 2005-05-18 15:23:36.000000000 +0600 +++ kopete-3.4.0/kopete/kopete/chatwindow/chatmessagepart.h 2005-05-18 15:25:24.000000000 +0600 @@ -55,6 +55,7 @@ public: * use */ void keepScrolledDown(); + void setCodepage(const QString& page); public slots: /** @@ -91,7 +92,8 @@ public slots: * Appends a message to the messave view * @param message The message to be appended */ - void appendMessage( Kopete::Message &message ); + void appendMessage( Kopete::Message &message,bool encode=true ); + void slotConvert(const QString& string); signals: /** @@ -157,6 +159,7 @@ private: KAction *printAction; KAction *closeAction; KAction *copyURLAction; + QString codepage; void readOverrides(); diff -Nurp ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/chatview.cpp kopete-3.4.0/kopete/kopete/chatwindow/chatview.cpp --- ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/chatview.cpp 2005-05-18 15:23:36.000000000 +0600 +++ kopete-3.4.0/kopete/kopete/chatwindow/chatview.cpp 2005-05-18 15:25:24.000000000 +0600 @@ -693,8 +693,11 @@ void ChatView::setCaption( const QString void ChatView::appendMessage(Kopete::Message &message) { remoteTyping( message.from(), false ); - - messagePart()->appendMessage( message ); + + if ( message.direction() != Kopete::Message::Inbound ) + messagePart()->appendMessage( message,false); + else + messagePart()->appendMessage(message); if( !d->isActive ) { switch ( message.importance() ) diff -Nurp ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.cpp kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.cpp --- ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.cpp 2005-05-18 15:23:36.000000000 +0600 +++ kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.cpp 2005-05-18 15:25:24.000000000 +0600 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include #include "chatmessagepart.h" +#include "chatmemberslistwidget.h" #include "chattexteditpart.h" #include "chatview.h" #include "../kopeteapplication.h" @@ -163,6 +165,12 @@ KopeteChatWindow *KopeteChatWindow::wind return myWindow; } +/** + * + * @param parent + * @param name + * @return + */ KopeteChatWindow::KopeteChatWindow( QWidget *parent, const char* name ) : KParts::MainWindow( parent, name ) { @@ -215,6 +223,11 @@ KopeteChatWindow::KopeteChatWindow( QWid KGlobal::config()->setGroup( QString::fromLatin1("ChatWindowSettings") ); m_alwaysShowTabs = KGlobal::config()->readBoolEntry( QString::fromLatin1("AlwaysShowTabs"), false ); + kdDebug(14010)<<"creating toolbar"<ref(); } @@ -802,6 +815,11 @@ void KopeteChatWindow::setActiveView( QW { disconnect( m_activeView, SIGNAL( canSendChanged(bool) ), this, SLOT( slotUpdateSendEnabled() ) ); guiFactory()->removeClient(m_activeView->msgManager()); + disconnect(m_encoding,SIGNAL(activated( const QString&)), + m_activeView->messagePart(),SLOT(slotConvert( const QString&))); + disconnect(m_encoding,SIGNAL(activated( const QString&)), + this,SLOT(slotEncodingSelected( const QString&))); + } guiFactory()->addClient(view->msgManager()); @@ -812,11 +830,43 @@ void KopeteChatWindow::setActiveView( QW m_activeView = view; + + if( !chatViewList.contains( view ) ) attachChatView( view ); connect( m_activeView, SIGNAL( canSendChanged(bool) ), this, SLOT( slotUpdateSendEnabled() ) ); + Kopete::ContactPtrList cList; + cList=m_activeView->membersList()->session()->members(); + Kopete::Contact* ct; + ct=cList.first(); + QString uid; + if(ct) + { + KConfig* cf=KGlobal::config(); + uid=ct->contactId(); + QString gr=cf->group(); + cf->setGroup("Encodings"); + QString enc=cf->readEntry(uid,"Unicode"); + cf->setGroup(gr); + m_activeView->messagePart()->slotConvert(enc); + int i; + for(i=0;imaxCount();i++) + { + if(m_encoding->text(i)==enc) + { + m_encoding->setCurrentItem(i); + break; + } + } + } + + connect(m_encoding,SIGNAL(activated( const QString&)), + m_activeView->messagePart(),SLOT(slotConvert( const QString&))); + connect(m_encoding,SIGNAL(activated( const QString&)), + this,SLOT(slotEncodingSelected( const QString&))); + //Tell it it is active m_activeView->setActive( true ); @@ -1120,6 +1170,9 @@ void KopeteChatWindow::slotConfKeys() dlg.configure(); } +/** + * + */ void KopeteChatWindow::slotConfToolbar() { saveMainWindowSettings(KGlobal::config(), QString::fromLatin1( "KopeteChatWindow" )); @@ -1142,3 +1195,72 @@ void KopeteChatWindow::slotConfToolbar() // vim: set noet ts=4 sts=4 sw=4: + + +void KopeteChatWindow::initEncodings() +{ + QStringList lst=QStringList::split('\n', +"Unicode\n\ +Big5\n\ +Big5-HKSCS\n\ +eucJP\n\ +eucKR\n\ +GB2312\n\ +GBK\n\ +GB18030\n\ +JIS7\n\ +Shift-JIS\n\ +TSCII\n\ +KOI8-R\n\ +KOI8-U\n\ +ISO8859-1\n\ +ISO8859-2\n\ +ISO8859-3\n\ +ISO8859-4\n\ +ISO8859-5\n\ +ISO8859-6\n\ +ISO8859-7\n\ +ISO8859-8\n\ +ISO8859-8-i\n\ +ISO8859-9\n\ +ISO8859-10\n\ +ISO8859-13\n\ +ISO8859-14\n\ +ISO8859-15\n\ +IBM 850\n\ +IBM 866\n\ +CP874\n\ +CP1250\n\ +CP1251\n\ +CP1252\n\ +CP1253\n\ +CP1254\n\ +CP1255\n\ +CP1256\n\ +CP1257\n\ +CP1258\n\ +Apple Roman\n\ +TIS-620"); + m_encoding->insertStringList(lst); +} + + +void KopeteChatWindow::slotEncodingSelected(const QString& string) +{ + if(!m_activeView) + return; + Kopete::ContactPtrList cList; + cList=m_activeView->membersList()->session()->members(); + Kopete::Contact* ct; + ct=cList.first(); + QString uid; + if(ct) + { + KConfig* cf=KGlobal::config(); + uid=ct->contactId(); + QString gr=cf->group(); + cf->setGroup("Encodings"); + cf->writeEntry(uid,string); + cf->setGroup(gr); + } +} diff -Nurp ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.cpp.orig kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.cpp.orig --- ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.cpp.orig 1970-01-01 06:00:00.000000000 +0600 +++ kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.cpp.orig 2005-05-18 15:22:07.000000000 +0600 @@ -0,0 +1,1144 @@ +/* + kopetechatwindow.cpp - Chat Window + + Copyright (c) 2002-2005 by Olivier Goffart + Copyright (c) 2003-2004 by Richard Smith + Copyright (C) 2002 by James Grant + Copyright (c) 2002 by Stefan Gehn + Copyright (c) 2002-2004 by Martijn Klingens + + Kopete (c) 2002-2005 by the Kopete developers + + ************************************************************************* + * * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chatmessagepart.h" +#include "chattexteditpart.h" +#include "chatview.h" +#include "../kopeteapplication.h" +#include "kopetechatwindow.h" +#include "kopeteemoticonaction.h" +#include "kopetegroup.h" +#include "kopetemessagemanager.h" +#include "kopetemetacontact.h" +#include "kopetepluginmanager.h" +#include "kopeteprefs.h" +#include "kopeteprotocol.h" +#include "kopetestdaction.h" +#include "kopeteviewmanager.h" + +#include +#include + +typedef QMap AccountMap; +typedef QMap GroupMap; +typedef QMap MetaContactMap; +typedef QPtrList WindowList; + +namespace +{ + AccountMap accountMap; + GroupMap groupMap; + MetaContactMap mcMap; + WindowList windows; +} + +KopeteChatWindow *KopeteChatWindow::window( Kopete::ChatSession *manager ) +{ + bool windowCreated = false; + KopeteChatWindow *myWindow; + + //Take the first and the first? What else? + Kopete::Group *group = 0L; + Kopete::ContactPtrList members = manager->members(); + Kopete::MetaContact *metaContact = members.first()->metaContact(); + + if ( metaContact ) + { + Kopete::GroupList gList = metaContact->groups(); + group = gList.first(); + } + + switch( KopetePrefs::prefs()->chatWindowPolicy() ) + { + case GROUP_BY_ACCOUNT: //Open chats from the same protocol in the same window + if( accountMap.contains( manager->account() ) ) + myWindow = accountMap[ manager->account() ]; + else + windowCreated = true; + break; + + case GROUP_BY_GROUP: //Open chats from the same group in the same window + if( group && groupMap.contains( group ) ) + myWindow = groupMap[ group ]; + else + windowCreated = true; + break; + + case GROUP_BY_METACONTACT: //Open chats from the same metacontact in the same window + if( mcMap.contains( metaContact ) ) + myWindow = mcMap[ metaContact ]; + else + windowCreated = true; + break; + + case GROUP_ALL: //Open all chats in the same window + if( windows.isEmpty() ) + windowCreated = true; + else + { + //Here we are finding the window with the most tabs and + //putting it there. Need this for the cases where config changes + //midstream + + int viewCount = -1; + for ( KopeteChatWindow *thisWindow = windows.first(); thisWindow; thisWindow = windows.next() ) + { + if( thisWindow->chatViewCount() > viewCount ) + { + myWindow = thisWindow; + viewCount = thisWindow->chatViewCount(); + } + } + } + break; + + case NEW_WINDOW: //Open every chat in a new window + default: + windowCreated = true; + break; + } + + if ( windowCreated ) + { + myWindow = new KopeteChatWindow(); + + if ( !accountMap.contains( manager->account() ) ) + accountMap.insert( manager->account(), myWindow ); + + if ( !mcMap.contains( metaContact ) ) + mcMap.insert( metaContact, myWindow ); + + if ( group && !groupMap.contains( group ) ) + groupMap.insert( group, myWindow ); + } + +// kdDebug( 14010 ) << k_funcinfo << "Open Windows: " << windows.count() << endl; + + return myWindow; +} + +KopeteChatWindow::KopeteChatWindow( QWidget *parent, const char* name ) + : KParts::MainWindow( parent, name ) +{ + m_activeView = 0L; + m_popupView = 0L; + backgroundFile = 0L; + updateBg = true; + m_tabBar = 0L; + + initActions(); + + QVBox *vBox = new QVBox( this ); + vBox->setLineWidth( 0 ); + vBox->setSpacing( 0 ); + vBox->setFrameStyle( QFrame::NoFrame ); + // set default window size. This could be removed by fixing the size hints of the contents + resize( 500, 500 ); + setCentralWidget( vBox ); + + mainArea = new QFrame( vBox ); + mainArea->setLineWidth( 0 ); + mainArea->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); + mainLayout = new QVBoxLayout( mainArea ); + + if ( KopetePrefs::prefs()->chatWShowSend() ) + { + //Send Button + m_button_send = new KPushButton( i18n("Send"), statusBar() ); + m_button_send->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) ); + m_button_send->setEnabled( false ); + m_button_send->setFont( statusBar()->font() ); + m_button_send->setFixedHeight( statusBar()->sizeHint().height() ); + connect( m_button_send, SIGNAL( clicked() ), this, SLOT( slotSendMessage() ) ); + statusBar()->addWidget( m_button_send, 0, true ); + } + else + m_button_send = 0L; + + m_status_text = new KSqueezedTextLabel( i18n("Ready."), statusBar(), "m_status_text" ); + m_status_text->setAlignment( AlignLeft | AlignVCenter ); + m_status_text->setFont( statusBar()->font() ); + m_status_text->setFixedHeight( statusBar()->sizeHint().height() ); + statusBar()->addWidget( m_status_text, 1 ); + + readOptions(); + setWFlags( Qt::WDestructiveClose ); + + windows.append( this ); + windowListChanged(); + + KGlobal::config()->setGroup( QString::fromLatin1("ChatWindowSettings") ); + m_alwaysShowTabs = KGlobal::config()->readBoolEntry( QString::fromLatin1("AlwaysShowTabs"), false ); +// kdDebug( 14010 ) << k_funcinfo << "Open Windows: " << windows.count() << endl; + kapp->ref(); +} + +KopeteChatWindow::~KopeteChatWindow() +{ + // kdDebug( 14010 ) << k_funcinfo << endl; + + emit( closing( this ) ); + + for( AccountMap::Iterator it = accountMap.begin(); it != accountMap.end(); ) + { + AccountMap::Iterator mayDeleteIt = it; + ++it; + if( mayDeleteIt.data() == this ) + accountMap.remove( mayDeleteIt.key() ); + } + + for( GroupMap::Iterator it = groupMap.begin(); it != groupMap.end(); ) + { + GroupMap::Iterator mayDeleteIt = it; + ++it; + if( mayDeleteIt.data() == this ) + groupMap.remove( mayDeleteIt.key() ); + } + + for( MetaContactMap::Iterator it = mcMap.begin(); it != mcMap.end(); ) + { + MetaContactMap::Iterator mayDeleteIt = it; + ++it; + if( mayDeleteIt.data() == this ) + mcMap.remove( mayDeleteIt.key() ); + } + + windows.remove( this ); + windowListChanged(); + +// kdDebug( 14010 ) << "Open Windows: " << windows.count() << endl; + + saveOptions(); + + if( backgroundFile ) + { + backgroundFile->close(); + backgroundFile->unlink(); + delete backgroundFile; + } + + delete anim; + kapp->deref(); +} + +void KopeteChatWindow::windowListChanged() +{ + // update all windows' Move Tab to Window action + for ( QPtrListIterator it( windows ); *it; ++it ) + (*it)->checkDetachEnable(); +} + +void KopeteChatWindow::slotNickComplete() +{ + if( m_activeView ) + m_activeView->nickComplete(); +} + +void KopeteChatWindow::slotTabContextMenu( QWidget *tab, const QPoint &pos ) +{ + m_popupView = static_cast( tab ); + + KPopupMenu *popup = new KPopupMenu; + popup->insertTitle( KStringHandler::rsqueeze( m_popupView->caption() ) ); + + actionContactMenu->plug( popup ); + popup->insertSeparator(); + actionTabPlacementMenu->plug( popup ); + tabDetach->plug( popup ); + actionDetachMenu->plug( popup ); + tabClose->plug( popup ); + popup->exec( pos ); + + delete popup; + m_popupView = 0; +} + +ChatView *KopeteChatWindow::activeView() +{ + return m_activeView; +} + +void KopeteChatWindow::initActions(void) +{ + KActionCollection *coll = actionCollection(); + + createStandardStatusBarAction(); + + chatSend = new KAction( i18n( "&Send Message" ), QString::fromLatin1( "mail_send" ), 0, + this, SLOT( slotSendMessage() ), coll, "chat_send" ); + //Default to 'Return' for sending messages + chatSend->setShortcut( QKeySequence(Key_Return) ); + chatSend->setEnabled( false ); + + KStdAction::save ( this, SLOT(slotChatSave()), coll ); + KStdAction::print ( this, SLOT(slotChatPrint()), coll ); + KStdAction::quit ( this, SLOT(close()), coll ); + + tabClose = KStdAction::close ( this, SLOT(slotChatClosed()), coll, "tabs_close" ); + + tabRight=new KAction( i18n( "&Activate Next Tab" ), 0, KStdAccel::tabNext(), + this, SLOT( slotNextTab() ), coll, "tabs_right" ); + tabLeft=new KAction( i18n( "&Activate Previous Tab" ), 0, KStdAccel::tabPrev(), + this, SLOT( slotPreviousTab() ), coll, "tabs_left" ); + tabLeft->setEnabled( false ); + tabRight->setEnabled( false ); + + nickComplete = new KAction( i18n( "Nic&k Completion" ), QString::null, 0, this, SLOT( slotNickComplete() ), coll , "nick_compete"); + nickComplete->setShortcut( QKeySequence( Key_Tab ) ); + + tabDetach = new KAction( i18n( "&Detach Chat" ), QString::fromLatin1( "tab_breakoff" ), 0, + this, SLOT( slotDetachChat() ), coll, "tabs_detach" ); + tabDetach->setEnabled( false ); + + actionDetachMenu = new KActionMenu( i18n( "&Move Tab to Window" ), QString::fromLatin1( "tab_breakoff" ), coll, "tabs_detachmove" ); + actionDetachMenu->setDelayed( false ); + + connect ( actionDetachMenu->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(slotPrepareDetachMenu()) ); + connect ( actionDetachMenu->popupMenu(), SIGNAL(activated(int)), this, SLOT(slotDetachChat(int)) ); + + actionTabPlacementMenu = new KActionMenu( i18n( "&Tab Placement" ), coll, "tabs_placement" ); + connect ( actionTabPlacementMenu->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(slotPreparePlacementMenu()) ); + connect ( actionTabPlacementMenu->popupMenu(), SIGNAL(activated(int)), this, SLOT(slotPlaceTabs(int)) ); + + tabDetach->setShortcut( QKeySequence(CTRL + SHIFT + Key_B) ); + + KStdAction::cut( this, SLOT(slotCut()), coll); + KStdAction::copy( this, SLOT(slotCopy()), coll); + KStdAction::paste( this, SLOT(slotPaste()), coll); + + new KAction( i18n( "Set Default &Font..." ), QString::fromLatin1( "charset" ), 0, this, SLOT( slotSetFont() ), coll, "format_font" ); + new KAction( i18n( "Set Default Text &Color..." ), QString::fromLatin1( "pencil" ), 0, this, SLOT( slotSetFgColor() ), coll, "format_fgcolor" ); + new KAction( i18n( "Set &Background Color..." ), QString::fromLatin1( "fill" ), 0, this, SLOT( slotSetBgColor() ), coll, "format_bgcolor" ); + + historyUp = new KAction( i18n( "Previous History" ), QString::null, 0, + this, SLOT( slotHistoryUp() ), coll, "history_up" ); + historyUp->setShortcut( QKeySequence(CTRL + Key_Up) ); + + historyDown = new KAction( i18n( "Next History" ), QString::null, 0, + this, SLOT( slotHistoryDown() ), coll, "history_down" ); + historyDown->setShortcut( QKeySequence(CTRL + Key_Down) ); + + KStdAction::prior( this, SLOT( slotPageUp() ), coll, "scroll_up" ); + KStdAction::next( this, SLOT( slotPageDown() ), coll, "scroll_down" ); + + KStdAction::showMenubar( this, SLOT(slotViewMenuBar()), coll ); + + membersLeft = new KToggleAction( i18n( "Place to Left of Chat Area" ), QString::null, 0, + this, SLOT( slotViewMembersLeft() ), coll, "options_membersleft" ); + membersRight = new KToggleAction( i18n( "Place to Right of Chat Area" ), QString::null, 0, + this, SLOT( slotViewMembersRight() ), coll, "options_membersright" ); + toggleMembers = new KToggleAction( i18n( "Show" ), QString::null, 0, + this, SLOT( slotToggleViewMembers() ), coll, "options_togglemembers" ); +#if KDE_IS_VERSION(3,2,90) + toggleMembers->setCheckedState(i18n("Hide")); +#endif + + actionSmileyMenu = new KopeteEmoticonAction( coll, "format_smiley" ); + actionSmileyMenu->setDelayed( false ); + connect(actionSmileyMenu, SIGNAL(activated(const QString &)), this, SLOT(slotSmileyActivated(const QString &))); + + actionContactMenu = new KActionMenu(i18n("Co&ntacts"), coll, "contacts_menu" ); + actionContactMenu->setDelayed( false ); + connect ( actionContactMenu->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(slotPrepareContactMenu()) ); + + // add configure key bindings menu item +#if KDE_IS_VERSION(3, 2, 90) + KStdAction::keyBindings( guiFactory(), SLOT( configureShortcuts() ), coll ); +#else // when we will drop the KDE 3.2 compatibility, do not forget to remove slotConfKeys + KStdAction::keyBindings( this, SLOT( slotConfKeys() ), coll ); + #endif + + + KStdAction::configureToolbars(this, SLOT(slotConfToolbar()), coll); + KopeteStdAction::preferences( coll , "settings_prefs" ); + + //The Sending movie + normalIcon = QPixmap( BarIcon( QString::fromLatin1( "kopete" ) ) ); + animIcon = KGlobal::iconLoader()->loadMovie( QString::fromLatin1( "newmessage" ), KIcon::Toolbar); + + // Pause the animation because otherwise it's running even when we're not + // showing it. This eats resources, and also triggers a pixmap leak in + // QMovie in at least Qt 3.1, Qt 3.2 and the current Qt 3.3 beta + if( !animIcon.isNull() ) //and another QT bug: it crash if we pause a null movie + animIcon.pause(); + + // we can't set the tool bar as parent, if we do, it will be deleted when we configure toolbars + anim = new QLabel( QString::null, 0L ,"kde toolbar widget" ); + anim->setMargin(5); + anim->setPixmap( normalIcon ); + + + new KWidgetAction( anim , i18n("Toolbar Animation") , 0, 0 , 0 , coll , "toolbar_animation"); + + //toolBar()->insertWidget( 99, anim->width(), anim ); + //toolBar()->alignItemRight( 99 ); + setStandardToolBarMenuEnabled( true ); + + setXMLFile( QString::fromLatin1( "kopetechatwindow.rc" ) ); + createGUI( 0L ); + +#if !KDE_IS_VERSION( 3, 1, 90 ) + mStatusbarAction->setChecked(!statusBar()->isHidden()); +#endif +} + +const QString KopeteChatWindow::fileContents( const QString &path ) const +{ + QString contents; + QFile file( path ); + if ( file.open( IO_ReadOnly ) ) + { + QTextStream stream( &file ); + contents = stream.read(); + file.close(); + } + + return contents; +} + +void KopeteChatWindow::slotStopAnimation( ChatView* view ) +{ + if( view == m_activeView ) + anim->setPixmap( normalIcon ); +} + +void KopeteChatWindow::slotUpdateSendEnabled() +{ + if ( !m_activeView ) return; + + bool enabled = m_activeView->canSend(); + chatSend->setEnabled( enabled ); + if(m_button_send) + m_button_send->setEnabled( enabled ); +} + +void KopeteChatWindow::updateMembersActions() +{ + if( m_activeView ) + { + const KDockWidget::DockPosition pos = m_activeView->membersListPosition(); + bool visibleMembers = m_activeView->visibleMembersList(); + membersLeft->setChecked( pos == KDockWidget::DockLeft ); + membersLeft->setEnabled( visibleMembers ); + membersRight->setChecked( pos == KDockWidget::DockRight ); + membersRight->setEnabled( visibleMembers ); + toggleMembers->setChecked( visibleMembers ); + } +} + +void KopeteChatWindow::slotViewMembersLeft() +{ + m_activeView->placeMembersList( KDockWidget::DockLeft ); + updateMembersActions(); +} + +void KopeteChatWindow::slotViewMembersRight() +{ + m_activeView->placeMembersList( KDockWidget::DockRight ); + updateMembersActions(); +} + +void KopeteChatWindow::slotToggleViewMembers() +{ + m_activeView->toggleMembersVisibility(); + updateMembersActions(); +} + +void KopeteChatWindow::slotHistoryUp() +{ + if( m_activeView ) + m_activeView->editPart()->historyUp(); +} + +void KopeteChatWindow::slotHistoryDown() +{ + if( m_activeView ) + m_activeView->editPart()->historyDown(); +} + +void KopeteChatWindow::slotPageUp() +{ + if( m_activeView ) + m_activeView->messagePart()->pageUp(); +} + +void KopeteChatWindow::slotPageDown() +{ + if( m_activeView ) + m_activeView->messagePart()->pageDown(); +} + +void KopeteChatWindow::slotCut() +{ + m_activeView->cut(); +} + +void KopeteChatWindow::slotCopy() +{ + m_activeView->copy(); +} + +void KopeteChatWindow::slotPaste() +{ + m_activeView->paste(); +} + + +void KopeteChatWindow::slotSetFont() +{ + m_activeView->setFont(); +} + +void KopeteChatWindow::slotSetFgColor() +{ + m_activeView->setFgColor(); +} + +void KopeteChatWindow::slotSetBgColor() +{ + m_activeView->setBgColor(); +} + +void KopeteChatWindow::setStatus(const QString &text) +{ + m_status_text->setText(text); +} + +void KopeteChatWindow::createTabBar() +{ + if( !m_tabBar ) + { + KGlobal::config()->setGroup( QString::fromLatin1("ChatWindowSettings") ); + + m_tabBar = new KTabWidget( mainArea ); + m_tabBar->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); + m_tabBar->setHoverCloseButton(KGlobal::config()->readBoolEntry( QString::fromLatin1("HoverClose"), false )); + m_tabBar->setTabReorderingEnabled(true); + m_tabBar->setAutomaticResizeTabs(true); + connect( m_tabBar, SIGNAL( closeRequest( QWidget* )), this, SLOT( slotCloseChat( QWidget* ) ) ); + + QToolButton* m_rightWidget = new QToolButton( m_tabBar ); + connect( m_rightWidget, SIGNAL( clicked() ), this, SLOT( slotChatClosed() ) ); + m_rightWidget->setIconSet( SmallIcon( "tab_remove" ) ); + m_rightWidget->adjustSize(); + QToolTip::add( m_rightWidget, i18n("Close the current tab")); + m_tabBar->setCornerWidget( m_rightWidget, QWidget::TopRight ); + + mainLayout->addWidget( m_tabBar ); + m_tabBar->show(); + connect ( m_tabBar, SIGNAL(currentChanged(QWidget *)), this, SLOT(setActiveView(QWidget *)) ); + connect ( m_tabBar, SIGNAL(contextMenu(QWidget *, const QPoint & )), this, SLOT(slotTabContextMenu( QWidget *, const QPoint & )) ); + + for( ChatView *view = chatViewList.first(); view; view = chatViewList.next() ) + addTab( view ); + + if( m_activeView ) + m_tabBar->showPage( m_activeView ); + else + setActiveView( chatViewList.first() ); + + int tabPosition = KGlobal::config()->readNumEntry( QString::fromLatin1("Tab Placement") , 0 ); + slotPlaceTabs( tabPosition ); + } +} + +void KopeteChatWindow::slotCloseChat( QWidget *chatView ) +{ + static_cast( chatView )->closeView(); +} + +void KopeteChatWindow::addTab( ChatView *view ) +{ + QPtrList chatMembers=view->msgManager()->members(); + Kopete::Contact *c=0L; + for ( Kopete::Contact *contact = chatMembers.first(); contact; contact = chatMembers.next() ) + { + if(!c || c->onlineStatus() < contact->onlineStatus()) + c=contact; + } + QPixmap pluginIcon = c ? view->msgManager()->contactOnlineStatus( c ).iconFor( c) : SmallIcon( view->msgManager()->protocol()->pluginIcon() ); + + view->reparent( m_tabBar, 0, QPoint(), true ); + m_tabBar->addTab( view, pluginIcon, QString::null ); + view->setTabBar( m_tabBar ); + if( view == m_activeView ) + view->show(); + else + view->hide(); + view->setCaption( view->caption(), false ); +} + +void KopeteChatWindow::setPrimaryChatView( ChatView *view ) +{ + //TODO figure out what else we have to save here besides the font + //reparent clears a lot of stuff out + QFont savedFont = view->font(); + view->reparent( mainArea, 0, QPoint(), true ); + view->setTabBar( 0L ); + view->setFont( savedFont ); + view->show(); + + mainLayout->addWidget( view ); + setActiveView( view ); +} + +void KopeteChatWindow::deleteTabBar() +{ + if( m_tabBar ) + { + disconnect ( m_tabBar, SIGNAL(currentChanged(QWidget *)), this, SLOT(setActiveView(QWidget *)) ); + disconnect ( m_tabBar, SIGNAL(contextMenu(QWidget *, const QPoint & )), this, SLOT(slotTabContextMenu( QWidget *, const QPoint & )) ); + + if( !chatViewList.isEmpty() ) + setPrimaryChatView( chatViewList.first() ); + + m_tabBar->deleteLater(); + m_tabBar = 0L; + } +} + +void KopeteChatWindow::attachChatView( ChatView* newView ) +{ + chatViewList.append( newView ); + + if ( !m_alwaysShowTabs && chatViewList.count() == 1 ) + setPrimaryChatView( newView ); + else + { + if ( !m_tabBar ) + createTabBar(); + else + addTab( newView ); + newView->setActive( false ); + } + + newView->setMainWindow( this ); + newView->editWidget()->installEventFilter( this ); + + KCursor::setAutoHideCursor( newView->editWidget(), true, true ); + connect( newView, SIGNAL(captionChanged( bool)), this, SLOT(slotSetCaption(bool)) ); + connect( newView, SIGNAL(messageSuccess( ChatView* )), this, SLOT(slotStopAnimation( ChatView* )) ); + connect( newView, SIGNAL(updateStatusIcon( const ChatView* )), this, SLOT(slotUpdateCaptionIcons( const ChatView* )) ); + + checkDetachEnable(); +} + +void KopeteChatWindow::checkDetachEnable() +{ + bool haveTabs = (chatViewList.count() > 1); + tabDetach->setEnabled( haveTabs ); + tabLeft->setEnabled( haveTabs ); + tabRight->setEnabled( haveTabs ); + actionTabPlacementMenu->setEnabled( m_tabBar != 0 ); + + bool otherWindows = (windows.count() > 1); + actionDetachMenu->setEnabled( otherWindows ); +} + +void KopeteChatWindow::detachChatView( ChatView *view ) +{ + if( !chatViewList.removeRef( view ) ) + return; + + disconnect( view, SIGNAL(captionChanged( bool)), this, SLOT(slotSetCaption(bool)) ); + disconnect( view, SIGNAL(updateStatusIcon( const ChatView *)), this, SLOT(slotUpdateCaptionIcons( const ChatView * )) ); + view->editWidget()->removeEventFilter( this ); + + if( m_tabBar ) + { + int curPage = m_tabBar->currentPageIndex(); + QWidget *page = m_tabBar->page( curPage ); + + // if the current view is to be detached, switch to a different one + if( page == view ) + { + if( curPage > 0 ) + m_tabBar->setCurrentPage( curPage - 1 ); + else + m_tabBar->setCurrentPage( curPage + 1 ); + } + + view->setTabBar( 0L ); + m_tabBar->removePage( view ); + + if( m_tabBar->currentPage() ) + setActiveView( static_cast(m_tabBar->currentPage()) ); + } + + if( chatViewList.isEmpty() ) + close(); + else if( !m_alwaysShowTabs && chatViewList.count() == 1) + deleteTabBar(); + + checkDetachEnable(); +} + +void KopeteChatWindow::slotDetachChat( int newWindowIndex ) +{ + KopeteChatWindow *newWindow = 0L; + ChatView *detachedView; + + if( m_popupView ) + detachedView = m_popupView; + else + detachedView = m_activeView; + + if( !detachedView ) + return; + + //if we don't do this, we might crash + createGUI(0L); + guiFactory()->removeClient(detachedView->msgManager()); + + if( newWindowIndex == -1 ) + newWindow = new KopeteChatWindow(); + else + newWindow = windows.at( newWindowIndex ); + + newWindow->show(); + newWindow->raise(); + + detachChatView( detachedView ); + newWindow->attachChatView( detachedView ); +} + +void KopeteChatWindow::slotPreviousTab() +{ + int curPage = m_tabBar->currentPageIndex(); + if( curPage > 0 ) + m_tabBar->setCurrentPage( curPage - 1 ); + else + m_tabBar->setCurrentPage( m_tabBar->count() - 1 ); +} + +void KopeteChatWindow::slotNextTab() +{ + int curPage = m_tabBar->currentPageIndex(); + if( curPage == ( m_tabBar->count() - 1 ) ) + m_tabBar->setCurrentPage( 0 ); + else + m_tabBar->setCurrentPage( curPage + 1 ); +} + +void KopeteChatWindow::slotSetCaption( bool active ) +{ + if( active && m_activeView ) + { + setCaption( m_activeView->caption(), false ); + } +} + +void KopeteChatWindow::updateBackground( const QPixmap &pm ) +{ + if( updateBg ) + { + updateBg = false; + if( backgroundFile != 0L ) + { + backgroundFile->close(); + backgroundFile->unlink(); + } + + backgroundFile = new KTempFile( QString::null, QString::fromLatin1( ".bmp" ) ); + pm.save( backgroundFile->name(), "BMP" ); + QTimer::singleShot( 100, this, SLOT( slotEnableUpdateBg() ) ); + } +} + +void KopeteChatWindow::setActiveView( QWidget *widget ) +{ + ChatView *view = static_cast(widget); + + if( m_activeView == view ) + return; + + if(m_activeView) + { + disconnect( m_activeView, SIGNAL( canSendChanged(bool) ), this, SLOT( slotUpdateSendEnabled() ) ); + guiFactory()->removeClient(m_activeView->msgManager()); + } + + guiFactory()->addClient(view->msgManager()); + createGUI( view->part() ); + + if( m_activeView ) + m_activeView->setActive( false ); + + m_activeView = view; + + if( !chatViewList.contains( view ) ) + attachChatView( view ); + + connect( m_activeView, SIGNAL( canSendChanged(bool) ), this, SLOT( slotUpdateSendEnabled() ) ); + + //Tell it it is active + m_activeView->setActive( true ); + + //Update icons to match + slotUpdateCaptionIcons( m_activeView ); + + //Update chat members actions + updateMembersActions(); + + if ( m_activeView->sendInProgress() && !animIcon.isNull() ) + { + anim->setMovie( animIcon ); + animIcon.unpause(); + } + else + { + anim->setPixmap( normalIcon ); + if( !animIcon.isNull() ) + animIcon.pause(); + } + + if ( m_alwaysShowTabs || chatViewList.count() > 1 ) + { + if( !m_tabBar ) + createTabBar(); + + m_tabBar->showPage( m_activeView ); + } + + setCaption( m_activeView->caption() ); + setStatus( m_activeView->statusText() ); + m_activeView->setFocus(); + + slotUpdateSendEnabled(); +} + +void KopeteChatWindow::slotUpdateCaptionIcons( const ChatView *view ) +{ + if(!view||!m_activeView||view!=m_activeView ) + return; //(pas de charité) + QPtrList chatMembers=view->msgManager()->members(); + Kopete::Contact *c=0L; + for ( Kopete::Contact *contact = chatMembers.first(); contact; contact = chatMembers.next() ) + { + if(!c || c->onlineStatus() < contact->onlineStatus()) + c=contact; + } + QPixmap icon16 = c ? view->msgManager()->contactOnlineStatus( c ).iconFor( c , 16) : SmallIcon( view->msgManager()->protocol()->pluginIcon() ); + QPixmap icon32 = c ? view->msgManager()->contactOnlineStatus( c ).iconFor( c , 32) : SmallIcon( view->msgManager()->protocol()->pluginIcon() ); + + KWin::setIcons( winId(), icon32, icon16 ); +} + +void KopeteChatWindow::slotChatClosed() +{ + if( m_popupView ) + m_popupView->closeView(); + else + m_activeView->closeView(); +} + +void KopeteChatWindow::slotPrepareDetachMenu(void) +{ + QPopupMenu *detachMenu = actionDetachMenu->popupMenu(); + detachMenu->clear(); + + for ( unsigned id=0; id < windows.count(); id++ ) + { + KopeteChatWindow *win = windows.at( id ); + if( win != this ) + detachMenu->insertItem( win->caption(), id ); + } +} + +void KopeteChatWindow::slotSendMessage() +{ + if ( m_activeView && m_activeView->canSend() ) + { + if( !animIcon.isNull() ) + { + anim->setMovie( animIcon ); + animIcon.unpause(); + } + m_activeView->sendMessage(); + } +} + +void KopeteChatWindow::slotPrepareContactMenu(void) +{ + QPopupMenu *contactsMenu = actionContactMenu->popupMenu(); + contactsMenu->clear(); + + Kopete::Contact *contact; + Kopete::ContactPtrList m_them; + + if( m_popupView ) + m_them = m_popupView->msgManager()->members(); + else + m_them = m_activeView->msgManager()->members(); + + //TODO: don't display a menu with one contact in it, display that + // contact's menu instead. Will require changing text and icon of + // 'Contacts' action, or something cleverer. + uint contactCount = 0; + + for ( contact = m_them.first(); contact; contact = m_them.next() ) + { + KPopupMenu *p = contact->popupMenu(); + connect ( actionContactMenu->popupMenu(), SIGNAL(aboutToHide()), + p, SLOT(deleteLater() ) ); + + if( contact->metaContact() ) + contactsMenu->insertItem( contact->onlineStatus().iconFor( contact ) , contact->metaContact()->displayName(), p ); + else + contactsMenu->insertItem( contact->onlineStatus().iconFor( contact ) , contact->contactId(), p ); + + //FIXME: This number should be a config option + if( ++contactCount == 15 && contact != m_them.getLast() ) + { + KActionMenu *moreMenu = new KActionMenu( i18n("More..."), + QString::fromLatin1("folder_open"), contactsMenu ); + connect ( actionContactMenu->popupMenu(), SIGNAL(aboutToHide()), + moreMenu, SLOT(deleteLater() ) ); + moreMenu->plug( contactsMenu ); + contactsMenu = moreMenu->popupMenu(); + contactCount = 0; + } + } +} + +void KopeteChatWindow::slotPreparePlacementMenu() +{ + QPopupMenu *placementMenu = actionTabPlacementMenu->popupMenu(); + placementMenu->clear(); + + placementMenu->insertItem( i18n("Top"), 0 ); + placementMenu->insertItem( i18n("Bottom"), 1 ); +} + +void KopeteChatWindow::slotPlaceTabs( int placement ) +{ + if( m_tabBar ) + { + + if( placement == 0 ) + m_tabBar->setTabPosition( QTabWidget::Top ); + else + m_tabBar->setTabPosition( QTabWidget::Bottom ); + + saveOptions(); + } +} + +void KopeteChatWindow::readOptions() +{ + // load and apply config file settings affecting the appearance of the UI +// kdDebug(14010) << k_funcinfo << endl; + KConfig *config = KGlobal::config(); + applyMainWindowSettings( config, QString::fromLatin1( "KopeteChatWindow" ) ); + config->setGroup( QString::fromLatin1("ChatWindowSettings") ); +} + +void KopeteChatWindow::saveOptions() +{ +// kdDebug(14010) << k_funcinfo << endl; + + KConfig *config = KGlobal::config(); + + // saves menubar,toolbar and statusbar setting + saveMainWindowSettings( config, QString::fromLatin1( "KopeteChatWindow" ) ); + config->setGroup( QString::fromLatin1("ChatWindowSettings") ); + if( m_tabBar ) + config->writeEntry ( QString::fromLatin1("Tab Placement"), m_tabBar->tabPosition() ); + + config->sync(); +} + +void KopeteChatWindow::slotChatSave() +{ +// kdDebug(14010) << "KopeteChatWindow::slotChatSave()" << endl; + if( isActiveWindow() && m_activeView ) + m_activeView->messagePart()->save(); +} + +void KopeteChatWindow::windowActivationChange( bool ) +{ + if( isActiveWindow() && m_activeView ) + m_activeView->setActive( true ); +} + +void KopeteChatWindow::slotChatPrint() +{ + m_activeView->messagePart()->print(); +} + +void KopeteChatWindow::slotToggleStatusBar() +{ + if (statusBar()->isVisible()) + statusBar()->hide(); + else + statusBar()->show(); +} + +void KopeteChatWindow::slotViewMenuBar() +{ + if( !menuBar()->isHidden() ) + menuBar()->hide(); + else + menuBar()->show(); +} + +void KopeteChatWindow::slotSmileyActivated(const QString &sm) +{ + if ( !sm.isNull() ) + m_activeView->addText( sm ); +} + +bool KopeteChatWindow::queryClose() +{ + bool canClose = true; + +// kdDebug( 14010 ) << " Windows left open:" << endl; +// for( QPtrListIterator it( chatViewList ); it; ++it) +// kdDebug( 14010 ) << " " << *it << " (" << (*it)->caption() << ")" << endl; + + for( QPtrListIterator it( chatViewList ); it; ) + { + ChatView *view = *it; + // move out of the way before view is removed + ++it; + + // FIXME: This should only check if it *can* close + // and not start closing if the close can be aborted halfway, it would + // leave us with half the chats open and half of them closed. - Martijn + + // if the view is closed, it is removed from chatViewList for us + if ( !view->closeView() ) + { + kdDebug() << k_funcinfo << "Closing view failed!" << endl; + canClose = false; + } + } + return canClose; +} + +bool KopeteChatWindow::queryExit() +{ + KopeteApplication *app = static_cast( kapp ); + if ( app->sessionSaving() + || app->isShuttingDown() /* only set if KopeteApplication::quitKopete() or + KopeteApplication::commitData() called */ + || !KopetePrefs::prefs()->showTray() /* also close if our tray icon is hidden! */ + || !isShown() ) + { + Kopete::PluginManager::self()->shutdown(); + return true; + } + else + return false; +} + +void KopeteChatWindow::closeEvent( QCloseEvent * e ) +{ + // if there's a system tray applet and we are not shutting down then just do what needs to be done if a + // window is closed. + KopeteApplication *app = static_cast( kapp ); + if ( KopetePrefs::prefs()->showTray() && !app->isShuttingDown() && !app->sessionSaving() ) { + // BEGIN of code borrowed from KMainWindow::closeEvent + // Save settings if auto-save is enabled, and settings have changed + if ( settingsDirty() && autoSaveSettings() ) + saveAutoSaveSettings(); + + if ( queryClose() ) { + e->accept(); + } + // END of code borrowed from KMainWindow::closeEvent + } + else + KMainWindow::closeEvent( e ); +} + +void KopeteChatWindow::slotConfKeys() +{ + KKeyDialog dlg( false, this ); + dlg.insert( actionCollection() ); + if( m_activeView ) + { + dlg.insert(m_activeView->msgManager()->actionCollection() , i18n("Plugin Actions") ); + QPtrListIterator it( *m_activeView->msgManager()->childClients() ); + KXMLGUIClient *c = 0; + while( (c = it.current()) != 0 ) + { + dlg.insert( c->actionCollection() /*, i18n("Plugin Actions")*/ ); + ++it; + } + + if( m_activeView->part() ) + dlg.insert( m_activeView->part()->actionCollection(), m_activeView->part()->name() ); + } + + dlg.configure(); +} + +void KopeteChatWindow::slotConfToolbar() +{ + saveMainWindowSettings(KGlobal::config(), QString::fromLatin1( "KopeteChatWindow" )); + KEditToolbar *dlg = new KEditToolbar(factory(), this ); + if (dlg->exec()) + { + if( m_activeView ) + { + createGUI( m_activeView->part() ); + //guiFactory()->addClient(m_activeView->msgManager()); + } + else + createGUI( 0L ); + applyMainWindowSettings(KGlobal::config(), QString::fromLatin1( "KopeteChatWindow" )); + } + delete dlg; +} + +#include "kopetechatwindow.moc" + +// vim: set noet ts=4 sts=4 sw=4: + diff -Nurp ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.h kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.h --- ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.h 2005-05-18 15:23:36.000000000 +0600 +++ kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.h 2005-05-18 15:25:24.000000000 +0600 @@ -28,6 +28,7 @@ class KAction; class KToggleAction; class KActionMenu; class KTempFile; +class KComboBox; class QPixmap; class QTabWidget; class KSqueezedTextLabel; @@ -123,6 +124,7 @@ private: void addTab( ChatView* ); void setPrimaryChatView( ChatView* ); const QString fileContents( const QString &file ) const; + void initEncodings(); ChatView *m_activeView; ChatView *m_popupView; @@ -136,6 +138,7 @@ private: QLabel *anim; QMovie animIcon; QPixmap normalIcon; + KComboBox* m_encoding; KAction *chatSend; KAction *historyUp; @@ -217,6 +220,7 @@ private slots: void slotStopAnimation( ChatView* ); void slotNickComplete(); void slotCloseChat( QWidget* ); + void slotEncodingSelected(const QString& string); protected: virtual void closeEvent( QCloseEvent *e ); diff -Nurp ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.h.orig kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.h.orig --- ../work-orig/kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.h.orig 1970-01-01 06:00:00.000000000 +0600 +++ kopete-3.4.0/kopete/kopete/chatwindow/kopetechatwindow.h.orig 2005-05-18 15:22:07.000000000 +0600 @@ -0,0 +1,229 @@ +/* + kopetechatwindow.h - Chat Window + + Copyright (c) 2002 by Olivier Goffart + Copyright (c) 2004 by Martijn Klingens + + Kopete (c) 2002-2004 by the Kopete developers + + ************************************************************************* + * * + * 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 KOPETECHATWINDOW_H +#define KOPETECHATWINDOW_H + +#include +#include +#include "kopetecontact.h" +#include "kdeversion.h" + +class KAction; +class KToggleAction; +class KActionMenu; +class KTempFile; +class QPixmap; +class QTabWidget; +class KSqueezedTextLabel; +class KPushButton; +class QVBox; +class QVBoxLayout; +class QFrame; +class KTabWidget; +class QLabel; +class KopeteEmoticonAction; +class KopeteView; +class KSelectAction; +class ChatView; + +namespace Kopete +{ +class Message; +class ChatSession; +class Contact; +class Protocol; +typedef QPtrList ContactPtrList; +} + +class KopeteChatWindow : public KParts::MainWindow +{ + Q_OBJECT + + enum {NEW_WINDOW, GROUP_BY_ACCOUNT, GROUP_ALL, GROUP_BY_GROUP, GROUP_BY_METACONTACT}; + +public: + /** + * Find the appropriate window for a ChatView of the given protocol to + * dock into. If no such window exists, create one. + * @param protocol The protocol we are creating a view for + * @return A KopeteChatWindow suitable for docking a ChatView into. Guaranteed + * to be a valid pointer. + */ + static KopeteChatWindow *window( Kopete::ChatSession *manager ); + ~KopeteChatWindow(); + + /** + * Attach an unattached chatview to this window + * @param chat The chat view to attach + */ + void attachChatView( ChatView *chat ); + + /** + * Detach a chat view from this window + * @param chat The chat view to detach + */ + void detachChatView( ChatView *chat ); + + /** + * Returns the number of chat views attached to this window + */ + const int chatViewCount() { return chatViewList.count(); } + + /** + * Returns the chatview in the currently active tab, or the only chat view + * if chatViewCount() == 1 + */ + ChatView *activeView(); + + void updateMembersActions(); + void setStatus( const QString & ); + + /** + * Reimplemented from KMainWindow - asks each ChatView in the window if it is ok to close the window + * @return true if no ChatView objects to closing. + */ + virtual bool queryClose(); + virtual bool queryExit(); + + KTempFile *backgroundFile; + QPtrList chatViewList; + +private: + // All KopeteChatWindows are created by the findWindow function + KopeteChatWindow( QWidget *parent = 0, const char* name = "KopeteChatWindow" ); + + /** + * The window list has changed: + * For each chat window, update it's Move Tab to Window action + */ + static void windowListChanged(); + + void initActions(void); + void saveOptions(void); + void readOptions(void); + void checkDetachEnable(); + void createTabBar(); + void deleteTabBar(); + void addTab( ChatView* ); + void setPrimaryChatView( ChatView* ); + const QString fileContents( const QString &file ) const; + + ChatView *m_activeView; + ChatView *m_popupView; + bool m_alwaysShowTabs; + bool updateBg; + KTabWidget *m_tabBar; + KPushButton *m_button_send; + KSqueezedTextLabel *m_status_text; + QVBoxLayout *mainLayout; + QFrame *mainArea; + QLabel *anim; + QMovie animIcon; + QPixmap normalIcon; + + KAction *chatSend; + KAction *historyUp; + KAction *historyDown; + KAction *nickComplete; + +#if !KDE_IS_VERSION( 3, 1, 90 ) + KToggleAction *mStatusbarAction; +#endif + + KAction *tabLeft; + KAction *tabRight; + KAction *tabDetach; + KAction* tabClose; + + KToggleAction* membersLeft; + KToggleAction* membersRight; + KToggleAction* toggleMembers; + + KopeteEmoticonAction *actionSmileyMenu; + KActionMenu *actionActionMenu; + KActionMenu *actionContactMenu; + KActionMenu *actionDetachMenu; + KActionMenu *actionTabPlacementMenu; + QString statusMsg; + +signals: + void closing( KopeteChatWindow* ); + +public slots: + void slotSmileyActivated( const QString & ); + void setActiveView( QWidget *active ); + void updateBackground( const QPixmap &pm ); + +private slots: +// void slotPrepareSmileyMenu(); + void slotPrepareContactMenu(); + void slotPrepareDetachMenu(); + void slotPreparePlacementMenu(); + void slotUpdateSendEnabled(); + + void slotCut(); + void slotCopy(); + void slotPaste(); + + void slotSetBgColor(); + void slotSetFgColor(); + void slotSetFont(); + + void slotHistoryUp(); + void slotHistoryDown(); + void slotPageUp(); + void slotPageDown(); + + void slotSendMessage(); + void slotChatSave(); + void slotChatPrint(); + + void slotPreviousTab(); + void slotNextTab(); + void slotDetachChat( int newWindowIndex = -1 ); + void slotPlaceTabs( int tabPlacement ); + + void slotViewMenuBar(); + void slotToggleStatusBar(); + + void slotConfKeys(); + void slotConfToolbar(); + + void slotViewMembersLeft(); + void slotViewMembersRight(); + void slotToggleViewMembers(); + void slotEnableUpdateBg() { updateBg = true; } + + void slotSetCaption( bool ); + void slotUpdateCaptionIcons( const ChatView * ); + void slotChatClosed(); + void slotTabContextMenu( QWidget*, const QPoint & ); + void slotStopAnimation( ChatView* ); + void slotNickComplete(); + void slotCloseChat( QWidget* ); + +protected: + virtual void closeEvent( QCloseEvent *e ); + virtual void windowActivationChange( bool ); +}; + +#endif + +// vim: set noet ts=4 sts=4 sw=4: + diff -Nurp ../work-orig/kopete-3.4.0/kopete/kopete/kopeteiface.cpp kopete-3.4.0/kopete/kopete/kopeteiface.cpp --- ../work-orig/kopete-3.4.0/kopete/kopete/kopeteiface.cpp 2005-05-18 15:23:36.000000000 +0600 +++ kopete-3.4.0/kopete/kopete/kopeteiface.cpp 2005-05-18 15:25:24.000000000 +0600 @@ -84,7 +84,6 @@ QStringList KopeteIface::contactFileProt { return Kopete::ContactList::self()->contactFileProtocols(displayName); } - QString KopeteIface::messageContact( const QString &contactId, const QString &messageText ) { Kopete::MetaContact *mc = Kopete::ContactList::self()->findMetaContactByContactId( contactId ); diff -Nurp ../work-orig/kopete-3.4.0/kopete/kopete/systemtray.cpp kopete-3.4.0/kopete/kopete/systemtray.cpp --- ../work-orig/kopete-3.4.0/kopete/kopete/systemtray.cpp 2005-05-18 15:23:36.000000000 +0600 +++ kopete-3.4.0/kopete/kopete/systemtray.cpp 2005-05-18 15:25:24.000000000 +0600 @@ -19,6 +19,7 @@ #include "systemtray.h" +#include #include #include #include @@ -29,6 +30,8 @@ #include #include #include +#include + #include "kopeteuiglobal.h" #include "kopetemessagemanagerfactory.h" #include "kopeteballoon.h" @@ -258,10 +261,26 @@ void KopeteSystemTray::addBalloon() msgFrom = msg.from()->metaContact()->displayName(); else msgFrom = msg.from()->contactId(); - + + KConfig* cf=KGlobal::config(); + QString uid=msg.from()->contactId(); + QString gr=cf->group(); + cf->setGroup("Encodings"); + QString codepage=cf->readEntry(uid,"Unicode"); + cf->setGroup(gr); + if(codepage != "Unicode") + { + QCString locallyEncoded = msgText.ascii(); + QTextCodec *codec = QTextCodec::codecForName(codepage.ascii()); + if(codec) + msgText=codec->toUnicode( locallyEncoded ); + } + m_balloon = new KopeteBalloon( i18n( "New Message from %1:
\"%2\"
" ) .arg( msgFrom, msgText ), QString::null ); + kdDebug()<<"baloon from "< + Copyright (c) 2002-2003 by Martijn Klingens + Copyright (c) 2003-2004 by Olivier Goffart + + Kopete (c) 2002-2004 by the Kopete developers + + ************************************************************************* + * * + * 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 "systemtray.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "kopeteuiglobal.h" +#include "kopetemessagemanagerfactory.h" +#include "kopeteballoon.h" +#include "kopeteprefs.h" +#include "kopetemetacontact.h" +#include "kopeteaccount.h" +#include "kopeteaccountmanager.h" +#include "kopetecontact.h" +#include "kopetewindow.h" + +KopeteSystemTray* KopeteSystemTray::s_systemTray = 0L; + +KopeteSystemTray* KopeteSystemTray::systemTray( QWidget *parent, const char* name ) +{ + if( !s_systemTray ) + s_systemTray = new KopeteSystemTray( parent, name ); + + return s_systemTray; +} + +KopeteSystemTray::KopeteSystemTray(QWidget* parent, const char* name) + : KSystemTray(parent,name) +{ +// kdDebug(14010) << "Creating KopeteSystemTray" << endl; + QToolTip::add( this, kapp->aboutData()->shortDescription() ); + + mIsBlinkIcon = false; + mIsBlinking = false; + mBlinkTimer = new QTimer(this, "mBlinkTimer"); + + mKopeteIcon = loadIcon("kopete"); + + connect(mBlinkTimer, SIGNAL(timeout()), this, SLOT(slotBlink())); + connect(Kopete::ChatSessionManager::self() , SIGNAL(newEvent(Kopete::MessageEvent*)), + this, SLOT(slotNewEvent(Kopete::MessageEvent*))); + connect(KopetePrefs::prefs(), SIGNAL(saved()), this, SLOT(slotConfigChanged())); + + connect(Kopete::AccountManager::self(), + SIGNAL(accountOnlineStatusChanged(Kopete::Account *, + const Kopete::OnlineStatus &, const Kopete::OnlineStatus &)), + this, SLOT(slotReevaluateAccountStates())); + + // the slot called by default by the quit action, KSystemTray::maybeQuit(), + // just closes the parent window, which is hard to distinguish in that window's closeEvent() + // from a click on the window's close widget + // in the quit case, we want to quit the application + // in the close widget click case, we only want to hide the parent window + // so instead, we make it call our general purpose quit slot on the window, which causes a window close and everything else we need + // KDE4 - app will have to listen for quitSelected instead + KAction *quit = actionCollection()->action( "file_quit" ); + quit->disconnect(); + KopeteWindow *myParent = static_cast( parent ); + connect( quit, SIGNAL( activated() ), myParent, SLOT( slotQuit() ) ); + + //setPixmap(mKopeteIcon); + slotReevaluateAccountStates(); + slotConfigChanged(); + + m_balloon=0l; +} + +KopeteSystemTray::~KopeteSystemTray() +{ +// kdDebug(14010) << "[KopeteSystemTray] ~KopeteSystemTray" << endl; +// delete mBlinkTimer; + Kopete::UI::Global::setSysTrayWId( 0 ); +} + +void KopeteSystemTray::mousePressEvent( QMouseEvent *me ) +{ + if ( + (me->button() == QEvent::MidButton || me->button() == QEvent::LeftButton) && + mIsBlinking ) + { + mouseDoubleClickEvent( me ); + return; + } + + KSystemTray::mousePressEvent( me ); +} + +void KopeteSystemTray::mouseDoubleClickEvent( QMouseEvent *me ) +{ + if ( !mIsBlinking ) + { + KSystemTray::mousePressEvent( me ); + } + else + { + if(!mEventList.isEmpty()) + mEventList.first()->apply(); + } +} + +void KopeteSystemTray::contextMenuAboutToShow( KPopupMenu *me ) +{ + //kdDebug(14010) << k_funcinfo << "Called." << endl; + emit aboutToShowMenu( me ); +} + +void KopeteSystemTray::startBlink( const QString &icon ) +{ + startBlink( KGlobal::iconLoader()->loadIcon( icon , KIcon::Panel ) ); +} + +void KopeteSystemTray::startBlink( const QPixmap &icon ) +{ + mBlinkIcon = icon; + if ( mBlinkTimer->isActive() == false ) + { + mIsBlinkIcon = true; + mIsBlinking = true; + mBlinkTimer->start( 1000, false ); + } + else + { + mBlinkTimer->stop(); + mIsBlinkIcon = true; + mIsBlinking = true; + mBlinkTimer->start( 1000, false ); + } +} + +void KopeteSystemTray::startBlink( const QMovie &movie ) +{ + //kdDebug( 14010 ) << k_funcinfo << "starting movie." << endl; + const_cast( movie ).unpause(); + setMovie( movie ); + mIsBlinking = true; +} + +void KopeteSystemTray::startBlink() +{ + if ( mMovie.isNull() ) + mMovie = KGlobal::iconLoader()->loadMovie( QString::fromLatin1( "newmessage" ), KIcon::Panel ); + + startBlink( mMovie ); +} + +void KopeteSystemTray::stopBlink() +{ + if ( movie() ) + kdDebug( 14010 ) << k_funcinfo << "stopping movie." << endl; + else if ( mBlinkTimer->isActive() ) + mBlinkTimer->stop(); + + if ( !mMovie.isNull() ) + mMovie.pause(); + + mIsBlinkIcon = false; + mIsBlinking = false; + //setPixmap( mKopeteIcon ); + slotReevaluateAccountStates(); +} + +void KopeteSystemTray::slotBlink() +{ + setPixmap( mIsBlinkIcon ? mKopeteIcon : mBlinkIcon ); + + mIsBlinkIcon = !mIsBlinkIcon; +} + +void KopeteSystemTray::slotNewEvent( Kopete::MessageEvent *event ) +{ + mEventList.append( event ); + connect(event, SIGNAL(done(Kopete::MessageEvent*)), + this, SLOT(slotEventDone(Kopete::MessageEvent*))); + + if( event->message().manager() != 0 ) + { + if( event->message().manager()->account() ) + { + if( !event->message().manager()->account()->isAway() || + KopetePrefs::prefs()->soundIfAway() ) + { + addBalloon(); + } + else + { + kdDebug(14000) << k_funcinfo << "Supressing balloon, account is away" << endl; + } + } + } + else + kdDebug(14000) << k_funcinfo << "NULL message().manager()!" << endl; + + // tray animation + if ( KopetePrefs::prefs()->trayflashNotify() ) + startBlink(); +} + +void KopeteSystemTray::slotEventDone(Kopete::MessageEvent *event) +{ + bool current= event==mEventList.first(); + mEventList.remove(event); + + if(current && m_balloon) + { + m_balloon->deleteLater(); + m_balloon=0l; + if(!mEventList.isEmpty()) + addBalloon(); + } + + if(mEventList.isEmpty()) + stopBlink(); +} + +void KopeteSystemTray::addBalloon() +{ + /*kdDebug(14010) << k_funcinfo << + m_balloon << ":" << KopetePrefs::prefs()->showTray() << + ":" << KopetePrefs::prefs()->balloonNotify() + << ":" << !mEventList.isEmpty() << endl;*/ + + if( !m_balloon && KopetePrefs::prefs()->showTray() && KopetePrefs::prefs()->balloonNotify() && !mEventList.isEmpty() ) + { + Kopete::Message msg = mEventList.first()->message(); + + if ( msg.from() ) + { + QString msgText = squashMessage( msg ); + kdDebug(14010) << k_funcinfo << "msg text=" << msgText << endl; + + QString msgFrom; + if( msg.from()->metaContact() ) + msgFrom = msg.from()->metaContact()->displayName(); + else + msgFrom = msg.from()->contactId(); + + m_balloon = new KopeteBalloon( + i18n( "New Message from %1:
\"%2\"
" ) + .arg( msgFrom, msgText ), QString::null ); + connect(m_balloon, SIGNAL(signalBalloonClicked()), mEventList.first() , SLOT(apply())); + connect(m_balloon, SIGNAL(signalButtonClicked()), mEventList.first() , SLOT(apply())); + connect(m_balloon, SIGNAL(signalIgnoreButtonClicked()), mEventList.first() , SLOT(ignore())); + m_balloon->setAnchor(mapToGlobal(pos())); + m_balloon->show(); + KWin::setOnAllDesktops(m_balloon->winId(), true); + } + } +} + +void KopeteSystemTray::slotConfigChanged() +{ +// kdDebug(14010) << k_funcinfo << "called." << endl; + if ( KopetePrefs::prefs()->showTray() ) + show(); + else + hide(); // for users without kicker or a similar docking app +} + +void KopeteSystemTray::slotReevaluateAccountStates() +{ + // If there is a pending message, we don't need to refresh the system tray now. + // This function will even be called when the animation will stop. + if ( mIsBlinking ) + return; + + + //kdDebug(14010) << k_funcinfo << endl; + bool bOnline = false; + bool bAway = false; + bool bOffline = false; + Kopete::Contact *c = 0; + + for (QPtrListIterator it(Kopete::AccountManager::self()->accounts()); it.current(); ++it) + { + c = it.current()->myself(); + if (!c) + continue; + + if (c->onlineStatus().status() == Kopete::OnlineStatus::Online) + { + bOnline = true; // at least one contact is online + } + else if (c->onlineStatus().status() == Kopete::OnlineStatus::Away + || c->onlineStatus().status() == Kopete::OnlineStatus::Invisible) + { + bAway = true; // at least one contact is away or invisible + } + else // this account must be offline (or unknown, which I don't know how to handle) + { + bOffline = true; + } + } + + if (!bOnline && !bAway && !bOffline) // special case, no accounts defined (yet) + bOffline = true; + + if (bAway) + { + if (!bOnline && !bOffline) // none online and none offline -> all away + setPixmap(loadIcon("kopete_all_away")); + else + setPixmap(loadIcon("kopete_some_away")); + } + else if(bOnline) + { + /*if(bOffline) // at least one offline and at least one online -> some accounts online + setPixmap(loadIcon("kopete_some_online")); + else*/ // none offline and none away -> all online + setPixmap(mKopeteIcon); + } + else // none away and none online -> all offline + { + //kdDebug(14010) << k_funcinfo << "All Accounts offline!" << endl; + setPixmap(loadIcon("kopete_offline")); + } +} + + +QString KopeteSystemTray::squashMessage( const Kopete::Message& msg ) +{ + QString msgText = msg.parsedBody(); + + QRegExp rx( "(((http://)?(.+)))" ); + rx.setMinimal( true ); + if ( rx.search( msgText ) == -1 ) + { + // no URLs in text, just pick the first 30 chars of + // the parsed text if necessary. We used parsed text + // so that things like "" show correctly + // Escape it after snipping it to not snip entities + msgText =msg.plainBody() ; + if( msgText.length() > 30 ) + msgText = msgText.left( 30 ) + QString::fromLatin1( " ..." ); + msgText=Kopete::Message::escape(msgText); + } + else + { + QString plainText = msg.plainBody(); + if ( plainText.length() > 30 ) + { + QString fullUrl = rx.cap( 2 ); + QString shorterUrl; + if ( fullUrl.length() > 30 ) + { + QString urlWithoutProtocol = rx.cap( 4 ); + shorterUrl = urlWithoutProtocol.left( 27 ) + + QString::fromLatin1( "... " ); + } + else + { + shorterUrl = fullUrl.left( 27 ) + + QString::fromLatin1( "... " ); + } + // remove message text + msgText = QString::fromLatin1( "... " ) + + rx.cap( 1 ) + + QString::fromLatin1( " ..." ); + // find last occurrence of URL (the one inside the tag) + int revUrlOffset = msgText.findRev( fullUrl ); + msgText.replace( revUrlOffset, + fullUrl.length(), shorterUrl ); + } + } + return msgText; +} + +#include "systemtray.moc" +// vim: set noet ts=4 sts=4 sw=4: