~ubuntu-branches/ubuntu/saucy/kopete/saucy-proposed

« back to all changes in this revision

Viewing changes to libkopete/kopetecontact.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-06-21 02:22:39 UTC
  • Revision ID: package-import@ubuntu.com-20130621022239-63l3zc8p0nf26pt6
Tags: upstream-4.10.80
ImportĀ upstreamĀ versionĀ 4.10.80

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    kopetecontact.cpp - Kopete Contact
 
3
 
 
4
    Copyright (c) 2002-2004 by Duncan Mac-Vicar Prett <duncan@kde.org>
 
5
    Copyright (c) 2002-2003 by Martijn Klingens       <klingens@kde.org>
 
6
    Copyright (c) 2002-2004 by Olivier Goffart        <ogoffart @ kde.org>
 
7
 
 
8
    Kopete    (c) 2002-2004 by the Kopete developers  <kopete-devel@kde.org>
 
9
 
 
10
    *************************************************************************
 
11
    *                                                                       *
 
12
    * This library is free software; you can redistribute it and/or         *
 
13
    * modify it under the terms of the GNU Lesser General Public            *
 
14
    * License as published by the Free Software Foundation; either          *
 
15
    * version 2 of the License, or (at your option) any later version.      *
 
16
    *                                                                       *
 
17
    *************************************************************************
 
18
*/
 
19
 
 
20
#include "kopetecontact.h"
 
21
 
 
22
#include <QApplication>
 
23
#include <QTextDocument>
 
24
#include <QTimer>
 
25
 
 
26
#include <KDebug>
 
27
 
 
28
#include <kdeversion.h>
 
29
#include <kinputdialog.h>
 
30
 
 
31
#include <kabcpersistence.h>
 
32
#include <kdialog.h>
 
33
#include <klocale.h>
 
34
#include <kicon.h>
 
35
#include <kmenu.h>
 
36
#include <kmessagebox.h>
 
37
#include <k3listviewsearchline.h>
 
38
 
 
39
#include "kopetecontactlist.h"
 
40
#include "kopeteglobal.h"
 
41
#include "kopeteuiglobal.h"
 
42
#include "kopeteprotocol.h"
 
43
#include "kopeteaccount.h"
 
44
#include "kopetestdaction.h"
 
45
#include "kopetechatsession.h"
 
46
#include "kopeteview.h"
 
47
#include "kopetemetacontact.h"
 
48
#include "kopeteappearancesettings.h"
 
49
#include "kopetebehaviorsettings.h"
 
50
#include "metacontactselectorwidget.h"
 
51
#include "kopeteemoticons.h"
 
52
#include "kopetestatusmessage.h"
 
53
#include "kopeteinfodialog.h"
 
54
#include "kopetedeletecontacttask.h"
 
55
 
 
56
//For the moving to another metacontact dialog
 
57
#include <qlabel.h>
 
58
#include <qimage.h>
 
59
#include <qmime.h>
 
60
#include <kvbox.h>
 
61
#include <k3listview.h>
 
62
#include <qcheckbox.h>
 
