21
#include"groupchatdlg.h"
25
#include<qpushbutton.h>
27
#include<qmessagebox.h>
32
#include<qtoolbutton.h>
33
#include<qinputdialog.h>
34
#include<qguardedptr.h>
36
#include<qobjectlist.h>
37
#include<qpopupmenu.h>
40
#include"psiaccount.h"
43
#include"busywidget.h"
46
#include"iconwidget.h"
47
#include"iconselect.h"
48
#include"psitoolbar.h"
49
#include"iconaction.h"
21
// TODO: Move all the 'logic' of groupchats into MUCManager. See MUCManager
24
#include "groupchatdlg.h"
28
#include <qpushbutton.h>
30
#include <qmessagebox.h>
32
#include <QColorGroup>
33
#include <qsplitter.h>
36
#include <qtoolbutton.h>
37
#include <qinputdialog.h>
41
#include <q3popupmenu.h>
44
#include <QCloseEvent>
47
#include <QResizeEvent>
48
#include <QHBoxLayout>
51
#include <QVBoxLayout>
52
#include <QContextMenuEvent>
53
#include <QTextCursor>
54
#include <QTextDocument> // for Qt::escape()
57
#include "psiaccount.h"
58
#include "capsmanager.h"
60
#include "mucconfigdlg.h"
62
#include "statusdlg.h"
63
#include "xmpp_message.h"
64
#include "psiiconset.h"
65
#include "stretchwidget.h"
66
#include "mucmanager.h"
67
#include "busywidget.h"
70
#include "iconwidget.h"
71
#include "iconselect.h"
72
#include "psitoolbar.h"
73
#include "iconaction.h"
74
#include "psitooltip.h"
75
#include "psioptions.h"
76
#include "shortcutmanager.h"
77
#include "psicontactlist.h"
78
#include "accountlabel.h"
79
#include "gcuserview.h"
56
//----------------------------------------------------------------------------
58
//----------------------------------------------------------------------------
59
class GCJoinDlg::Private
66
AccountsComboBox *cb_ident;
72
GCJoinDlg::GCJoinDlg(PsiCon *psi, PsiAccount *pa)
73
:GCJoinUI(0, 0, false, WDestructiveClose)
78
d->psi->dialogRegister(this);
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);
88
d->rl = d->psi->recentGCList();
89
for(QStringList::ConstIterator it = d->rl.begin(); it != d->rl.end(); ++it) {
91
QString s = tr("%1 on %2").arg(j.resource()).arg(j.userHost());
92
cb_recent->insertItem(s);
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);
108
GCJoinDlg::~GCJoinDlg()
111
d->psi->dialogUnregister(this);
113
d->pa->dialogUnregister(this);
117
/*void GCJoinDlg::closeEvent(QCloseEvent *e)
123
void GCJoinDlg::done(int r)
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"));
129
d->pa->groupChatLeave(d->jid.host(), d->jid.user());
134
void GCJoinDlg::updateIdentity(PsiAccount *pa)
137
disconnect(d->pa, SIGNAL(disconnected()), this, SLOT(pa_disconnected()));
140
pb_join->setEnabled(d->pa);
147
connect(d->pa, SIGNAL(disconnected()), this, SLOT(pa_disconnected()));
150
void GCJoinDlg::pa_disconnected()
152
if(d->busy->isActive()) {
157
void GCJoinDlg::recent_activated(int x)
162
for(QStringList::ConstIterator it = d->rl.begin(); it != d->rl.end(); ++it) {
174
le_host->setText(j.host());
175
le_room->setText(j.user());
176
le_nick->setText(j.resource());
179
void GCJoinDlg::doJoin()
181
if(!d->pa->checkConnected(this))
184
QString host = le_host->text();
185
QString room = le_room->text();
186
QString nick = le_nick->text();
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."));
193
Jid j = room + '@' + host + '/' + nick;
195
QMessageBox::information(this, tr("Error"), tr("You entered an invalid room name."));
199
if(!d->pa->groupChatJoin(host, room, nick)) {
200
QMessageBox::information(this, tr("Error"), tr("You are in or joining this room already!"));
204
d->psi->dialogUnregister(this);
205
d->jid = room + '@' + host + '/' + nick;
206
d->pa->dialogRegister(this, d->jid);
212
void GCJoinDlg::disableWidgets()
214
d->cb_ident->setEnabled(false);
215
cb_recent->setEnabled(false);
216
gb_info->setEnabled(false);
217
pb_join->setEnabled(false);
220
void GCJoinDlg::enableWidgets()
222
d->cb_ident->setEnabled(true);
224
cb_recent->setEnabled(true);
225
gb_info->setEnabled(true);
226
pb_join->setEnabled(true);
229
void GCJoinDlg::joined()
231
d->psi->recentGCAdd(d->jid.full());
238
void GCJoinDlg::error(int, const QString &str)
245
d->pa->dialogUnregister(this);
246
d->psi->dialogRegister(this);
248
QMessageBox::information(this, tr("Error"), tr("Unable to join groupchat.\nReason: %1").arg(str));
252
//----------------------------------------------------------------------------
254
//----------------------------------------------------------------------------
255
GCUserViewItem::GCUserViewItem(QListView *par)
260
GCUserView::GCUserView(QWidget *parent, const char *name)
261
:QListView(parent, name), QToolTip(viewport())
263
setResizeMode(QListView::AllColumns);
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)));
272
GCUserView::~GCUserView()
276
void GCUserView::updateAll()
278
for(GCUserViewItem *i = (GCUserViewItem *)firstChild(); i; i = (GCUserViewItem *)i->nextSibling())
279
i->setPixmap(0, is->status(i->s));
282
QStringList GCUserView::nickList() const
286
for(QListViewItem *lvi = firstChild(); lvi; lvi = lvi->nextSibling())
287
list << lvi->text(0);
289
qstringlistisort(list); // caseless sorting
293
QListViewItem *GCUserView::findEntry(const QString &nick)
295
for(QListViewItem *lvi = firstChild(); lvi; lvi = lvi->nextSibling()) {
296
if(lvi->text(0) == nick)
302
void GCUserView::updateEntry(const QString &nick, const Status &s)
304
GCUserViewItem *lvi = (GCUserViewItem *)findEntry(nick);
306
lvi = new GCUserViewItem(this);
307
lvi->setText(0, nick);
311
lvi->setPixmap(0, is->status(lvi->s));
314
void GCUserView::removeEntry(const QString &nick)
316
QListViewItem *lvi = findEntry(nick);
321
void GCUserView::maybeTip(const QPoint &pos)
323
GCUserViewItem *lvi = (GCUserViewItem *)itemAt(pos);
327
QRect r(itemRect(lvi));
329
const QString &nick = lvi->text(0);
330
const Status &s = lvi->s;
332
// SICK SICK SICK SICK
333
u.setJid(((GCMainDlg *)topLevelWidget())->jid().withResource(nick));
336
// make a resource so the contact appears online
340
u.userResourceList().append(ur);
345
void GCUserView::qlv_doubleClicked(QListViewItem *i)
347
GCUserViewItem *lvi = (GCUserViewItem *)i;
351
if(option.defaultAction == 0)
352
action(lvi->text(0), lvi->s, 0);
354
action(lvi->text(0), lvi->s, 1);
357
void GCUserView::qlv_contextMenuRequested(QListViewItem *i, const QPoint &pos, int)
359
GCUserViewItem *lvi = (GCUserViewItem *)i;
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);
376
action(lvi->text(0), lvi->s, x);
380
85
//----------------------------------------------------------------------------
382
87
//----------------------------------------------------------------------------
416
123
QStringList hist;
419
QGuardedPtr<GCFindDlg> findDlg;
126
QPointer<GCFindDlg> findDlg;
420
127
QString lastSearch;
129
QPointer<MUCConfigDlg> configDlg;
134
int oldTrackBarPosition;
137
ChatEdit* mle() const { return dlg->ui_.mle->chatEdit(); }
138
ChatView* te_log() const { return dlg->ui_.log; }
423
void addEmoticon(const Icon *icon) {
141
void addEmoticon(const PsiIcon *icon) {
424
142
if ( !dlg->isActiveWindow() )
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()) + " ";
147
QHash<QString,QString> itext = icon->text();
148
for ( QHash<QString,QString>::ConstIterator it = itext.begin(); it != itext.end(); ++it) {
149
if ( !it->isEmpty() ) {
438
155
if ( !text.isEmpty() )
156
mle()->insert( text );
442
159
void addEmoticon(QString text) {
443
160
if ( !dlg->isActiveWindow() )
446
mle->insert( text + " " );
163
mle()->insert( text + " " );
449
166
void deferredScroll() {
450
167
//QTimer::singleShot(250, this, SLOT(slotScroll()));
451
te_log->scrollToBottom();
168
te_log()->scrollToBottom();
455
172
void slotScroll() {
456
te_log->scrollToBottom();
173
te_log()->scrollToBottom();
177
bool internalFind(QString str, bool startFromBeginning = false)
179
if (startFromBeginning) {
180
QTextCursor cursor = te_log()->textCursor();
181
cursor.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor);
182
cursor.clearSelection();
183
te_log()->setTextCursor(cursor);
186
bool found = te_log()->find(str);
188
if (!startFromBeginning)
189
return internalFind(str, true);
198
void removeTrackBar(QTextCursor &cursor)
200
if (oldTrackBarPosition) {
201
cursor.setPosition(oldTrackBarPosition, QTextCursor::KeepAnchor);
202
QTextBlockFormat blockFormat = cursor.blockFormat();
203
blockFormat.clearProperty(QTextFormat::BlockTrailingHorizontalRulerWidth);
204
cursor.clearSelection();
205
cursor.setBlockFormat(blockFormat);
209
void addTrackBar(QTextCursor &cursor)
211
cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
212
oldTrackBarPosition = cursor.position();
213
QTextBlockFormat blockFormat = cursor.blockFormat();
214
blockFormat.setProperty(QTextFormat::BlockTrailingHorizontalRulerWidth, QVariant(true));
215
cursor.clearSelection();
216
cursor.setBlockFormat(blockFormat);
224
// save position, because our manipulations could change it
225
int scrollbarValue = te_log()->verticalScrollBar()->value();
227
QTextCursor cursor = te_log()->textCursor();
228
cursor.beginEditBlock();
229
PsiTextView::Selection selection = te_log()->saveSelection(cursor);
231
removeTrackBar(cursor);
234
te_log()->restoreSelection(cursor, selection);
235
cursor.endEditBlock();
236
te_log()->setTextCursor(cursor);
238
te_log()->verticalScrollBar()->setValue(scrollbarValue);
242
QString lastReferrer; // contains nick of last person, who have said "yourNick: ..."
460
244
// Nick auto-completion code follows...
461
245
enum TypingStatus {
462
246
Typing_Normal = 0,
666
464
GCMainDlg::GCMainDlg(PsiAccount *pa, const Jid &j)
667
:AdvancedWidget<QWidget>(0, 0, WDestructiveClose)
465
: AdvancedWidget<QWidget>(0)
467
setAttribute(Qt::WA_DeleteOnClose);
468
if ( option.brushedMetal )
469
setAttribute(Qt::WA_MacMetalStyle);
670
471
d = new Private(this);
672
473
d->jid = j.userHost();
673
d->self = j.resource();
474
d->self = d->prev_self = j.resource();
674
475
d->pa->dialogRegister(this, d->jid);
675
476
connect(d->pa, SIGNAL(updatedActivity()), SLOT(pa_updatedActivity()));
477
d->mucManager = new MUCManager(d->pa->client(),d->jid);
479
options_ = PsiOptions::instance();
678
482
d->flashTimer = 0;
483
d->connecting = false;
684
d->trackBarParagraph = 0;
686
489
d->state = Private::Connected;
491
setAcceptDrops(true);
689
setIcon(IconsetFactory::icon("psi/groupChat"));
494
setWindowIcon(IconsetFactory::icon("psi/groupChat").icon());
692
QVBoxLayout *dlg_layout = new QVBoxLayout(this, 4);
695
if ( !option.chatLineEdit ) {
696
vsplit = new QSplitter(this);
697
((QSplitter *)vsplit)->setOrientation( QSplitter::Vertical );
698
dlg_layout->addWidget(vsplit);
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);
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 );
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);
719
d->le_topic = new QLineEdit(sp_top_top);
720
d->le_topic->setReadOnly(true);
721
hb_top->addWidget(d->le_topic);
723
d->act_find = new IconAction(tr("Find"), "psi/search", tr("&Find"), CTRL+Key_F, this);
498
ui_.lb_ident->setAccount(d->pa);
499
ui_.lb_ident->setShowJid(false);
501
connect(ui_.pb_topic, SIGNAL(clicked()), SLOT(doTopic()));
502
PsiToolTip::install(ui_.le_topic);
504
connect(d->pa->psi(), SIGNAL(accountCountChanged()), this, SLOT(updateIdentityVisibility()));
505
updateIdentityVisibility();
507
d->act_find = new IconAction(tr("Find"), "psi/search", tr("&Find"), 0, this);
724
508
connect(d->act_find, SIGNAL(activated()), SLOT(openFind()));
725
d->act_find->addTo( sp_top_top );
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);
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);
737
d->te_log = new ChatView(hsp);
738
d->te_log->setTextFormat( RichText );
509
ui_.tb_find->setDefaultAction(d->act_find);
511
ui_.tb_emoticons->setIcon(IconsetFactory::icon("psi/smile").icon());
740
connect(d->te_log,SIGNAL(selectionChanged()),SLOT(logSelectionChanged()));
741
d->te_log->setFocusPolicy(QWidget::NoFocus);
514
connect(ui_.log, SIGNAL(selectionChanged()), SLOT(logSelectionChanged()));
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)));
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);
517
ui_.lv_users->setMainDlg(this);
518
connect(ui_.lv_users, SIGNAL(action(const QString &, const Status &, int)), SLOT(lv_action(const QString &, const Status &, int)));
756
520
d->act_clear = new IconAction (tr("Clear chat window"), "psi/clearChat", tr("Clear chat window"), 0, this);
757
521
connect( d->act_clear, SIGNAL( activated() ), SLOT( doClearButton() ) );
523
d->act_configure = new IconAction(tr("Configure Room"), "psi/configure-room", tr("&Configure Room"), 0, this);
524
connect(d->act_configure, SIGNAL(activated()), SLOT(configureRoom()));
527
d->act_whiteboard = new IconAction(tr("Open a whiteboard"), "psi/whiteboard", tr("Open a &whiteboard"), 0, this);
528
connect(d->act_whiteboard, SIGNAL(activated()), SLOT(openWhiteboard()));
759
531
connect(pa->psi()->iconSelectPopup(), SIGNAL(textSelected(QString)), d, SLOT(addEmoticon(QString)));
760
532
d->act_icon = new IconAction( tr( "Select icon" ), "psi/smile", tr( "Select icon" ), 0, this );
761
d->act_icon->setPopup( pa->psi()->iconSelectPopup() );
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 );
768
d->act_clear->addTo( d->toolbar );
769
d->toolbar->setStretchableWidget(new StretchWidget(d->toolbar));
770
d->act_icon->addTo( d->toolbar );
773
if ( !option.chatLineEdit ) {
774
d->mle = new ChatEdit(sp_bottom);
775
vb_bottom->addWidget(d->mle);
778
QHBoxLayout *hb5 = new QHBoxLayout( dlg_layout );
779
d->mle = new LineEdit( vsplit );
781
hb5->addSpacing( 16 );
783
hb5->addWidget( d->mle );
785
hb5->addSpacing( 16 );
789
d->mle->installEventFilter( d );
791
d->pm_settings = new QPopupMenu(this);
533
d->act_icon->setMenu( pa->psi()->iconSelectPopup() );
534
ui_.tb_emoticons->setMenu(pa->psi()->iconSelectPopup());
536
ui_.toolbar->setIconSize(QSize(16,16));
537
ui_.toolbar->addAction(d->act_clear);
538
ui_.toolbar->addAction(d->act_configure);
540
ui_.toolbar->addAction(d->act_whiteboard);
542
ui_.toolbar->addWidget(new StretchWidget(ui_.toolbar));
543
ui_.toolbar->addAction(d->act_icon);
544
ui_.toolbar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum);
547
d->act_send = new QAction(this);
548
addAction(d->act_send);
549
connect(d->act_send,SIGNAL(activated()), SLOT(mle_returnPressed()));
550
d->act_close = new QAction(this);
551
addAction(d->act_close);
552
connect(d->act_close,SIGNAL(activated()), SLOT(close()));
553
d->act_scrollup = new QAction(this);
554
addAction(d->act_scrollup);
555
connect(d->act_scrollup,SIGNAL(activated()), SLOT(scrollUp()));
556
d->act_scrolldown = new QAction(this);
557
addAction(d->act_scrolldown);
558
connect(d->act_scrolldown,SIGNAL(activated()), SLOT(scrollDown()));
560
connect(ui_.mle, SIGNAL(textEditCreated(QTextEdit*)), SLOT(chatEditCreated()));
563
d->pm_settings = new Q3PopupMenu(this);
792
564
connect(d->pm_settings, SIGNAL(aboutToShow()), SLOT(buildMenu()));
565
ui_.tb_actions->setMenu(d->pm_settings);
794
567
// resize the horizontal splitter
795
QValueList<int> list;
571
ui_.hsplitter->setSizes(list);
803
if ( !option.chatLineEdit )
804
(( QSplitter *)vsplit)->setSizes(list);
808
d->smallChat = option.smallChats;
576
ui_.vsplitter->setSizes(list);
809
578
X11WM_CLASS("groupchat");
580
ui_.mle->chatEdit()->setFocus();
581
resize(PsiOptions::instance()->getOption("options.ui.muc.size").toSize());
583
// Connect signals from MUC manager
584
connect(d->mucManager,SIGNAL(action_error(MUCManager::Action, int, const QString&)), SLOT(action_error(MUCManager::Action, int, const QString&)));
817
592
GCMainDlg::~GCMainDlg()
819
594
if(d->state != Private::Idle)
820
595
d->pa->groupChatLeave(d->jid.host(), d->jid.user());
822
//QMimeSourceFactory *m = d->te_log->mimeSourceFactory();
823
//d->te_log->setMimeSourceFactory(0);
597
//QMimeSourceFactory *m = ui_.log->mimeSourceFactory();
598
//ui_.log->setMimeSourceFactory(0);
826
601
d->pa->dialogUnregister(this);
602
delete d->mucManager;
606
void GCMainDlg::setShortcuts()
608
d->act_clear->setShortcuts(ShortcutManager::instance()->shortcuts("chat.clear"));
609
d->act_find->setShortcuts(ShortcutManager::instance()->shortcuts("chat.find"));
610
//d->act_send->setShortcuts(ShortcutManager::instance()->shortcuts("chat.send"));
611
//d->act_close->setShortcuts(ShortcutManager::instance()->shortcuts("common.close"));
612
d->act_scrollup->setShortcuts(ShortcutManager::instance()->shortcuts("common.scroll-up"));
613
d->act_scrolldown->setShortcuts(ShortcutManager::instance()->shortcuts("common.scroll-down"));
616
void GCMainDlg::scrollUp() {
617
ui_.log->verticalScrollBar()->setValue(ui_.log->verticalScrollBar()->value() - ui_.log->verticalScrollBar()->pageStep()/2);
620
void GCMainDlg::scrollDown() {
621
ui_.log->verticalScrollBar()->setValue(ui_.log->verticalScrollBar()->value() + ui_.log->verticalScrollBar()->pageStep()/2);
624
// FIXME: This should be unnecessary, since these keys are all registered as
625
// actions in the constructor. Somehow, Qt ignores this.
830
626
void GCMainDlg::keyPressEvent(QKeyEvent *e)
832
if(e->key() == Key_Return || e->key() == Key_Enter || (e->key() == Key_S && (e->state() & AltButton)))
628
QKeySequence key = e->key() + ( e->modifiers() & ~Qt::KeypadModifier);
629
if(!option.useTabs && ShortcutManager::instance()->shortcuts("common.close").contains(key))
631
else if(ShortcutManager::instance()->shortcuts("chat.send").contains(key))
833
632
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);
633
else if(ShortcutManager::instance()->shortcuts("common.scroll-up").contains(key))
635
else if(ShortcutManager::instance()->shortcuts("common.scroll-down").contains(key))
664
ui_.mle->chatEdit()->setFocus();
860
665
d->trackBar = false;
862
667
d->trackBar = true;
671
void GCMainDlg::mucInfoDialog(const QString& title, const QString& message, const Jid& actor, const QString& reason)
675
if (!actor.isEmpty())
676
m += tr(" by %1").arg(actor.full());
679
if (!reason.isEmpty())
680
m += tr("\nReason: %1").arg(reason);
682
QMessageBox::information(this, title, m);
867
685
void GCMainDlg::logSelectionChanged()
870
688
// A hack to only give the message log focus when text is selected
871
if (d->te_log->hasSelectedText())
872
d->te_log->setFocus();
689
if (ui_.log->hasSelectedText())
692
ui_.mle->chatEdit()->setFocus();
696
void GCMainDlg::setConnecting()
698
d->connecting = true;
699
QTimer::singleShot(5000,this,SLOT(unsetConnecting()));
702
void GCMainDlg::updateIdentityVisibility()
704
ui_.lb_ident->setVisible(d->pa->psi()->contactList()->enabledAccounts().count() > 1);
708
void GCMainDlg::openWhiteboard()
710
d->pa->actionOpenWhiteboardSpecific(d->jid, d->jid.withResource(d->self), true);
714
void GCMainDlg::unsetConnecting()
716
d->connecting = false;
719
void GCMainDlg::action_error(MUCManager::Action, int, const QString& err)
721
appendSysMsg(err, false);
878
724
void GCMainDlg::mle_returnPressed()
880
if(d->mle->text().isEmpty())
726
if(ui_.mle->chatEdit()->text().isEmpty())
883
QString str = d->mle->text();
729
QString str = ui_.mle->chatEdit()->text();
884
730
if(str == "/clear") {
888
734
d->hist.prepend(str);
735
ui_.mle->chatEdit()->setText("");
893
739
if(str.lower().startsWith("/nick ")) {
894
740
QString nick = str.mid(6).stripWhiteSpace();
895
741
if ( !nick.isEmpty() ) {
742
d->prev_self = d->self;
897
744
d->pa->groupChatChangeNick(d->jid.host(), d->jid.user(), d->self, d->pa->status());
746
ui_.mle->chatEdit()->setText("");
970
816
bringToFront(d->findDlg);
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 &)));
818
d->findDlg = new GCFindDlg(d->lastSearch, this);
819
connect(d->findDlg, SIGNAL(find(const QString &)), SLOT(doFind(const QString &)));
974
820
d->findDlg->show();
978
void GCMainDlg::doFind(int para, int index, const QString &str)
824
void GCMainDlg::configureRoom()
827
bringToFront(d->configDlg);
829
GCUserViewItem* c = (GCUserViewItem*)ui_.lv_users->findEntry(d->self);
830
d->configDlg = new MUCConfigDlg(d->mucManager, this);
831
d->configDlg->setRoleAffiliation(c->s.mucItem().role(), c->s.mucItem().affiliation());
832
d->configDlg->show();
836
void GCMainDlg::doFind(const QString &str)
980
838
d->lastSearch = str;
982
if(!d->te_log->find(str, false, false, true, ¶, &index))
839
if (d->internalFind(str))
983
842
d->findDlg->error(str);
985
// pass one character over
986
d->findDlg->found(para, index+1);
990
845
void GCMainDlg::goDisc()
992
847
if(d->state != Private::Idle) {
993
848
d->state = Private::Idle;
994
d->pb_topic->setEnabled(false);
849
ui_.pb_topic->setEnabled(false);
995
850
appendSysMsg(tr("Disconnected."), true);
851
ui_.mle->chatEdit()->setEnabled(false);
1045
929
void GCMainDlg::presence(const QString &nick, const Status &s)
933
if (s.errorCode() == 409) {
934
message = tr("Please choose a different nickname");
935
d->self = d->prev_self;
938
message = tr("An error occurred");
939
appendSysMsg(message, false, QDateTime::currentDateTime());
943
if ((nick == "") && (s.mucStatus() == 100)) {
944
d->nonAnonymous = true;
947
if (nick == d->self) {
948
// Update configuration dialog
950
d->configDlg->setRoleAffiliation(s.mucItem().role(),s.mucItem().affiliation());
951
d->act_configure->setEnabled(s.mucItem().affiliation() >= MUCItem::Member);
1047
954
if(s.isAvailable()) {
1048
/*if ((option.showJoins)&&(d->lv_users->findEntry(nick)==0)) {
956
if (s.mucStatus() == 201) {
957
appendSysMsg(tr("New room created"), false, QDateTime::currentDateTime());
958
if (options_->getOption("options.muc.accept-defaults").toBool())
959
d->mucManager->setDefaultConfiguration();
960
else if (options_->getOption("options.muc.auto-configure").toBool())
961
QTimer::singleShot(0, this, SLOT(configureRoom()));
964
GCUserViewItem* contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick);
965
if (contact == NULL) {
1049
966
//contact joining
1050
QString m=nick+tr(" has joined the channel");
1051
appendSysMsg(m, false, QDateTime::currentDateTime());
1053
d->lv_users->updateEntry(nick, s);
1055
/*if (option.showJoins) {
1057
QString m=nick+tr(" has left the channel");
1058
appendSysMsg(m, false, QDateTime::currentDateTime());
1060
d->lv_users->removeEntry(nick);
967
if ( !d->connecting && options_->getOption("options.muc.show-joins").toBool() ) {
968
QString message = tr("%1 has joined the room");
970
if ( options_->getOption("options.muc.show-role-affiliation").toBool() ) {
971
if (s.mucItem().role() != MUCItem::NoRole) {
972
if (s.mucItem().affiliation() != MUCItem::NoAffiliation) {
973
message = tr("%3 has joined the room as %1 and %2").arg(MUCManager::roleToString(s.mucItem().role(),true)).arg(MUCManager::affiliationToString(s.mucItem().affiliation(),true));
976
message = tr("%2 has joined the room as %1").arg(MUCManager::roleToString(s.mucItem().role(),true));
979
else if (s.mucItem().affiliation() != MUCItem::NoAffiliation) {
980
message = tr("%2 has joined the room as %1").arg(MUCManager::affiliationToString(s.mucItem().affiliation(),true));
983
if (!s.mucItem().jid().isEmpty())
984
message = message.arg(QString("%1 (%2)").arg(nick).arg(s.mucItem().jid().full()));
986
message = message.arg(nick);
987
appendSysMsg(message, false, QDateTime::currentDateTime());
992
if ( !d->connecting && options_->getOption("options.muc.show-role-affiliation").toBool() ) {
994
if (contact->s.mucItem().role() != s.mucItem().role() && s.mucItem().role() != MUCItem::NoRole) {
995
if (contact->s.mucItem().affiliation() != s.mucItem().affiliation()) {
996
message = tr("%1 is now %2 and %3").arg(nick).arg(MUCManager::roleToString(s.mucItem().role(),true)).arg(MUCManager::affiliationToString(s.mucItem().affiliation(),true));
999
message = tr("%1 is now %2").arg(nick).arg(MUCManager::roleToString(s.mucItem().role(),true));
1002
else if (contact->s.mucItem().affiliation() != s.mucItem().affiliation()) {
1003
message += tr("%1 is now %2").arg(nick).arg(MUCManager::affiliationToString(s.mucItem().affiliation(),true));
1006
if (!message.isEmpty())
1007
appendSysMsg(message, false, QDateTime::currentDateTime());
1009
if ( !d->connecting && options_->getOption("options.muc.show-status-changes").toBool() ) {
1010
if (s.status() != contact->s.status() || s.show() != contact->s.show()) {
1013
if (s.show().isEmpty())
1017
message = tr("%1 is now %2").arg(nick).arg(st);
1018
if (!s.status().isEmpty())
1019
message+=QString(" (%1)").arg(s.status());
1020
appendSysMsg(message, false, QDateTime::currentDateTime());
1024
ui_.lv_users->updateEntry(nick, s);
1028
if (s.hasMUCDestroy()) {
1029
// Room was destroyed
1030
QString message = tr("This room has been destroyed.");
1031
if (!s.mucDestroy().reason().isEmpty()) {
1033
message += tr("Reason: %1").arg(s.mucDestroy().reason());
1035
if (!s.mucDestroy().jid().isEmpty()) {
1037
message += tr("Do you want to join the alternate venue '%1' ?").arg(s.mucDestroy().jid().full());
1038
int ret = QMessageBox::information(this, tr("Room Destroyed"), message, QMessageBox::Yes, QMessageBox::No);
1039
if (ret == QMessageBox::Yes) {
1040
d->pa->actionJoin(s.mucDestroy().jid().full());
1044
QMessageBox::information(this,tr("Room Destroyed"), message);
1048
if ( !d->connecting && options_->getOption("options.muc.show-joins").toBool() ) {
1051
GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick);
1052
if (contact && !contact->s.mucItem().jid().isEmpty())
1053
nickJid = QString("%1 (%2)").arg(nick).arg(contact->s.mucItem().jid().full());
1057
switch (s.mucStatus()) {
1060
if (nick == d->self) {
1061
mucInfoDialog(tr("Banned"), tr("You have been banned from the room"), s.mucItem().actor(), s.mucItem().reason());
1065
if (!s.mucItem().actor().isEmpty())
1066
message = tr("%1 has been banned by %2").arg(nickJid, s.mucItem().actor().full());
1068
message = tr("%1 has been banned").arg(nickJid);
1070
if (!s.mucItem().reason().isEmpty())
1071
message += QString(" (%1)").arg(s.mucItem().reason());
1075
message = tr("%1 is now known as %2").arg(nick).arg(s.mucItem().nick());
1076
ui_.lv_users->updateEntry(s.mucItem().nick(), s);
1081
if (nick == d->self) {
1082
mucInfoDialog(tr("Kicked"), tr("You have been kicked from the room"), s.mucItem().actor(), s.mucItem().reason());
1086
if (!s.mucItem().actor().isEmpty())
1087
message = tr("%1 has been kicked by %2").arg(nickJid).arg(s.mucItem().actor().full());
1089
message = tr("%1 has been kicked").arg(nickJid);
1090
if (!s.mucItem().reason().isEmpty())
1091
message += QString(" (%1)").arg(s.mucItem().reason());
1095
// Remove due to affiliation change
1096
if (nick == d->self) {
1097
mucInfoDialog(tr("Removed"), tr("You have been removed from the room due to an affiliation change"), s.mucItem().actor(), s.mucItem().reason());
1101
if (!s.mucItem().actor().isEmpty())
1102
message = tr("%1 has been removed from the room by %2 due to an affilliation change").arg(nickJid).arg(s.mucItem().actor().full());
1104
message = tr("%1 has been removed from the room due to an affilliation change").arg(nickJid);
1106
if (!s.mucItem().reason().isEmpty())
1107
message += QString(" (%1)").arg(s.mucItem().reason());
1111
// Remove due to members only
1112
if (nick == d->self) {
1113
mucInfoDialog(tr("Removed"), tr("You have been removed from the room because the room was made members only"), s.mucItem().actor(), s.mucItem().reason());
1117
if (!s.mucItem().actor().isEmpty())
1118
message = tr("%1 has been removed from the room by %2 because the room was made members-only").arg(nickJid).arg(s.mucItem().actor().full());
1120
message = tr("%1 has been removed from the room because the room was made members-only").arg(nickJid);
1122
if (!s.mucItem().reason().isEmpty())
1123
message += QString(" (%1)").arg(s.mucItem().reason());
1128
message = tr("%1 has left the room").arg(nickJid);
1129
if (!s.status().isEmpty())
1130
message += QString(" (%1)").arg(s.status());
1132
appendSysMsg(message, false, QDateTime::currentDateTime());
1134
ui_.lv_users->removeEntry(nick);
1137
if (!s.capsNode().isEmpty()) {
1138
Jid caps_jid(s.mucItem().jid().isEmpty() || !d->nonAnonymous ? Jid(d->jid).withResource(nick) : s.mucItem().jid());
1139
d->pa->capsManager()->updateCaps(caps_jid,s.capsNode(),s.capsVersion(),s.capsExt());
1064
void GCMainDlg::message(const Message &m)
1144
void GCMainDlg::message(const Message &_m)
1066
1147
QString from = m.from().resource();
1067
1148
bool alert = false;
1069
1150
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()));
1151
ui_.le_topic->setText(m.subject());
1152
ui_.le_topic->setCursorPosition(0);
1153
ui_.le_topic->setToolTip(QString("<qt><p>%1</p></qt>").arg(m.subject()));
1154
if(m.body().isEmpty()) {
1155
if (!from.isEmpty())
1156
m.setBody(QString("/me ") + tr("has set the topic to: %1").arg(m.subject()));
1158
// The topic was set by the server
1159
m.setBody(tr("The topic has been set to: %1").arg(m.subject()));
1163
if(m.body().isEmpty())
1075
1166
// code to determine if the speaker was addressing this client in chat
1076
if(m.body().contains(d->self) > 0)
1167
if(m.body().contains(d->self))
1079
1170
if (m.body().left(d->self.length()) == d->self)
1106
1197
void GCMainDlg::joined()
1108
1199
if(d->state == Private::Connecting) {
1109
d->lv_users->QListView::clear();
1200
ui_.lv_users->clear();
1110
1201
d->state = Private::Connected;
1111
d->pb_topic->setEnabled(true);
1202
ui_.pb_topic->setEnabled(true);
1203
ui_.mle->chatEdit()->setEnabled(true);
1112
1205
appendSysMsg(tr("Connected."), true);
1209
void GCMainDlg::setPassword(const QString& p)
1214
const QString& GCMainDlg::nick() const
1116
1219
void GCMainDlg::appendSysMsg(const QString &str, bool alert, const QDateTime &ts)
1118
bool atBottom = d->te_log->contentsY() >= d->te_log->contentsHeight() - d->te_log->visibleHeight();
1122
hr = QString("<hr>");
1123
d->trackBar = false;
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 );
1131
d->trackBarParagraph = d->te_log->paragraphs();
1135
1224
if (!option.gcHighlighting)
1227
QDateTime time = QDateTime::currentDateTime();
1139
1228
if(!ts.isNull())
1142
time = QDateTime::currentDateTime();
1144
//timestr.sprintf("%02d:%02d:%02d", time.time().hour(), time.time().minute(), time.time().second());
1145
timestr = time.time().toString(LocalDate);
1147
/*int y = d->te_log->contentsHeight() - d->te_log->visibleHeight();
1150
bool atBottom = (d->te_log->contentsY() < y - 32) ? false: true;*/
1152
d->te_log->append(hr + QString("<font color=\"#00A000\">[%1]").arg(timestr) + QString(" *** %1</font>").arg(expandEntities(str)));
1155
d->deferredScroll();
1231
QString timestr = ui_.log->formatTimeStamp(time);
1232
ui_.log->appendText(QString("<font color=\"#00A000\">[%1]").arg(timestr) + QString(" *** %1</font>").arg(Qt::escape(str)));
1242
txt = plain2rich(m.body().mid(4));
1298
txt = TextUtil::plain2rich(m.body().mid(4));
1244
txt = plain2rich(m.body());
1300
txt = TextUtil::plain2rich(m.body());
1302
txt = TextUtil::linkify(txt);
1248
1304
if(option.useEmoticons)
1249
txt = emoticonify(txt);
1305
txt = TextUtil::emoticonify(txt);
1306
if( PsiOptions::instance()->getOption("options.ui.chat.legacy-formatting").toBool() )
1307
txt = TextUtil::legacyFormat(txt);
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>");
1310
//ui_.log->append(QString("<font color=\"%1\">").arg(color) + QString("[%1]").arg(timestr) + QString(" *%1 ").arg(Qt::escape(who)) + txt + "</font>");
1311
ui_.log->appendText(QString("<font color=\"%1\">").arg(nickcolor) + QString("[%1]").arg(timestr) + QString(" *%1 ").arg(Qt::escape(who)) + alerttagso + txt + alerttagsc + "</font>");
1256
1314
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>");
1315
//ui_.log->append(QString("<font color=\"%1\">").arg(color) + QString("[%1] ").arg(timestr) + QString("%1 says:").arg(Qt::escape(who)) + "</font><br>" + txt);
1316
ui_.log->appendText(QString("<font color=\"%1\">").arg(nickcolor) + QString("[%1] ").arg(timestr) + QString("%1 says:").arg(Qt::escape(who)) + "</font><br>" + QString("<font color=\"%1\">").arg(textcolor) + alerttagso + txt + alerttagsc + "</font>");
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>");
1319
//ui_.log->append(QString("<font color=\"%1\">").arg(color) + QString("[%1] <").arg(timestr) + Qt::escape(who) + QString("></font> ") + txt);
1320
ui_.log->appendText(QString("<font color=\"%1\">").arg(nickcolor) + QString("[%1] <").arg(timestr) + Qt::escape(who) + QString("></font> ") + QString("<font color=\"%1\">").arg(textcolor) + alerttagso + txt + alerttagsc +"</font>");
1266
//if(local || atBottom)
1267
if(m.from().resource() == d->self || atBottom)
1325
if(m.from().resource() == d->self)
1268
1326
d->deferredScroll();
1270
1328
// if we're not active, notify the user by changing the title
1417
1486
else if(x == 4) {
1418
1487
d->pa->invokeGCFile(d->jid.withResource(nick));
1490
d->mucManager->kick(nick);
1493
GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick);
1494
d->mucManager->ban(contact->s.mucItem().jid());
1497
GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick);
1498
if (contact->s.mucItem().role() != MUCItem::Visitor)
1499
d->mucManager->setRole(nick, MUCItem::Visitor);
1502
GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick);
1503
if (contact->s.mucItem().role() != MUCItem::Participant)
1504
d->mucManager->setRole(nick, MUCItem::Participant);
1507
GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick);
1508
if (contact->s.mucItem().role() != MUCItem::Moderator)
1509
d->mucManager->setRole(nick, MUCItem::Moderator);
1511
/*else if(x == 15) {
1512
GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick);
1513
if (contact->s.mucItem().affiliation() != MUCItem::NoAffiliation)
1514
d->mucManager->setAffiliation(contact->s.mucItem().jid(), MUCItem::NoAffiliation);
1517
GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick);
1518
if (contact->s.mucItem().affiliation() != MUCItem::Member)
1519
d->mucManager->setAffiliation(contact->s.mucItem().jid(), MUCItem::Member);
1522
GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick);
1523
if (contact->s.mucItem().affiliation() != MUCItem::Admin)
1524
d->mucManager->setAffiliation(contact->s.mucItem().jid(), MUCItem::Admin);
1527
GCUserViewItem *contact = (GCUserViewItem*) ui_.lv_users->findEntry(nick);
1528
if (contact->s.mucItem().affiliation() != MUCItem::Owner)
1529
d->mucManager->setAffiliation(contact->s.mucItem().jid(), MUCItem::Owner);
1422
1533
void GCMainDlg::contextMenuEvent(QContextMenuEvent *)