/* kopetemetacontactlvi.cpp - Kopete Meta Contact TDEListViewItem Copyright (c) 2004 by Richard Smith Copyright (c) 2002-2004 by Martijn Klingens Copyright (c) 2002-2005 by Olivier Goffart Copyright (c) 2002 by Duncan Mac-Vicar P 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 #include #include #include #include #include "knotification.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "addcontactpage.h" #include "kopeteaccount.h" #include "kopeteaccountmanager.h" #include "kopetecontactlist.h" #include "kopetecontactlistview.h" #include "kopeteemoticons.h" #include "kopeteuiglobal.h" #include "kopetegroup.h" #include "kopetegroupviewitem.h" #include "kopetemetacontact.h" #include "kopetemetacontactlvi.h" #include "kopetepluginmanager.h" #include "kopeteprefs.h" #include "kopetestdaction.h" #include "systemtray.h" #include "kopeteglobal.h" #include "kopetecontact.h" #include "tdeabcpersistence.h" #include using namespace Kopete::UI; namespace Kopete { namespace UI { namespace ListView { class MetaContactToolTipSource : public ToolTipSource { public: MetaContactToolTipSource( MetaContact *mc ) : metaContact( mc ) { } TQString operator()( ComponentBase *, const TQPoint &, TQRect & ) { // We begin with the meta contact display name at the top of the tooltip TQString toolTip = TQString::fromLatin1(""); toolTip += TQString::fromLatin1("
"); if ( ! metaContact->photo().isNull() ) { TQString photoName = TQString::fromLatin1("kopete-metacontact-photo:%1").arg( KURL::encode_string( metaContact->metaContactId() )); //TQMimeSourceFactory::defaultFactory()->setImage( "contactimg", metaContact->photo() ); toolTip += TQString::fromLatin1("").arg( photoName ); } toolTip += TQString::fromLatin1(""); TQString displayName; Kopete::Emoticons *e = Kopete::Emoticons::self(); TQValueList t = e->tokenize( metaContact->displayName()); TQValueList::iterator it; for( it = t.begin(); it != t.end(); ++it ) { if( (*it).type == Kopete::Emoticons::Image ) { displayName += (*it).picHTMLCode; } else if( (*it).type == Kopete::Emoticons::Text ) { displayName += TQStyleSheet::escape( (*it).text ); } } toolTip += TQString::fromLatin1("%1

").arg( displayName ); TQPtrList contacts = metaContact->contacts(); if ( contacts.count() == 1 ) { return toolTip + contacts.first()->toolTip() + TQString::fromLatin1("
"); } toolTip += TQString::fromLatin1(""); // We are over a metacontact with > 1 child contacts, and not over a specific contact // Iterate through children and display a summary tooltip for(Contact *c = contacts.first(); c; c = contacts.next()) { TQString iconName = TQString::fromLatin1("kopete-contact-icon:%1:%2:%3") .arg( KURL::encode_string( c->protocol()->pluginId() ), KURL::encode_string( c->account()->accountId() ), KURL::encode_string( c->contactId() ) ); toolTip += i18n("", "") .arg( iconName, Kopete::Emoticons::parseEmoticons(c->property(Kopete::Global::Properties::self()->nickName()).value().toString()) , c->contactId(), c->onlineStatus().description() ); } return toolTip + TQString::fromLatin1("
STATUS ICON PROTOCOL NAME (ACCOUNT NAME)STATUS DESCRIPTION
 %2 (%3)%4
"); } private: MetaContact *metaContact; }; } // END namespace ListView } // END namespace UI } // END namespace Kopete class KopeteMetaContactLVI::Private { public: Private() : metaContactIcon( 0L ), nameText( 0L ), extraText( 0L ), contactIconBox( 0L ), currentMode( -1 ), currentIconMode( -1 ), hbox(NULL) {} ListView::ContactBoxComponent *hbox; ListView::FaceComponent *metaContactIcon; ListView::DisplayNameComponent *nameText; ListView::DisplayNameComponent *extraText; ListView::BoxComponent *contactIconBox; ListView::BoxComponent *spacerBox; std::auto_ptr toolTipSource; // metacontact icon size int iconSize; // protocol icon size int contactIconSize; int currentMode; int currentIconMode; TQPtrList events; }; KopeteMetaContactLVI::KopeteMetaContactLVI( Kopete::MetaContact *contact, KopeteGroupViewItem *parent ) : ListView::Item( parent, contact, "MetaContactLVI" ) //: TQObject( contact, "MetaContactLVI" ), TDEListViewItem( parent ) { m_metaContact = contact; m_isTopLevel = false; m_parentGroup = parent; m_parentView = 0L; initLVI(); parent->refreshDisplayName(); } KopeteMetaContactLVI::KopeteMetaContactLVI( Kopete::MetaContact *contact, TQListViewItem *parent ) : ListView::Item( parent, contact, "MetaContactLVI" ) //: TQObject( contact, "MetaContactLVI" ), TDEListViewItem( parent ) { m_metaContact = contact; m_isTopLevel = true; m_parentGroup = 0L; m_parentView = 0L; initLVI(); } KopeteMetaContactLVI::KopeteMetaContactLVI( Kopete::MetaContact *contact, TQListView *parent ) : ListView::Item( parent, contact, "MetaContactLVI" ) //: TQObject( contact, "MetaContactLVI" ), TDEListViewItem( parent ) { m_metaContact = contact; m_isTopLevel = true; m_parentGroup = 0L; m_parentView = parent; initLVI(); } void KopeteMetaContactLVI::initLVI() { d = new Private; d->toolTipSource.reset( new ListView::MetaContactToolTipSource( m_metaContact ) ); m_oldStatus = m_metaContact->status(); connect( m_metaContact, TQT_SIGNAL( displayNameChanged( const TQString &, const TQString & ) ), TQT_SLOT( slotDisplayNameChanged() ) ); connect( m_metaContact, TQT_SIGNAL( photoChanged() ), TQT_SLOT( slotPhotoChanged() ) ); connect( m_metaContact, TQT_SIGNAL( onlineStatusChanged( Kopete::MetaContact *, Kopete::OnlineStatus::StatusType ) ), TQT_SLOT( slotPhotoChanged() ) ); connect( m_metaContact, TQT_SIGNAL( onlineStatusChanged( Kopete::MetaContact *, Kopete::OnlineStatus::StatusType ) ), this, TQT_SLOT(slotIdleStateChanged( ) ) ); connect( m_metaContact, TQT_SIGNAL( contactStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus & ) ), TQT_SLOT( slotContactStatusChanged( Kopete::Contact * ) ) ); connect( m_metaContact, TQT_SIGNAL( contactAdded( Kopete::Contact * ) ), TQT_SLOT( slotContactAdded( Kopete::Contact * ) ) ); connect( m_metaContact, TQT_SIGNAL( contactRemoved( Kopete::Contact * ) ), TQT_SLOT( slotContactRemoved( Kopete::Contact * ) ) ); connect( m_metaContact, TQT_SIGNAL( iconAppearanceChanged() ), TQT_SLOT( slotUpdateMetaContact() ) ); connect( m_metaContact, TQT_SIGNAL( useCustomIconChanged( bool ) ), TQT_SLOT( slotUpdateMetaContact() ) ); connect( m_metaContact, TQT_SIGNAL( contactIdleStateChanged( Kopete::Contact * ) ), TQT_SLOT( slotIdleStateChanged( Kopete::Contact * ) ) ); connect( KopetePrefs::prefs(), TQT_SIGNAL( contactListAppearanceChanged() ), TQT_SLOT( slotConfigChanged() ) ); connect( kapp, TQT_SIGNAL( appearanceChanged() ), TQT_SLOT( slotConfigChanged() ) ); mBlinkTimer = new TQTimer( this, "mBlinkTimer" ); connect( mBlinkTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotBlink() ) ); mIsBlinkIcon = false; //if ( !mBlinkIcon ) // mBlinkIcon = new TQPixmap( TDEGlobal::iconLoader()->loadIcon( TQString::fromLatin1( "newmsg" ), TDEIcon::Small ) ); slotConfigChanged(); // this calls slotIdleStateChanged(), which sets up the constituent components, spacing, fonts and indirectly, the contact icon slotDisplayNameChanged(); updateContactIcons(); } KopeteMetaContactLVI::~KopeteMetaContactLVI() { delete d; //if ( m_parentGroup ) // m_parentGroup->refreshDisplayName(); } void KopeteMetaContactLVI::movedToDifferentGroup() { KopeteContactListView *lv = dynamic_cast( listView() ); if ( !lv ) return; if ( m_parentGroup ) m_parentGroup->refreshDisplayName(); // create a spacer if wanted // I assume that the safety property that allows the delete in slotConfigChanged holds here - Will delete d->spacerBox->component( 0 ); if ( TDEListViewItem::parent() && KopetePrefs::prefs()->contactListIndentContacts() && !KopetePrefs::prefs()->treeView() ) { new ListView::SpacerComponent( d->spacerBox, 20, 0 ); } KopeteGroupViewItem *group_item = dynamic_cast(TDEListViewItem::parent()); if ( group_item ) { m_isTopLevel = false; m_parentGroup = group_item; m_parentView = 0L; group_item->refreshDisplayName(); } else { m_isTopLevel = true; m_parentGroup = 0L; m_parentView = lv; } } void KopeteMetaContactLVI::rename( const TQString& newName ) { TQString oldName = m_metaContact->displayName(); KopeteContactListView *lv = dynamic_cast( listView() ); if ( lv ) { KopeteContactListView::UndoItem *u=new KopeteContactListView::UndoItem(KopeteContactListView::UndoItem::MetaContactRename, m_metaContact); // HACK but args are strings not ints u->nameSource = m_metaContact->displayNameSource(); // additional args if ( m_metaContact->displayNameSource() == Kopete::MetaContact::SourceCustom ) { u->args << m_metaContact->customDisplayName(); } else if ( m_metaContact->displayNameSource() == Kopete::MetaContact::SourceContact ) { Kopete::Contact* c = m_metaContact->displayNameSourceContact(); if(c) u->args << c->contactId() << c->protocol()->pluginId() << c->account()->accountId(); } // source tdeabc requires no arguments lv->insertUndoItem(u); } if ( newName.isEmpty() ) { // fallback to KABC if ( !m_metaContact->metaContactId().isEmpty() ) { m_metaContact->setDisplayNameSource(Kopete::MetaContact::SourceKABC); if ( ! m_metaContact->displayName().isEmpty() ) { slotDisplayNameChanged(); return; } } // bad luck with KABC m_metaContact->setDisplayNameSource(Kopete::MetaContact::SourceContact); // TODO iterate though all subcontacts to check non empty nick m_metaContact->setDisplayNameSourceContact( m_metaContact->contacts().first() ); slotDisplayNameChanged(); } else // user changed name manually, set source to custom { m_metaContact->setDisplayNameSource( Kopete::MetaContact::SourceCustom ); m_metaContact->setDisplayName( newName ); slotDisplayNameChanged(); } kdDebug( 14000 ) << k_funcinfo << "newName=" << newName << endl; } void KopeteMetaContactLVI::slotContactStatusChanged( Kopete::Contact *c ) { updateContactIcon( c ); // FIXME: All this code should be in kopetemetacontact.cpp.. having it in the LVI makes it all fire // multiple times if the user is in multiple groups - Jason // comparing the status of the previous and new preferred contact is the determining factor in deciding to notify Kopete::OnlineStatus newStatus; if ( m_metaContact->preferredContact() ) newStatus = m_metaContact->preferredContact()->onlineStatus(); else { // the last child contact has gone offline or otherwise unreachable, so take the changed contact's online status newStatus = c->onlineStatus(); } // ensure we are not suppressing notifications, because connecting or disconnected if ( !(c->account()->suppressStatusNotification() || ( c->account()->myself()->onlineStatus().status() == Kopete::OnlineStatus::Connecting ) || !c->account()->isConnected() ) ) { if ( !c->account()->isAway() || KopetePrefs::prefs()->soundIfAway() ) { //int winId = KopeteSystemTray::systemTray() ? KopeteSystemTray::systemTray()->winId() : 0; TQString text = i18n( "%1 is now %2." ) .arg( Kopete::Emoticons::parseEmoticons( TQStyleSheet::escape(m_metaContact->displayName()) ) , TQStyleSheet::escape(c->onlineStatus().description())); // figure out what's happened enum ChangeType { noChange, noEvent, signedIn, changedStatus, signedOut }; ChangeType t = noChange; //kdDebug( 14000 ) << k_funcinfo << m_metaContact->displayName() << //" - Old MC Status: " << m_oldStatus.status() << ", New MC Status: " << newStatus.status() << endl; // first, exclude changes due to blocking or subscription changes at the protocol level if ( ( m_oldStatus.status() == Kopete::OnlineStatus::Unknown || newStatus.status() == Kopete::OnlineStatus::Unknown ) ) t = noEvent; // This means the contact's changed from or to unknown - due to a protocol state change, not a contact state change else // we're dealing with a genuine contact state change { if ( m_oldStatus.status() == Kopete::OnlineStatus::Offline ) { if ( newStatus.status() != Kopete::OnlineStatus::Offline ) { //kdDebug( 14000 ) << "signed in" << endl; t = signedIn; // contact has gone from offline to something else, it's a sign-in } } else if ( m_oldStatus.status() == Kopete::OnlineStatus::Online || m_oldStatus.status() == Kopete::OnlineStatus::Away || m_oldStatus.status() == Kopete::OnlineStatus::Invisible) { if ( newStatus.status() == Kopete::OnlineStatus::Offline ) { //kdDebug( 14000 ) << "signed OUT" << endl; t = signedOut; // contact has gone from an online state to an offline state, it's a sign out } else if ( m_oldStatus > newStatus || m_oldStatus < newStatus ) // operator!= is useless because it's an identity operator, not an equivalence operator { // contact has changed online states, it's a status change, // and the preferredContact changed status, or there is a new preferredContacat // so it's worth notifying //kdDebug( 14000 ) << "changed status" << endl; t = changedStatus; } } else if ( m_oldStatus != newStatus ) { //kdDebug( 14000 ) << "non-event" << endl; // catch-all for any other status change we don't know about t = noEvent; } // if none of the above were true, t will still be noChange } // now issue the appropriate notification switch ( t ) { case noEvent: case noChange: break; case signedIn: connect(KNotification::event(m_metaContact, "kopete_contact_online", text, m_metaContact->photo(), KopeteSystemTray::systemTray(), i18n( "Chat" )) , TQT_SIGNAL(activated(unsigned int )) , this, TQT_SLOT( execute() ) ); break; case changedStatus: connect(KNotification::event(m_metaContact, "kopete_contact_status_change", text, m_metaContact->photo(), KopeteSystemTray::systemTray(), i18n( "Chat" )) , TQT_SIGNAL(activated(unsigned int )) , this, TQT_SLOT( execute() )); break; case signedOut: KNotification::event(m_metaContact, "kopete_contact_offline", text, m_metaContact->photo(), KopeteSystemTray::systemTray()); break; } } //blink if the metacontact icon has changed. if ( !mBlinkTimer->isActive() && d->metaContactIcon /*&& d->metaContactIcon->pixmap() != m_oldStatusIcon */) { mIsBlinkIcon = false; m_blinkLeft = 9; mBlinkTimer->start( 400, false ); } } else { //the status icon probably changed, but we didn't blink. //So the olfStatusIcon will not be set to the real after the blink. //we set it now. if( !mBlinkTimer->isActive() ) m_oldStatusIcon=d->metaContactIcon ? d->metaContactIcon->pixmap() : TQPixmap(); } // make a note of the current status for the next time we get a status change m_oldStatus = newStatus; if ( m_parentGroup ) m_parentGroup->refreshDisplayName(); updateVisibility(); } void KopeteMetaContactLVI::slotUpdateMetaContact() { slotIdleStateChanged( 0 ); updateVisibility(); if ( m_parentGroup ) m_parentGroup->refreshDisplayName(); } void KopeteMetaContactLVI::execute() const { if ( d->events.first() ) d->events.first()->apply(); else m_metaContact->execute(); //The selection is removed, but the contact still hihjlihted, remove the selection in the contactlist (see bug 106090) Kopete::ContactList::self()->setSelectedItems( TQPtrList() , TQPtrList() ); } void KopeteMetaContactLVI::slotDisplayNameChanged() { if ( d->nameText ) { d->nameText->setText( m_metaContact->displayName() ); // delay the sort if we can if ( ListView::ListView *lv = dynamic_cast( listView() ) ) lv->delayedSort(); else listView()->sort(); } } void KopeteMetaContactLVI::slotPhotoChanged() { if ( d->metaContactIcon && d->currentIconMode == KopetePrefs::PhotoPic ) { m_oldStatusIcon= d->metaContactIcon->pixmap(); TQPixmap photoPixmap; //TQPixmap defaultIcon( TDEGlobal::iconLoader()->loadIcon( "x-office-address-book", TDEIcon::Desktop ) ); TQImage photoImg = m_metaContact->photo(); if ( !photoImg.isNull() && (photoImg.width() > 0) && (photoImg.height() > 0) ) { int photoSize = d->iconSize; photoImg = photoImg.smoothScale( photoSize, photoSize, TQ_ScaleMin ); KImageEffect *effect = 0L; switch ( m_metaContact->status() ) { case Kopete::OnlineStatus::Online: break; case Kopete::OnlineStatus::Away: effect = new KImageEffect(); effect->fade(photoImg, 0.5, TQt::white); break; case Kopete::OnlineStatus::Offline: effect = new KImageEffect(); effect->fade(photoImg, 0.4, TQt::white); effect->toGray(photoImg); break; case Kopete::OnlineStatus::Unknown: default: effect = new KImageEffect(); effect->fade(photoImg, 0.8, TQt::white); } delete effect; photoPixmap = photoImg; } else { photoPixmap=SmallIcon(m_metaContact->statusIcon(), d->iconSize); } d->metaContactIcon->setPixmap( photoPixmap, false); if(mBlinkTimer->isActive()) m_originalBlinkIcon=photoPixmap; } } /* void KopeteMetaContactLVI::slotRemoveThisUser() { kdDebug( 14000 ) << k_funcinfo << " Removing user" << endl; //m_metaContact->removeThisUser(); if ( KMessageBox::warningContinueCancel( Kopete::UI::Global::mainWidget(), i18n( "Are you sure you want to remove %1 from your contact list?" ). arg( m_metaContact->displayName() ), i18n( "Remove Contact" ), KGuiItem(i18n("Remove"),"delete_user") ) == KMessageBox::Continue ) { Kopete::ContactList::self()->removeMetaContact( m_metaContact ); } } void KopeteMetaContactLVI::slotRemoveFromGroup() { if ( m_metaContact->isTemporary() ) return; m_metaContact->removeFromGroup( group() ); } */ void KopeteMetaContactLVI::startRename( int /*col*/ ) { TDEListViewItem::startRename( 0 ); } void KopeteMetaContactLVI::okRename( int col ) { TDEListViewItem::okRename( col ); setRenameEnabled( 0, false ); } void KopeteMetaContactLVI::cancelRename( int col ) { TDEListViewItem::cancelRename( col ); setRenameEnabled( 0, false ); } /* void KopeteMetaContactLVI::slotMoveToGroup() { if ( m_actionMove && !m_metaContact->isTemporary() ) { if ( m_actionMove->currentItem() == 0 ) { // we are moving to top-level if ( group() != Kopete::Group::toplevel ) m_metaContact->moveToGroup( group(), Kopete::Group::toplevel ); } else { Kopete::Group *to = Kopete::ContactList::self()->getGroup( m_actionMove->currentText() ); if ( !m_metaContact->groups().contains( to ) ) m_metaContact->moveToGroup( group(), to ); } } } void KopeteMetaContactLVI::slotAddToGroup() { if ( m_actionCopy ) { kdDebug( 14000 ) << "KopeteMetaContactLVI::slotAddToGroup " << endl; if ( m_actionCopy->currentItem() == 0 ) { // we are adding to top-level m_metaContact->addToGroup( Kopete::Group::toplevel ); } else { m_metaContact->addToGroup( Kopete::ContactList::self()->getGroup( m_actionCopy->currentText() ) ); } } } */ //FIXME: this is not used... remove? void KopeteMetaContactLVI::slotAddToNewGroup() { if ( m_metaContact->isTemporary() ) return; TQString groupName = KInputDialog::getText( i18n( "New Group" ), i18n( "Please enter the name for the new group:" ) ); if ( !groupName.isEmpty() ) m_metaContact->addToGroup( Kopete::ContactList::self()->findGroup( groupName ) ); } void KopeteMetaContactLVI::slotConfigChanged() { if (d->hbox != NULL) d->hbox->reloadTheme(); setDisplayMode( KopetePrefs::prefs()->contactListDisplayMode(), KopetePrefs::prefs()->contactListIconMode() ); // create a spacer if wanted delete d->spacerBox->component( 0 ); if ( TDEListViewItem::parent() && KopetePrefs::prefs()->contactListIndentContacts() && !KopetePrefs::prefs()->treeView() ) { new ListView::SpacerComponent( d->spacerBox, 20, 0 ); } if ( KopetePrefs::prefs()->contactListUseCustomFonts() ) { d->nameText->setFont( KopetePrefs::prefs()->contactListCustomNormalFont() ); if ( d->extraText ) d->extraText->setFont( KopetePrefs::prefs()->contactListSmallFont() ); } else { TQFont font=listView()->font(); d->nameText->setFont( font ); if(d->extraText) { if ( font.pixelSize() != -1 ) font.setPixelSize( (font.pixelSize() * 3) / 4 ); else font.setPointSizeFloat( font.pointSizeFloat() * 0.75 ); d->extraText->setFont( font ); } } updateVisibility(); updateContactIcons(); slotIdleStateChanged( 0 ); if(d->nameText) d->nameText->redraw(); if(d->extraText) d->extraText->redraw(); } void KopeteMetaContactLVI::setMetaContactToolTipSourceForComponent( ListView::Component *comp ) { if ( comp ) comp->setToolTipSource( d->toolTipSource.get() ); } void KopeteMetaContactLVI::setDisplayMode( int mode, int iconmode ) { if ( mode == d->currentMode && iconmode == d->currentIconMode ) return; d->currentMode = mode; d->currentIconMode = iconmode; // empty... while ( component( 0 ) ) delete component( 0 ); d->nameText = 0L; d->extraText = 0L; d->metaContactIcon = 0L; d->contactIconSize = 12; if (mode == KopetePrefs::Detailed) { d->iconSize = iconmode == KopetePrefs::IconPic ? TDEIcon::SizeMedium : TDEIcon::SizeLarge; } else { d->iconSize = iconmode == KopetePrefs::IconPic ? IconSize( TDEIcon::Small ) : TDEIcon::SizeMedium; } disconnect( Kopete::KABCPersistence::self()->addressBook() , 0 , this , 0); // generate our contents using namespace ListView; d->hbox = new ContactBoxComponent( this, BoxComponent::Horizontal ); d->hbox->reloadTheme(); Component *hbox = d->hbox; d->spacerBox = new BoxComponent( hbox, BoxComponent::Horizontal ); if (iconmode == KopetePrefs::PhotoPic) { Component *imageBox = new BoxComponent( hbox, BoxComponent::Vertical ); new VSpacerComponent( imageBox ); d->metaContactIcon = new FaceComponent( imageBox, d->iconSize , d->iconSize ); new VSpacerComponent( imageBox ); if(!metaContact()->photoSource() && !Kopete::KABCPersistence::self()->addressBook()->findByUid( metaContact()->metaContactId() ).isEmpty() ) { //if the photo is the one of the kaddressbook, track every change in the adressbook, it might be the photo of our contact. connect( Kopete::KABCPersistence::self()->addressBook() , TQT_SIGNAL(addressBookChanged (AddressBook *) ) , this , TQT_SLOT(slotPhotoChanged())); } } else { d->metaContactIcon = new FaceComponent( hbox ); } new SpacerComponent(hbox, 8, 8); if( mode == KopetePrefs::Detailed ) { d->contactIconSize = IconSize( TDEIcon::Small ); Component *vbox = new BoxComponent( hbox, BoxComponent::Vertical ); d->nameText = new DisplayNameComponent( vbox ); d->extraText = new DisplayNameComponent( vbox ); Component *box = new BoxComponent( vbox, BoxComponent::Horizontal ); d->contactIconBox = new BoxComponent( box, BoxComponent::Horizontal ); } else if( mode == KopetePrefs::RightAligned ) // old right-aligned contact { d->nameText = new DisplayNameComponent( hbox ); new HSpacerComponent( hbox ); d->contactIconBox = new BoxComponent( hbox, BoxComponent::Horizontal ); } else // older left-aligned contact { d->nameText = new DisplayNameComponent( hbox ); d->contactIconBox = new BoxComponent( hbox, BoxComponent::Horizontal ); } // set some components to have the metacontact tooltip setMetaContactToolTipSourceForComponent( d->metaContactIcon ); setMetaContactToolTipSourceForComponent( d->nameText ); setMetaContactToolTipSourceForComponent( d->extraText ); // update the display name slotDisplayNameChanged(); slotPhotoChanged(); slotIdleStateChanged( 0 ); // finally, re-add all contacts so their icons appear. remove them first for consistency. TQPtrList contacts = m_metaContact->contacts(); for ( TQPtrListIterator it( contacts ); it.current(); ++it ) { slotContactRemoved( *it ); slotContactAdded( *it ); } m_oldStatusIcon=d->metaContactIcon ? d->metaContactIcon->pixmap() : TQPixmap(); if( mBlinkTimer->isActive() ) m_originalBlinkIcon=m_oldStatusIcon; } void KopeteMetaContactLVI::updateVisibility() { if ( KopetePrefs::prefs()->showOffline() || !d->events.isEmpty() ) setTargetVisibility( true ); else if ( !m_metaContact->isOnline() && !mBlinkTimer->isActive() ) setTargetVisibility( false ); else setTargetVisibility( true ); } void KopeteMetaContactLVI::slotContactPropertyChanged( Kopete::Contact *contact, const TQString &key, const TQVariant &old, const TQVariant &newVal ) { // if ( key == TQString::fromLatin1("awayMessage") ) // kdDebug( 14000 ) << k_funcinfo << "contact=" << contact->contactId() << ", isonline=" << contact->isOnline() << ", alloffline=" << !m_metaContact->isOnline() << ", oldvalue=" << old.toString() << ", newvalue=" << newVal.toString() << endl; if ( key == TQString::fromLatin1("awayMessage") && d->extraText && old != newVal ) { bool allOffline = !m_metaContact->isOnline(); if ( newVal.toString().isEmpty() || ( !contact->isOnline() && !allOffline ) ) { // try to find a more suitable away message to be displayed when: // -new away message is empty or // -contact who set it is offline and there are contacts online in the metacontact bool allAwayMessagesEmpty = true; TQPtrList contacts = m_metaContact->contacts(); for ( Kopete::Contact *c = contacts.first(); c; c = contacts.next() ) { // kdDebug( 14000 ) << k_funcinfo << "ccontact=" << c->contactId() << ", isonline=" << c->isOnline() << ", awaymsg=" << c->property( key ).value().toString() << endl; TQString awayMessage( c->property( key ).value().toString() ); if ( ( allOffline || c->isOnline() ) && !awayMessage.isEmpty() ) { // display this contact's away message when: // -this contact's away message is not empty and // -this contact is online or there are no contacts online at all allAwayMessagesEmpty = false; d->extraText->setText( awayMessage ); break; } } if ( allAwayMessagesEmpty ) d->extraText->setText( TQString() ); } else { // just use new away message when: // -new away message is not empty and // -contact who set it is online or there are no contacts online at all d->extraText->setText( newVal.toString() ); } } // wtf? KopeteMetaContact also connects this signals and emits photoChanged! why no connect photoChanged to slotPhotoChanged? /*else if ( key == TQString::fromLatin1("photo") && (m_metaContact->photoSourceContact() == contact) && (m_metaContact->photoSource() == Kopete::MetaContact::SourceContact)) { slotPhotoChanged(); }*/ } void KopeteMetaContactLVI::slotContactAdded( Kopete::Contact *c ) { connect( c, TQT_SIGNAL( propertyChanged( Kopete::Contact *, const TQString &, const TQVariant &, const TQVariant & ) ), this, TQT_SLOT( slotContactPropertyChanged( Kopete::Contact *, const TQString &, const TQVariant &, const TQVariant & ) ) ); connect( c->account() , TQT_SIGNAL( colorChanged(const TQColor& ) ) , this, TQT_SLOT( updateContactIcons() ) ); updateContactIcon( c ); slotContactPropertyChanged( c, TQString::fromLatin1("awayMessage"), TQVariant(), c->property( TQString::fromLatin1("awayMessage") ).value() ); } void KopeteMetaContactLVI::slotContactRemoved( Kopete::Contact *c ) { disconnect( c, TQT_SIGNAL( propertyChanged( Kopete::Contact *, const TQString &, const TQVariant &, const TQVariant & ) ), this, TQT_SLOT( slotContactPropertyChanged( Kopete::Contact *, const TQString &, const TQVariant &, const TQVariant & ) ) ); disconnect( c->account() , TQT_SIGNAL( colorChanged(const TQColor& ) ) , this, TQT_SLOT( updateContactIcons() ) ); if ( ListView::Component *comp = contactComponent( c ) ) delete comp; slotContactPropertyChanged( c, TQString::fromLatin1("awayMessage"), c->property( TQString::fromLatin1("awayMessage") ).value(), TQVariant() ); } void KopeteMetaContactLVI::updateContactIcons() { // show offline contacts setting may have changed TQPtrList contacts = m_metaContact->contacts(); for ( TQPtrListIterator it( contacts ); it.current(); ++it ) updateContactIcon( *it ); } void KopeteMetaContactLVI::updateContactIcon( Kopete::Contact *c ) { TDEGlobal::config()->setGroup( TQString::fromLatin1("ContactList") ); bool bHideOffline = TDEGlobal::config()->readBoolEntry( TQString::fromLatin1("HideOfflineContacts"), false ); if ( KopetePrefs::prefs()->showOffline() ) bHideOffline = false; ListView::ContactComponent *comp = contactComponent( c ); bool bShow = !bHideOffline || c->isOnline(); if ( bShow && !comp ) (void)new ListView::ContactComponent( d->contactIconBox, c, d->contactIconSize ); else if ( !bShow && comp ) delete comp; else if ( comp ) comp->updatePixmap(); } Kopete::Contact *KopeteMetaContactLVI::contactForPoint( const TQPoint &p ) const { if ( ListView::ContactComponent *comp = dynamic_cast( d->contactIconBox->componentAt( p ) ) ) return comp->contact(); return 0L; } ListView::ContactComponent *KopeteMetaContactLVI::contactComponent( const Kopete::Contact *c ) const { for ( uint n = 0; n < d->contactIconBox->components(); ++n ) { if ( ListView::ContactComponent *comp = dynamic_cast( d->contactIconBox->component( n ) ) ) { if ( comp->contact() == c ) return comp; } } return 0; } TQRect KopeteMetaContactLVI::contactRect( const Kopete::Contact *c ) const { if ( ListView::Component *comp = contactComponent( c ) ) return comp->rect(); return TQRect(); } Kopete::Group *KopeteMetaContactLVI::group() { if ( m_parentGroup && m_parentGroup->group() != Kopete::Group::topLevel() ) return m_parentGroup->group(); else return Kopete::Group::topLevel(); } TQString KopeteMetaContactLVI::key( int, bool ) const { char importanceChar; switch ( m_metaContact->status() ) { case Kopete::OnlineStatus::Online: importanceChar = 'A'; break; case Kopete::OnlineStatus::Away: importanceChar = 'B'; break; case Kopete::OnlineStatus::Offline: importanceChar = 'C'; break; case Kopete::OnlineStatus::Unknown: default: importanceChar = 'D'; } return importanceChar + d->nameText->text().lower(); } bool KopeteMetaContactLVI::isTopLevel() const { return m_isTopLevel; } bool KopeteMetaContactLVI::isGrouped() const { if ( m_parentView ) return true; if ( !m_parentGroup || !m_parentGroup->group() ) return false; if ( m_parentGroup->group() == Kopete::Group::temporary() && !KopetePrefs::prefs()->sortByGroup() ) return false; return true; } void KopeteMetaContactLVI::slotIdleStateChanged( Kopete::Contact *c ) { bool doWeHaveToGrayThatContact = KopetePrefs::prefs()->greyIdleMetaContacts() && ( m_metaContact->idleTime() >= 10 * 60 ); if ( doWeHaveToGrayThatContact ) { d->nameText->setColor( KopetePrefs::prefs()->idleContactColor() ); if ( d->extraText ) d->extraText->setColor( KopetePrefs::prefs()->idleContactColor() ); } else { d->nameText->setDefaultColor(); if ( d->extraText ) d->extraText->setDefaultColor(); } if(d->metaContactIcon && d->currentIconMode==KopetePrefs::IconPic) { m_oldStatusIcon=d->metaContactIcon->pixmap(); TQPixmap icon = SmallIcon( m_metaContact->statusIcon(), d->iconSize ); if ( doWeHaveToGrayThatContact ) { // TODO: TQPixmapCache this result TDEIconEffect::semiTransparent( icon ); } d->metaContactIcon->setPixmap( icon ); if(mBlinkTimer->isActive()) m_originalBlinkIcon=icon; } // we only need to update the contact icon if one was supplied; // if none was supplied, we only need to update the MC appearance if ( c ) updateContactIcon( c ); else return; } void KopeteMetaContactLVI::catchEvent( Kopete::MessageEvent *event ) { d->events.append( event ); connect( event, TQT_SIGNAL( done( Kopete::MessageEvent* ) ), this, TQT_SLOT( slotEventDone( Kopete::MessageEvent * ) ) ); if ( mBlinkTimer->isActive() ) mBlinkTimer->stop(); m_oldStatusIcon= d->metaContactIcon ? d->metaContactIcon->pixmap() : TQPixmap(); mBlinkTimer->start( 400, false ); //show the contact if it was hidden because offline. updateVisibility(); } void KopeteMetaContactLVI::slotBlink() { bool haveEvent = !d->events.isEmpty(); if ( mIsBlinkIcon ) { if(d->metaContactIcon) d->metaContactIcon->setPixmap( m_originalBlinkIcon ); if ( !haveEvent && m_blinkLeft <= 0 ) { mBlinkTimer->stop(); m_oldStatusIcon=d->metaContactIcon ? d->metaContactIcon->pixmap() : TQPixmap(); updateVisibility(); m_originalBlinkIcon=TQPixmap(); //i hope this help to reduce memory consuption } } else { if(d->metaContactIcon) m_originalBlinkIcon=d->metaContactIcon->pixmap(); if ( haveEvent ) { if(d->metaContactIcon) d->metaContactIcon->setPixmap( SmallIcon( "newmsg", d->iconSize ) ); } else { if(d->metaContactIcon) d->metaContactIcon->setPixmap( m_oldStatusIcon ); m_blinkLeft--; } } mIsBlinkIcon = !mIsBlinkIcon; } void KopeteMetaContactLVI::slotEventDone( Kopete::MessageEvent *event ) { d->events.remove( event ); if ( d->events.isEmpty() ) { if ( mBlinkTimer->isActive() ) { mBlinkTimer->stop(); //If the contact gone offline while the timer was actif, //the visibility has not been correctly updated. so do it now updateVisibility(); } if(d->metaContactIcon) d->metaContactIcon->setPixmap( m_originalBlinkIcon ); m_originalBlinkIcon=TQPixmap(); //i hope this help to reduce memory consuption mIsBlinkIcon = false; } } TQString KopeteMetaContactLVI::text( int column ) const { if ( column == 0 ) return d->nameText->text(); else return TDEListViewItem::text( column ); } void KopeteMetaContactLVI::setText( int column, const TQString &text ) { if ( column == 0 ) rename( text ); else TDEListViewItem::setText( column, text ); } #include "kopetemetacontactlvi.moc"