~ubuntu-branches/ubuntu/jaunty/psi/jaunty

« back to all changes in this revision

Viewing changes to src/groupchatdlg.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2005-01-10 17:41:43 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050110174143-ltocv5zapl6blf5d
Tags: 0.9.3-1
* New upstream release
* Cleaned up debian/rules (some things are done by upstream Makefiles now)
* Fixed some lintian warnings:
  - removed executable bit from some .png files
  - moved psi.desktop to /usr/share/applications
* Updated menu files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * groupchatdlg.cpp - dialogs for handling groupchat
 
3
 * Copyright (C) 2001, 2002  Justin Karneges
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this library; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 *
 
19
 */
 
20
 
 
21
#include"groupchatdlg.h"
 
22
 
 
23
#include<qlabel.h>
 
24
#include<qlayout.h>
 
25
#include<qpushbutton.h>
 
26
#include<qgroupbox.h>
 
27
#include<qmessagebox.h>
 
28
#include<qtextedit.h>
 
29
#include<qsplitter.h>
 
30
#include<qtimer.h>
 
31
#include<qheader.h>
 
32
#include<qtoolbutton.h>
 
33
#include<qinputdialog.h>
 
34
#include<qguardedptr.h>
 
35
#include<qaction.h>
 
36
#include<qobjectlist.h>
 
37
#include<qpopupmenu.h>
 
38
#include"psicon.h"
 
39
#include"psiaccount.h"
 
40
#include"userlist.h"
 
41
#include"statusdlg.h"
 
42
#include"busywidget.h"
 
43
#include"common.h"
 
44
#include"msgmle.h"
 
45
#include"iconwidget.h"
 
46
#include"iconselect.h"
 
47
#include"iconaction.h"
 
48
 
 
49
#ifdef Q_WS_WIN
 
50
#include<windows.h>
 
51
#endif
 
52
 
 
53
 
 
54
//----------------------------------------------------------------------------
 
55
// GCJoinDlg
 
56
//----------------------------------------------------------------------------
 
57
class GCJoinDlg::Private
 
58
{
 
59
public:
 
60
        Private() {}
 
61
 
 
62
        PsiCon *psi;
 
63
        PsiAccount *pa;
 
64
        AccountsComboBox *cb_ident;
 
65
        BusyWidget *busy;
 
66
        QStringList rl;
 
67
        Jid jid;
 
68
};
 
69
 
 
70
GCJoinDlg::GCJoinDlg(PsiCon *psi, PsiAccount *pa)
 
71
:GCJoinUI(0, 0, false, WDestructiveClose)
 
72
{
 
73
        d = new Private;
 
74
        d->psi = psi;
 
75
        d->pa = 0;
 
76
        d->psi->dialogRegister(this);
 
77
        d->busy = busy;
 
78
 
 
79
        updateIdentity(pa);
 
80
 
 
81
        d->cb_ident = d->psi->accountsComboBox(this,true);
 
82
        connect(d->cb_ident, SIGNAL(activated(PsiAccount *)), SLOT(updateIdentity(PsiAccount *)));
 
83
        d->cb_ident->setAccount(pa);
 
84
        replaceWidget(lb_ident, d->cb_ident);
 
85
 
 
86
        d->rl = d->psi->recentGCList();
 
87
        for(QStringList::ConstIterator it = d->rl.begin(); it != d->rl.end(); ++it) {
 
88
                Jid j(*it);
 
89
                QString s = tr("%1 on %2").arg(j.resource()).arg(j.userHost());
 
90
                cb_recent->insertItem(s);
 
91
        }
 
92
 
 
93
        setCaption(CAP(caption()));
 
94
        pb_join->setDefault(true);
 
95
        connect(pb_close, SIGNAL(clicked()), SLOT(close()));
 
96
        connect(pb_join, SIGNAL(clicked()), SLOT(doJoin()));
 
97
        connect(cb_recent, SIGNAL(activated(int)), SLOT(recent_activated(int)));
 
98
        if(d->rl.isEmpty()) {
 
99
                cb_recent->setEnabled(false);
 
100
                le_host->setFocus();
 
101
        }
 
102
        else
 
103
                recent_activated(0);
 
104
}
 
105
 
 
106
GCJoinDlg::~GCJoinDlg()
 
107
{
 
108
        if(d->psi)
 
109
                d->psi->dialogUnregister(this);
 
110
        if(d->pa)
 
111
                d->pa->dialogUnregister(this);
 
112
        delete d;
 
113
}
 
114
 
 
115
/*void GCJoinDlg::closeEvent(QCloseEvent *e)
 
116
{
 
117
        e->ignore();
 
118
        reject();
 
119
}*/
 
120
 
 
121
void GCJoinDlg::done(int r)
 
122
{
 
123
        if(d->busy->isActive()) {
 
124
                int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to cancel joining groupchat?"), tr("&Yes"), tr("&No"));
 
125
                if(n != 0)
 
126
                        return;
 
127
                d->pa->groupChatLeave(d->jid.host(), d->jid.user());
 
128
        }
 
129
        QDialog::done(r);
 
130
}
 
131
 
 
132
void GCJoinDlg::updateIdentity(PsiAccount *pa)
 
133
{
 
134
        if(d->pa)
 
135
                disconnect(d->pa, SIGNAL(disconnected()), this, SLOT(pa_disconnected()));
 
136
 
 
137
        d->pa = pa;
 
138
        pb_join->setEnabled(d->pa);
 
139
 
 
140
        if(!d->pa) {
 
141
                d->busy->stop();
 
142
                return;
 
143
        }
 
144
 
 
145
        connect(d->pa, SIGNAL(disconnected()), this, SLOT(pa_disconnected()));
 
146
}
 
147
 
 
148
void GCJoinDlg::pa_disconnected()
 
149
{
 
150
        if(d->busy->isActive()) {
 
151
                d->busy->stop();
 
152
        }
 
153
}
 
154
 
 
155
void GCJoinDlg::recent_activated(int x)
 
156
{
 
157
        int n = 0;
 
158
        bool found = false;
 
159
        QString str;
 
160
        for(QStringList::ConstIterator it = d->rl.begin(); it != d->rl.end(); ++it) {
 
161
                if(n == x) {
 
162
                        found = true;
 
163
                        str = *it;
 
164
                        break;
 
165
                }
 
166
                ++n;
 
167
        }
 
168
        if(!found)
 
169
                return;
 
170
 
 
171
        Jid j(str);
 
172
        le_host->setText(j.host());
 
173
        le_room->setText(j.user());
 
174
        le_nick->setText(j.resource());
 
175
}
 
176
 
 
177
void GCJoinDlg::doJoin()
 
178
{
 
179
        if(!d->pa->checkConnected(this))
 
180
                return;
 
181
 
 
182
        QString host = le_host->text();
 
183
        QString room = le_room->text();
 
184
        QString nick = le_nick->text();
 
185
 
 
186
        if(host.isEmpty() || room.isEmpty() || nick.isEmpty()) {
 
187
                QMessageBox::information(this, tr("Error"), tr("You must fill out the fields in order to join."));
 
188
                return;
 
189
        }
 
190
 
 
191
        Jid j = room + '@' + host + '/' + nick;
 
192
        if(!j.isValid()) {
 
193
                QMessageBox::information(this, tr("Error"), tr("You entered an invalid room name."));
 
194
                return;
 
195
        }
 
196
 
 
197
        if(!d->pa->groupChatJoin(host, room, nick)) {
 
198
                QMessageBox::information(this, tr("Error"), tr("You are in or joining this room already!"));
 
199
                return;
 
200
        }
 
201
 
 
202
        d->psi->dialogUnregister(this);
 
203
        d->jid = room + '@' + host + '/' + nick;
 
204
        d->pa->dialogRegister(this, d->jid);
 
205
 
 
206
        disableWidgets();
 
207
        d->busy->start();
 
208
}
 