63
 
 
64
 
 
65
namespace Kopete {
 
66
 
 
67
class Contact::Private
 
68
{
 
69
public:
 
70
        bool fileCapable;
 
71
 
 
72
        OnlineStatus onlineStatus;
 
73
        Account *account;
 
74
 
 
75
        MetaContact *metaContact;
 
76
 
 
77
        QString contactId;
 
78
        QString icon;
 
79
 
 
80
        QTime idleTimer;
 
81
        unsigned long int idleTime;
 
82
 
 
83
        Kopete::StatusMessage statusMessage;
 
84
        KToggleAction* toggleAlwaysVisibleAction;
 
85
};
 
86
 
 
87
Contact::Contact( Account *account, const QString &contactId,
 
88
        MetaContact *parent, const QString &icon )
 
89
        : ContactListElement( parent ), d(new Private())
 
90
{
 
91
        //kDebug( 14010 ) << "Creating contact with id " << contactId;
 
92
 
 
93
        d->contactId = contactId;
 
94
        d->metaContact = parent;
 
95
        connect( d->metaContact, SIGNAL(destroyed(QObject*)), this, SLOT(slotMetaContactDestroyed(QObject*)) );
 
96
 
 
97
        d->fileCapable = false;
 
98
        d->account = account;
 
99
        d->idleTime = 0;
 
100
        d->icon = icon;
 
101
 
 
102
        bool duplicate = false;
 
103
        // If can happend that a MetaContact may be used without a account
 
104
        // (ex: for unit tests or chat window style preview)
 
105
        if ( account )
 
106
        {
 
107
                // Don't register myself contacts because otherwise we can't have own contact in contact list.
 
108
                if ( d->metaContact != Kopete::ContactList::self()->myself() )
 
109
                        duplicate = !account->registerContact( this );
 
110
 
 
111
                connect( account, SIGNAL(isConnectedChanged()), SLOT(slotAccountIsConnectedChanged()) );
 
112
        }
 
113
 
 
114
        // Need to check this because myself() may have no parent
 
115
        // Maybe too the metaContact doesn't have a valid protocol()
 
116
        // (ex: for unit tests or chat window style preview)
 
117
 
 
118
        // if alreadyRegistered is true (which mean that this is duplicate contact) we will not add
 
119
        // parent and the contact will die out on next Kopete restart.
 
120
        if( !duplicate && parent && protocol() )
 
121
                parent->addContact( this );
 
122
}
 
123
 
 
124
Contact::~Contact()
 
125
{
 
126
        //kDebug(14010) ;
 
127
        emit( contactDestroyed( this ) );
 
128
        delete d;
 
129
}
 
130
 
 
131
 
 
132
 
 
133
OnlineStatus Contact::onlineStatus() const
 
134
{
 
135
        if ( this == account()->myself() || account()->isConnected() )
 
136
                return d->onlineStatus;
 
137
        else
 
138
                return protocol()->accountOfflineStatus();
 
139
}
 
140
 
 
141
void Contact::setOnlineStatus( const OnlineStatus &status )
 
142
{
 
143
        if( status == d->onlineStatus )
 
144
                return;
 
145
 
 
146
        const bool oldCanAcceptFiles = canAcceptFiles();
 
147
        OnlineStatus oldStatus = d->onlineStatus;
 
148
        d->onlineStatus = status;
 
149
 
 
150
        Kopete::Global::Properties *globalProps = Kopete::Global::Properties::self();
 
151
 
 
152
        // Contact changed from Offline to another known online status
 
153
        if( oldStatus.status() == OnlineStatus::Offline &&
 
154
                status.status() != OnlineStatus::Unknown &&
 
155
                status.status() != OnlineStatus::Offline )
 
156
        {
 
157
                if ( !hasProperty( globalProps->onlineSince().key() ) )
 
158
                        setProperty( globalProps->onlineSince(), QDateTime::currentDateTime() );
 
159
                // kDebug(14010) << "REMOVING lastSeen property for " << nickName();
 
160
                removeProperty( globalProps->lastSeen() );
 
161
        }
 
162
        else if( oldStatus.status() != OnlineStatus::Offline &&
 
163
                oldStatus.status() != OnlineStatus::Unknown &&
 
164
                status.status() == OnlineStatus::Offline ) // Contact went back offline
 
165
        {
 
166
                removeProperty( globalProps->onlineSince() );
 
167
                // kDebug(14010) << "SETTING lastSeen property for " << nickName();
 
168
                setProperty( globalProps->lastSeen(), QDateTime::currentDateTime() );
 
169
        }
 
170
 
 
171
        if ( this == account()->myself() || account()->isConnected() )
 
172
                emit onlineStatusChanged( this, status, oldStatus );
 
173
 
 
174
        if ( oldCanAcceptFiles != canAcceptFiles() )
 
175
                emit canAcceptFilesChanged();
 
176
}
 
177
 
 
178
Kopete::StatusMessage Contact::statusMessage() const
 
179
{
 
180
        return d->statusMessage;
 
181
}
 
182
 
 
183
void Contact::setStatusMessage( const Kopete::StatusMessage &statusMessage )
 
184
{
 
185
        bool emitUpdate = true;
 
186
 
 
187
        if ( d->statusMessage.title() == statusMessage.title() && d->statusMessage.message() == statusMessage.message() )
 
188
                emitUpdate = false;
 
189
 
 
190
        d->statusMessage = statusMessage;
 
191
 
 
192
        kDebug(14010) << "Setting up the status title property with this: " << statusMessage.title();
 
193
        if( !statusMessage.title().isEmpty() )
 
194
                setProperty( Kopete::Global::Properties::self()->statusTitle(), statusMessage.title() );
 
195
        else
 
196
                removeProperty( Kopete::Global::Properties::self()->statusTitle() );
 
197
 
 
198
        kDebug(14010) << "Setting up the status message property with this: " << statusMessage.message();
 
199
        if( !statusMessage.message().isEmpty() )
 
200
                setProperty( Kopete::Global::Properties::self()->statusMessage(), statusMessage.message() );
 
201
        else
 
202
                removeProperty( Kopete::Global::Properties::self()->statusMessage() );
 
203
 
 
204
        if ( emitUpdate )
 
205
                emit statusMessageChanged( this );
 
206
}
 
207
 
 
208
void Contact::slotAccountIsConnectedChanged()
 
209
{
 
210
        if ( this == account()->myself() )
 
211
                return;
 
212
 
 
213
        if ( account()->isConnected() )
 
214
                emit onlineStatusChanged( this, d->onlineStatus, protocol()->accountOfflineStatus() );
 
215
        else
 
216
                emit onlineStatusChanged( this, protocol()->accountOfflineStatus(), d->onlineStatus );
 
217
}
 
218
 
 
219
 
 
220
void Contact::sendFile( const KUrl &, const QString &, uint )
 
221
{
 
222
        kWarning( 14010 ) << "Plugin "
 
223
                << protocol()->pluginId() << " has enabled file sending, "
 
224
                << "but didn't implement it!" << endl;
 
225
}
 
226
 
 
227
void Contact::slotAddContact()
 
228
{
 
229
        if( metaContact() )
 
230
        {
 
231
                metaContact()->setTemporary( false );
 
232
                ContactList::self()->addMetaContact( metaContact() );
 
233
        }
 
234
}
 
235
 
 
236
KMenu* Contact::popupMenu( ChatSession *manager )
 
237
{
 
238
        KMenu *menu = new KMenu();
 
239
 
 
240
        QString titleText;
 
241
        const QString nick = property( Kopete::Global::Properties::self()->nickName() ).value().toString();
 
242
        if( nick.isEmpty() )
 
243
                titleText = QString::fromLatin1( "%1 (%2)" ).arg( contactId(), onlineStatus().description() );
 
244
        else
 
245
                titleText = QString::fromLatin1( "%1 <%2> (%3)" ).arg( nick, contactId(), onlineStatus().description() );
 
246
        menu->addTitle( titleText );
 
247
 
 
248
        if( metaContact() && metaContact()->isTemporary() && contactId() != account()->myself()->contactId() )
 
249
        {
 
250
                KAction *actionAddContact = new KAction( KIcon("list-add-user"), i18n( "&Add to Your Contact List" ), menu );
 
251
                connect( actionAddContact, SIGNAL(triggered(bool)), this, SLOT(slotAddContact()) );
 
252
 
 
253
                menu->addAction(actionAddContact);
 
254
                menu->addSeparator();
 
255
        }
 
256
 
 
257
        // FIXME: After KDE 3.2 we should make isReachable do the isConnected call so it can be removed here - Martijn
 
258
        const bool reach = account()->isConnected() && isReachable();
 
259
        const bool myself = (this == account()->myself());
 
260
 
 
261
        KAction *actionSendMessage = KopeteStdAction::sendMessage( this, SLOT(sendMessage()), menu );
 
262
        actionSendMessage->setEnabled( reach && !myself );
 
263
        menu->addAction( actionSendMessage );
 
264
 
 
265
        KAction *actionChat = KopeteStdAction::chat( this, SLOT(startChat()), menu );
 
266
        actionChat->setEnabled( reach && !myself );
 
267
        menu->addAction( actionChat );
 
268
 
 
269
        KAction *actionSendFile = KopeteStdAction::sendFile( this, SLOT(sendFile()), menu );
 
270
        actionSendFile->setEnabled( reach && d->fileCapable && !myself );
 
271
        menu->addAction( actionSendFile );
 
272
 
 
273
        // Protocol specific options will go below this separator
 
274
        // through the use of the customContextMenuActions() function
 
275
 
 
276
        // Get the custom actions from the protocols ( pure virtual function )
 
277
        QList<KAction*> *customActions = customContextMenuActions();
 
278
        if( customActions && !customActions->isEmpty() )
 
279
        {
 
280
                menu->addSeparator();
 
281
                QList<KAction*>::iterator it, itEnd = customActions->end();
 
282
                for( it = customActions->begin(); it != itEnd; ++it )
 
283
                        menu->addAction( (*it) );
 
284
        }
 
285
        delete customActions;
 
286
 
 
287
        menu->addSeparator();
 
288
 
 
289
        if( metaContact() && !metaContact()->isTemporary() )
 
290
        {
 
291
                KAction* changeMetaContact = KopeteStdAction::changeMetaContact( this, SLOT(changeMetaContact()), menu );
 
292
                menu->addAction( changeMetaContact );
 
293
 
 
294
                d->toggleAlwaysVisibleAction = new KToggleAction( i18n( "Visible when offline" ), menu );
 
295
                d->toggleAlwaysVisibleAction->setChecked( property( Kopete::Global::Properties::self()->isAlwaysVisible() ).value().toBool() );
 
296
                menu->addAction( d->toggleAlwaysVisibleAction );
 
297
                connect( d->toggleAlwaysVisibleAction, SIGNAL(toggled(bool)), this, SLOT(toggleAlwaysVisible()) );
 
298
        }
 
299
 
 
300
        menu->addAction( KopeteStdAction::contactInfo( this, SLOT(slotUserInfo()), menu ) );
 
301
 
 
302
#if 0 //this is not fully implemented yet (and doesn't work).  disable for now   - Olivier 2005-01-11
 
303
        if ( account()->isBlocked( d->contactId ) )
 
304
                KopeteStdAction::unblockContact( this, SLOT(slotUnblock()), menu, "actionUnblockContact" )->plug( menu );
 
305
        else
 
306
                KopeteStdAction::blockContact( this, SLOT(slotBlock()), menu, "actionBlockContact" )->plug( menu );
 
307
#endif
 
308
 
 
309
        if( metaContact() && !metaContact()->isTemporary() )
 
310
                menu->addAction( KopeteStdAction::deleteContact( this, SLOT(slotDelete()), menu ) );
 
311
 
 
312
        return menu;
 
313
}
 
314
 
 
315
void Contact::toggleAlwaysVisible()
 
316
{
 
317
        bool alwaysVisible = property( Kopete::Global::Properties::self()->isAlwaysVisible() ).value().toBool();
 
318
        setProperty( Kopete::Global::Properties::self()->isAlwaysVisible(), !alwaysVisible );
 
319
        d->toggleAlwaysVisibleAction->setChecked( !alwaysVisible );
 
320
}
 
321
 
 
322
void Contact::changeMetaContact()
 
323
{
 
324
        QPointer <KDialog> moveDialog = new KDialog( Kopete::UI::Global::mainWidget() );
 
325
        moveDialog->setCaption( i18n( "Move Contact" ) );
 
326
        moveDialog->setButtons( KDialog::Ok | KDialog::Cancel );
 
327
        moveDialog->setDefaultButton( KDialog::Ok );
 
328
        moveDialog->showButtonSeparator( true );
 
329
 
 
330
        KVBox *w = new KVBox( moveDialog );
 
331
        w->setSpacing( KDialog::spacingHint() );
 
332
        Kopete::UI::MetaContactSelectorWidget *selector = new Kopete::UI::MetaContactSelectorWidget(w);
 
333
        selector->setLabelMessage(i18n( "Select the meta contact to which you want to move this contact:" ));
 
334
        // exclude this metacontact as a target metacontact for the move
 
335
        selector->excludeMetaContact( metaContact() );
 
336
        QCheckBox *chkCreateNew = new QCheckBox( i18n( "Create a new metacontact for this contact" ), w );
 
337
        chkCreateNew ->setWhatsThis( i18n( "If you select this option, a new metacontact will be created in the top-level group "
 
338
                "with the name of this contact and the contact will be moved to it." ) );
 
339
        QObject::connect( chkCreateNew , SIGNAL(toggled(bool)) ,  selector , SLOT (setDisabled(bool)) ) ;
 
340
 
 
341
        moveDialog->setMainWidget(w);
 
342
        if( moveDialog->exec() == QDialog::Accepted )
 
343
        {
 
344
                Kopete::MetaContact *mc = selector->metaContact();
 
345
                if(chkCreateNew->isChecked())
 
346
                {
 
347
                        mc=new Kopete::MetaContact();
 
348
 
 
349
                        if ( metaContact() )
 
350
                        {       // Add new metaContact to old groups so we don't move it to Top Level group
 
351
                                foreach ( Kopete::Group* group, metaContact()->groups() )
 
352
                                        mc->addToGroup( group );
 
353
                        }
 
354
 
 
355
                        Kopete::ContactList::self()->addMetaContact(mc);
 
356
                }
 
357
                if( mc )
 
358
                {
 
359
                        setMetaContact( mc );
 
360
                }
 
361
        }
 
362
 
 
363
        if ( moveDialog )
 
364
                moveDialog->deleteLater();
 
365
}
 
366
 
 
367
void Contact::slotMetaContactDestroyed( QObject* mc )
 
368
{
 
369
        if (mc != d->metaContact)
 
370
                return;
 
371
 
 
372
        d->metaContact = 0;
 
373
}
 
374
 
 
375
void Contact::setMetaContact( MetaContact *m )
 
376
{
 
377
        MetaContact *old = d->metaContact;
 
378
        if(old==m) //that make no sens
 
379
                return;
 
380
 
 
381
        if( old )
 
382
        {
 
383
                old->removeContact( this );
 
384
                disconnect( old, SIGNAL(destroyed(QObject*)), this, SLOT(slotMetaContactDestroyed(QObject*)) );
 
385
 
 
386
                if(old->contacts().isEmpty())
 
387
                {
 
388
                        //remove the old metacontact.  (this delete the MC)
 
389
                        ContactList::self()->removeMetaContact(old);
 
390
                }
 
391
                else
 
392
                {
 
393
                        d->metaContact = m; //i am forced to do that now if i want the next line works
 
394
                        //remove cached data for this protocol which will not be removed since we disconnected
 
395
                        protocol()->serialize( old );
 
396
                }
 
397
        }
 
398
 
 
399
        d->metaContact = m;
 
400
        setParent( m );
 
401
 
 
402
        if( m )
 
403
        {
 
404
                m->addContact( this );
 
405
                connect( m, SIGNAL(destroyed(QObject*)), this, SLOT(slotMetaContactDestroyed(QObject*)) );
 
406
                // it is necessary to call this write here, because MetaContact::addContact() does not differentiate
 
407
                // between adding completely new contacts (which should be written to kabc) and restoring upon restart
 
408
                // (where no write is needed).
 
409
                KABCPersistence::self()->write( m );
 
410
        }
 
411
        sync();
 
412
}
 
413
 
 
414
void Contact::serialize( QMap<QString, QString> &/*serializedData*/,
 
415
        QMap<QString, QString> & /* addressBookData */ )
 
416
{
 
417
}
 
418
 
 
419
bool Contact::isReachable()
 
420
{
 
421
        // The default implementation returns false when offline and true
 
422
        // otherwise. Subclass if you need more control over the process.
 
423
        return onlineStatus().status() != OnlineStatus::Offline;
 
424
}
 
425
 
 
426
 
 
427
void Contact::startChat()
 
428
{
 
429
        KopeteView *v=manager( CanCreate )->view(true, QString::fromLatin1("kopete_chatwindow") );
 
430
        if(v)
 
431
                v->raise(true);
 
432
}
 
433
 
 
434
void Contact::sendMessage()
 
435
{
 
436
        KopeteView *v=manager( CanCreate )->view(true, QString::fromLatin1("kopete_emailwindow") );
 
437
        if(v)
 
438
                v->raise(true);
 
439
}
 
440
 
 
441
void Contact::execute()
 
442
{
 
443
        // FIXME: After KDE 3.2 remove the isConnected check and move it to isReachable - Martijn
 
444
        if ( account()->isConnected() && isReachable() )
 
445
        {
 
446
                KopeteView *v=manager( CanCreate )->view(true, Kopete::BehaviorSettings::self()->viewPlugin() );
 
447
                if(v)
 
448
                        v->raise(true);
 
449
        }
 
450
        else
 
451
        {
 
452
                KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
 
453
                        i18n( "This user is not reachable at the moment. Please try a protocol that supports offline sending, or wait "
 
454
                        "until this user comes online." ), i18n( "User is Not Reachable" ) );
 
455
        }
 
456
}
 
