00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <tdeconfig.h>
00010
00011 #include <tqapplication.h>
00012 #include <tqlabel.h>
00013 #include <tqlayout.h>
00014 #include <tqtimer.h>
00015 #include <tqvbox.h>
00016 #include <tqpainter.h>
00017 #include <tqtooltip.h>
00018 #include <tqbitmap.h>
00019 #include <tqpointarray.h>
00020
00021 #include <kdebug.h>
00022 #include <kdialog.h>
00023 #include <kpixmap.h>
00024 #include <kpixmapeffect.h>
00025 #include <tdeglobalsettings.h>
00026
00027 #include "config.h"
00028 #ifdef Q_WS_X11
00029 #include <netwm.h>
00030 #endif
00031
00032 #include "kpassivepopup.h"
00033 #include "kpassivepopup.moc"
00034
00035 class KPassivePopup::Private
00036 {
00037 public:
00038 int popupStyle;
00039 TQPointArray surround;
00040 TQPoint anchor;
00041 TQPoint fixedPosition;
00042 };
00043
00044 static const int DEFAULT_POPUP_TYPE = KPassivePopup::Boxed;
00045 static const int DEFAULT_POPUP_TIME = 6*1000;
00046 static const int POPUP_FLAGS = TQt::WStyle_Customize | TQt::WDestructiveClose | TQt::WX11BypassWM
00047 | TQt::WStyle_StaysOnTop | TQt::WStyle_Tool | TQt::WStyle_NoBorder;
00048
00049 KPassivePopup::KPassivePopup( TQWidget *parent, const char *name, WFlags f )
00050 : TQFrame( 0, name, (WFlags)(f ? (int)f : POPUP_FLAGS) ),
00051 window( parent ? parent->winId() : 0L ), msgView( 0 ), topLayout( 0 ),
00052 hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new TQTimer( this, "hide_timer" ) ),
00053 m_autoDelete( false )
00054 {
00055 init( DEFAULT_POPUP_TYPE );
00056 }
00057
00058 KPassivePopup::KPassivePopup( WId win, const char *name, WFlags f )
00059 : TQFrame( 0, name, (WFlags)(f ? (int)f : POPUP_FLAGS) ),
00060 window( win ), msgView( 0 ), topLayout( 0 ),
00061 hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new TQTimer( this, "hide_timer" ) ),
00062 m_autoDelete( false )
00063 {
00064 init( DEFAULT_POPUP_TYPE );
00065 }
00066
00067 KPassivePopup::KPassivePopup( int popupStyle, TQWidget *parent, const char *name, WFlags f )
00068 : TQFrame( 0, name, (WFlags)(f ? (int)f : POPUP_FLAGS) ),
00069 window( parent ? parent->winId() : 0L ), msgView( 0 ), topLayout( 0 ),
00070 hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new TQTimer( this, "hide_timer" ) ),
00071 m_autoDelete( false )
00072 {
00073 init( popupStyle );
00074 }
00075
00076 KPassivePopup::KPassivePopup( int popupStyle, WId win, const char *name, WFlags f )
00077 : TQFrame( 0, name, (WFlags)(f ? (int)f : POPUP_FLAGS) ),
00078 window( win ), msgView( 0 ), topLayout( 0 ),
00079 hideDelay( DEFAULT_POPUP_TIME ), hideTimer( new TQTimer( this, "hide_timer" ) ),
00080 m_autoDelete( false )
00081 {
00082 init( popupStyle );
00083 }
00084
00085 void KPassivePopup::init( int popupStyle )
00086 {
00087 d = new Private;
00088 d->popupStyle = popupStyle;
00089 if( popupStyle == Boxed )
00090 {
00091 setFrameStyle( TQFrame::Box| TQFrame::Plain );
00092 setLineWidth( 2 );
00093 }
00094 else if( popupStyle == Balloon )
00095 {
00096 setPalette(TQToolTip::palette());
00097 setAutoMask(TRUE);
00098 }
00099 connect( hideTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( hide() ) );
00100 connect( this, TQT_SIGNAL( clicked() ), TQT_SLOT( hide() ) );
00101 }
00102
00103 KPassivePopup::~KPassivePopup()
00104 {
00105 delete d;
00106 }
00107
00108 void KPassivePopup::setView( TQWidget *child )
00109 {
00110 delete msgView;
00111 msgView = child;
00112
00113 delete topLayout;
00114 topLayout = new TQVBoxLayout( this, d->popupStyle == Balloon ? 22 : KDialog::marginHint(), KDialog::spacingHint() );
00115 topLayout->addWidget( msgView );
00116 topLayout->activate();
00117 }
00118
00119 void KPassivePopup::setView( const TQString &caption, const TQString &text,
00120 const TQPixmap &icon )
00121 {
00122
00123 setView( standardView( caption, text, icon, this ) );
00124 }
00125
00126 static void truncateStringToFit(TQString &string, TQFont font, int max_width) {
00127 bool truncated = false;
00128 TQFontMetrics fm(font);
00129 while (fm.width(string) > max_width) {
00130 string.truncate(string.length() - 1);
00131 truncated = true;
00132 }
00133 if (truncated) {
00134 string += " ...";
00135 }
00136 }
00137
00138 TQVBox * KPassivePopup::standardView(const TQString& caption,
00139 const TQString& text,
00140 const TQPixmap& icon,
00141 TQWidget *parent)
00142 {
00143 TQString sizedCaption = caption;
00144 TQString sizedText = text;
00145
00146 #ifdef Q_WS_X11
00147 int max_width;
00148
00149 NETRootInfo info( tqt_xdisplay(),
00150 NET::NumberOfDesktops |
00151 NET::CurrentDesktop |
00152 NET::WorkArea,
00153 -1, false );
00154 info.activate();
00155 NETRect workArea = info.workArea(info.currentDesktop());
00156 max_width = workArea.size.width / 3;
00157 #endif
00158
00159 TQVBox *vb = new TQVBox( parent ? parent : this );
00160 vb->setSpacing( KDialog::spacingHint() );
00161
00162 TQHBox *hb=0;
00163 if ( !icon.isNull() ) {
00164 hb = new TQHBox( vb );
00165 hb->setMargin( 0 );
00166 hb->setSpacing( KDialog::spacingHint() );
00167 ttlIcon = new TQLabel( hb, "title_icon" );
00168 ttlIcon->setPixmap( icon );
00169 ttlIcon->setAlignment( AlignLeft );
00170 }
00171
00172 if ( !sizedCaption.isEmpty() ) {
00173 ttl = new TQLabel( sizedCaption, hb ? hb : vb, "title_label" );
00174 TQFont fnt = ttl->font();
00175 #ifdef Q_WS_X11
00176 truncateStringToFit(sizedCaption, fnt, max_width);
00177 ttl->setText(sizedCaption);
00178 #endif
00179 fnt.setBold( true );
00180 ttl->setFont( fnt );
00181 ttl->setAlignment( Qt::AlignHCenter );
00182 if ( hb ) {
00183 hb->setStretchFactor( ttl, 10 );
00184 }
00185 }
00186
00187 if ( !sizedText.isEmpty() ) {
00188 msg = new TQLabel( sizedText, vb, "msg_label" );
00189 #ifdef Q_WS_X11
00190 TQStringList textLines = TQStringList::split("\n", sizedText, true);
00191 for (TQStringList::Iterator it = textLines.begin(); it != textLines.end(); ++it) {
00192 truncateStringToFit(*it, msg->font(), max_width);
00193 }
00194
00195
00196 if (textLines.count() > 5) {
00197 int count = 3;
00198 TQStringList truncatedLines;
00199 for (TQStringList::Iterator it = textLines.begin(); it != textLines.end(); ++it) {
00200 truncatedLines.append(*it);
00201 if (count > 5) {
00202 truncatedLines.append("...");
00203 break;
00204 }
00205 count++;
00206 }
00207 textLines = truncatedLines;
00208 }
00209 sizedText = textLines.join("\n");
00210 msg->setText(sizedText);
00211 #endif
00212 msg->setAlignment( AlignLeft );
00213 }
00214
00215 return vb;
00216 }
00217
00218 void KPassivePopup::setView( const TQString &caption, const TQString &text )
00219 {
00220 setView( caption, text, TQPixmap() );
00221 }
00222
00223 void KPassivePopup::setTimeout( int delay )
00224 {
00225 hideDelay = delay;
00226 if( hideTimer->isActive() )
00227 {
00228 if( delay ) {
00229 hideTimer->changeInterval( delay );
00230 } else {
00231 hideTimer->stop();
00232 }
00233 }
00234 }
00235
00236 void KPassivePopup::setAutoDelete( bool autoDelete )
00237 {
00238 m_autoDelete = autoDelete;
00239 }
00240
00241 void KPassivePopup::mouseReleaseEvent( TQMouseEvent *e )
00242 {
00243 emit clicked();
00244 emit clicked( e->pos() );
00245 }
00246
00247
00248
00249
00250
00251 void KPassivePopup::show()
00252 {
00253 TQSize desiredSize = sizeHint();
00254
00255 if (size() != desiredSize) {
00256 resize(desiredSize);
00257 }
00258
00259 if (d->fixedPosition.isNull()) {
00260 positionSelf();
00261 }
00262 else {
00263 if( d->popupStyle == Balloon ) {
00264 setAnchor(d->fixedPosition);
00265 }
00266 else {
00267 move(d->fixedPosition);
00268 }
00269 }
00270 TQFrame::show();
00271
00272 int delay = hideDelay;
00273 if ( delay < 0 ) {
00274 delay = DEFAULT_POPUP_TIME;
00275 }
00276
00277 if ( delay > 0 ) {
00278 hideTimer->start( delay );
00279 }
00280 }
00281
00282 void KPassivePopup::show(const TQPoint &p)
00283 {
00284 d->fixedPosition = p;
00285 show();
00286 }
00287
00288 void KPassivePopup::hideEvent( TQHideEvent * )
00289 {
00290 hideTimer->stop();
00291 emit( hidden( this ) );
00292 if ( m_autoDelete )
00293 deleteLater();
00294 }
00295
00296 TQRect KPassivePopup::defaultArea() const
00297 {
00298 #ifdef Q_WS_X11
00299 NETRootInfo info( tqt_xdisplay(),
00300 NET::NumberOfDesktops |
00301 NET::CurrentDesktop |
00302 NET::WorkArea,
00303 -1, false );
00304 info.activate();
00305 NETRect workArea = info.workArea( info.currentDesktop() );
00306 TQRect r;
00307 r.setRect( workArea.pos.x, workArea.pos.y, 0, 0 );
00308 #else
00309
00310 TQRect r;
00311 r.setRect( 100, 100, 200, 200 );
00312 #endif
00313 return r;
00314 }
00315
00316 void KPassivePopup::positionSelf()
00317 {
00318 TQRect target;
00319
00320 #ifdef Q_WS_X11
00321 if ( !window ) {
00322 target = defaultArea();
00323 }
00324
00325 else {
00326 NETWinInfo ni( tqt_xdisplay(), window, tqt_xrootwin(),
00327 NET::WMIconGeometry | NET::WMKDESystemTrayWinFor );
00328
00329
00330
00331 if ( ni.kdeSystemTrayWinFor() ) {
00332 NETRect frame, win;
00333 ni.kdeGeometry( frame, win );
00334 target.setRect( win.pos.x, win.pos.y,
00335 win.size.width, win.size.height );
00336 }
00337 else if ( ni.state() & NET::SkipTaskbar ) {
00338 target = defaultArea();
00339 }
00340 else {
00341 NETRect r = ni.iconGeometry();
00342 target.setRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
00343 if ( target.isNull() ) {
00344 NETRect dummy;
00345 ni.kdeGeometry( dummy, r );
00346 target.setRect( r.pos.x, r.pos.y,
00347 r.size.width, r.size.height);
00348 }
00349 }
00350 }
00351 #else
00352 target = defaultArea();
00353 #endif
00354 moveNear( target );
00355 }
00356
00357 void KPassivePopup::moveNear( TQRect target )
00358 {
00359 TQPoint pos = target.topLeft();
00360 int x = pos.x();
00361 int y = pos.y();
00362 int w = width();
00363 int h = height();
00364
00365 TQRect r = TDEGlobalSettings::desktopGeometry(TQPoint(x+w/2,y+h/2));
00366
00367 if( d->popupStyle == Balloon )
00368 {
00369
00370 if( x + w > r.width() ){
00371 x = x + target.width();
00372 }
00373
00374 if( y + h > r.height() ){
00375 y = y + target.height();
00376 }
00377 } else
00378 {
00379 if ( x < r.center().x() )
00380 x = x + target.width();
00381 else
00382 x = x - w;
00383
00384
00385 if ( (y + h) > r.bottom() )
00386 y = r.bottom() - h;
00387
00388 if ( (x + w) > r.right() )
00389 x = r.right() - w;
00390 }
00391 if ( y < r.top() )
00392 y = r.top();
00393
00394 if ( x < r.left() )
00395 x = r.left();
00396
00397 if( d->popupStyle == Balloon )
00398 setAnchor( TQPoint( x, y ) );
00399 else
00400 move( x, y );
00401 }
00402
00403 void KPassivePopup::setAnchor(const TQPoint &anchor)
00404 {
00405 d->anchor = anchor;
00406 updateMask();
00407 }
00408
00409 void KPassivePopup::paintEvent( TQPaintEvent* pe )
00410 {
00411 if( d->popupStyle == Balloon ) {
00412 TQPainter p;
00413 p.begin( this );
00414 p.drawPolygon( d->surround );
00415 }
00416 else {
00417 TQFrame::paintEvent( pe );
00418 }
00419 }
00420
00421 void KPassivePopup::updateMask()
00422 {
00423
00424
00425 TQRect deskRect = TDEGlobalSettings::desktopGeometry(d->anchor);
00426
00427 int xh = 70, xl = 40;
00428 if( width() < 80 )
00429 xh = xl = 40;
00430 else if( width() < 110 )
00431 xh = width() - 40;
00432
00433 bool bottom = (d->anchor.y() + height()) > ((deskRect.y() + deskRect.height()-48));
00434 bool right = (d->anchor.x() + width()) > ((deskRect.x() + deskRect.width()-48));
00435
00436 TQPoint corners[4] = {
00437 TQPoint( width() - 50, 10 ),
00438 TQPoint( 10, 10 ),
00439 TQPoint( 10, height() - 50 ),
00440 TQPoint( width() - 50, height() - 50 )
00441 };
00442
00443 TQBitmap mask( width(), height(), true );
00444 TQPainter p( &mask );
00445 TQBrush brush( Qt::white, Qt::SolidPattern );
00446 p.setBrush( brush );
00447
00448 int i = 0, z = 0;
00449 for (; i < 4; ++i) {
00450 TQPointArray corner;
00451 corner.makeArc(corners[i].x(), corners[i].y(), 40, 40, i * 16 * 90, 16 * 90);
00452
00453 d->surround.resize( z + corner.count() );
00454 for (unsigned int s = 0; s < corner.count() - 1; s++) {
00455 d->surround.setPoint( z++, corner[s] );
00456 }
00457
00458 if (bottom && i == 2) {
00459 if (right) {
00460 d->surround.resize( z + 3 );
00461 d->surround.setPoint( z++, TQPoint( width() - xh, height() - 11 ) );
00462 d->surround.setPoint( z++, TQPoint( width() - 20, height() ) );
00463 d->surround.setPoint( z++, TQPoint( width() - xl, height() - 11 ) );
00464 } else {
00465 d->surround.resize( z + 3 );
00466 d->surround.setPoint( z++, TQPoint( xl, height() - 11 ) );
00467 d->surround.setPoint( z++, TQPoint( 20, height() ) );
00468 d->surround.setPoint( z++, TQPoint( xh, height() - 11 ) );
00469 }
00470 } else if (!bottom && i == 0) {
00471 if (right) {
00472 d->surround.resize( z + 3 );
00473 d->surround.setPoint( z++, TQPoint( width() - xl, 10 ) );
00474 d->surround.setPoint( z++, TQPoint( width() - 20, 0 ) );
00475 d->surround.setPoint( z++, TQPoint( width() - xh, 10 ) );
00476 } else {
00477 d->surround.resize( z + 3 );
00478 d->surround.setPoint( z++, TQPoint( xh, 10 ) );
00479 d->surround.setPoint( z++, TQPoint( 20, 0 ) );
00480 d->surround.setPoint( z++, TQPoint( xl, 10 ) );
00481 }
00482 }
00483 }
00484
00485 d->surround.resize( z + 1 );
00486 d->surround.setPoint( z, d->surround[0] );
00487 p.drawPolygon( d->surround );
00488 setMask(mask);
00489
00490 move( right ? d->anchor.x() - width() + 20 : ( d->anchor.x() < 11 ? 11 : d->anchor.x() - 20 ),
00491 bottom ? d->anchor.y() - height() : ( d->anchor.y() < 11 ? 11 : d->anchor.y() ) );
00492
00493 update();
00494 }
00495
00496
00497
00498
00499
00500 KPassivePopup *KPassivePopup::message( const TQString &caption, const TQString &text,
00501 const TQPixmap &icon,
00502 TQWidget *parent, const char *name, int timeout )
00503 {
00504 return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, name, timeout );
00505 }
00506
00507 KPassivePopup *KPassivePopup::message( const TQString &text, TQWidget *parent, const char *name )
00508 {
00509 return message( DEFAULT_POPUP_TYPE, TQString::null, text, TQPixmap(), parent, name );
00510 }
00511
00512 KPassivePopup *KPassivePopup::message( const TQString &caption, const TQString &text,
00513 TQWidget *parent, const char *name )
00514 {
00515 return message( DEFAULT_POPUP_TYPE, caption, text, TQPixmap(), parent, name );
00516 }
00517
00518 KPassivePopup *KPassivePopup::message( const TQString &caption, const TQString &text,
00519 const TQPixmap &icon, WId parent, const char *name, int timeout )
00520 {
00521 return message( DEFAULT_POPUP_TYPE, caption, text, icon, parent, name, timeout );
00522 }
00523
00524 KPassivePopup *KPassivePopup::message( int popupStyle, const TQString &caption, const TQString &text,
00525 const TQPixmap &icon,
00526 TQWidget *parent, const char *name, int timeout )
00527 {
00528 KPassivePopup *pop = new KPassivePopup( popupStyle, parent, name );
00529 pop->setAutoDelete( true );
00530 pop->setView( caption, text, icon );
00531 pop->hideDelay = timeout;
00532 pop->show();
00533
00534 return pop;
00535 }
00536
00537 KPassivePopup *KPassivePopup::message( int popupStyle, const TQString &text, TQWidget *parent, const char *name )
00538 {
00539 return message( popupStyle, TQString::null, text, TQPixmap(), parent, name );
00540 }
00541
00542 KPassivePopup *KPassivePopup::message( int popupStyle, const TQString &caption, const TQString &text,
00543 TQWidget *parent, const char *name )
00544 {
00545 return message( popupStyle, caption, text, TQPixmap(), parent, name );
00546 }
00547
00548 KPassivePopup *KPassivePopup::message( int popupStyle, const TQString &caption, const TQString &text,
00549 const TQPixmap &icon, WId parent, const char *name, int timeout )
00550 {
00551 KPassivePopup *pop = new KPassivePopup( popupStyle, parent, name );
00552 pop->setAutoDelete( true );
00553 pop->setView( caption, text, icon );
00554 pop->hideDelay = timeout;
00555 pop->show();
00556
00557 return pop;
00558 }
00559
00560
00561
00562