209
 
 
210
void GCJoinDlg::disableWidgets()
 
211
{
 
212
        d->cb_ident->setEnabled(false);
 
213
        cb_recent->setEnabled(false);
 
214
        gb_info->setEnabled(false);
 
215
        pb_join->setEnabled(false);
 
216
}
 
217
 
 
218
void GCJoinDlg::enableWidgets()
 
219
{
 
220
        d->cb_ident->setEnabled(true);
 
221
        if(!d->rl.isEmpty())
 
222
                cb_recent->setEnabled(true);
 
223
        gb_info->setEnabled(true);
 
224
        pb_join->setEnabled(true);
 
225
}
 
226
 
 
227
void GCJoinDlg::joined()
 
228
{
 
229
        d->psi->recentGCAdd(d->jid.full());
 
230
        d->busy->stop();
 
231
 
 
232
        closeDialogs(this);
 
233
        deleteLater();
 
234
}
 
235
 
 
236
void GCJoinDlg::error(int, const QString &str)
 
237
{
 
238
        d->busy->stop();
 
239
        enableWidgets();
 
240
 
 
241
        pb_join->setFocus();
 
242
 
 
243
        d->pa->dialogUnregister(this);
 
244
        d->psi->dialogRegister(this);
 
245
 
 
246
        QMessageBox::information(this, tr("Error"), tr("Unable to join groupchat.\nReason: %1").arg(str));
 
247
}
 
248
 
 
249
 
 
250
//----------------------------------------------------------------------------
 
251
// GCUserView
 
252
//----------------------------------------------------------------------------
 
253
GCUserViewItem::GCUserViewItem(QListView *par)
 
254
:QListViewItem(par)
 
255
{
 
256
}
 
257
 
 
258
GCUserView::GCUserView(QWidget *parent, const char *name)
 
259
:QListView(parent, name), QToolTip(viewport())
 
260
{
 
261
        setResizeMode(QListView::AllColumns);
 
262
        setSorting(0);
 
263
        header()->hide();
 
264
        addColumn("");
 
265
 
 
266
        connect(this, SIGNAL(doubleClicked(QListViewItem *)), SLOT(qlv_doubleClicked(QListViewItem *)));
 
267
        connect(this, SIGNAL(contextMenuRequested(QListViewItem *, const QPoint &, int)), SLOT(qlv_contextMenuRequested(QListViewItem *, const QPoint &, int)));
 
268
}
 
269
 
 
270
GCUserView::~GCUserView()
 
271
{
 
272
}
 
273
 
 
274
void GCUserView::updateAll()
 
275
{
 
276
        for(GCUserViewItem *i = (GCUserViewItem *)firstChild(); i; i = (GCUserViewItem *)i->nextSibling())
 
277
                i->setPixmap(0, is->status(i->s));
 
278
}
 
279
 
 
280
QStringList GCUserView::nickList() const
 
281
{
 
282
        QStringList list;
 
283
 
 
284
        for(QListViewItem *lvi = firstChild(); lvi; lvi = lvi->nextSibling())
 
285
                list << lvi->text(0);
 
286
 
 
287
        qstringlistisort(list); // caseless sorting
 
288
        return list;
 
289
}
 
290
 
 
291
QListViewItem *GCUserView::findEntry(const QString &nick)
 
292
{
 
293
        for(QListViewItem *lvi = firstChild(); lvi; lvi = lvi->nextSibling()) {
 
294
                if(lvi->text(0) == nick)
 
295
                        return lvi;
 
296
        }
 
297
        return 0;
 
298
}
 
299
 
 
300
void GCUserView::updateEntry(const QString &nick, const Status &s)
 
301
{
 
302
        GCUserViewItem *lvi = (GCUserViewItem *)findEntry(nick);
 
303
        if(!lvi) {
 
304
                lvi = new GCUserViewItem(this);
 
305
                lvi->setText(0, nick);
 
306
        }
 
307
 
 
308
        lvi->s = s;
 
309
        lvi->setPixmap(0, is->status(lvi->s));
 
310
}
 
311
 
 
312
void GCUserView::removeEntry(const QString &nick)
 
313
{
 
314
        QListViewItem *lvi = findEntry(nick);
 
315
        if(lvi)
 
316
                delete lvi;
 
317
}
 
318
 
 
319
void GCUserView::maybeTip(const QPoint &pos)
 
320
{
 
321
        GCUserViewItem *lvi = (GCUserViewItem *)itemAt(pos);
 
322
        if(!lvi)
 
323
                return;
 
324
 
 
325
        QRect r(itemRect(lvi));
 
326
 
 
327
        const QString &nick = lvi->text(0);
 
328
        const Status &s = lvi->s;
 
329
        UserListItem u;
 
330
        // SICK SICK SICK SICK
 
331
        u.setJid(((GCMainDlg *)topLevelWidget())->jid().withResource(nick));
 
332
        u.setName(nick);
 
333
 
 
334
        // make a resource so the contact appears online
 
335
        UserResource ur;
 
336
        ur.setName(nick);
 
337
        ur.setStatus(s);
 
338
        u.userResourceList().append(ur);
 
339
 
 
340
        tip(r, u.makeTip());
 
341
}
 
342
 
 
343
void GCUserView::qlv_doubleClicked(QListViewItem *i)
 
344
{
 
345
        GCUserViewItem *lvi = (GCUserViewItem *)i;
 
346
        if(!lvi)
 
347
                return;
 
348
 
 
349
        if(option.defaultAction == 0)
 
350
                action(lvi->text(0), lvi->s, 0);
 
351
        else
 
352
                action(lvi->text(0), lvi->s, 1);
 
353
}
 
354
 
 
355
void GCUserView::qlv_contextMenuRequested(QListViewItem *i, const QPoint &pos, int)
 
356
{
 
357
        GCUserViewItem *lvi = (GCUserViewItem *)i;
 
358
        if(!lvi)
 
359
                return;
 
360
 
 
361
        QPopupMenu *pm = new QPopupMenu;
 
362
        pm->insertItem(IconsetFactory::icon("psi/sendMessage"), tr("Send &message"), 0);
 
363
        pm->insertItem(IconsetFactory::icon("psi/chat"), tr("Open &chat window"), 1);
 
364
        pm->insertSeparator();
 
365
        //pm->insertItem(tr("Send &file"), 4);
 
366
        //pm->insertSeparator();
 
367
        pm->insertItem(tr("Check &Status"), 2);
 
368
        pm->insertItem(IconsetFactory::icon("psi/vCard"), tr("User &Info"), 3);
 
369
        int x = pm->exec(pos);
 
370
        delete pm;
 
371
 
 
372
        if(x == -1)
 
373
                return;
 
374
        action(lvi->text(0), lvi->s, x);
 
375
}
 
376
 
 
377
 
 
378
//----------------------------------------------------------------------------
 
379
// GCMainDlg
 
380
//----------------------------------------------------------------------------
 
381
class GCMainDlg::Private : public QObject
 
