|
|
|
/*
|
|
|
|
kopetecontact.cpp - Kopete Contact
|
|
|
|
|
|
|
|
Copyright (c) 2002-2004 by Duncan Mac-Vicar Prett <duncan@kde.org>
|
|
|
|
Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
|
|
|
|
Copyright (c) 2002-2004 by Olivier Goffart <ogoffart @tiscalinet.be>
|
|
|
|
|
|
|
|
Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
|
|
|
|
|
|
|
|
*************************************************************************
|
|
|
|
* *
|
|
|
|
* This library is free software; you can redistribute it and/or *
|
|
|
|
* modify it under the terms of the GNU Lesser General Public *
|
|
|
|
* License as published by the Free Software Foundation; either *
|
|
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
*************************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kopetecontact.h"
|
|
|
|
|
|
|
|
#include <tqapplication.h>
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include <kdeversion.h>
|
|
|
|
#include <kinputdialog.h>
|
|
|
|
|
|
|
|
#include <kabcpersistence.h>
|
|
|
|
#include <kdialogbase.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kpopupmenu.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <klistviewsearchline.h>
|
|
|
|
|
|
|
|
#include "kopetecontactlist.h"
|
|
|
|
#include "kopeteglobal.h"
|
|
|
|
#include "kopeteuiglobal.h"
|
|
|
|
#include "kopeteprotocol.h"
|
|
|
|
#include "kopeteaccount.h"
|
|
|
|
#include "kopetestdaction.h"
|
|
|
|
#include "kopetechatsession.h"
|
|
|
|
#include "kopeteview.h"
|
|
|
|
#include "kopetemetacontact.h"
|
|
|
|
#include "kopeteprefs.h"
|
|
|
|
#include "metacontactselectorwidget.h"
|
|
|
|
#include "kopeteemoticons.h"
|
|
|
|
|
|
|
|
//For the moving to another metacontact dialog
|
|
|
|
#include <tqlabel.h>
|
|
|
|
#include <tqimage.h>
|
|
|
|
#include <tqmime.h>
|
|
|
|
#include <tqvbox.h>
|
|
|
|
#include <klistview.h>
|
|
|
|
#include <tqcheckbox.h>
|
|
|
|
#include <tqwhatsthis.h>
|
|
|
|
#include <tqstylesheet.h>
|
|
|
|
|
|
|
|
namespace Kopete {
|
|
|
|
|
|
|
|
struct Contact::Private
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
bool fileCapable;
|
|
|
|
|
|
|
|
OnlineStatus onlinetqStatus;
|
|
|
|
Account *account;
|
|
|
|
|
|
|
|
MetaContact *metaContact;
|
|
|
|
|
|
|
|
TQString contactId;
|
|
|
|
TQString icon;
|
|
|
|
|
|
|
|
TQTime idleTimer;
|
|
|
|
unsigned long int idleTime;
|
|
|
|
|
|
|
|
Kopete::ContactProperty::Map properties;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
Contact::Contact( Account *account, const TQString &contactId,
|
|
|
|
MetaContact *tqparent, const TQString &icon )
|
|
|
|
: TQObject( tqparent )
|
|
|
|
{
|
|
|
|
d = new Private;
|
|
|
|
|
|
|
|
//kdDebug( 14010 ) << k_funcinfo << "Creating contact with id " << contactId << endl;
|
|
|
|
|
|
|
|
d->contactId = contactId;
|
|
|
|
d->metaContact = tqparent;
|
|
|
|
d->fileCapable = false;
|
|
|
|
d->account = account;
|
|
|
|
d->idleTime = 0;
|
|
|
|
d->icon = icon;
|
|
|
|
|
|
|
|
// If can happend that a MetaContact may be used without a account
|
|
|
|
// (ex: for unit tests or chat window style preview)
|
|
|
|
if ( account )
|
|
|
|
{
|
|
|
|
account->registerContact( this );
|
|
|
|
connect( account, TQT_SIGNAL( isConnectedChanged() ), TQT_SLOT( slotAccountIsConnectedChanged() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Need to check this because myself() may have no tqparent
|
|
|
|
// Maybe too the metaContact doesn't have a valid protocol()
|
|
|
|
// (ex: for unit tests or chat window style preview)
|
|
|
|
if( tqparent && protocol() )
|
|
|
|
{
|
|
|
|
connect( tqparent, TQT_SIGNAL( aboutToSave( Kopete::MetaContact * ) ),
|
|
|
|
protocol(), TQT_SLOT( slotMetaContactAboutToSave( Kopete::MetaContact * ) ) );
|
|
|
|
|
|
|
|
tqparent->addContact( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Contact::~Contact()
|
|
|
|
{
|
|
|
|
//kdDebug(14010) << k_funcinfo << endl;
|
|
|
|
emit( contactDestroyed( this ) );
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OnlineStatus Contact::onlinetqStatus() const
|
|
|
|
{
|
|
|
|
if ( this == account()->myself() || account()->isConnected() )
|
|
|
|
return d->onlinetqStatus;
|
|
|
|
else
|
|
|
|
return protocol()->accountOfflinetqStatus();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::setOnlineStatus( const OnlineStatus &status )
|
|
|
|
{
|
|
|
|
if( status == d->onlinetqStatus )
|
|
|
|
return;
|
|
|
|
|
|
|
|
OnlineStatus oldtqStatus = d->onlinetqStatus;
|
|
|
|
d->onlinetqStatus = status;
|
|
|
|
|
|
|
|
Kopete::Global::Properties *globalProps = Kopete::Global::Properties::self();
|
|
|
|
|
|
|
|
// Contact changed from Offline to another status
|
|
|
|
if( oldtqStatus.status() == OnlineStatus::Offline &&
|
|
|
|
status.status() != OnlineStatus::Offline )
|
|
|
|
{
|
|
|
|
setProperty( globalProps->onlineSince(), TQDateTime::tqcurrentDateTime() );
|
|
|
|
/*kdDebug(14010) << k_funcinfo << "REMOVING lastSeen property for " <<
|
|
|
|
d->displayName << endl;*/
|
|
|
|
removeProperty( globalProps->lastSeen() );
|
|
|
|
}
|
|
|
|
else if( oldtqStatus.status() != OnlineStatus::Offline &&
|
|
|
|
oldtqStatus.status() != OnlineStatus::Unknown &&
|
|
|
|
status.status() == OnlineStatus::Offline ) // Contact went back offline
|
|
|
|
{
|
|
|
|
removeProperty( globalProps->onlineSince() );
|
|
|
|
/*kdDebug(14010) << k_funcinfo << "SETTING lastSeen property for " <<
|
|
|
|
d->displayName << endl;*/
|
|
|
|
setProperty( globalProps->lastSeen(), TQDateTime::tqcurrentDateTime() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( this == account()->myself() || account()->isConnected() )
|
|
|
|
emit onlineStatusChanged( this, status, oldtqStatus );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::slotAccountIsConnectedChanged()
|
|
|
|
{
|
|
|
|
if ( this == account()->myself() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( account()->isConnected() )
|
|
|
|
emit onlineStatusChanged( this, d->onlinetqStatus, protocol()->accountOfflinetqStatus() );
|
|
|
|
else
|
|
|
|
emit onlineStatusChanged( this, protocol()->accountOfflinetqStatus(), d->onlinetqStatus );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Contact::sendFile( const KURL &, const TQString &, uint )
|
|
|
|
{
|
|
|
|
kdWarning( 14010 ) << k_funcinfo << "Plugin "
|
|
|
|
<< protocol()->pluginId() << " has enabled file sending, "
|
|
|
|
<< "but didn't implement it!" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::slotAddContact()
|
|
|
|
{
|
|
|
|
if( metaContact() )
|
|
|
|
{
|
|
|
|
metaContact()->setTemporary( false );
|
|
|
|
ContactList::self()->addMetaContact( metaContact() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KPopupMenu* Contact::popupMenu( ChatSession *manager )
|
|
|
|
{
|
|
|
|
// Build the menu
|
|
|
|
KPopupMenu *menu = new KPopupMenu();
|
|
|
|
|
|
|
|
// insert title
|
|
|
|
TQString titleText;
|
|
|
|
TQString nick = property( Kopete::Global::Properties::self()->nickName() ).value().toString();
|
|
|
|
if( nick.isEmpty() )
|
|
|
|
titleText = TQString::tqfromLatin1( "%1 (%2)" ).tqarg( contactId(), onlinetqStatus().description() );
|
|
|
|
else
|
|
|
|
titleText = TQString::tqfromLatin1( "%1 <%2> (%3)" ).tqarg( nick, contactId(), onlinetqStatus().description() );
|
|
|
|
menu->insertTitle( titleText );
|
|
|
|
|
|
|
|
if( metaContact() && metaContact()->isTemporary() && contactId() != account()->myself()->contactId() )
|
|
|
|
{
|
|
|
|
KAction *actionAddContact = new KAction( i18n( "&Add to Your Contact List" ), TQString::tqfromLatin1( "add_user" ),
|
|
|
|
0, TQT_TQOBJECT(this), TQT_SLOT( slotAddContact() ), TQT_TQOBJECT(menu), "actionAddContact" );
|
|
|
|
actionAddContact->plug( menu );
|
|
|
|
menu->insertSeparator();
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: After KDE 3.2 we should make isReachable do the isConnected call so it can be removed here - Martijn
|
|
|
|
bool reach = account()->isConnected() && isReachable();
|
|
|
|
bool myself = (this == account()->myself());
|
|
|
|
|
|
|
|
KAction *actionSendMessage = KopeteStdAction::sendMessage( TQT_TQOBJECT(this), TQT_SLOT( sendMessage() ), TQT_TQOBJECT(menu), "actionSendMessage" );
|
|
|
|
actionSendMessage->setEnabled( reach && !myself );
|
|
|
|
actionSendMessage->plug( menu );
|
|
|
|
|
|
|
|
KAction *actionChat = KopeteStdAction::chat( TQT_TQOBJECT(this), TQT_SLOT( startChat() ), TQT_TQOBJECT(menu), "actionChat" );
|
|
|
|
actionChat->setEnabled( reach && !myself );
|
|
|
|
actionChat->plug( menu );
|
|
|
|
|
|
|
|
KAction *actionSendFile = KopeteStdAction::sendFile( TQT_TQOBJECT(this), TQT_SLOT( sendFile() ), TQT_TQOBJECT(menu), "actionSendFile" );
|
|
|
|
actionSendFile->setEnabled( reach && d->fileCapable && !myself );
|
|
|
|
actionSendFile->plug( menu );
|
|
|
|
|
|
|
|
// Protocol specific options will go below this separator
|
|
|
|
// through the use of the customContextMenuActions() function
|
|
|
|
|
|
|
|
// Get the custom actions from the protocols ( pure virtual function )
|
|
|
|
TQPtrList<KAction> *customActions = customContextMenuActions( manager );
|
|
|
|
if( customActions && !customActions->isEmpty() )
|
|
|
|
{
|
|
|
|
menu->insertSeparator();
|
|
|
|
|
|
|
|
for( KAction *a = customActions->first(); a; a = customActions->next() )
|
|
|
|
a->plug( menu );
|
|
|
|
}
|
|
|
|
delete customActions;
|
|
|
|
|
|
|
|
menu->insertSeparator();
|
|
|
|
|
|
|
|
if( metaContact() && !metaContact()->isTemporary() )
|
|
|
|
KopeteStdAction::changeMetaContact( TQT_TQOBJECT(this), TQT_SLOT( changeMetaContact() ), TQT_TQOBJECT(menu), "actionChangeMetaContact" )->plug( menu );
|
|
|
|
|
|
|
|
KopeteStdAction::contactInfo( TQT_TQOBJECT(this), TQT_SLOT( slotUserInfo() ), TQT_TQOBJECT(menu), "actionUserInfo" )->plug( menu );
|
|
|
|
|
|
|
|
#if 0 //this is not fully implemented yet (and doesn't work). disable for now - Olivier 2005-01-11
|
|
|
|
if ( account()->isBlocked( d->contactId ) )
|
|
|
|
KopeteStdAction::unblockContact( this, TQT_SLOT( slotUnblock() ), menu, "actionUnblockContact" )->plug( menu );
|
|
|
|
else
|
|
|
|
KopeteStdAction::blockContact( this, TQT_SLOT( slotBlock() ), menu, "actionBlockContact" )->plug( menu );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if( metaContact() && !metaContact()->isTemporary() )
|
|
|
|
KopeteStdAction::deleteContact( TQT_TQOBJECT(this), TQT_SLOT( slotDelete() ), TQT_TQOBJECT(menu), "actionDeleteContact" )->plug( menu );
|
|
|
|
|
|
|
|
return menu;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::changeMetaContact()
|
|
|
|
{
|
|
|
|
KDialogBase *moveDialog = new KDialogBase( Kopete::UI::Global::mainWidget(), "moveDialog", true, i18n( "Move Contact" ),
|
|
|
|
KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, true );
|
|
|
|
|
|
|
|
TQVBox *w = new TQVBox( moveDialog );
|
|
|
|
w->setSpacing( KDialog::spacingHint() );
|
|
|
|
Kopete::UI::MetaContactSelectorWidget *selector = new Kopete::UI::MetaContactSelectorWidget(w);
|
|
|
|
selector->setLabelMessage(i18n( "Select the meta contact to which you want to move this contact:" ));
|
|
|
|
// exclude this metacontact as a target metacontact for the move
|
|
|
|
selector->excludeMetaContact( metaContact() );
|
|
|
|
TQCheckBox *chkCreateNew = new TQCheckBox( i18n( "Create a new metacontact for this contact" ), w );
|
|
|
|
TQWhatsThis::add( chkCreateNew , i18n( "If you select this option, a new metacontact will be created in the top-level group "
|
|
|
|
"with the name of this contact and the contact will be moved to it." ) );
|
|
|
|
TQObject::connect( chkCreateNew , TQT_SIGNAL( toggled(bool) ) , selector , TQT_SLOT ( setDisabled(bool) ) ) ;
|
|
|
|
|
|
|
|
moveDialog->setMainWidget(w);
|
|
|
|
if( moveDialog->exec() == TQDialog::Accepted )
|
|
|
|
{
|
|
|
|
Kopete::MetaContact *mc = selector->metaContact();
|
|
|
|
if(chkCreateNew->isChecked())
|
|
|
|
{
|
|
|
|
mc=new Kopete::MetaContact();
|
|
|
|
Kopete::ContactList::self()->addMetaContact(mc);
|
|
|
|
}
|
|
|
|
if( mc )
|
|
|
|
{
|
|
|
|
setMetaContact( mc );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
moveDialog->deleteLater();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::setMetaContact( MetaContact *m )
|
|
|
|
{
|
|
|
|
MetaContact *old = d->metaContact;
|
|
|
|
if(old==m) //that make no sens
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( old )
|
|
|
|
{
|
|
|
|
int result=KMessageBox::No;
|
|
|
|
if( old->isTemporary() )
|
|
|
|
result=KMessageBox::Yes;
|
|
|
|
else if( old->contacts().count()==1 )
|
|
|
|
{ //only one contact, including this one, that mean the contact will be empty efter the move
|
|
|
|
result = KMessageBox::questionYesNoCancel( Kopete::UI::Global::mainWidget(), i18n( "You are moving the contact `%1' to the meta contact `%2'.\n"
|
|
|
|
"`%3' will be empty afterwards. Do you want to delete this contact?" )
|
|
|
|
.tqarg(contactId(), m ? m->displayName() : TQString(), old->displayName())
|
|
|
|
, i18n( "Move Contact" ), KStdGuiItem::del(), i18n( "&Keep" ) , TQString::tqfromLatin1("delete_old_contact_when_move") );
|
|
|
|
if(result==KMessageBox::Cancel)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
old->removeContact( this );
|
|
|
|
disconnect( old, TQT_SIGNAL( aboutToSave( Kopete::MetaContact * ) ),
|
|
|
|
protocol(), TQT_SLOT( slotMetaContactAboutToSave( Kopete::MetaContact * ) ) );
|
|
|
|
|
|
|
|
if(result==KMessageBox::Yes)
|
|
|
|
{
|
|
|
|
//remove the old metacontact. (this delete the MC)
|
|
|
|
ContactList::self()->removeMetaContact(old);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->metaContact = m; //i am forced to do that now if i want the next line works
|
|
|
|
//remove cached data for this protocol which will not be removed since we disconnected
|
|
|
|
protocol()->slotMetaContactAboutToSave( old );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d->metaContact = m;
|
|
|
|
|
|
|
|
if( m )
|
|
|
|
{
|
|
|
|
m->addContact( this );
|
|
|
|
m->insertChild( this );
|
|
|
|
// it is necessary to call this write here, because MetaContact::addContact() does not differentiate
|
|
|
|
// between adding completely new contacts (which should be written to kabc) and restoring upon restart
|
|
|
|
// (where no write is needed).
|
|
|
|
KABCPersistence::self()->write( m );
|
|
|
|
connect( d->metaContact, TQT_SIGNAL( aboutToSave( Kopete::MetaContact * ) ),
|
|
|
|
protocol(), TQT_SLOT( slotMetaContactAboutToSave( Kopete::MetaContact * ) ) );
|
|
|
|
}
|
|
|
|
sync();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::serialize( TQMap<TQString, TQString> &/*serializedData*/,
|
|
|
|
TQMap<TQString, TQString> & /* addressBookData */ )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Contact::serializeProperties(TQMap<TQString, TQString> &serializedData)
|
|
|
|
{
|
|
|
|
|
|
|
|
Kopete::ContactProperty::Map::ConstIterator it;// = d->properties.ConstIterator;
|
|
|
|
for (it=d->properties.begin(); it != d->properties.end(); ++it)
|
|
|
|
{
|
|
|
|
if (!it.data().tmpl().persistent())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
TQVariant val = it.data().value();
|
|
|
|
TQString key = TQString::tqfromLatin1("prop_%1_%2").tqarg(TQString::tqfromLatin1(val.typeName()), it.key());
|
|
|
|
|
|
|
|
serializedData[key] = val.toString();
|
|
|
|
|
|
|
|
} // end for()
|
|
|
|
} // end serializeProperties()
|
|
|
|
|
|
|
|
void Contact::deserializeProperties(
|
|
|
|
TQMap<TQString, TQString> &serializedData )
|
|
|
|
{
|
|
|
|
TQMap<TQString, TQString>::ConstIterator it;
|
|
|
|
for ( it=serializedData.begin(); it != serializedData.end(); ++it )
|
|
|
|
{
|
|
|
|
TQString key = it.key();
|
|
|
|
|
|
|
|
if ( !key.startsWith( TQString::tqfromLatin1("prop_") ) ) // avoid parsing other serialized data
|
|
|
|
continue;
|
|
|
|
|
|
|
|
TQStringList keyList = TQStringList::split( TQChar('_'), key, false );
|
|
|
|
if( keyList.count() < 3 ) // invalid key, not enough parts in string "prop_X_Y"
|
|
|
|
continue;
|
|
|
|
|
|
|
|
key = keyList[2]; // overwrite key var with the real key name this property has
|
|
|
|
TQString type( keyList[1] ); // needed for TQVariant casting
|
|
|
|
|
|
|
|
TQVariant variant( it.data() );
|
|
|
|
if( !variant.cast(TQVariant::nameToType(type.latin1())) )
|
|
|
|
{
|
|
|
|
kdDebug(14010) << k_funcinfo <<
|
|
|
|
"Casting TQVariant to needed type FAILED" <<
|
|
|
|
"key=" << key << ", type=" << type << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Kopete::ContactPropertyTmpl tmpl = Kopete::Global::Properties::self()->tmpl(key);
|
|
|
|
if( tmpl.isNull() )
|
|
|
|
{
|
|
|
|
kdDebug( 14010 ) << k_funcinfo << "no ContactPropertyTmpl defined for" \
|
|
|
|
" key " << key << ", cannot restore persistent property" << endl;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
setProperty(tmpl, variant);
|
|
|
|
} // end for()
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Contact::isReachable()
|
|
|
|
{
|
|
|
|
// The default implementation returns false when offline and true
|
|
|
|
// otherwise. Subclass if you need more control over the process.
|
|
|
|
return onlinetqStatus().status() != OnlineStatus::Offline;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Contact::startChat()
|
|
|
|
{
|
|
|
|
KopeteView *v=manager( CanCreate )->view(true, TQString::tqfromLatin1("kopete_chatwindow") );
|
|
|
|
if(v)
|
|
|
|
v->raise(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::sendMessage()
|
|
|
|
{
|
|
|
|
KopeteView *v=manager( CanCreate )->view(true, TQString::tqfromLatin1("kopete_emailwindow") );
|
|
|
|
if(v)
|
|
|
|
v->raise(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::execute()
|
|
|
|
{
|
|
|
|
// FIXME: After KDE 3.2 remove the isConnected check and move it to isReachable - Martijn
|
|
|
|
if ( account()->isConnected() && isReachable() )
|
|
|
|
{
|
|
|
|
KopeteView *v=manager( CanCreate )->view(true, KopetePrefs::prefs()->interfacePreference() );
|
|
|
|
if(v)
|
|
|
|
v->raise(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
|
|
|
|
i18n( "This user is not reachable at the moment. Please try a protocol that supports offline sending, or wait "
|
|
|
|
"until this user comes online." ), i18n( "User is Not Reachable" ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::slotDelete()
|
|
|
|
{
|
|
|
|
if ( KMessageBox::warningContinueCancel( Kopete::UI::Global::mainWidget(),
|
|
|
|
i18n( "Are you sure you want to remove the contact '%1' from your contact list?" ).
|
|
|
|
arg( d->contactId ), i18n( "Remove Contact" ), KGuiItem(i18n("Remove"), TQString::tqfromLatin1("delete_user") ),
|
|
|
|
TQString::tqfromLatin1("askRemoveContact"), KMessageBox::Notify | KMessageBox::Dangerous )
|
|
|
|
== KMessageBox::Continue )
|
|
|
|
{
|
|
|
|
deleteContact();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::deleteContact()
|
|
|
|
{
|
|
|
|
// Default implementation simply deletes the contact
|
|
|
|
deleteLater();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MetaContact * Contact::metaContact() const
|
|
|
|
{
|
|
|
|
return d->metaContact;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Contact::contactId() const
|
|
|
|
{
|
|
|
|
return d->contactId;
|
|
|
|
}
|
|
|
|
|
|
|
|
Protocol * Contact::protocol() const
|
|
|
|
{
|
|
|
|
return d->account ? d->account->protocol() : 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
Account * Contact::account() const
|
|
|
|
{
|
|
|
|
return d->account;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Contact::sync(unsigned int)
|
|
|
|
{
|
|
|
|
/* Default implementation does nothing */
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString& Contact::icon() const
|
|
|
|
{
|
|
|
|
return d->icon;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::setIcon( const TQString& icon )
|
|
|
|
{
|
|
|
|
d->icon = icon;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPtrList<KAction> *Contact::customContextMenuActions()
|
|
|
|
{
|
|
|
|
return 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQPtrList<KAction> *Contact::customContextMenuActions( ChatSession * /* manager */ )
|
|
|
|
{
|
|
|
|
return customContextMenuActions();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Contact::isOnline() const
|
|
|
|
{
|
|
|
|
return onlinetqStatus().isDefinitelyOnline();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Contact::isFileCapable() const
|
|
|
|
{
|
|
|
|
return d->fileCapable;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::setFileCapable( bool filecap )
|
|
|
|
{
|
|
|
|
d->fileCapable = filecap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Contact::canAcceptFiles() const
|
|
|
|
{
|
|
|
|
return isOnline() && d->fileCapable;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long int Contact::idleTime() const
|
|
|
|
{
|
|
|
|
if(d->idleTime==0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return d->idleTime+(d->idleTimer.elapsed()/1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::setIdleTime( unsigned long int t )
|
|
|
|
{
|
|
|
|
bool idleChanged = false;
|
|
|
|
if(d->idleTime != t)
|
|
|
|
idleChanged = true;
|
|
|
|
d->idleTime=t;
|
|
|
|
if(t > 0)
|
|
|
|
d->idleTimer.start();
|
|
|
|
//FIXME: if t == 0, idleTime() will now return garbage
|
|
|
|
// else
|
|
|
|
// d->idleTimer.stop();
|
|
|
|
if(idleChanged)
|
|
|
|
emit idleStateChanged(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQStringList Contact::properties() const
|
|
|
|
{
|
|
|
|
return d->properties.keys();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Contact::hasProperty(const TQString &key) const
|
|
|
|
{
|
|
|
|
return d->properties.tqcontains(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
const ContactProperty &Contact::property(const TQString &key) const
|
|
|
|
{
|
|
|
|
if(hasProperty(key))
|
|
|
|
return d->properties[key];
|
|
|
|
else
|
|
|
|
return Kopete::ContactProperty::null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Kopete::ContactProperty &Contact::property(
|
|
|
|
const Kopete::ContactPropertyTmpl &tmpl) const
|
|
|
|
{
|
|
|
|
if(hasProperty(tmpl.key()))
|
|
|
|
return d->properties[tmpl.key()];
|
|
|
|
else
|
|
|
|
return Kopete::ContactProperty::null;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Contact::setProperty(const Kopete::ContactPropertyTmpl &tmpl,
|
|
|
|
const TQVariant &value)
|
|
|
|
{
|
|
|
|
if(tmpl.isNull() || tmpl.key().isEmpty())
|
|
|
|
{
|
|
|
|
kdDebug(14000) << k_funcinfo <<
|
|
|
|
"No valid template for property passed!" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(value.isNull() || value.canCast(TQVariant::String) && value.toString().isEmpty())
|
|
|
|
{
|
|
|
|
removeProperty(tmpl);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TQVariant oldValue = property(tmpl.key()).value();
|
|
|
|
|
|
|
|
if(oldValue != value)
|
|
|
|
{
|
|
|
|
Kopete::ContactProperty prop(tmpl, value);
|
|
|
|
d->properties.insert(tmpl.key(), prop, true);
|
|
|
|
|
|
|
|
emit propertyChanged(this, tmpl.key(), oldValue, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::removeProperty(const Kopete::ContactPropertyTmpl &tmpl)
|
|
|
|
{
|
|
|
|
if(!tmpl.isNull() && !tmpl.key().isEmpty())
|
|
|
|
{
|
|
|
|
|
|
|
|
TQVariant oldValue = property(tmpl.key()).value();
|
|
|
|
d->properties.remove(tmpl.key());
|
|
|
|
emit propertyChanged(this, tmpl.key(), oldValue, TQVariant());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TQString Contact::toolTip() const
|
|
|
|
{
|
|
|
|
Kopete::ContactProperty p;
|
|
|
|
TQString tip;
|
|
|
|
TQStringList shownProps = KopetePrefs::prefs()->toolTipContents();
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
// Fixed part of tooltip
|
|
|
|
|
|
|
|
TQString iconName = TQString::tqfromLatin1("kopete-contact-icon:%1:%2:%3")
|
|
|
|
.tqarg( KURL::encode_string( protocol()->pluginId() ),
|
|
|
|
KURL::encode_string( account()->accountId() ),
|
|
|
|
KURL::encode_string( contactId() ) );
|
|
|
|
|
|
|
|
// TODO: the nickname should be a configurable properties, like others. -Olivier
|
|
|
|
TQString nick = property( Kopete::Global::Properties::self()->nickName() ).value().toString();
|
|
|
|
if ( nick.isEmpty() )
|
|
|
|
{
|
|
|
|
tip = i18n( "<b>DISPLAY NAME</b><br><img src=\"%2\"> CONTACT STATUS",
|
|
|
|
"<b><nobr>%3</nobr></b><br><img src=\"%2\"> %1" ).
|
|
|
|
arg( Kopete::Message::escape( onlinetqStatus().description() ), iconName,
|
|
|
|
Kopete::Message::escape( d->contactId ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tip = i18n( "<b>DISPLAY NAME</b> (CONTACT ID)<br><img src=\"%2\"> CONTACT STATUS",
|
|
|
|
"<nobr><b>%4</b> (%3)</nobr><br><img src=\"%2\"> %1" ).
|
|
|
|
arg( Kopete::Message::escape( onlinetqStatus().description() ), iconName,
|
|
|
|
Kopete::Message::escape( contactId() ),
|
|
|
|
Kopete::Emoticons::parseEmoticons( Kopete::Message::escape( nick ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
// Configurable part of tooltip
|
|
|
|
|
|
|
|
for(TQStringList::Iterator it=shownProps.begin(); it!=shownProps.end(); ++it)
|
|
|
|
{
|
|
|
|
if((*it) == TQString::tqfromLatin1("FormattedName"))
|
|
|
|
{
|
|
|
|
TQString name = formattedName();
|
|
|
|
if(!name.isEmpty())
|
|
|
|
{
|
|
|
|
tip += i18n("<br><b>Full Name:</b> FORMATTED NAME",
|
|
|
|
"<br><b>Full Name:</b> <nobr>%1</nobr>").tqarg(TQStyleSheet::escape(name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((*it) == TQString::tqfromLatin1("FormattedIdleTime"))
|
|
|
|
{
|
|
|
|
TQString time = formattedIdleTime();
|
|
|
|
if(!time.isEmpty())
|
|
|
|
{
|
|
|
|
tip += i18n("<br><b>Idle:</b> FORMATTED IDLE TIME",
|
|
|
|
"<br><b>Idle:</b> <nobr>%1</nobr>").tqarg(time);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((*it) == TQString::tqfromLatin1("homePage"))
|
|
|
|
{
|
|
|
|
TQString url = property(*it).value().toString();
|
|
|
|
if(!url.isEmpty())
|
|
|
|
{
|
|
|
|
tip += i18n("<br><b>Home Page:</b> FORMATTED URL",
|
|
|
|
"<br><b>Home Page:</b> <a href=\"%1\"><nobr>%2</nobr></a>").
|
|
|
|
arg( KURL::encode_string( url ), Kopete::Message::escape( TQStyleSheet::escape(url) ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((*it) == TQString::tqfromLatin1("awayMessage"))
|
|
|
|
{
|
|
|
|
TQString awaymsg = property(*it).value().toString();
|
|
|
|
if(!awaymsg.isEmpty())
|
|
|
|
{
|
|
|
|
tip += i18n("<br><b>Away Message:</b> FORMATTED AWAY MESSAGE",
|
|
|
|
"<br><b>Away Message:</b> %1").arg ( Kopete::Emoticons::parseEmoticons( Kopete::Message::escape(awaymsg) ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p = property(*it);
|
|
|
|
if(!p.isNull())
|
|
|
|
{
|
|
|
|
TQVariant val = p.value();
|
|
|
|
TQString valueText;
|
|
|
|
|
|
|
|
switch(val.type())
|
|
|
|
{
|
|
|
|
case TQVariant::DateTime:
|
|
|
|
valueText = KGlobal::locale()->formatDateTime(val.toDateTime());
|
|
|
|
valueText = Kopete::Message::escape( valueText );
|
|
|
|
break;
|
|
|
|
case TQVariant::Date:
|
|
|
|
valueText = KGlobal::locale()->formatDate(val.toDate());
|
|
|
|
valueText = Kopete::Message::escape( valueText );
|
|
|
|
break;
|
|
|
|
case TQVariant::Time:
|
|
|
|
valueText = KGlobal::locale()->formatTime(val.toTime());
|
|
|
|
valueText = Kopete::Message::escape( valueText );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if( p.isRichText() )
|
|
|
|
{
|
|
|
|
valueText = val.toString();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
valueText = Kopete::Message::escape( val.toString() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tip += i18n("<br><b>PROPERTY LABEL:</b> PROPERTY VALUE",
|
|
|
|
"<br><nobr><b>%2:</b></nobr> %1").
|
|
|
|
arg( valueText, TQStyleSheet::escape(p.tmpl().label()) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tip;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Kopete::Contact::formattedName() const
|
|
|
|
{
|
|
|
|
if( hasProperty(TQString::tqfromLatin1("FormattedName")) )
|
|
|
|
return property(TQString::tqfromLatin1("FormattedName")).value().toString();
|
|
|
|
|
|
|
|
TQString ret;
|
|
|
|
Kopete::ContactProperty first, last;
|
|
|
|
|
|
|
|
first = property(TQString::tqfromLatin1("firstName"));
|
|
|
|
last = property(TQString::tqfromLatin1("lastName"));
|
|
|
|
if(!first.isNull())
|
|
|
|
{
|
|
|
|
if(!last.isNull()) // contact has both first and last name
|
|
|
|
{
|
|
|
|
ret = i18n("firstName lastName", "%2 %1")
|
|
|
|
.tqarg(last.value().toString())
|
|
|
|
.tqarg(first.value().toString());
|
|
|
|
}
|
|
|
|
else // only first name set
|
|
|
|
{
|
|
|
|
ret = first.value().toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(!last.isNull()) // only last name set
|
|
|
|
{
|
|
|
|
ret = last.value().toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Kopete::Contact::formattedIdleTime() const
|
|
|
|
{
|
|
|
|
TQString ret;
|
|
|
|
unsigned long int leftTime = idleTime();
|
|
|
|
|
|
|
|
if ( leftTime > 0 )
|
|
|
|
{ // FIXME: duplicated from code in kopetecontactlistview.cpp
|
|
|
|
unsigned long int days, hours, mins, secs;
|
|
|
|
|
|
|
|
days = leftTime / ( 60*60*24 );
|
|
|
|
leftTime = leftTime % ( 60*60*24 );
|
|
|
|
hours = leftTime / ( 60*60 );
|
|
|
|
leftTime = leftTime % ( 60*60 );
|
|
|
|
mins = leftTime / 60;
|
|
|
|
secs = leftTime % 60;
|
|
|
|
|
|
|
|
if ( days != 0 )
|
|
|
|
{
|
|
|
|
ret = i18n( "<days>d <hours>h <minutes>m <seconds>s",
|
|
|
|
"%4d %3h %2m %1s" )
|
|
|
|
.tqarg( secs )
|
|
|
|
.tqarg( mins )
|
|
|
|
.tqarg( hours )
|
|
|
|
.tqarg( days );
|
|
|
|
}
|
|
|
|
else if ( hours != 0 )
|
|
|
|
{
|
|
|
|
ret = i18n( "<hours>h <minutes>m <seconds>s", "%3h %2m %1s" )
|
|
|
|
.tqarg( secs )
|
|
|
|
.tqarg( mins )
|
|
|
|
.tqarg( hours );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret = i18n( "<minutes>m <seconds>s", "%2m %1s" )
|
|
|
|
.tqarg( secs )
|
|
|
|
.tqarg( mins );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Kopete::Contact::slotBlock()
|
|
|
|
{
|
|
|
|
account()->block( d->contactId );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Kopete::Contact::slotUnblock()
|
|
|
|
{
|
|
|
|
account()->unblock( d->contactId );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Kopete::Contact::setNickName( const TQString &name )
|
|
|
|
{
|
|
|
|
setProperty( Kopete::Global::Properties::self()->nickName(), name );
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Kopete::Contact::nickName() const
|
|
|
|
{
|
|
|
|
TQString nick = property( Kopete::Global::Properties::self()->nickName() ).value().toString();
|
|
|
|
if( !nick.isEmpty() )
|
|
|
|
return nick;
|
|
|
|
|
|
|
|
return contactId();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Contact::virtual_hook( uint , void * )
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
} //END namespace Kopete
|
|
|
|
|
|
|
|
|
|
|
|
#include "kopetecontact.moc"
|
|
|
|
|
|
|
|
|