1
/****************************************************************************
2
** mainwin.cpp - the main window. holds contactlist and buttons.
3
** Copyright (C) 2001, 2002 Justin Karneges
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.
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.
15
** You should have received a copy of the GNU General Public License
16
** along with this program; if not, write to the Free Software
17
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA.
19
****************************************************************************/
24
#include"showtextdlg.h"
26
#include<qmessagebox.h>
32
// deletes submenus in a popupmenu
33
void qpopupmenuclear(QPopupMenu *p)
36
QMenuItem *item = p->findItem(p->idAt(0));
37
QPopupMenu *popup = item->popup();
46
//*******************************************************
48
//*******************************************************
49
MainWin::MainWin(bool _onTop, QWidget *parent, const char *name)
50
:QWidget(parent, name, _onTop ? WStyle_StaysOnTop: 0)
52
wmdock[0] = QImage("./image/psiwmdock1.png");
54
setIcon(status2pix(STATUS_OFFLINE));
58
localStatus = STATUS_OFFLINE;
70
vb_main = new QVBoxLayout(this, 2);
71
QHBoxLayout *hb_tools = new QHBoxLayout(vb_main);
73
tb_offline = new MToolButton(this);
74
tb_offline->setToggleButton(TRUE);
75
tb_offline->setOn(TRUE);
76
hb_tools->addWidget(tb_offline);
78
tb_away = new MToolButton(this);
79
tb_away->setToggleButton(TRUE);
81
hb_tools->addWidget(tb_away);
83
tb_agents = new MToolButton(this);
84
tb_agents->setToggleButton(TRUE);
85
tb_agents->setOn(TRUE);
86
hb_tools->addWidget(tb_agents);
90
hb_tools->addStretch(1);
92
QToolTip::add(tb_offline, tr("Show Offline Contacts"));
93
QToolTip::add(tb_away, tr("Show Away/XA/DnD"));
94
QToolTip::add(tb_agents, tr("Show Agents/Transports"));
96
cvlist = new ContactView(this);
97
//connect(cvlist, SIGNAL(totalAlerts(int)), this, SLOT(totalAlerts(int)));
98
connect(tb_offline, SIGNAL(toggled(bool)), cvlist, SLOT(setShowOffline(bool)));
99
connect(tb_away, SIGNAL(toggled(bool)), cvlist, SLOT(setShowAway(bool)));
100
connect(tb_agents, SIGNAL(toggled(bool)), cvlist, SLOT(setShowAgents(bool)));
101
connect(cvlist, SIGNAL(showOffline(bool)), tb_offline, SLOT(setPressed(bool)));
102
connect(cvlist, SIGNAL(showAway(bool)), tb_away, SLOT(setPressed(bool)));
103
connect(cvlist, SIGNAL(showAgents(bool)), tb_agents, SLOT(setPressed(bool)));
104
vb_main->addWidget(cvlist);
106
QHBoxLayout *hb1 = new QHBoxLayout(vb_main);
107
lb_info = new MLabel(this);
108
connect(lb_info, SIGNAL(clicked(int)), SLOT(statusClicked(int)));
109
connect(lb_info, SIGNAL(doubleClicked()), SLOT(doRecvNextEvent()));
110
lb_info->setMinimumWidth(48);
111
lb_info->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
112
lb_info->setFrameStyle(QFrame::Panel | QFrame::Sunken);
113
hb1->addWidget(lb_info);
114
lb_ssl = new QLabel(this);
115
lb_ssl->setFrameStyle(QFrame::Panel | QFrame::Sunken);
117
hb1->addWidget(lb_ssl);
119
hb_status = new QHBoxLayout(vb_main);
120
pb_options = new QPushButton(this);
121
pb_options->setPixmap(*pix_main);
122
pb_options->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
123
hb_status->addWidget(pb_options);
125
pb_status = new MPushButton(this);
126
pb_status->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
127
decorateButton(STATUS_OFFLINE);
128
hb_status->addWidget(pb_status);
130
statusMenu = new QPopupMenu(this);
131
optionsMenu = new QPopupMenu(this);
134
connect(statusMenu, SIGNAL(aboutToShow()), SLOT(buildStatusMenu()));
135
connect(statusMenu, SIGNAL(activated(int)), SLOT(activatedStatusMenu(int)));
136
connect(optionsMenu, SIGNAL(aboutToShow()), SLOT(buildOptionsMenu()));
137
connect(optionsMenu, SIGNAL(activated(int)), SLOT(activatedOptionsMenu(int)));
139
pb_options->setPopup(optionsMenu);
140
pb_status->setPopup(statusMenu);
143
vb_main->addSpacing(16);
159
void MainWin::setAlwaysOnTop(bool _onTop)
166
reparent(parentWidget(), onTop ? WStyle_StaysOnTop: 0, p, FALSE);
171
void MainWin::setUseDock(bool use)
187
trayMenu = new QPopupMenu;
188
connect(trayMenu, SIGNAL(aboutToShow()), SLOT(buildTrayMenu()));
190
tray = new TrayIcon(makeTrayIcon(status2qim(localStatus)), "Psi", trayMenu);
191
connect(tray, SIGNAL(clicked(const QPoint &, int)), SLOT(trayClicked(const QPoint &, int)));
192
connect(tray, SIGNAL(doubleClicked(const QPoint &)), SLOT(trayDoubleClicked()));
193
connect(tray, SIGNAL(closed()), SIGNAL(closeProgram()));
196
updateReadNext(nextType, nextAmount);
199
void MainWin::setInfo(const QString &str)
204
lb_info->setText(QString("<nobr>") + infoString + "</nobr>");
207
void MainWin::setUsingSSL(bool use)
210
lb_ssl->setPixmap(usingSSL ? *pix_ssl_yes : *pix_ssl_no);
211
QToolTip::add(lb_ssl, usingSSL ? tr("Connection is encrypted") : tr("Connection is not encrypted"));
214
void MainWin::buildStatusMenu()
218
statusMenu->insertItem(QIconSet(status2pix(STATUS_ONLINE)), status2txt(STATUS_ONLINE), STATUS_ONLINE);
219
statusMenu->insertItem(QIconSet(status2pix(STATUS_AWAY)), status2txt(STATUS_AWAY), STATUS_AWAY);
220
statusMenu->insertItem(QIconSet(status2pix(STATUS_XA)), status2txt(STATUS_XA), STATUS_XA);
221
statusMenu->insertItem(QIconSet(status2pix(STATUS_DND)), status2txt(STATUS_DND), STATUS_DND);
222
statusMenu->insertSeparator();
223
statusMenu->insertItem(QIconSet(status2pix(STATUS_OFFLINE)), status2txt(STATUS_OFFLINE), STATUS_OFFLINE);
226
void MainWin::activatedStatusMenu(int id)
231
void MainWin::buildOptionsMenu()
233
// clear the menu and submenus
234
qpopupmenuclear(optionsMenu);
236
QPopupMenu *helpMenu = new QPopupMenu(optionsMenu);
237
helpMenu->insertItem(tr("&ReadMe"), 13);
238
helpMenu->insertItem(tr("&Hints"), 14);
239
helpMenu->insertItem(tr("&License"), 11);
240
helpMenu->insertItem(tr("&Warning"), 12);
241
helpMenu->insertSeparator();
242
helpMenu->insertItem(tr("&About"), 7);
243
helpMenu->insertItem(tr("About &Qt"), 8);
244
helpMenu->setItemEnabled(14, FALSE);
245
connect(helpMenu, SIGNAL(activated(int)), SLOT(activatedOptionsMenu(int)));
248
optionsMenu->insertItem(QIconSet(*pix_add), tr("&Add a contact"), 0);
249
optionsMenu->insertItem(QIconSet(*pix_send), tr("New &blank message"), 1);
250
optionsMenu->insertItem(QIconSet(transport2icon("", STATUS_ONLINE)), tr("Manage &services"), 15);
251
optionsMenu->insertItem(tr("File sharing"), 4);
252
optionsMenu->setItemEnabled(4, FALSE);
253
optionsMenu->insertItem(QIconSet(*pix_account), tr("Account Setup"), 16);
254
optionsMenu->insertItem(QIconSet(*pix_info), tr("Personal &info"), 6);
255
optionsMenu->insertItem(tr("&Options"), 9);
256
optionsMenu->insertItem(tr("&Log window"), 10);
257
optionsMenu->insertItem(QIconSet(*pix_changeacc), tr("&Change profile"),3);
258
optionsMenu->insertItem(tr("Play &sounds"), 2);
259
optionsMenu->setItemChecked(2, useSound);
260
optionsMenu->insertSeparator();
261
optionsMenu->insertItem(tr("&Help"), helpMenu);
262
optionsMenu->insertItem(tr("&Quit"), 5);
265
void MainWin::activatedOptionsMenu(int id)
267
QString dstr; dstr.sprintf("mainwin: id=%d\n", id);
268
pdb(DEBUG_MAINWIN, dstr);
290
QString content = QString("<h3>%1 v%2</h3>\n").arg(PROG_NAME).arg(PROG_VERSION);
292
content += "Copyright (C) 2001,2002<br>\n";
293
content += "By Justin Karneges<br>\n";
294
content += "infiniti@affinix.com<br>\n";
295
content += "http://psi.affinix.com/<br>\n";
297
content += "Psi is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. See Help->License for details.<br>\n";
299
content += "A capable Jabber client written in C++ using the Qt GUI Toolkit.<br>\n";
302
content += "Mac port contributed by Bill Myers.<br>\n";
304
content += "Graphics by Jason Kim, Justin Karneges, Hideaki Omuro, and other contributers.<br>\n";
306
AboutDlg *w = new AboutDlg(*pix_icon_48, content, this);
307
w->setCaption(tr("About"));
308
//w->setIcon(*pix_online);
311
//QMessageBox::about(this, CAP("About"), content);
314
QMessageBox::aboutQt(this);
320
debug_window->show();
322
ShowTextDlg *w = new ShowTextDlg(g.pathBase + "/COPYING");
323
w->setCaption(CAP(tr("License")));
327
unfinishedSoftware();
332
ShowTextDlg *w = new ShowTextDlg(g.pathBase + "/readme.txt");
334
ShowTextDlg *w = new ShowTextDlg(g.pathBase + "/README");
336
w->setCaption(CAP(tr("ReadMe")));
352
void MainWin::buildTrayMenu()
359
trayMenu->insertItem(tr("Receive next event"), this, SLOT(doRecvNextEvent()));
360
trayMenu->insertSeparator();
364
trayMenu->insertItem(tr("Un&hide"), this, SLOT(trayShow()));
366
trayMenu->insertItem(tr("&Hide"), this, SLOT(trayHide()));
367
trayMenu->insertItem(tr("&Status"), statusMenu);
368
trayMenu->insertSeparator();
369
trayMenu->insertItem(tr("&Quit"), this, SLOT(tryCloseProgram()));
372
void MainWin::decorateButton(int status)
374
setIcon(status2pix(status));
375
if(tray && !v_isActive)
376
tray->setIcon(makeTrayIcon(status2qim(status)));
379
icon.setPixmap(status2pix(status), QIconSet::Small);
381
pb_status->setIconSet(icon);
382
pb_status->setText(status2txt(status));
385
bool MainWin::askQuit()
387
if(localStatus != STATUS_OFFLINE) {
388
int n = QMessageBox::information(0, tr("Warning"), tr("You are currently logged in. Are you sure you want to close Psi?"), tr("&Yes"), tr("&No"));
396
void MainWin::tryCloseProgram()
402
void MainWin::closeEvent(QCloseEvent *e)
416
void MainWin::updateCaption()
423
if(localJid.isEmpty())
434
void MainWin::localUpdate(const JabRosterEntry &e)
439
localStatus = e.local()->status;
441
localStatus = STATUS_OFFLINE;
443
if(!localJid.isEmpty()) {
444
statusTip = makeToolTip(e);
445
QToolTip::add(lb_info, statusTip);
448
QToolTip::remove(lb_info);
452
tray->setToolTip(status2txt(localStatus));
457
QString MainWin::makeToolTip(const JabRosterEntry &e)
459
QString statusString = "";
461
statusString = e.local()->statusString;
464
QString nick = e.nick;
466
QString str = QString("<qt>");
467
str += QString("<nobr>%1: %2</nobr>").arg(jidnick(jid,nick)).arg(status2txt(localStatus));
469
str += QString("<br>[%1]").arg(jid);
471
if(e.isAvailable()) {
472
JabResource *pr = e.res.priority();
481
str += QString("<br><nobr>") + QString(tr("Resource: %1")).arg(curres) + "</nobr>";
486
QPtrListIterator<JabResource> it(e.res);
487
for(; (r = it.current()); ++it) {
488
// skip the local resource
498
resources += r->name;
501
if(!resources.isEmpty())
502
str += QString("<br><nobr>") + QString(tr("Other(s): %1")).arg(resources) + "</nobr>";
505
if(!statusString.isEmpty()) {
506
QString head = tr("Status Message");
507
str += QString("<br><u>%1</u><br>%2").arg(head).arg(plain2rich(statusString));
514
void MainWin::setToolBarIcons()
516
tb_offline->setIconSet(QIconSet(*pix_offline));
517
tb_away->setIconSet(QIconSet(status2pix(STATUS_AWAY)));
518
tb_agents->setIconSet(QIconSet(transport2icon("", STATUS_ONLINE)));
521
void MainWin::optionsUpdate()
523
decorateButton(localStatus);
526
// if the tray animation is active, reset it
527
if(tray && v_isActive) {
528
traySetAnim(messagetype2anim(nextType));
532
QPixmap MainWin::makeTrayIcon(const QImage &_in)
536
QImage real = wmdock[0];
541
// make sure it is no bigger than 16x16
542
if(in.width() > 16 || in.height() > 16)
543
in = in.smoothScale(16,16);
551
for(n = 0; n < 22; ++n) {
552
real.setPixel(n + xo, yo, qRgb(0x80,0x80,0x80));
553
real.setPixel(n + xo, yo + 21, qRgb(0x00,0x00,0x00));
554
real.setPixel(xo, yo + n, qRgb(0x80,0x80,0x80));
555
real.setPixel(xo + 21, yo + n, qRgb(0x00,0x00,0x00));
562
for(n2 = 0; n2 < in.height(); ++n2) {
563
for(n = 0; n < in.width(); ++n) {
564
if(qAlpha(_in.pixel(n,n2))) {
565
real.setPixel(n + xo + 2, n2 + yo + 2, qRgb(0x80,0x80,0x80));
569
for(n2 = 0; n2 < in.height(); ++n2) {
570
for(n = 0; n < in.width(); ++n) {
571
if(qAlpha(_in.pixel(n,n2))) {
572
real.setPixel(n + xo, n2 + yo, _in.pixel(n,n2));
578
icon.convertFromImage(real);
582
// on X11, the KDE dock is 22x22. let's make our icon "seem" bigger.
583
QImage real(22,22,32);
584
//QImage in = _in.convertToImage();
588
real.setAlphaBuffer(TRUE);
590
// make sure it is no bigger than 16x16
591
if(in.width() > 16 || in.height() > 16)
592
in = in.smoothScale(16,16);
594
int xo = (real.width() - in.width()) / 2;
595
int yo = (real.height() - in.height()) / 2;
600
for(n = 0; n < 22; ++n) {
601
real.setPixel(n, 0, qRgb(0x80,0x80,0x80));
602
real.setPixel(n, 21, qRgb(0x00,0x00,0x00));
603
real.setPixel( 0, n, qRgb(0x80,0x80,0x80));
604
real.setPixel(21, n, qRgb(0x00,0x00,0x00));
608
for(n2 = 0; n2 < in.height(); ++n2) {
609
for(n = 0; n < in.width(); ++n) {
610
if(qAlpha(in.pixel(n,n2))) {
613
real.setPixel(x, y, qRgba(0x80,0x80,0x80,0xff));
618
for(n2 = 0; n2 < in.height(); ++n2) {
619
for(n = 0; n < in.width(); ++n) {
620
if(qAlpha(in.pixel(n,n2))) {
621
QRgb c = in.pixel(n, n2);
622
real.setPixel(n + xo, n2 + yo, qRgba(qRed(c), qGreen(c), qBlue(c), 0xff));
626
// create the alpha layer
627
/*for(n2 = real.height()-2; n2 >= 0; --n2) {
628
for(n = 0; n < real.width(); ++n) {
629
uint c = real.pixel(n, n2);
631
QRgb old = real.pixel(n, n2);
632
real.setPixel(n, n2, qRgba(qRed(old), qGreen(old), qBlue(old), 0xff));
638
icon.convertFromImage(real);
643
icon.convertFromImage(_in);
648
void MainWin::trayClicked(const QPoint &, int button)
650
if(option.dockDCstyle)
653
if(button == MidButton) {
664
void MainWin::trayDoubleClicked()
666
if(!option.dockDCstyle)
677
void MainWin::trayShow()
683
void MainWin::trayHide()
688
void MainWin::updateReadNext(int type, int amount)
694
lb_info->setText(QString("<nobr>") + infoString + "</nobr>");
696
lb_info->setText(QString("<nobr><b>") + tr("%1 event(s) received").arg(nextAmount) + "</b></nobr>");
702
traySetAnim(messagetype2anim(nextType));
707
stopDockTileBounce();
715
void MainWin::traySetAnim(Anim *_anim)
720
if(option.alertStyle == 0)
721
tray->setIcon(makeTrayIcon(anim->qim_base()));
725
trayTimer = new QTimer(this);
726
connect(trayTimer, SIGNAL(timeout()), SLOT(trayAnimate()));
727
trayTimer->start(120);
736
// change back to normal icon
737
tray->setIcon(makeTrayIcon(status2qim(localStatus)));
742
void MainWin::trayAnimate()
744
if(anim->isAnim() && option.alertStyle == 2) {
745
tray->setIcon(makeTrayIcon(anim->qim_frame(animStep)));
748
if(animStep >= anim->numFrames()-1)
751
else if(option.alertStyle != 0) {
753
tray->setIcon(makeTrayIcon(anim->qim_base()));
754
else if(animStep == 4) {
755
QImage blank(16,16,32);
757
blank.setAlphaBuffer(TRUE);
758
tray->setIcon(makeTrayIcon(blank));
767
void MainWin::doRecvNextEvent()
772
void MainWin::statusClicked(int x)
779
//*******************************************************
781
//*******************************************************
782
MPushButton::MPushButton(QWidget *parent, const char *name)
783
:QPushButton(parent, name)
786
setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
791
void MPushButton::setText(const QString &_text)
794
QToolTip::remove(this);
798
QPushButton::setText(_text);
801
void MPushButton::drawButtonLabel(QPainter *p)
803
// crazy code ahead! watch out for potholes and deer.
805
// this gets us the width of the "text area" on the button.
806
// adapted from qt/src/styles/qcommonstyle.cpp and qt/src/widgets/qpushbutton.cpp
807
QRect r = style().subRect(QStyle::SR_PushButtonContents, this);
809
r.setWidth(r.width() - style().pixelMetric(QStyle::PM_MenuButtonIndicator, this));
810
if(iconSet() && !iconSet()->isNull())
811
r.setWidth(r.width() - (iconSet()->pixmap(QIconSet::Small, QIconSet::Normal, QIconSet::Off).width() + 4));
814
QFontMetrics fm(font());
816
// w1 = width of button text, w2 = width of text area
817
int w1 = fm.width(text());
820
// backup original text
821
QString oldtext = text();
823
// button text larger than what will fit?
826
QToolTip::add(this, text());
830
// make a string that fits
834
for(n = oldtext.length(); n > 0; --n) {
835
if(fm.width(oldtext, n) < w2) {
841
newtext = oldtext.mid(0, n);
845
// set the new text that fits. updates must be off, or we recurse.
846
setUpdatesEnabled(FALSE);
847
QButton::setText(newtext);
848
setUpdatesEnabled(TRUE);
852
QToolTip::remove(this);
858
QPushButton::drawButtonLabel(p);
860
// restore original button text now that we are done drawing.
861
setUpdatesEnabled(FALSE);
862
QButton::setText(oldtext);
863
setUpdatesEnabled(TRUE);
867
//*******************************************************
869
//*******************************************************
870
MToolButton::MToolButton(QWidget *parent, const char *name)
871
:QToolButton(parent, name)
875
void MToolButton::setPressed(bool x)
881
//*******************************************************
883
//*******************************************************
884
MLabel::MLabel(QWidget *parent, const char *name)
885
:QLabel(parent, name)
889
void MLabel::mouseReleaseEvent(QMouseEvent *e)
891
clicked(e->button());
895
void MLabel::mouseDoubleClickEvent(QMouseEvent *e)
897
if(e->button() == LeftButton)
904
//*******************************************************
906
//*******************************************************
907
AboutDlg::AboutDlg(const QPixmap &icon, const QString &content, QWidget *par)
908
:QDialog(par, 0, TRUE)
911
QVBoxLayout *vb = new QVBoxLayout(this, 8);
912
QHBoxLayout *hb = new QHBoxLayout(vb);
915
col = new QVBoxLayout(hb);
916
l = new QLabel(this);
921
col = new QVBoxLayout(hb);
922
l = new QLabel(this);
927
hb = new QHBoxLayout(vb);
929
QPushButton *pb_ok = new QPushButton("&OK", this);
930
connect(pb_ok, SIGNAL(clicked()), SLOT(close()));
931
hb->addWidget(pb_ok);