382
{
 
383
        Q_OBJECT
 
384
public:
 
385
        enum { Connecting, Connected, Idle };
 
386
        Private(GCMainDlg *d) {
 
387
                dlg = d;
 
388
                nickSeparator = ":";
 
389
                typingStatus = Typing_Normal;
 
390
        }
 
391
 
 
392
        GCMainDlg *dlg;
 
393
        int state;
 
394
        PsiAccount *pa;
 
395
        Jid jid;
 
396
        QString self;
 
397
        ChatView *te_log;
 
398
        ChatEdit *mle;
 
399
        QLineEdit *le_topic;
 
400
        GCUserView *lv_users;
 
401
        QPushButton *pb_topic;
 
402
        IconAction *act_find;
 
403
        IconToolButton *tb_clear, *tb_icon;
 
404
        int pending;
 
405
 
 
406
        bool trackBar;
 
407
        int  trackBarParagraph;
 
408
 
 
409
        QTimer *flashTimer;
 
410
        int flashCount;
 
411
 
 
412
        QStringList hist;
 
413
        int histAt;
 
414
 
 
415
        QGuardedPtr<GCFindDlg> findDlg;
 
416
        QString lastSearch;
 
417
 
 
418
public slots:
 
419
        void addEmoticon(const Icon *icon) {
 
420
                if ( !dlg->isActiveWindow() )
 
421
                     return;
 
422
 
 
423
                QString text;
 
424
 
 
425
                QDict<QString> itext = icon->text();
 
426
                QDictIterator<QString> it ( itext );
 
427
                for ( ; it.current(); ++it) {
 
428
                        if ( it.current() && !it.current()->isEmpty() ) {
 
429
                                text = *(it.current()) + " ";
 
430
                                break;
 
431
                        }
 
432
                }
 
433
 
 
434
                if ( !text.isEmpty() )
 
435
                        mle->insert( text );
 
436
        }
 
437
 
 
438
        void addEmoticon(QString text) {
 
439
                if ( !dlg->isActiveWindow() )
 
440
                     return;
 
441
 
 
442
                mle->insert( text + " " );
 
443
        }
 
444
 
 
445
        void deferredScroll() {
 
446
                //QTimer::singleShot(250, this, SLOT(slotScroll()));
 
447
                te_log->scrollToBottom();
 
448
        }
 
449
 
 
450
protected slots:
 
451
        void slotScroll() {
 
452
                te_log->scrollToBottom();
 
453
        }
 
454
 
 
455
public:
 
456
        // Nick auto-completion code follows...
 
457
        enum TypingStatus {
 
458
                Typing_Normal = 0,
 
459
                Typing_TabPressed,
 
460
                Typing_TabbingNicks,
 
461
                Typing_MultipleSuggestions
 
462
        };
 
463
        TypingStatus typingStatus;
 
464
        QString lastReferrer;  // contains nick of last person, who have said "yourNick: ..."
 
465
        QString nickSeparator; // in case of "nick: ...", it equals ":"
 
466
        QStringList suggestedNicks;
 
467
        int  suggestedIndex;
 
468
        bool suggestedFromStart;
 
469
 
 
470
        QString beforeNickText(QString text) {
 
471
                int i;
 
472
                for (i = text.length() - 1; i >= 0; --i)
 
473
                        if ( text[i].isSpace() )
 
474
                                break;
 
475
 
 
476
                QString beforeNick = text.left(i+1);
 
477
                return beforeNick;
 
478
        }
 
479
 
 
480
        QStringList suggestNicks(QString text, bool fromStart) {
 
481
                QString nickText = text;
 
482
                QString beforeNick;
 
483
                if ( !fromStart ) {
 
484
                        beforeNick = beforeNickText(text);
 
485
                        nickText   = text.mid(beforeNick.length());
 
486
                }
 
487
 
 
488
                QStringList nicks = lv_users->nickList();
 
489
                QStringList::Iterator it = nicks.begin();
 
490
                QStringList suggestedNicks;
 
491
                for ( ; it != nicks.end(); ++it) {
 
492
                        if ( (*it).left(nickText.length()).lower() == nickText.lower() ) {
 
493
                                if ( fromStart )
 
494
                                        suggestedNicks << *it;
 
495
                                else
 
496
                                        suggestedNicks << beforeNick + *it;
 
497
                        }
 
498
                }
 
499
 
 
500
                return suggestedNicks;
 
501
        }
 
502
 
 
503
        QString longestSuggestedString(QStringList suggestedNicks) {
 
504
                QString testString = suggestedNicks.first();
 
505
                while ( testString.length() > 0 ) {
 
506
                        bool found = true;
 
507
                        QStringList::Iterator it = suggestedNicks.begin();
 
508
                        for ( ; it != suggestedNicks.end(); ++it) {
 
509
                                if ( (*it).left(testString.length()).lower() != testString.lower() ) {
 
510
                                        found = false;
 
511
                                        break;
 
512
                                }
 
513
                        }
 
514
 
 
515
                        if ( found )
 
516
                                break;
 
517
 
 
518
                        testString = testString.left( testString.length() - 1 );
 
519
                }
 
520
 
 
521
                return testString;
 
522
        }
 
523
 
 
524
        QString insertNick(bool fromStart, QString beforeNick = "") {
 
525
                typingStatus = Typing_MultipleSuggestions;
 
526
                suggestedFromStart = fromStart;
 
527
                suggestedNicks = lv_users->nickList();
 
528
                QStringList::Iterator it = suggestedNicks.begin();
 
529
                for ( ; it != suggestedNicks.end(); ++it)
 
530
                        *it = beforeNick + *it;
 
531
 
 
532
                QString newText;
 
533
                if ( !lastReferrer.isEmpty() ) {
 
534
                        newText = beforeNick + lastReferrer;
 
535
                        suggestedIndex = -1;
 
536
                }
 
537
                else {
 
538
                        newText = suggestedNicks.first();
 
539
                        suggestedIndex = 0;
 
540
                }
 
541
 
 
542
                if ( fromStart ) {
 
543
                        newText += nickSeparator;
 
544
                        newText += " ";
 
545
                }
 
546
 
 
547
                return newText;
 
548
        }
 
549
 
 
550
        QString suggestNick(bool fromStart, QString origText, bool *replaced) {
 
551
                suggestedFromStart = fromStart;
 
552
                suggestedNicks = suggestNicks(origText, fromStart);
 
553
                suggestedIndex = -1;
 
554
 
 
555
                QString newText;
 
556
                if ( suggestedNicks.count() ) {
 
557
                        if ( suggestedNicks.count() == 1 ) {
 
558
                                newText = suggestedNicks.first();
 
559
                                if ( fromStart ) {
 
560
                                        newText += nickSeparator;
 
561
                                        newText += " ";
 
562
                                }
 
563
                        }
 
564
                        else {
 
565
                                newText = longestSuggestedString(suggestedNicks);
 
566
                                if ( !newText.length() )
 
567
                                        return origText;
 
568
 
 
569
                                typingStatus = Typing_MultipleSuggestions;
 
570
                                // TODO: display a tooltip that will contain all suggestedNicks
 
571
                        }
 
572
 
 
573
                        *replaced = true;
 
574
                }
 
575
 
 
576
                return newText;
 
577
        }
 
578
 
 
579
        void doAutoNickInsertion() {
 
580
                int para, index;
 
581
                mle->getCursorPosition(&para, &index);
 
582
                QString paraText = mle->text(para);
 
583
                QString origText = paraText.left(index);
 
584
                QString newText;
 
585
 
 
586
                bool replaced = false;
 
587
 
 
588
                if ( typingStatus == Typing_MultipleSuggestions ) {
 
589
                        suggestedIndex++;
 
590
                        if ( suggestedIndex >= (int)suggestedNicks.count() )
 
591
                                suggestedIndex = 0;
 
592
 
 
593
                        newText = suggestedNicks[suggestedIndex];
 
594
                        if ( suggestedFromStart ) {
 
595
                                newText += nickSeparator;
 
596
                                newText += " ";
 
597
                        }
 
598
 
 
599
                        replaced = true;
 
600
                }
 
601
 
 
602
                if ( !para && !replaced ) {
 
603
                        if ( !index && typingStatus == Typing_TabbingNicks ) {
 
604
                                newText = insertNick(true, "");
 
605
                                replaced = true;
 
606
                        }
 
607
                        else {
 
608
                                newText = suggestNick(true, origText, &replaced);
 
609
                        }
 
610
                }
 
611
 
 
612
                if ( !replaced ) {
 
613
                        if ( (!index || origText[index-1].isSpace()) && typingStatus == Typing_TabbingNicks ) {
 
614
                                newText = insertNick(false, beforeNickText(origText));
 
615
                                replaced = true;
 
616
                        }
 
617
                        else {
 
618
                                newText = suggestNick(false, origText, &replaced);
 
619
                        }
 
620
                }
 
621
 
 
622
                if ( replaced ) {
 
623
                        mle->setUpdatesEnabled( false );
 
624
                        QString newParaText = newText + paraText.mid(index, paraText.length() - index - 1);
 
625
                        mle->insertParagraph(newParaText, para);
 
626
                        mle->removeParagraph(para+1);
 
627
                        mle->setCursorPosition(para, newText.length());
 
628
                        mle->setUpdatesEnabled( true );
 
629
                        mle->viewport()->update();
 
630
                }
 
631
        }
 
632
 
 
633
        bool eventFilter( QObject *obj, QEvent *ev ) {
 
634
                if ( obj == mle && ev->type() == QEvent::KeyPress ) {
 
635
                        QKeyEvent *e = (QKeyEvent *)ev;
 
636
 
 
637
                        if ( e->key() == Key_Tab ) {
 
638
                                switch ( typingStatus ) {
 
639
                                case Typing_Normal:
 
640
                                        typingStatus = Typing_TabPressed;
 
641
                                        break;
 
642
                                case Typing_TabPressed:
 
643
                                        typingStatus = Typing_TabbingNicks;
 
644
                                        break;
 
645
                                default:
 
646
                                        break;
 
647
                                }
 
648
 
 
649
                                doAutoNickInsertion();
 
650
                                return TRUE;
 
651
                        }
 
652
 
 
653
                        typingStatus = Typing_Normal;
 
654
 
 
655
                        return FALSE;
 
656
                }
 
657
 
 
658
                return QObject::eventFilter( obj, ev );
 
659
        }
 
660
};
 
