• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

Plasma

tooltipmanager.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2007 by Dan Meltzer <hydrogen@notyetimplemented.com>
00003  * Copyright 2008 by Aaron Seigo <aseigo@kde.org>
00004  * Copyright 2008 by Alexis Ménard <darktears31@gmail.com>
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor,
00019  * Boston, MA  02110-1301  USA
00020  */
00021 
00022 #include "tooltipmanager.h"
00023 
00024 //Qt
00025 #include <QCoreApplication>
00026 #include <QLabel>
00027 #include <QTimer>
00028 #include <QGridLayout>
00029 #include <QGraphicsView>
00030 
00031 //KDE
00032 #include <kwindowsystem.h>
00033 
00034 //X11
00035 #ifdef Q_WS_X11
00036 #include <QtGui/QX11Info>
00037 #include <X11/Xlib.h>
00038 #include <fixx11h.h>
00039 #endif
00040 
00041 //Plasma
00042 #include "plasma/applet.h"
00043 #include "plasma/containment.h"
00044 #include "plasma/corona.h"
00045 #include "plasma/framesvg.h"
00046 #include "plasma/popupapplet.h"
00047 #include "plasma/theme.h"
00048 #include "plasma/view.h"
00049 #include "plasma/private/tooltip_p.h"
00050 
00051 namespace Plasma
00052 {
00053 
00054 class ToolTipManagerPrivate
00055 {
00056 public :
00057     ToolTipManagerPrivate()
00058         : currentWidget(0),
00059           showTimer(0),
00060           hideTimer(0),
00061           tipWidget(new ToolTip(0)),
00062           state(ToolTipManager::Activated),
00063           isShown(false),
00064           delayedHide(false)
00065     {
00066 
00067     }
00068 
00069     ~ToolTipManagerPrivate()
00070     {
00071         if (!QCoreApplication::closingDown()) {
00072             delete tipWidget;
00073         }
00074     }
00075 
00076     void showToolTip();
00077     void resetShownState();
00078 
00082     void onWidgetDestroyed(QObject * object);
00083     void removeWidget(QGraphicsWidget *w);
00084     void clearTips();
00085     void doDelayedHide();
00086 
00087     QGraphicsWidget *currentWidget;
00088     QTimer *showTimer;
00089     QTimer *hideTimer;
00090     QHash<QGraphicsWidget *, ToolTipContent> tooltips;
00091     ToolTip *tipWidget;
00092     ToolTipManager::State state;
00093     bool isShown : 1;
00094     bool delayedHide : 1;
00095 };
00096 
00097 //TOOLTIP IMPLEMENTATION
00098 class ToolTipManagerSingleton
00099 {
00100     public:
00101     ToolTipManagerSingleton()
00102     {
00103     }
00104     ToolTipManager self;
00105 };
00106 K_GLOBAL_STATIC(ToolTipManagerSingleton, privateInstance)
00107 
00108 ToolTipManager *ToolTipManager::self()
00109 {
00110     return &privateInstance->self;
00111 }
00112 
00113 ToolTipManager::ToolTipManager(QObject *parent)
00114   : QObject(parent),
00115     d(new ToolTipManagerPrivate)
00116 {
00117     d->showTimer = new QTimer(this);
00118     d->showTimer->setSingleShot(true);
00119     d->hideTimer = new QTimer(this);
00120     d->hideTimer->setSingleShot(true);
00121 
00122     connect(d->showTimer, SIGNAL(timeout()), SLOT(showToolTip()));
00123     connect(d->hideTimer, SIGNAL(timeout()), SLOT(resetShownState()));
00124 }
00125 
00126 ToolTipManager::~ToolTipManager()
00127 {
00128     delete d;
00129 }
00130 
00131 void ToolTipManager::show(QGraphicsWidget *widget)
00132 {
00133     if (!d->tooltips.contains(widget)) {
00134         return;
00135     }
00136 
00137     d->hideTimer->stop();
00138     d->delayedHide = false;
00139     d->showTimer->stop();
00140     d->currentWidget = widget;
00141 
00142     if (d->isShown) {
00143         // small delay to prevent unnecessary showing when the mouse is moving quickly across items
00144         // which can be too much for less powerful CPUs to keep up with
00145         d->showTimer->start(200);
00146     } else {
00147         d->showTimer->start(700);
00148     }
00149 }
00150 
00151 bool ToolTipManager::isVisible(QGraphicsWidget *widget) const
00152 {
00153     return d->currentWidget == widget && d->tipWidget->isVisible();
00154 }
00155 
00156 void ToolTipManagerPrivate::doDelayedHide()
00157 {
00158     showTimer->stop();  // stop the timer to show the tooltip
00159     delayedHide = true;
00160     hideTimer->start(250);
00161 }
00162 
00163 void ToolTipManager::hide(QGraphicsWidget *widget)
00164 {
00165     if (d->currentWidget != widget) {
00166         return;
00167     }
00168 
00169     d->currentWidget = 0;
00170     d->showTimer->stop();  // stop the timer to show the tooltip
00171     d->delayedHide = false;
00172     d->tipWidget->hide();
00173 }
00174 
00175 void ToolTipManager::registerWidget(QGraphicsWidget *widget)
00176 {
00177     if (d->state == Deactivated || d->tooltips.contains(widget)) {
00178         return;
00179     }
00180 
00181     //the tooltip is not registered we add it in our map of tooltips
00182     d->tooltips.insert(widget, ToolTipContent());
00183     widget->installEventFilter(this);
00184     connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(onWidgetDestroyed(QObject*)));
00185 }
00186 
00187 void ToolTipManager::unregisterWidget(QGraphicsWidget *widget)
00188 {
00189     if (!d->tooltips.contains(widget)) {
00190         return;
00191     }
00192 
00193     widget->removeEventFilter(this);
00194     d->removeWidget(widget);
00195 }
00196 
00197 void ToolTipManager::setContent(QGraphicsWidget *widget, const ToolTipContent &data)
00198 {
00199     if (d->state == Deactivated) {
00200         return;
00201     }
00202 
00203     registerWidget(widget);
00204     d->tooltips[widget] = data;
00205 
00206     if (d->currentWidget == widget) {
00207         if (data.isEmpty()) {
00208             hide(widget);
00209         } else {
00210             d->delayedHide = data.autohide();
00211             if (d->delayedHide) {
00212                 //kDebug() << "starting authoide";
00213                 d->hideTimer->start(3000);
00214             } else {
00215                 d->hideTimer->stop();
00216             }
00217         }
00218 
00219         d->tipWidget->setContent(widget, data);
00220         d->tipWidget->prepareShowing();
00221         d->tipWidget->moveTo(m_corona->popupPosition(d->currentWidget, d->tipWidget->size()));
00222     }
00223 }
00224 
00225 void ToolTipManager::clearContent(QGraphicsWidget *widget)
00226 {
00227     setContent(widget, ToolTipContent());
00228 }
00229 
00230 void ToolTipManager::setState(ToolTipManager::State state)
00231 {
00232     d->state = state;
00233 
00234     switch (state) {
00235         case Activated:
00236             break;
00237         case Deactivated:
00238             d->clearTips();
00239             //fallthrough
00240         case Inhibited:
00241             d->resetShownState();
00242             break;
00243     }
00244 }
00245 
00246 ToolTipManager::State ToolTipManager::state() const
00247 {
00248     return d->state;
00249 }
00250 
00251 void ToolTipManagerPrivate::onWidgetDestroyed(QObject *object)
00252 {
00253     if (!object) {
00254         return;
00255     }
00256 
00257     // we do a static_cast here since it really isn't a QGraphicsWidget by this
00258     // point anymore since we are in the QObject dtor. we don't actually
00259     // try and do anything with it, we just need the value of the pointer
00260     // so this unsafe looking code is actually just fine.
00261     //
00262     // NOTE: DO NOT USE THE w VARIABLE FOR ANYTHING OTHER THAN COMPARING
00263     //       THE ADDRESS! ACTUALLY USING THE OBJECT WILL RESULT IN A CRASH!!!
00264     QGraphicsWidget *w = static_cast<QGraphicsWidget*>(object);
00265     removeWidget(w);
00266 }
00267 
00268 void ToolTipManagerPrivate::removeWidget(QGraphicsWidget *w)
00269 {
00270     // DO NOTE ACCESS w HERE!! IT MAY BE IN THE PROCESS OF DELETION!
00271     if (currentWidget == w) {
00272         currentWidget = 0;
00273         showTimer->stop();  // stop the timer to show the tooltip
00274         tipWidget->setContent(0, ToolTipContent());
00275         tipWidget->hide();
00276         delayedHide = false;
00277     }
00278 
00279     tooltips.remove(w);
00280 }
00281 
00282 void ToolTipManagerPrivate::clearTips()
00283 {
00284     tooltips.clear();
00285 }
00286 
00287 void ToolTipManagerPrivate::resetShownState()
00288 {
00289     if (currentWidget) {
00290         if (!tipWidget->isVisible() || delayedHide) {
00291             //One might have moused out and back in again
00292             delayedHide = false;
00293             isShown = false;
00294             currentWidget = 0;
00295             tipWidget->hide();
00296         }
00297     }
00298 }
00299 
00300 void ToolTipManagerPrivate::showToolTip()
00301 {
00302     if (state != ToolTipManager::Activated ||
00303         !currentWidget ||
00304         QApplication::activePopupWidget() ||
00305         QApplication::activeModalWidget()) {
00306         return;
00307     }
00308 
00309     PopupApplet *popup = qobject_cast<PopupApplet*>(currentWidget);
00310     if (popup && popup->isPopupShowing()) {
00311         return;
00312     }
00313 
00314     QMetaObject::invokeMethod(currentWidget, "toolTipAboutToShow");
00315     QHash<QGraphicsWidget *, ToolTipContent>::const_iterator tooltip = tooltips.constFind(currentWidget);
00316 
00317     if (tooltip == tooltips.constEnd() || tooltip.value().isEmpty()) {
00318         return;
00319     }
00320 
00321     Containment *c = dynamic_cast<Containment *>(currentWidget->topLevelItem());
00322     //kDebug() << "about to show" << (QObject*)c;
00323     if (c) {
00324         tipWidget->setDirection(Plasma::locationToDirection(c->location()));
00325     }
00326 
00327     tipWidget->setContent(currentWidget, tooltip.value());
00328     tipWidget->prepareShowing();
00329     tipWidget->moveTo(ToolTipManager::self()->m_corona->popupPosition(currentWidget, tipWidget->size()));
00330     tipWidget->show();
00331     isShown = true;  //ToolTip is visible
00332 
00333     delayedHide = tooltip.value().autohide();
00334     if (delayedHide) {
00335         //kDebug() << "starting authoide";
00336         hideTimer->start(3000);
00337     } else {
00338         hideTimer->stop();
00339     }
00340 }
00341 
00342 bool ToolTipManager::eventFilter(QObject *watched, QEvent *event)
00343 {
00344     QGraphicsWidget * widget = dynamic_cast<QGraphicsWidget *>(watched);
00345     if (d->state != Activated || !widget) {
00346         return QObject::eventFilter(watched, event);
00347     }
00348 
00349     switch (event->type()) {
00350         case QEvent::GraphicsSceneHoverMove:
00351             // If the tooltip isn't visible, run through showing the tooltip again
00352             // so that it only becomes visible after a stationary hover
00353             if (Plasma::ToolTipManager::self()->isVisible(widget)) {
00354                 break;
00355             }
00356 
00357             // Don't restart the show timer on a mouse move event if there hasn't
00358             // been an enter event or the current widget has been cleared by a click
00359             // or wheel event.
00360             if (!d->currentWidget) {
00361                 break;
00362             }
00363 
00364         case QEvent::GraphicsSceneHoverEnter:
00365         {
00366             // Check that there is a tooltip to show
00367             if (!d->tooltips.contains(widget)) {
00368                 break;
00369             }
00370 
00371             // If the mouse is in the widget's area at the time that it is being
00372             // created the widget can receive a hover event before it is fully
00373             // initialized, in which case view() will return 0.
00374             QGraphicsView *parentView = viewFor(widget);
00375             if (parentView) {
00376                 show(widget);
00377             }
00378 
00379             break;
00380         }
00381 
00382         case QEvent::GraphicsSceneHoverLeave:
00383             d->doDelayedHide();
00384             break;
00385 
00386         case QEvent::GraphicsSceneMousePress:
00387         case QEvent::GraphicsSceneWheel:
00388             hide(widget);
00389 
00390         default:
00391             break;
00392     }
00393 
00394     return QObject::eventFilter(watched, event);
00395 }
00396 
00397 } // Plasma namespace
00398 
00399 #include "tooltipmanager.moc"
00400 

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal