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