661
 
 
662
GCMainDlg::GCMainDlg(PsiAccount *pa, const Jid &j)
 
663
:QWidget(0, 0, WDestructiveClose)
 
664
{
 
665
        nicknumber=0;
 
666
        d = new Private(this);
 
667
        d->pa = pa;
 
668
        d->jid = j.userHost();
 
669
        d->self = j.resource();
 
670
        d->pa->dialogRegister(this, d->jid);
 
671
        connect(d->pa, SIGNAL(updatedActivity()), SLOT(pa_updatedActivity()));
 
672
 
 
673
        d->pending = 0;
 
674
        d->flashTimer = 0;
 
675
 
 
676
        d->histAt = 0;
 
677
        d->findDlg = 0;
 
678
 
 
679
        d->trackBar = false;
 
680
        d->trackBarParagraph = 0;
 
681
 
 
682
        d->state = Private::Connected;
 
683
 
 
684
#ifndef Q_WS_MAC
 
685
        setIcon(IconsetFactory::icon("psi/groupChat"));
 
686
#endif
 
687
 
 
688
        d->act_find = new IconAction(tr("Find"), "psi/search", tr("&Find"), CTRL+Key_F, this);
 
689
        connect(d->act_find, SIGNAL(activated()), SLOT(openFind()));
 
690
 
 
691
        QVBoxLayout *dlg_layout = new QVBoxLayout(this);
 
692
 
 
693
        QSplitter *vsplit = new QSplitter(this);
 
694
        vsplit->setOrientation( QSplitter::Vertical );
 
695
        dlg_layout->addWidget(vsplit);
 
696
 
 
697
        // --- top part ---
 
698
        QWidget *sp_top = new QWidget(vsplit);
 
699
        QVBoxLayout *vb_top = new QVBoxLayout(sp_top, 4);
 
700
 
 
701
        // top row
 
702
        QHBoxLayout *hb_top = new QHBoxLayout(vb_top);
 
703
 
 
704
        d->pb_topic = new QPushButton(tr("Topic:"), sp_top);
 
705
        connect(d->pb_topic, SIGNAL(clicked()), SLOT(doTopic()));
 
706
        hb_top->addWidget(d->pb_topic);
 
707
 
 
708
        d->le_topic = new QLineEdit(sp_top);
 
709
        d->le_topic->setReadOnly(true);
 
710
        hb_top->addWidget(d->le_topic);
 
711
 
 
712
        IconToolButton *tb_find = new IconToolButton(sp_top);
 
713
        tb_find->setIcon(IconsetFactory::iconPtr("psi/search"));
 
714
        connect(tb_find, SIGNAL(clicked()), SLOT(openFind()));
 
715
        hb_top->addWidget(tb_find);
 
716
 
 
717
        QLabel *lb_ident = d->pa->accountLabel(sp_top, true);
 
718
        lb_ident->setSizePolicy(QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ));
 
719
        hb_top->addWidget(lb_ident);
 
720
 
 
721
        // bottom row
 
722
        QSplitter *hsp = new QSplitter(sp_top);
 
723
        hsp->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
 
724
        vb_top->addWidget(hsp);
 
725
        hsp->setOrientation(QSplitter::Horizontal);
 
726
 
 
727
        d->te_log = new ChatView(hsp);
 
728
        d->te_log->setTextFormat( RichText );
 
729
 
 
730
        d->lv_users = new GCUserView(hsp);
 
731
        d->lv_users->setMinimumWidth(20);
 
732
        connect(d->lv_users, SIGNAL(action(const QString &, const Status &, int)), SLOT(lv_action(const QString &, const Status &, int)));
 
733
 
 
734
        // --- bottom part ---
 
735
        QWidget *sp_bottom = new QWidget(vsplit);
 
736
        QVBoxLayout *vb_bottom = new QVBoxLayout(sp_bottom, 4);
 
737
 
 
738
        // top row
 
739
        // icon selector
 
740
        //connect(pa->psi->iconSelectPopup(), SIGNAL(iconSelected(const Icon *)), d, SLOT(addEmoticon(const Icon *)));
 
741
        connect(pa->psi()->iconSelectPopup(), SIGNAL(textSelected(QString)), d, SLOT(addEmoticon(QString)));
 
742
 
 
743
        d->tb_clear = new IconToolButton(sp_bottom) ;
 
744
        d->tb_clear->setIcon(IconsetFactory::iconPtr("psi/clearChat"));
 
