2
* mainwin_p.cpp - classes used privately by the main window.
3
* Copyright (C) 2001-2003 Justin Karneges, Michail Pishchagin
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 library; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
#include "mainwin_p.h"
24
#include <qapplication.h>
28
#include <qsignalmapper.h>
29
#include <qobjectlist.h>
30
#include <qpixmapcache.h>
31
#include "psiaccount.h"
32
#include "iconwidget.h"
33
#include "alerticon.h"
35
//----------------------------------------------------------------------------
37
//----------------------------------------------------------------------------
39
class PopupActionButton : public QPushButton
43
PopupActionButton(QWidget *parent = 0, const char *name = 0);
46
void setIcon(Icon *, bool showText);
49
void pixmapUpdated(const QPixmap &);
52
void drawButtonLabel(QPainter *p);
58
PopupActionButton::PopupActionButton(QWidget *parent, const char *name)
59
: QPushButton(parent, name)
61
setWFlags(getWFlags() | WRepaintNoErase);
67
PopupActionButton::~PopupActionButton()
73
void PopupActionButton::setIcon(Icon *i, bool st)
77
disconnect (icon, 0, this, 0);
85
pixmapUpdated(icon->pixmap());
87
connect(icon, SIGNAL(pixmapChanged(const QPixmap &)), SLOT(pixmapUpdated(const QPixmap &)));
92
void PopupActionButton::pixmapUpdated(const QPixmap &pix)
100
void PopupActionButton::drawButtonLabel(QPainter *p)
102
// code by Justin Karneges :-)
103
// crazy code ahead! watch out for potholes and deer.
105
// this gets us the width of the "text area" on the button.
106
// adapted from qt/src/styles/qcommonstyle.cpp and qt/src/widgets/qpushbutton.cpp
107
QRect r = style().subRect(QStyle::SR_PushButtonContents, this);
109
r.setWidth(r.width() - style().pixelMetric(QStyle::PM_MenuButtonIndicator, this));
110
if(iconSet() && !iconSet()->isNull())
111
r.setWidth(r.width() - (iconSet()->pixmap(QIconSet::Small, QIconSet::Normal, QIconSet::Off).width() + 4));
114
QFontMetrics fm(font());
116
// w1 = width of button text, w2 = width of text area
117
int w1 = fm.width(text());
120
// backup original text
121
QString oldtext = text();
123
// button text larger than what will fit?
126
QToolTip::add(this, text());
130
// make a string that fits
134
for(n = oldtext.length(); n > 0; --n) {
135
if(fm.width(oldtext, n) < w2) {
141
newtext = oldtext.mid(0, n);
145
// set the new text that fits. updates must be off, or we recurse.
146
setUpdatesEnabled(FALSE);
147
QButton::setText(newtext);
148
setUpdatesEnabled(TRUE);
152
QToolTip::remove(this);
158
QPushButton::drawButtonLabel(p);
160
// restore original button text now that we are done drawing.
161
setUpdatesEnabled(FALSE);
162
QButton::setText(oldtext);
163
setUpdatesEnabled(TRUE);
166
//----------------------------------------------------------------------------
167
// PopupAction -- the IconButton with popup or QPopupMenu
168
//----------------------------------------------------------------------------
170
class PopupAction::Private : public QObject
174
QPtrList<PopupActionButton> buttons;
178
Private (QObject *parent)
193
PopupAction::PopupAction (const QString &label, QPopupMenu *_menu, QObject *parent, const char *name)
194
: IconAction (label, label, 0, parent, name)
196
d = new Private (this);
200
void PopupAction::setSizePolicy (const QSizePolicy &p)
205
void PopupAction::setAlert (const Icon *icon)
207
setIcon(icon, d->showText, true);
210
void PopupAction::setIcon (const Icon *icon, bool showText, bool alert)
218
d->showText = showText;
222
d->icon = new Icon(*icon);
224
d->icon = new AlertIcon(icon);
226
IconAction::setIconSet(*icon);
230
IconAction::setIconSet(QIconSet());
233
for ( QPtrListIterator<PopupActionButton> it(d->buttons); it.current(); ++it ) {
234
PopupActionButton *btn = it.current();
235
btn->setIcon (d->icon, showText);
243
void PopupAction::setText (const QString &text)
245
IconAction::setText (text);
246
for ( QPtrListIterator<PopupActionButton> it(d->buttons); it.current(); ++it ) {
247
PopupActionButton *btn = it.current();
252
bool PopupAction::addTo (QWidget *w)
254
if ( w->inherits("QPopupMenu") ) {
255
QPopupMenu *m = (QPopupMenu*)w;
257
m->insertItem (iconSet(), menuText(), popup());
259
m->insertItem (QIconSet(), menuText(), popup());
262
else if ( w->inherits("QToolBar") ) {
263
QCString bname = name() + QCString("_action_button");
264
PopupActionButton *btn = new PopupActionButton ( (QToolBar*)w, bname );
265
d->buttons.append ( btn );
266
btn->setPopup ( popup() );
267
btn->setText ( text() );
268
btn->setIcon ( d->icon, d->showText );
269
btn->setSizePolicy ( d->size );
270
btn->setEnabled ( isEnabled() );
272
connect( btn, SIGNAL( destroyed() ), SLOT( objectDestroyed() ) );
280
void PopupAction::objectDestroyed ()
282
const QObject *obj = sender();
283
d->buttons.removeRef( (PopupActionButton *) obj );
286
void PopupAction::setEnabled (bool e)
288
IconAction::setEnabled (e);
289
for ( QPtrListIterator<PopupActionButton> it(d->buttons); it.current(); ++it ) {
290
PopupActionButton *btn = it.current();
295
IconAction *PopupAction::copy() const
297
PopupAction *act = new PopupAction(text(), popup(), 0, name());
304
PopupAction &PopupAction::operator=( const PopupAction &from )
306
*( (IconAction *)this ) = from;
308
d->size = from.d->size;
309
setIcon( from.d->icon );
310
d->showText = from.d->showText;
315
//----------------------------------------------------------------------------
316
// MLabel -- a clickable label
317
//----------------------------------------------------------------------------
319
MLabel::MLabel(QWidget *parent, const char *name)
320
:QLabel(parent, name)
323
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
324
setFrameStyle(QFrame::Panel | QFrame::Sunken);
327
void MLabel::mouseReleaseEvent(QMouseEvent *e)
329
emit clicked(e->button());
333
void MLabel::mouseDoubleClickEvent(QMouseEvent *e)
335
if(e->button() == LeftButton)
336
emit doubleClicked();
341
//----------------------------------------------------------------------------
343
//----------------------------------------------------------------------------
364
QRgb pixelBlend(QRgb p1, QRgb p2);
367
MTray::MTray(const QString &tip, QPopupMenu *popup, QObject *parent)
372
d->ti = new TrayIcon(d->makeIcon(), tip, popup);
373
d->ti->setWMDock(option.isWMDock);
374
connect(d->ti, SIGNAL(clicked(const QPoint &, int)), SIGNAL(clicked(const QPoint &, int)));
375
connect(d->ti, SIGNAL(doubleClicked(const QPoint &)), SIGNAL(doubleClicked(const QPoint &)));
376
connect(d->ti, SIGNAL(closed()), SIGNAL(closed()));
377
connect(qApp, SIGNAL(newTrayOwner()), d->ti, SLOT(newTrayOwner()));
378
connect(qApp, SIGNAL(trayOwnerDied()), d->ti, SLOT(hide()));
387
void MTray::setToolTip(const QString &str)
389
d->ti->setToolTip(str);
392
void MTray::setIcon(const Icon *icon, bool alert)
395
disconnect(d->icon, 0, this, 0 );
404
d->icon = new Icon(*icon);
406
d->icon = new AlertIcon(icon);
408
connect(d->icon, SIGNAL(pixmapChanged(const QPixmap &)), SLOT(animate()));
409
d->icon->activated();
412
d->icon = new Icon();
417
void MTray::setAlert(const Icon *icon)
422
bool MTray::isAnimating() const
424
return d->icon->isAnimated();
427
bool MTray::isWMDock()
429
return d->ti->isWMDock();
443
// a function to blend 2 pixels taking their alpha channels
444
// into consideration
445
// p1 is in the 1st layer, p2 is in the 2nd layer (over p1)
446
QRgb MTray::Private::pixelBlend(QRgb p1, QRgb p2)
449
if (a2 == 255) return p2; // don't calculate anything if p2 is completely opaque
451
double prop1 = double(a1*(255-a2))/double(255*255);
452
double prop2 = double(a2)/255.0;
453
int r = int( qRed(p1)*prop1 + qRed(p2)*prop2 );
454
int g = int( qGreen(p1)*prop1 + qGreen(p2)*prop2 );
455
int b = int( qBlue(p1)*prop1 + qBlue(p2)*prop2 );
456
return qRgba(r, g, b, (a1>a2) ? a1:a2);
460
QPixmap MTray::Private::makeIcon()
466
// on X11, the KDE dock is 22x22. let's make our icon "seem" bigger.
467
QImage real(22,22,32);
468
QImage in = icon->image();
470
real.setAlphaBuffer(true);
472
// make sure it is no bigger than 16x16
473
if(in.width() > 16 || in.height() > 16)
474
in = in.smoothScale(16,16);
476
int xo = (real.width() - in.width()) / 2;
477
int yo = (real.height() - in.height()) / 2;
481
// clear the output and make it transparent
482
// deprecates real.fill(0)
483
for(n2 = 0; n2 < real.height(); ++n2)
484
for(n = 0; n < real.width(); ++n)
485
real.setPixel(n, n2, qRgba(0,0,0,0));
488
for(n2 = 0; n2 < in.height(); ++n2) {
489
for(n = 0; n < in.width(); ++n) {
490
if(int a = qAlpha(in.pixel(n,n2))) {
493
real.setPixel(x, y, qRgba(0x80,0x80,0x80,a));
499
for(n2 = 0; n2 < in.height(); ++n2) {
500
for(n = 0; n < in.width(); ++n) {
501
if(qAlpha(in.pixel(n,n2))) {
502
QRgb pold = real.pixel(n + xo , n2 + yo);
503
QRgb pnew = in.pixel(n , n2);
504
real.setPixel(n + xo, n2 + yo, pixelBlend(pold, pnew));
510
pixmap.convertFromImage(real);
513
return icon->pixmap();
517
void MTray::animate()
523
QString cachedName = "PsiTray/" + option.defaultRosterIconset + "/" + d->icon->name() + "/" + QString::number( d->icon->framenumber() );
526
if ( !QPixmapCache::find(cachedName, p) ) {
528
QPixmapCache::insert( cachedName, p );
533
d->ti->setIcon( d->makeIcon() );
537
//----------------------------------------------------------------------------
539
//----------------------------------------------------------------------------
541
class MAction::Private : public QObject
548
Private (int _id, PsiCon *_psi, QObject *parent)
553
sm = new QSignalMapper(this, "MAction::Private::SignalMapper");
556
QPopupMenu *subMenu(QWidget *p)
558
QPopupMenu *pm = new QPopupMenu (p);
560
for ( PsiAccountListIt it(psi->accountList(TRUE)); it.current(); ++it, i++ )
562
PsiAccount *acc = it.current();
563
pm->insertItem( acc->name(), parent(), SLOT(itemActivated(int)), 0, id*1000 + i );
564
pm->setItemParameter ( id*1000 + i, i );
570
MAction::MAction(Icon i, const QString &s, int id, PsiCon *psi, QObject *parent)
571
: IconAction(s, s, 0, parent)
576
MAction::MAction(const QString &s, int id, PsiCon *psi, QObject *parent)
577
: IconAction(s, s, 0, parent)
579
init (Icon(), id, psi);
582
void MAction::init(Icon i, int id, PsiCon *psi)
584
d = new Private(id, psi, this);
586
connect(psi, SIGNAL(accountCountChanged()), SLOT(numAccountsChanged()));
587
setEnabled ( !d->psi->accountList(TRUE).isEmpty() );
588
connect (d->sm, SIGNAL(mapped(int)), SLOT(itemActivated(int)));
591
bool MAction::addTo(QWidget *w)
593
if ( w->inherits("QPopupMenu") )
595
QPopupMenu *menu = (QPopupMenu*)w;
600
if ( d->psi->accountList(TRUE).count() < 2 ) {
601
menu->insertItem ( iconset, menuText(), this, SLOT(itemActivated(int)), 0, d->id*1000 + 0 );
602
menu->setItemEnabled (d->id*1000 + 0, isEnabled());
603
menu->setItemParameter ( d->id*1000 + 0, 0 );
606
menu->insertItem(iconset, menuText(), d->subMenu(w));
609
return IconAction::addTo(w);
614
void MAction::addingToolButton(IconToolButton *btn)
616
connect (btn, SIGNAL(clicked()), d->sm, SLOT(map()));
617
d->sm->setMapping (btn, 0);
619
if ( d->psi->accountList(TRUE).count() >= 2 )
620
btn->setPopup ( d->subMenu(btn) );
625
void MAction::itemActivated(int n)
627
PsiAccountList list = (PsiAccountList)d->psi->accountList(TRUE);
629
if (n >= (int)list.count()) // just in case
632
emit activated((PsiAccount *)list.at(n), d->id);
635
void MAction::numAccountsChanged()
637
setEnabled ( !d->psi->accountList(TRUE).isEmpty() );
639
QPtrList<IconToolButton> btns = buttonList();
640
for ( QPtrListIterator<IconToolButton> it(btns); it.current(); ++it ) {
641
QToolButton *btn = it.current();
647
if ( d->psi->accountList(TRUE).count() >= 2 )
648
btn->setPopup ( d->subMenu(btn) );
652
IconAction *MAction::copy() const
654
MAction *act = new MAction(text(), d->id, d->psi, 0);
661
MAction &MAction::operator=( const MAction &from )
663
*( (IconAction *)this ) = from;
668
//----------------------------------------------------------------------------
670
//----------------------------------------------------------------------------
672
class SpacerAction::Private
677
class StretchWidget : public QWidget
680
StretchWidget(QWidget *parent)
683
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
688
SpacerAction::SpacerAction(QObject *parent, const char *name)
689
: IconAction(parent, name)
692
setText(tr("<Spacer>"));
693
setMenuText(tr("<Spacer>"));
694
setWhatsThis (tr("Spacer provides spacing to separate actions"));
697
SpacerAction::~SpacerAction()
702
bool SpacerAction::addTo(QWidget *w)
704
if ( w->inherits("QToolBar") ) {
705
new Private::StretchWidget(w);
712
IconAction *SpacerAction::copy() const
714
return new SpacerAction( 0 );
717
//----------------------------------------------------------------------------
719
//----------------------------------------------------------------------------
721
class SeparatorAction::Private
729
SeparatorAction::SeparatorAction( QObject *parent, const char *name )
730
: IconAction( tr("<Separator>"), tr("<Separator>"), 0, parent, name )
733
d->separator = new QAction(this, "qt_separator_action");
735
setWhatsThis (tr("Separator"));
738
SeparatorAction::~SeparatorAction()
743
bool SeparatorAction::addTo (QWidget *w)
745
return d->separator->addTo( w );
748
IconAction *SeparatorAction::copy() const
750
return new SeparatorAction( 0 );
753
//----------------------------------------------------------------------------
754
// EventNotifierAction
755
//----------------------------------------------------------------------------
757
class EventNotifierAction::Private
762
QPtrList<MLabel> labels;
766
EventNotifierAction::EventNotifierAction(QObject *parent, const char *name)
767
: IconAction(parent, name)
770
setMenuText(tr("<Event notifier>"));
774
EventNotifierAction::~EventNotifierAction()
779
bool EventNotifierAction::addTo(QWidget *w)
781
if ( w->inherits("QToolBar") ) {
782
MLabel *label = new MLabel(w, "EventNotifierAction::MLabel");
783
label->setText(text());
784
d->labels.append(label);
785
connect(label, SIGNAL(destroyed()), SLOT(objectDestroyed()));
786
connect(label, SIGNAL(doubleClicked()), SIGNAL(activated()));
787
connect(label, SIGNAL(clicked(int)), SIGNAL(clicked(int)));
798
void EventNotifierAction::setText(const QString &t)
800
IconAction::setText("<nobr>" + t + "</nobr>");
802
QPtrListIterator<MLabel> it ( d->labels );
803
for ( ; it.current(); ++it) {
804
MLabel *label = it.current();
805
label->setText(text());
809
void EventNotifierAction::objectDestroyed()
811
MLabel *label = (MLabel *)sender();
812
d->labels.removeRef(label);
815
void EventNotifierAction::hide()
819
QPtrListIterator<MLabel> it ( d->labels );
820
for ( ; it.current(); ++it) {
821
MLabel *label = it.current();
823
QToolBar *toolBar = (QToolBar *)label->parent();
825
QObjectList *l = toolBar->queryList( "QWidget" );
828
QObjectListIt it( *l );
830
for ( ; (obj = it.current()); ++it) {
831
if ( QCString(obj->name()).left(3) != "qt_" ) // misc internal Qt objects
836
if ( found == 1 ) // only MLabel is on ToolBar
841
void EventNotifierAction::show()
845
QPtrListIterator<MLabel> it ( d->labels );
846
for ( ; it.current(); ++it) {
847
MLabel *label = it.current();
848
QToolBar *toolBar = (QToolBar *)label->parent();
854
IconAction *EventNotifierAction::copy() const
856
EventNotifierAction *act = new EventNotifierAction( 0 );
863
EventNotifierAction &EventNotifierAction::operator=( const EventNotifierAction &from )
865
*( (IconAction *)this ) = from;
867
d->hide = from.d->hide;
872
#include "mainwin_p.moc"