00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "tooltip_p.h"
00021
00022 #include <QBitmap>
00023 #include <QHBoxLayout>
00024 #include <QLabel>
00025 #include <QMouseEvent>
00026 #include <QPixmap>
00027 #include <QTimer>
00028 #include <QGraphicsView>
00029 #ifdef Q_WS_X11
00030 #include <QX11Info>
00031 #endif
00032
00033 #include <KDebug>
00034 #include <KGlobal>
00035 #include <KWindowSystem>
00036 #include <plasma/theme.h>
00037 #include <plasma/panelsvg.h>
00038
00039 #ifdef Q_WS_X11
00040 #include <X11/Xlib.h>
00041 #include <fixx11h.h>
00042 #endif
00043
00044 #include "plasma/plasma.h"
00045
00046 namespace Plasma {
00047
00048 class ToolTipPrivate
00049 {
00050 public:
00051 ToolTipPrivate()
00052 : label(0)
00053 , imageLabel(0)
00054 , preview(0)
00055 , windowToPreview(0)
00056 , currentWidget(0)
00057 , isShown(false)
00058 , delayedHide(false)
00059 , showTimer(0)
00060 , hideTimer(0)
00061 { }
00062
00063 QLabel *label;
00064 QLabel *imageLabel;
00065 WindowPreview *preview;
00066 WId windowToPreview;
00067 Plasma::Widget *currentWidget;
00068 bool isShown;
00069 bool delayedHide;
00070 QTimer *showTimer;
00071 QTimer *hideTimer;
00072
00073 PanelSvg *background;
00074
00075 };
00076
00077 class ToolTipSingleton
00078 {
00079 public:
00080 ToolTip self;
00081 };
00082 K_GLOBAL_STATIC( ToolTipSingleton, privateInstance )
00083
00084 ToolTip *ToolTip::self()
00085 {
00086 return &privateInstance->self;
00087 }
00088
00089 void ToolTip::show(Plasma::Widget *widget)
00090 {
00091 d->hideTimer->stop();
00092 d->delayedHide = false;
00093 if (d->isShown && d->currentWidget) {
00094
00095
00096 d->currentWidget->updateToolTip(false);
00097 }
00098 d->currentWidget = widget;
00099 d->showTimer->stop();
00100
00101 if (d->isShown) {
00102
00103
00104 d->showTimer->start(200);
00105 } else {
00106 d->showTimer->start(500);
00107 }
00108 }
00109
00110 void ToolTip::delayedHide()
00111 {
00112 d->showTimer->stop();
00113 d->delayedHide = true;
00114 d->hideTimer->start(250);
00115 }
00116
00117 void ToolTip::hide()
00118 {
00119 d->currentWidget = 0;
00120 d->showTimer->stop();
00121 d->delayedHide = false;
00122 setVisible(false);
00123 d->hideTimer->start(250);
00124 }
00125
00126 Plasma::Widget *ToolTip::currentWidget() const
00127 {
00128 return d->currentWidget;
00129 }
00130
00131
00132 void ToolTip::showToolTip()
00133 {
00134 if (!d->currentWidget || !d->currentWidget->toolTip()) {
00135 return;
00136 }
00137
00138 QGraphicsView *v = d->currentWidget->view();
00139 if (v && v->mouseGrabber()) {
00140 return;
00141 }
00142
00143 d->currentWidget->updateToolTip(true);
00144 setData(*d->currentWidget->toolTip());
00145
00146 if( d->windowToPreview != 0 ) {
00147
00148 d->preview->show();
00149 } else {
00150 d->preview->hide();
00151 }
00152 layout()->activate();
00153
00154 resize(sizeHint());
00155 move(d->currentWidget->popupPosition(size()));
00156
00157 if (isVisible()) {
00158 d->preview->setInfo();
00159 } else {
00160 setVisible(true);
00161 }
00162
00163 d->isShown = true;
00164 }
00165
00166 void ToolTip::resetShownState()
00167 {
00168 if (!isVisible() ||
00169 d->delayedHide) {
00170 d->delayedHide = false;
00171 d->isShown = false;
00172 setVisible(false);
00173 if (d->currentWidget) {
00174 d->currentWidget->updateToolTip(false);
00175 }
00176 d->currentWidget = 0;
00177 }
00178 }
00179
00180 void ToolTip::showEvent(QShowEvent *e)
00181 {
00182 QWidget::showEvent(e);
00183 d->preview->setInfo();
00184 }
00185
00186 void ToolTip::mouseReleaseEvent(QMouseEvent* event)
00187 {
00188 if (rect().contains(event->pos())) {
00189 hide();
00190 }
00191 }
00192
00193 ToolTip::ToolTip()
00194 : QWidget(0)
00195 , d( new ToolTipPrivate )
00196 {
00197 setWindowFlags(Qt::ToolTip);
00198 QGridLayout *l = new QGridLayout;
00199 d->preview = new WindowPreview;
00200 d->label = new QLabel;
00201 d->label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
00202 d->label->setWordWrap(true);
00203 d->imageLabel = new QLabel;
00204 d->imageLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
00205
00206 d->background = new PanelSvg("widgets/tooltip", this);
00207 d->background->setBorderFlags(PanelSvg::DrawAllBorders);
00208
00209 connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(update()));
00210
00211 l->addWidget(d->preview, 0, 0, 1, 2);
00212 l->addWidget(d->imageLabel, 1, 0);
00213 l->addWidget(d->label, 1, 1);
00214 setLayout(l);
00215
00216 d->showTimer = new QTimer(this);
00217 d->showTimer->setSingleShot(true);
00218 d->hideTimer = new QTimer(this);
00219 d->hideTimer->setSingleShot(true);
00220
00221 connect(d->showTimer, SIGNAL(timeout()), SLOT(showToolTip()));
00222 connect(d->hideTimer, SIGNAL(timeout()), SLOT(resetShownState()));
00223
00224 connect(Plasma::Theme::self(), SIGNAL(themeChanged()), this, SLOT(themeUpdated()));
00225 themeUpdated();
00226 }
00227
00228 ToolTip::~ToolTip()
00229 {
00230 delete d;
00231 }
00232
00233 void ToolTip::setData(Plasma::Widget *widget, const Plasma::ToolTipData &data)
00234 {
00235 if (d->currentWidget && d->currentWidget == widget) {
00236 setData(data);
00237 }
00238 }
00239
00240 void ToolTip::setData(const Plasma::ToolTipData &data)
00241 {
00242
00243 d->label->setText("<qt><b>" + data.mainText + "</b><br>" + data.subText + "</qt>");
00244 d->imageLabel->setPixmap(data.image);
00245 d->windowToPreview = data.windowToPreview;
00246 d->preview->setWindowId( d->windowToPreview );
00247
00248 if (isVisible()) {
00249 resize(sizeHint());
00250
00251 if (d->currentWidget) {
00252 move(d->currentWidget->popupPosition(size()));
00253 }
00254 }
00255 }
00256
00257 void ToolTip::themeUpdated()
00258 {
00259 const int topHeight = d->background->marginSize(Plasma::TopMargin);
00260 const int leftWidth = d->background->marginSize(Plasma::LeftMargin);
00261 const int rightWidth = d->background->marginSize(Plasma::RightMargin);
00262 const int bottomHeight = d->background->marginSize(Plasma::BottomMargin);
00263 setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
00264
00265
00266 QPalette plasmaPalette = QPalette();
00267 plasmaPalette.setColor(QPalette::Window, Plasma::Theme::self()->backgroundColor());
00268 plasmaPalette.setColor(QPalette::WindowText, Plasma::Theme::self()->textColor());
00269 setAutoFillBackground(true);
00270 setPalette(plasmaPalette);
00271 }
00272
00273
00274
00275
00276
00277 void WindowPreview::setWindowId(WId w)
00278 {
00279 if (!previewsAvailable()) {
00280 id = 0;
00281 return;
00282 }
00283 id = w;
00284 readWindowSize();
00285 }
00286
00287 bool WindowPreview::previewsAvailable() const
00288 {
00289 if (!KWindowSystem::compositingActive()) {
00290 return false;
00291 }
00292 #ifdef Q_WS_X11
00293
00294
00295 Display* dpy = QX11Info::display();
00296 Atom atom = XInternAtom(dpy, "_KDE_WINDOW_PREVIEW", False);
00297 int cnt;
00298 Atom* list = XListProperties(dpy, DefaultRootWindow( dpy ), &cnt);
00299 if (list != NULL) {
00300 bool ret = ( qFind(list, list + cnt, atom) != list + cnt );
00301 XFree(list);
00302 return ret;
00303 }
00304 #endif
00305 return false;
00306 }
00307
00308 QSize WindowPreview::sizeHint() const
00309 {
00310 if (id == 0) {
00311 return QSize();
00312 }
00313 if (!windowSize.isValid()) {
00314 readWindowSize();
00315 }
00316 QSize s = windowSize;
00317 s.scale(200, 150, Qt::KeepAspectRatio);
00318 return s;
00319 }
00320
00321 void WindowPreview::readWindowSize() const
00322 {
00323 #ifdef Q_WS_X11
00324 Window r;
00325 int x, y;
00326 unsigned int w, h, b, d;
00327 if (XGetGeometry(QX11Info::display(), id, &r, &x, &y, &w, &h, &b, &d)) {
00328 windowSize = QSize( w, h );
00329 } else {
00330 windowSize = QSize();
00331 }
00332 #else
00333 windowSize = QSize();
00334 #endif
00335 }
00336
00337 void WindowPreview::setInfo()
00338 {
00339 #ifdef Q_WS_X11
00340 Display *dpy = QX11Info::display();
00341 Atom atom = XInternAtom(dpy, "_KDE_WINDOW_PREVIEW", False);
00342 if (id == 0) {
00343 XDeleteProperty(dpy, parentWidget()->winId(), atom);
00344 return;
00345 }
00346 if (!windowSize.isValid()) {
00347 readWindowSize();
00348 }
00349 if (!windowSize.isValid()) {
00350 XDeleteProperty(dpy, parentWidget()->winId(), atom);
00351 return;
00352 }
00353 Q_ASSERT( parentWidget()->isWindow());
00354 long data[] = { 1, 5, id, x(), y(), width(), height() };
00355 XChangeProperty(dpy, parentWidget()->winId(), atom, atom, 32, PropModeReplace,
00356 reinterpret_cast< unsigned char* >( data ), sizeof( data ) / sizeof( data[ 0 ] ));
00357 #endif
00358 }
00359
00360 void ToolTip::resizeEvent(QResizeEvent *e)
00361 {
00362 QWidget::resizeEvent(e);
00363 d->background->resize(size());
00364
00365 setMask(d->background->mask());
00366 }
00367
00368 void ToolTip::paintEvent(QPaintEvent *e)
00369 {
00370 QPainter painter(this);
00371 painter.setRenderHint(QPainter::Antialiasing);
00372 painter.setClipRect(e->rect());
00373 painter.setCompositionMode(QPainter::CompositionMode_Source );
00374 painter.fillRect(rect(), Qt::transparent);
00375
00376 d->background->paint(&painter, rect());
00377 }
00378
00379 }
00380 #include "tooltip_p.moc"