745
        connect(d->tb_clear, SIGNAL(clicked()), SLOT(doClearButton()));
 
746
 
 
747
        d->tb_icon = new IconToolButton(sp_bottom);
 
748
        d->tb_icon->setIcon(IconsetFactory::iconPtr("psi/smile"));
 
749
        d->tb_icon->setPopup(pa->psi()->iconSelectPopup());
 
750
        d->tb_icon->setPopupDelay (1);
 
751
 
 
752
        QHBoxLayout *toolbox = new QHBoxLayout(vb_bottom);
 
753
        toolbox->addWidget(d->tb_clear);
 
754
        toolbox->addStretch();
 
755
        toolbox->addWidget(d->tb_icon);
 
756
 
 
757
        // chat edit
 
758
        d->mle = new ChatEdit(sp_bottom);
 
759
        //d->mle->setFixedHeight(48);
 
760
        vb_bottom->addWidget(d->mle);
 
761
        d->mle->installEventFilter( d );
 
762
 
 
763
        // resize the horizontal splitter
 
764
        QValueList<int> list;
 
765
        list << 500;
 
766
        list << 80;
 
767
        hsp->setSizes(list);
 
768
 
 
769
        list.clear();
 
770
        list << 324;
 
771
        list << 10;
 
772
        vsplit->setSizes(list);
 
773
 
 
774
        resize(580,420);
 
775
 
 
776
        X11WM_CLASS("groupchat");
 
777
 
 
778
        d->mle->setFocus();
 
779
 
 
780
        setLooks();
 
781
        updateCaption();
 
782
}
 
783
 
 
784
GCMainDlg::~GCMainDlg()
 
785
{
 
786
        if(d->state != Private::Idle)
 
787
                d->pa->groupChatLeave(d->jid.host(), d->jid.user());
 
788
 
 
789
        //QMimeSourceFactory *m = d->te_log->mimeSourceFactory();
 
790
        //d->te_log->setMimeSourceFactory(0);
 
791
        //delete m;
 
792
 
 
793
        d->pa->dialogUnregister(this);
 
794
        delete d;
 
795
}
 
796
 
 
797
void GCMainDlg::keyPressEvent(QKeyEvent *e)
 
798
{
 
799
        if(e->key() == Key_Return || e->key() == Key_Enter || (e->key() == Key_S && (e->state() & AltButton)))
 
800
                mle_returnPressed();
 
801
        else if(e->key() == Key_PageUp && (e->state() & ShiftButton))
 
802
                d->te_log->setContentsPos(d->te_log->contentsX(), d->te_log->contentsY() - d->te_log->visibleHeight()/2);
 
803
        else if(e->key() == Key_PageDown && (e->state() & ShiftButton))
 
804
                d->te_log->setContentsPos(d->te_log->contentsX(), d->te_log->contentsY() + d->te_log->visibleHeight()/2);
 
805
        else
 
806
                e->ignore();
 
807
}
 
808
 
 
809
void GCMainDlg::closeEvent(QCloseEvent *e)
 
810
{
 
811
        e->accept();
 
812
}
 
813
 
 
814
void GCMainDlg::windowActivationChange(bool oldstate)
 
815
{
 
816
        QWidget::windowActivationChange(oldstate);
 
817
 
 
818
        // if we're bringing it to the front, get rid of the '*' if necessary
 
819
        if(isActiveWindow()) {
 
820
                if(d->pending > 0) {
 
821
                        d->pending = 0;
 
822
                        updateCaption();
 
823
                }
 
824
                doFlash(false);
 
825
 
 
826
                d->mle->setFocus();
 
827
                d->trackBar = false;
 
828
        } else {
 
829
                d->trackBar = true;
 
830
        }
 
831
}
 
832
 
 
833
void GCMainDlg::mle_returnPressed()
 
834
{
 
835
        if(d->mle->text().isEmpty())
 
836
                return;
 
837
 
 
838
        QString str = d->mle->text();
 
839
        if(str == "/clear") {
 
840
                doClear();
 
841
 
 
842
                d->histAt = 0;
 
843
                d->hist.prepend(str);
 
844
                d->mle->setText("");
 
845
                return;
 
846
        }
 
847
 
 
848
        if(str.lower().startsWith("/nick ")) {
 
849
                QString nick = str.mid(6).stripWhiteSpace();
 
850
                if ( !nick.isEmpty() ) {
 
851
                        d->self = nick;
 
852
                        d->pa->groupChatChangeNick(d->jid.host(), d->jid.user(), d->self, d->pa->status());
 
853
                }
 
854
                d->mle->setText("");
 
855
                return;
 
856
        }
 
857
 
 
858
        if(d->state != Private::Connected)
 
859
                return;
 
860
 
 
861
        Message m(d->jid);
 
862
        m.setType("groupchat");
 
863
        m.setBody(str);
 
864
        m.setTimeStamp(QDateTime::currentDateTime());
 
865
 
 
866
        aSend(m);
 
867
 
 
868
        d->histAt = 0;
 
869
        d->hist.prepend(str);
 
870
        d->mle->setText("");
 
871
}
 
872
 
 
873
/*void GCMainDlg::le_upPressed()
 
874
{
 
875
        if(d->histAt < (int)d->hist.count()) {
 
876
                ++d->histAt;
 
877
                d->le_input->setText(d->hist[d->histAt-1]);
 
878
        }
 
879
}
 
880
 
 
881
void GCMainDlg::le_downPressed()
 
882
{
 
883
        if(d->histAt > 0) {
 
884
                --d->histAt;
 
885
                if(d->histAt == 0)
 
886
                        d->le_input->setText("");
 
887
                else
 
888
                        d->le_input->setText(d->hist[d->histAt-1]);
 
889
        }
 
890
}*/
 
891
 
 
892
void GCMainDlg::doTopic()
 
893
{
 
894
        bool ok = false;
 
895
        QString str = QInputDialog::getText(
 
896
                tr("Set Groupchat Topic"),
 
897
                tr("Enter a topic:"),
 
898
                QLineEdit::Normal, d->le_topic->text(), &ok, this);
 
899
 
 
900
        if(ok) {
 
901
                Message m(d->jid);
 
902
                m.setType("groupchat");
 
903
                m.setSubject(str);
 
904
                m.setBody(QString("/me ") + tr("has set the topic to: %1").arg(str));
 
905
                m.setTimeStamp(QDateTime::currentDateTime());
 
906
                aSend(m);
 
907
        }
 
908
}
 
909
 
 
910
void GCMainDlg::doClear()
 
911
{
 
912
        d->te_log->setText("");
 
913
}
 
914
 
 
915
void GCMainDlg::doClearButton()
 
916
{
 
917
        int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to clear the chat window?\n(note: does not affect saved history)"), tr("&Yes"), tr("&No"));
 
918
        if(n == 0)
 
919
                doClear();
 
920
}
 
921
 
 
922
void GCMainDlg::openFind()
 
923
{
 
924
        if(d->findDlg)
 
925
                bringToFront(d->findDlg);
 
926
        else {
 
927
                d->findDlg = new GCFindDlg(0, 0, d->lastSearch, this);
 
928
                connect(d->findDlg, SIGNAL(find(int, int, const QString &)), SLOT(doFind(int, int, const QString &)));
 
929
                d->findDlg->show();
 
930
        }
 
931
}
 
932
 
 
933
void GCMainDlg::doFind(int para, int index, const QString &str)
 