457
 
 
458
void Contact::slotDelete()
 
459
{
 
460
        if ( KMessageBox::warningContinueCancel( Kopete::UI::Global::mainWidget(),
 
461
                i18n( "Are you sure you want to remove the contact  '%1' from your contact list?" ,
 
462
                 d->contactId ), i18n( "Remove Contact" ), KGuiItem(i18n("Remove"), QString::fromLatin1("list-remove-user") ), KStandardGuiItem::cancel(),
 
463
                QString::fromLatin1("askRemoveContact"), KMessageBox::Notify | KMessageBox::Dangerous )
 
464
                == KMessageBox::Continue )
 
465
        {
 
466
                Kopete::DeleteContactTask *deleteTask = new Kopete::DeleteContactTask(this);
 
467
                deleteTask->start();
 
468
        }
 
469
}
 
470
 
 
471
void Contact::deleteContact()
 
472
{
 
473
        // Default implementation simply deletes the contact
 
474
        deleteLater();
 
475
}
 
476
 
 
477
 
 
478
MetaContact * Contact::metaContact() const
 
479
{
 
480
        return d->metaContact;
 
481
}
 
482
 
 
483
QString Contact::contactId() const
 
484
{
 
485
        return d->contactId;
 
486
}
 
487
 
 
488
Protocol * Contact::protocol() const
 