934
{
 
935
        d->lastSearch = str;
 
936
 
 
937
        if(!d->te_log->find(str, false, false, true, &para, &index))
 
938
                d->findDlg->error(str);
 
939
        else {
 
940
                // pass one character over
 
941
                d->findDlg->found(para, index+1);
 
942
        }
 
943
}
 
944
 
 
945
void GCMainDlg::goDisc()
 
946
{
 
947
        if(d->state != Private::Idle) {
 
948
                d->state = Private::Idle;
 
949
                d->pb_topic->setEnabled(false);
 
950
                appendSysMsg(tr("Disconnected."), true);
 
951
        }
 
952
}
 
953
 
 
954
void GCMainDlg::goConn()
 
955
{
 
956
        if(d->state == Private::Idle) {
 
957
                d->state = Private::Connecting;
 
958
                appendSysMsg(tr("Reconnecting..."), true);
 
959
 
 
960
                QString host = d->jid.host();
 
961
                QString room = d->jid.user();
 
962
                QString nick = d->self;
 
963
 
 
964
                if(!d->pa->groupChatJoin(host, room, nick)) {
 
965
                        appendSysMsg(tr("Error: You are in or joining this room already!"), true);
 
966
                        d->state = Private::Idle;
 
967
                }
 
968
        }
 
969
}
 
970
 
 
971
void GCMainDlg::pa_updatedActivity()
 
972
{
 
973
        if(!d->pa->loggedIn())
 
974
                goDisc();
 
975
        else {
 
976
                if(d->state == Private::Idle)
 
977
                        goConn();
 
978
                else if(d->state == Private::Connected)
 
979
                        d->pa->groupChatSetStatus(d->jid.host(), d->jid.user(), d->pa->status());
 
980
        }
 
981
}
 
982
 
 
983
Jid GCMainDlg::jid() const
 
984
{
 
985
        return d->jid;
 
986
}
 
987
 
 
988
void GCMainDlg::error(int, const QString &str)
 
989
{
 
990
        d->pb_topic->setEnabled(false);
 
991
 
 
992
        if(d->state == Private::Connecting)
 
993
                appendSysMsg(tr("Unable to join groupchat.  Reason: %1").arg(str), true);
 
994
        else
 
995
                appendSysMsg(tr("Unexpected groupchat error: %1").arg(str), true);
 
996
 
 
997
        d->state = Private::Idle;
 
998
}
 
999
 
 
1000
void GCMainDlg::presence(const QString &nick, const Status &s)
 
1001
{
 
1002
        if(s.isAvailable()) {
 
1003
                /*if ((option.showJoins)&&(d->lv_users->findEntry(nick)==0)) {
 
1004
                        //contact joining
 
1005
                        QString m=nick+tr(" has joined the channel");
 
1006
                        appendSysMsg(m, false, QDateTime::currentDateTime());
 
1007
                }*/
 
1008
                d->lv_users->updateEntry(nick, s);
 
1009
        } else {
 
1010
                /*if (option.showJoins) {
 
1011
                        //contact leaving
 
1012
                        QString m=nick+tr(" has left the channel");
 
1013
                        appendSysMsg(m, false, QDateTime::currentDateTime());
 
1014
                }*/
 
1015
                d->lv_users->removeEntry(nick);
 
1016
        }
 
1017
}
 
1018
 
 
1019
void GCMainDlg::message(const Message &m)
 
1020
{
 
1021
        QString from = m.from().resource();
 
1022
        bool alert = false;
 
1023
 
 
1024
        if(!m.subject().isEmpty()) {
 
1025
                d->le_topic->setText(m.subject());
 
1026
                d->le_topic->setCursorPosition(0);
 
1027
                QToolTip::add(d->le_topic, QString("<qt><p>%1</p></qt>").arg(m.subject()));
 
1028
        }
 
1029
 
 
1030
        // code to determine if the speaker was addressing this client in chat
 
1031
        if(m.body().contains(d->self) > 0)
 
1032
                alert = true;
 
1033
 
 
1034
        if (m.body().left(d->self.length()) == d->self)
 
1035
                d->lastReferrer = m.from().resource();
 
1036
 
 
1037
        if(option.gcHighlighting) {
 
1038
                for(QStringList::Iterator it=option.gcHighlights.begin();it!=option.gcHighlights.end();it++) {
 
1039
                        if(m.body().contains((*it),false) > 0) {
 
1040
                                alert = true;
 
1041
                        }
 
1042
                }
 
1043
        }
 
1044
 
 
1045
        // play sound?
 
1046
        if(from == d->self) {
 
1047
                if(!m.spooled())
 
1048
                        d->pa->playSound(option.onevent[eSend]);
 
1049
        }
 
1050
        else {
 
1051
                if(alert || (!option.noGCSound && !m.spooled() && !from.isEmpty()) )
 
1052
                        d->pa->playSound(option.onevent[eChat2]);
 
1053
        }
 
1054
 
 
1055
        if(from.isEmpty())
 
1056
                appendSysMsg(m.body(), alert, m.timeStamp());
 
1057
        else
 
1058
                appendMessage(m, alert);
 
1059
}
 
1060
 
 
1061
void GCMainDlg::joined()
 
1062
{
 
1063
        if(d->state == Private::Connecting) {
 
1064
                d->lv_users->QListView::clear();
 
1065
                d->state = Private::Connected;
 
1066
                d->pb_topic->setEnabled(true);
 
1067
                appendSysMsg(tr("Connected."), true);
 
1068
        }
 
1069
}
 
1070
 
 
1071
void GCMainDlg::appendSysMsg(const QString &str, bool alert, const QDateTime &ts)
 
1072
{
 
1073
        bool atBottom = d->te_log->contentsY() >= d->te_log->contentsHeight() - d->te_log->visibleHeight();
 
1074
 
 
1075
        QString hr ="";
 
1076
        if (d->trackBar) {
 
1077
                hr = QString("<hr>");
 
1078
                d->trackBar = false;
 
1079
 
 
1080
                if ( d->trackBarParagraph ) {
 
1081
                        d->te_log->setUpdatesEnabled( false );
 
1082
                        d->te_log->setSelection(d->trackBarParagraph, 0, d->trackBarParagraph, 1, 1);
 
1083
                        d->te_log->removeSelectedText(1);
 
1084
                        d->te_log->setUpdatesEnabled( true );
 
1085
                }
 
1086
                d->trackBarParagraph = d->te_log->paragraphs();
 
1087
        }
 
1088
 
 
1089
        QString timestr;
 
1090
        if (!option.gcHighlighting)
 
1091
                alert=false;
 
1092
 
 
1093
        QDateTime time;
 
1094
        if(!ts.isNull())
 
1095
                time = ts;
 
1096
        else
 
1097
                time = QDateTime::currentDateTime();
 
1098
 
 
1099
        //timestr.sprintf("%02d:%02d:%02d", time.time().hour(), time.time().minute(), time.time().second());
 
1100
        timestr = time.time().toString(LocalDate);
 
1101
 
 
1102
        /*int y = d->te_log->contentsHeight() - d->te_log->visibleHeight();
 
1103
        if(y < 0)
 
1104
                y = 0;
 
1105
        bool atBottom = (d->te_log->contentsY() < y - 32) ? false: true;*/
 
1106
 
 
1107
        d->te_log->append(hr + QString("<font color=\"#00A000\">[%1]").arg(timestr) + QString(" *** %1</font>").arg(expandEntities(str)));
 
1108
 
 
1109
        if(atBottom)
 
1110
                d->deferredScroll();
 
1111
 
 
1112
        if(alert)
 
1113
                doAlert();
 
1114
}
 
1115
 
 
1116
QString GCMainDlg::getNickColor(QString nick)
 
1117
{
 
1118
        int sender;
 
1119
        if(nick == d->self||nick.isEmpty())
 
1120
                sender = -1;
 
1121
        else {
 
1122
                if (!nicks.contains(nick)) {
 
1123
                        //not found in map
 
1124
                        nicks.insert(nick,nicknumber);
 
1125
                        nicknumber++;
 
1126
                }
 
1127
                sender=nicks[nick];
 
1128
        }
 
1129
 
 
1130
        if(!option.gcNickColoring || option.gcNickColors.empty()) {
 
1131
                return "#000000";
 
1132
        }
 
1133
        else if(sender == -1 || option.gcNickColors.size() == 1) {
 
1134
                return option.gcNickColors[option.gcNickColors.size()-1];
 
1135
        }
 
1136
        else {
 
1137
                int n = sender % (option.gcNickColors.size()-1);
 
1138
                return option.gcNickColors[n];
 
1139
        }
 
1140
}
 
1141
 
 
1142
void GCMainDlg::appendMessage(const Message &m, bool alert)
 
1143
{
 
1144
        //QString who, color;
 
1145
        if (!option.gcHighlighting)
 
1146
                alert=false;
 
1147
        QString who, textcolor, nickcolor,alerttagso,alerttagsc;
 
1148
 
 
1149
        bool atBottom = d->te_log->contentsY() >= d->te_log->contentsHeight() - d->te_log->visibleHeight();
 
1150
 
 
1151
        who = m.from().resource();
 
1152
        QString hr = "";
 
1153
        if (d->trackBar&&m.from().resource() != d->self&&!m.spooled()) {
 
1154
                hr = QString("<hr>");
 
1155
                d->trackBar = false;
 
1156
 
 
1157
                if ( d->trackBarParagraph ) {
 
1158
                        d->te_log->setUpdatesEnabled( false );
 
1159
                        d->te_log->setSelection(d->trackBarParagraph, 0, d->trackBarParagraph, 1, 1);
 
1160
                        d->te_log->removeSelectedText(1);
 
1161
                        d->te_log->setUpdatesEnabled( true );
 
1162
                }
 
1163
                d->trackBarParagraph = d->te_log->paragraphs();
 
1164
        }
 
1165
        /*if(local) {
 
1166
                color = "#FF0000";
 
1167
        }
 
1168
        else {
 
1169
                color = "#0000FF";
 
1170
        }*/
 
1171
        nickcolor = getNickColor(who);
 
1172
        textcolor = d->te_log->palette().active().text().name();
 
1173
        if(alert) {
 
1174
                textcolor = "#FF0000";
 
1175
                alerttagso = "<b>";
 
1176
                alerttagsc = "</b>";
 
1177
        }
 
1178
        if(m.spooled())
 
1179
                nickcolor = "#008000"; //color = "#008000";
 
1180
 
 
1181
        QString timestr;
 
1182
        QDateTime time = m.timeStamp();
 
1183
        //timestr.sprintf("%02d:%02d:%02d", time.time().hour(), time.time().minute(), time.time().second());
 
1184
        timestr = time.time().toString(LocalDate);
 
1185
 
 
1186
        /*int y = d->te_log->contentsHeight() - d->te_log->visibleHeight();
 
1187
        if(y < 0)
 
1188
                y = 0;
 
1189
        bool atBottom = (d->te_log->contentsY() < y - 32) ? false: true;*/
 
1190
 
 
1191
        bool emote = false;
 
1192
        if(m.body().left(4) == "/me ")
 
1193
                emote = true;
 
1194
 
 
1195
        QString txt;
 
1196
        if(emote)
 
1197
                txt = plain2rich(m.body().mid(4));
 
1198
        else
 
1199
                txt = plain2rich(m.body());
 
1200
 
 
1201
        txt = linkify(txt);
 
1202
 
 
1203
        if(option.useEmoticons)
 
1204
                txt = emoticonify(txt);
 
1205
 
 
1206
        if(emote) {
 
1207
                //d->te_log->append(QString("<font color=\"%1\">").arg(color) + QString("[%1]").arg(timestr) + QString(" *%1 ").arg(expandEntities(who)) + txt + "</font>");
 
1208
                d->te_log->append(hr + QString("<font color=\"%1\">").arg(nickcolor) + QString("[%1]").arg(timestr) + QString(" *%1 ").arg(expandEntities(who)) + alerttagso + txt + alerttagsc + "</font>");
 
1209
        }
 
1210
        else {
 
1211
                if(option.chatSays) {
 
1212
                        //d->te_log->append(QString("<font color=\"%1\">").arg(color) + QString("[%1] ").arg(timestr) + QString("%1 says:").arg(expandEntities(who)) + "</font><br>" + txt);
 
1213
                        d->te_log->append(hr + QString("<font color=\"%1\">").arg(nickcolor) + QString("[%1] ").arg(timestr) + QString("%1 says:").arg(expandEntities(who)) + "</font><br>" + QString("<font color=\"%1\">").arg(textcolor) + alerttagso + txt + alerttagsc + "</font>");
 
1214
                }
 
1215
                else {
 
1216
                        //d->te_log->append(QString("<font color=\"%1\">").arg(color) + QString("[%1] &lt;").arg(timestr) + expandEntities(who) + QString("&gt;</font> ") + txt);
 
1217
                        d->te_log->append(hr + QString("<font color=\"%1\">").arg(nickcolor) + QString("[%1] &lt;").arg(timestr) + expandEntities(who) + QString("&gt;</font> ") + QString("<font color=\"%1\">").arg(textcolor) + alerttagso + txt + alerttagsc +"</font>");
 
1218
                }
 
1219
        }
 
1220
 
 
1221
        //if(local || atBottom)
 
1222
        if(m.from().resource() == d->self || atBottom)
 
1223
                d->deferredScroll();
 
1224
 
 
1225
        // if we're not active, notify the user by changing the title
 
1226
        if(!isActiveWindow()) {
 
1227
                ++d->pending;
 
1228
                updateCaption();
 
1229
        }
 
1230
 
 
1231
        //if someone directed their comments to us, notify the user
 
1232
        if(alert)
 
1233
                doAlert();
 
1234
 
 
1235
        //if the message spoke to us, alert the user before closing this window
 
1236
        //except that keepopen doesn't seem to be implemented for this class yet.
 
1237
        /*if(alert) {
 
1238
                d->keepOpen = true;
 
1239
                QTimer::singleShot(1000, this, SLOT(setKeepOpenFalse()));
 
1240
        }*/
 
1241
}
 
1242
 
 
1243
void GCMainDlg::doAlert()
 
1244
{
 
1245
        if(!isActiveWindow())
 
1246
                doFlash(true);
 
1247
}
 
1248
 
 
1249
void GCMainDlg::updateCaption()
 