489
{
 
490
        return d->account ? d->account->protocol() : 0L;
 
491
}
 
492
 
 
493
Account * Contact::account() const
 
494
{
 
495
        return d->account;
 
496
}
 
497
 
 
498
 
 
499
 
 
500
void Contact::sync(unsigned int)
 
501
{
 
502
        /* Default implementation does nothing */
 
503
}
 
504
 
 
505
QString& Contact::icon() const
 
506
{
 
507
        return d->icon;
 
508
}
 
509
 
 
510
void Contact::setIcon( const QString& icon )
 
511
{
 
512
        d->icon = icon;
 
513
        return;
 
514
}
 
515
 
 
516
QList<KAction *> *Contact::customContextMenuActions()
 
517
{
 
518
        return 0L;
 
519
}
 
520
 
 
521
bool Contact::isOnline() const
 
522
{
 
523
        return onlineStatus().isDefinitelyOnline();
 
524
}
 
525
 
 
526
bool Contact::isFileCapable() const
 
527
{
 
528
        return d->fileCapable;
 
529
}
 
530
 
 
531
void Contact::setFileCapable( bool filecap )
 
532
{
 
533
        if ( d->fileCapable != filecap )
 
534
        {
 
535
                d->fileCapable = filecap;
 
536
                emit canAcceptFilesChanged();
 
537
        }
 
538
}
 