1250
{
 
1251
        QString cap = "";
 
1252
 
 
1253
        if(d->pending > 0) {
 
1254
                cap += "* ";
 
1255
                if(d->pending > 1)
 
1256
                        cap += QString("[%1] ").arg(d->pending);
 
1257
        }
 
1258
        cap += d->jid.full();
 
1259
 
 
1260
        // if taskbar flash, then we need to erase first and redo
 
1261
#ifdef Q_WS_WIN
 
1262
        bool on = false;
 
1263
        if(d->flashTimer)
 
1264
                on = d->flashCount & 1;
 
1265
        if(on)
 
1266
                FlashWindow(winId(), true);
 
1267
#endif
 
1268
        setCaption(cap);
 
1269
#ifdef Q_WS_WIN
 
1270
        if(on)
 
1271
                FlashWindow(winId(), true);
 
1272
#endif
 
1273
}
 
1274
 
 
1275
#ifdef Q_WS_WIN
 
1276
void GCMainDlg::doFlash(bool yes)
 
1277
{
 
1278
        if(yes) {
 
1279
                if(d->flashTimer)
 
1280
                        return;
 
1281
                d->flashTimer = new QTimer(this);
 
1282
                connect(d->flashTimer, SIGNAL(timeout()), SLOT(flashAnimate()));
 
1283
                d->flashCount = 0;
 
1284
                flashAnimate(); // kick the first one immediately
 
1285
                d->flashTimer->start(500);
 
1286
        }
 
1287
        else {
 
1288
                if(d->flashTimer) {
 
1289
                        delete d->flashTimer;
 
1290
                        d->flashTimer = 0;
 
1291
                        FlashWindow(winId(), false);
 
1292
                }
 
1293
        }
 
1294
}
 
1295
#else
 
1296
void GCMainDlg::doFlash(bool)
 
1297
{
 
1298
}
 
1299
#endif
 
1300
 
 
1301
void GCMainDlg::flashAnimate()
 
1302
{
 
1303
#ifdef Q_WS_WIN
 
1304
        FlashWindow(winId(), true);
 
1305
        ++d->flashCount;
 
1306
        if(d->flashCount == 5)
 
1307
                d->flashTimer->stop();
 
1308
#endif
 
1309
}
 
1310
 
 
1311
void GCMainDlg::setLooks()
 
1312
{
 
1313
        // update the fonts
 
1314
        QFont f;
 
1315
        f.fromString(option.font[fChat]);
 
1316
        d->te_log->setFont(f);
 
1317
        d->mle->setFont(f);
 
1318
 
 
1319
        f.fromString(option.font[fRoster]);
 
1320
        d->lv_users->QListView::setFont(f);
 
1321
 
 
1322
        if ( option.useEmoticons ) {
 
1323
                //d->tb_clear->show();
 
1324
                d->tb_icon->show();
 
1325
        }
 
1326
        else {
 
1327
                //d->tb_clear->hide();
 
1328
                d->tb_icon->hide();
 
1329
        }
 
1330
 
 
1331
        // update the widget icon
 
1332
#ifndef Q_WS_MAC
 
1333
        setIcon(IconsetFactory::icon("psi/groupChat"));
 
1334
#endif
 
1335
}
 
1336
 
 
1337
void GCMainDlg::optionsUpdate()
 
1338
{
 
1339
        /*QMimeSourceFactory *m = d->te_log->mimeSourceFactory();
 
1340
        d->te_log->setMimeSourceFactory(is->emoticons.generateFactory());
 
1341
        delete m;*/
 
1342
 
 
1343
        setLooks();
 
1344
 
 
1345
        // update status icons
 
1346
        d->lv_users->updateAll();
 
1347
}
 
1348
 
 
1349
void GCMainDlg::lv_action(const QString &nick, const Status &s, int x)
 
1350
{
 
1351
        if(x == 0) {
 
1352
                d->pa->invokeGCMessage(d->jid.withResource(nick));
 
1353
        }
 
1354
        else if(x == 1) {
 
1355
                d->pa->invokeGCChat(d->jid.withResource(nick));
 
1356
        }
 
1357
        else if(x == 2) {
 
1358
                UserListItem u;
 
1359
                u.setJid(d->jid.withResource(nick));
 
1360
                u.setName(nick);
 
1361
 
 
1362
                // make a resource so the contact appears online
 
1363
                UserResource ur;
 
1364
                ur.setName(nick);
 
1365
                ur.setStatus(s);
 
1366
                u.userResourceList().append(ur);
 
1367
 
 
1368
                StatusShowDlg *w = new StatusShowDlg(u);
 
1369
                w->show();
 
1370
        }
 
1371
        else if(x == 3) {
 
1372
                d->pa->invokeGCInfo(d->jid.withResource(nick));
 
1373
        }
 
1374
        else if(x == 4) {
 
1375
                d->pa->invokeGCFile(d->jid.withResource(nick));
 
1376
        }
 
1377
}
 
1378
 
 
1379
 
 
1380
//----------------------------------------------------------------------------
 
1381
// GCFindDlg
 
1382
//----------------------------------------------------------------------------
 
1383
GCFindDlg::GCFindDlg(int startPara, int startIndex, const QString &str, QWidget *parent, const char *name)
 
1384
:QDialog(parent, name, false, WDestructiveClose)
 
1385
{
 
1386
        para = startPara;
 
1387
        index = startIndex;
 
1388
 
 
1389
        setCaption(tr("Find"));
 
1390
        QVBoxLayout *vb = new QVBoxLayout(this, 4);
 
1391
        QHBoxLayout *hb = new QHBoxLayout(vb);
 
1392
        QLabel *l = new QLabel(tr("Find:"), this);
 
1393
        hb->addWidget(l);
 
1394
        le_input = new QLineEdit(this);
 
1395
        hb->addWidget(le_input);
 
1396
        vb->addStretch(1);
 
1397
 
 
1398
        QFrame *Line1 = new QFrame(this);
 
1399
        Line1->setFrameShape( QFrame::HLine );
 
1400
        Line1->setFrameShadow( QFrame::Sunken );
 
1401
        Line1->setFrameShape( QFrame::HLine );
 
1402
        vb->addWidget(Line1);
 
1403
 
 
1404
        hb = new QHBoxLayout(vb);
 
1405
        hb->addStretch(1);
 
1406
        QPushButton *pb_close = new QPushButton(tr("&Close"), this);
 
1407
        connect(pb_close, SIGNAL(clicked()), SLOT(close()));
 
1408
        hb->addWidget(pb_close);
 
1409
        QPushButton *pb_find = new QPushButton(tr("&Find"), this);
 
1410
        pb_find->setDefault(true);
 
1411
        connect(pb_find, SIGNAL(clicked()), SLOT(doFind()));
 
1412
        hb->addWidget(pb_find);
 
1413
        pb_find->setAutoDefault(true);
 
1414
 
 
1415
        resize(200, minimumSize().height());
 
1416
 
 
1417
        le_input->setText(str);
 
1418
        le_input->setFocus();
 
1419
}
 
1420
 
 
1421
GCFindDlg::~GCFindDlg()
 
1422
{
 
1423
}
 
1424
 
 
1425
void GCFindDlg::found(int _para, int _index)
 
1426
{
 
1427
        para = _para;
 
1428
        index = _index;
 
1429
}
 
1430
 
 
1431
void GCFindDlg::error(const QString &str)
 
1432
{
 
1433
        QMessageBox::warning(this, tr("Find"), tr("Search string '%1' not found.").arg(str));
 
1434
        le_input->setFocus();
 
1435
}
 
1436
 
 
1437
void GCFindDlg::doFind()
 
1438
{
 
1439
        find(para, index, le_input->text());
 
1440
}
 
1441
 
 
1442
#include "groupchatdlg.moc"