539
 
 
540
bool Contact::canAcceptFiles() const
 
541
{
 
542
        return isOnline() && d->fileCapable;
 
543
}
 
544
 
 
545
unsigned long int Contact::idleTime() const
 
546
{
 
547
        if(d->idleTime==0)
 
548
                return 0;
 
549
 
 
550
        return d->idleTime+(d->idleTimer.elapsed()/1000);
 
551
}
 
552
 
 
553
void Contact::setIdleTime( unsigned long int t )
 
554
{
 
555
        bool idleChanged = false;
 
556
        if(d->idleTime != t)
 
557
                idleChanged = true;
 
558
        d->idleTime=t;
 
559
        if(t > 0)
 
560
                d->idleTimer.start();
 
561
//FIXME: if t == 0, idleTime() will now return garbage
 
562
//      else
 
563
//              d->idleTimer.stop();
 
564
        if(idleChanged)
 
565
                emit idleStateChanged(this);
 
566
}
 
567
 
 
568
QString Contact::toolTip() const
 
569
{
 
570
        Kopete::Property p;
 
571
        QString tip;
 
572
        const QStringList shownProps = Kopete::AppearanceSettings::self()->toolTipContents();
 
573
 
 
574
        // --------------------------------------------------------------------------
 
575
        // Fixed part of tooltip
 
576
 
 
577
        QString iconName;
 
578
        if ( this == account()->myself() )
 
579
        {
 
580
                iconName = QString::fromLatin1("kopete-account-icon:%1:%2")
 
581
                        .arg( QString(QUrl::toPercentEncoding( protocol()->pluginId() )),
 
582
                              QString(QUrl::toPercentEncoding( account()->accountId() )) );
 
583
 
 
584
        }
 
585
        else
 
586
        {
 
587
                iconName = QString::fromLatin1("kopete-contact-icon:%1:%2:%3")
 
588
                        .arg( QString(QUrl::toPercentEncoding( protocol()->pluginId() )),
 
589
                              QString(QUrl::toPercentEncoding( account()->accountId() )),
 
590
                              QString(QUrl::toPercentEncoding( contactId() )) );
 
591
        }
 
592
 
 
593
        // TODO:  the nickname should be a configurable properties, like others. -Olivier
 
594
        QString nick = property( Kopete::Global::Properties::self()->nickName() ).value().toString();
 
595
        if ( nick.isEmpty() )
 
596
        {
 
597
                tip = i18nc( "@label:textbox %3 is contact-display-name, %1 is its status",
 
598
                        "<b><nobr>%3</nobr></b><br /><img src=\"%2\">&nbsp;%1",
 
599
                        Kopete::Message::escape( onlineStatus().description() ), iconName,
 
600
                                Kopete::Message::escape( d->contactId ) );
 
601
        }
 
602
        else
 
603
        {
 
604
                tip = i18nc( "@label:textbox %4 is contact-display-name, %3 is contact-id, %1 is its status",
 
605
                        "<nobr><b>%4</b> (%3)</nobr><br /><img src=\"%2\">&nbsp;%1",
 
606
                                Kopete::Message::escape( onlineStatus().description() ), iconName,
 
607
                                        Kopete::Message::escape( contactId() ),
 
608
                                        Kopete::Emoticons::parseEmoticons( Kopete::Message::escape( nick ) ) );
 
609
        }
 
610
 
 
611
        // --------------------------------------------------------------------------
 
612
        // Configurable part of tooltip
 
613
 
 
614
        // FIXME: It shouldn't use QString to identity the properties. Instead it should use PropertyTmpl::key()
 
615
        for(QStringList::ConstIterator it=shownProps.constBegin(); it!=shownProps.constEnd(); ++it)
 
616
        {
 
617
                if((*it) == Kopete::Global::Properties::self()->fullName().key())
 
618
                {
 
619
                        const QString name = formattedName();
 
620
                        if(!name.isEmpty())
 
621
                        {
 
622
                                tip += i18nc("@label:textbox formatted name",
 
623
                                                        "<br /><b>Full Name:</b>&nbsp;<nobr>%1</nobr>", Qt::escape(name));
 
624
                        }
 
625
                }
 
626
                else if ((*it) == Kopete::Global::Properties::self()->idleTime().key())
 
627
                {
 
628
                        const QString time = formattedIdleTime();
 
629
                        if(!time.isEmpty())
 
630
                        {
 
631
                                tip += i18nc("@label:textbox formatted idle time",
 
632
                                        "<br /><b>Idle:</b>&nbsp;<nobr>%1</nobr>", time);
 
633
                        }
 
634
                }
 
635
                else if ((*it) == QString::fromLatin1("homePage"))
 
636
                {
 
637
                        const QString url = property(*it).value().toString();
 
638
                        if(!url.isEmpty())
 
639
                        {
 
640
                                tip += i18nc("@label:textbox formatted url",
 
641
                                        "<br /><b>Home Page:</b>&nbsp;<a href=\"%1\"><nobr>%2</nobr></a>",
 
642
                                                QString(QUrl::toPercentEncoding( url )), Kopete::Message::escape( Qt::escape(url) ) );
 
643
                        }
 
644
                }
 
645
                else if ((*it) == Kopete::Global::Properties::self()->statusTitle().key() )
 
646
                {
 
647
                        const QString statusTitle = property(*it).value().toString();
 
648
                        if(!statusTitle.isEmpty())
 
649
                        {
 
650
                                tip += i18nc("@label:textbox formatted status title",
 
651
                                             "<br /><b>Status&nbsp;Title:</b>&nbsp;%1",  Kopete::Emoticons::parseEmoticons( Kopete::Message::escape(statusTitle) ) );
 
652
                        }
 
653
                }
 
654
                else if ((*it) == Kopete::Global::Properties::self()->statusMessage().key() )
 
655
                {
 
656
                        const QString statusmsg = property(*it).value().toString();
 
657
                        if(!statusmsg.isEmpty())
 
658
                        {
 
659
                                tip += i18nc("@label:textbox formatted status message",
 
660
                                                        "<br /><b>Status&nbsp;Message:</b>&nbsp;%1",  Kopete::Emoticons::parseEmoticons( Kopete::Message::escape(statusmsg) ) );
 
661
                        }
 
662
                }
 
663
                else
 
664
                {
 
665
                        p = property(*it);
 
666
                        if(!p.isNull())
 
667
                        {
 
668
                                QVariant val = p.value();
 
669
                                QString valueText;
 
670
 
 
671
                                switch(val.type())
 
672
                                {
 
673
                                        case QVariant::DateTime:
 
674
                                                valueText = KGlobal::locale()->formatDateTime(val.toDateTime());
 
675
                                                valueText = Kopete::Message::escape( valueText );
 
676
                                                break;
 
677
                                        case QVariant::Date:
 
678
                                                valueText = KGlobal::locale()->formatDate(val.toDate());
 
679
                                                valueText = Kopete::Message::escape( valueText );
 
680
                                                break;
 
681
                                        case QVariant::Time:
 
682
                                                valueText = KGlobal::locale()->formatTime(val.toTime());
 
683
                                                valueText = Kopete::Message::escape( valueText );
 
684
                                                break;
 
685
                                        default:
 
686
                                                if( p.isRichText() )
 
687
                                                {
 
688
                                                        valueText = val.toString();
 
689
                                                }
 
690
                                                else
 
691
                                                {
 
692
                                                        valueText = Kopete::Message::escape( val.toString() );
 
693
                                                }
 
694
                                }
 
695
 
 
696
                                if (valueText.size() > 1000) {
 
697
                                        valueText.truncate(997);
 
698
                                        valueText += "...";
 
699
                                }
 
700
 
 
701
                                tip += i18nc("@label:textbox property label %2 is name, %1 is value",
 
702
                                        "<br /><nobr><b>%2:</b></nobr>&nbsp;%1",
 
703
                                                valueText, Qt::escape(p.tmpl().label()) );
 
704
                        }
 
705
                }
 
706
        }
 
707
 
 
708
        return tip;
 
709
}
 
710
 
 
711
QString Kopete::Contact::formattedName() const
 
712
{
 
713
        if( hasProperty( Kopete::Global::Properties::self()->fullName().key() ) )
 
714
                return property( Kopete::Global::Properties::self()->fullName() ).value().toString();
 
715
 
 
716
        QString ret;
 
717
        Kopete::Property first, last;
 
718
 
 
719
        first = property( Kopete::Global::Properties::self()->firstName() );
 
720
        last = property( Kopete::Global::Properties::self()->lastName() );
 
721
        if(!first.isNull())
 
722
        {
 
723
                if(!last.isNull()) // contact has both first and last name
 
724
                {
 
725
                        ret = i18nc("firstName lastName", "%2 %1",
 
726
                                 last.value().toString(),
 
727
                                 first.value().toString());
 
728
                }
 
729
                else // only first name set
 
730
                {
 
731
                        ret = first.value().toString();
 
732
                }
 
733
        }
 
734
        else if(!last.isNull()) // only last name set
 
735
        {
 
736
                ret = last.value().toString();
 
737
        }
 
738
 
 
739
        return ret;
 
740
}
 
741
 
 
742
QString Kopete::Contact::formattedIdleTime() const
 
743
{
 
744
        QString ret;
 
745
        unsigned long int leftTime = idleTime();
 
746
 
 
747
        if ( leftTime > 0 )
 
748
        {       // FIXME: duplicated from code in kopetecontact listview.cpp
 
749
                unsigned long int days, hours, mins, secs;
 
750
 
 
751
                days = leftTime / ( 60*60*24 );
 
752
                leftTime = leftTime % ( 60*60*24 );
 
753
                hours = leftTime / ( 60*60 );
 
754
                leftTime = leftTime % ( 60*60 );
 
755
                mins = leftTime / 60;
 
756
                secs = leftTime % 60;
 
757
 
 
758
                if ( days != 0 )
 
759
                {
 
760
                        ret = i18nc( "<days>d <hours>h <minutes>m <seconds>s",
 
761
                                "%4d %3h %2m %1s" ,
 
762
                                  secs ,
 
763
                                  mins ,
 
764
                                  hours ,
 
765
                                  days );
 
766
                }
 
767
                else if ( hours != 0 )
 
768
                {
 
769
                        ret = i18nc( "<hours>h <minutes>m <seconds>s", "%3h %2m %1s" ,
 
770
                                  secs ,
 
771
                                  mins ,
 
772
                                  hours );
 
773
                }
 
774
                else
 
775
                {
 
776
                        // xgettext: no-c-format
 
777
                        ret = i18nc( "<minutes>m <seconds>s", "%2m %1s" ,
 
778
                                  secs ,
 
779
                                  mins );
 
780
                }
 
781
        }
 
782
        return ret;
 
783
}
 
784
 
 
785
void Kopete::Contact::slotBlock()
 
786
{
 
787
        account()->block( d->contactId );
 
788
}
 
789
 
 
790
void Kopete::Contact::slotUnblock()
 
791
{
 
792
        account()->unblock( d->contactId );
 
793
}
 
794
 
 
795
void Kopete::Contact::setNickName( const QString &name )
 
796
{
 
797
        const QString oldNickName = nickName();
 
798
        setProperty( Kopete::Global::Properties::self()->nickName(), name );
 
799
}
 
800
 
 
801
QString Kopete::Contact::nickName() const
 
802
{
 
803
        const QString nick = property( Kopete::Global::Properties::self()->nickName() ).value().toString();
 
804
        if( !nick.isEmpty() )
 
805
                return nick;
 
806
 
 
807
        return contactId();
 
808
}
 
809
 
 
810
void Kopete::Contact::setPhoto(const QString &photoPath)
 
811
{
 
812
        setProperty( Kopete::Global::Properties::self()->photo(), photoPath );
 
813
}
 
814
 
 
815
 
 
816
} //END namespace Kopete
 
817
 
 
818
#include "kopetecontact.moc"