• Skip to content
  • Skip to link menu
KDE 4.3 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(ToolTipManager *manager)
00058         : q(manager),
00059           currentWidget(0),
00060           showTimer(0),
00061           hideTimer(0),
00062           tipWidget(new ToolTip(0)),
00063           state(ToolTipManager::Activated),
00064           isShown(false),
00065           delayedHide(false)
00066     {
00067 
00068     }
00069 
00070     ~ToolTipManagerPrivate()
00071     {
00072         if (!QCoreApplication::closingDown()) {
00073             delete tipWidget;
00074         }
00075     }
00076 
00077     void showToolTip();
00078     void resetShownState();
00079 
00083     void onWidgetDestroyed(QObject * object);
00084     void removeWidget(QGraphicsWidget *w);
00085     void clearTips();
00086     void doDelayedHide();
00087 
00088     ToolTipManager *q;
00089     QGraphicsWidget *currentWidget;
00090     QTimer *showTimer;
00091     QTimer *hideTimer;
00092     QHash<QGraphicsWidget *, ToolTipContent> tooltips;
00093     ToolTip *tipWidget;
00094     ToolTipManager::State state;
00095     bool isShown : 1;
00096     bool delayedHide : 1;
00097 };
00098 
00099 //TOOLTIP IMPLEMENTATION
00100 class ToolTipManagerSingleton
00101 {
00102     public:
00103     ToolTipManagerSingleton()
00104     {
00105     }
00106     ToolTipManager self;
00107 };
00108 K_GLOBAL_STATIC(ToolTipManagerSingleton, privateInstance)
00109 
00110 ToolTipManager *ToolTipManager::self()
00111 {
00112     return &privateInstance->self;
00113 }
00114 
00115 ToolTipManager::ToolTipManager(QObject *parent)
00116   : QObject(parent),
00117     d(new ToolTipManagerPrivate(this)),
00118     m_corona(0)
00119 {
00120     d->showTimer = new QTimer(this);
00121     d->showTimer->setSingleShot(true);
00122     d->hideTimer = new QTimer(this);
00123     d->hideTimer->setSingleShot(true);
00124 
00125     connect(d->showTimer, SIGNAL(timeout()), SLOT(showToolTip()));
00126     connect(d->hideTimer, SIGNAL(timeout()), SLOT(resetShownState()));
00127 }
00128 
00129 ToolTipManager::~ToolTipManager()
00130 {
00131     delete d;
00132 }
00133 
00134 void ToolTipManager::show(QGraphicsWidget *widget)
00135 {
00136     if (!d->tooltips.contains(widget)) {
00137         return;
00138     }
00139 
00140     d->hideTimer->stop();
00141     d->delayedHide = false;
00142     d->showTimer->stop();
00143     d->currentWidget = widget;
00144 
00145     if (d->isShown) {
00146         // small delay to prevent unnecessary showing when the mouse is moving quickly across items
00147         // which can be too much for less powerful CPUs to keep up with
00148         d->showTimer->start(200);
00149     } else {
00150         d->showTimer->start(700);
00151     }
00152 }
00153 
00154 bool ToolTipManager::isVisible(QGraphicsWidget *widget) const
00155 {
00156     return d->currentWidget == widget && d->tipWidget->isVisible();
00157 }
00158 
00159 void ToolTipManagerPrivate::doDelayedHide()
00160 {
00161     showTimer->stop();  // stop the timer to show the tooltip
00162     delayedHide = true;
00163     hideTimer->start(250);
00164 }
00165 
00166 void ToolTipManager::hide(QGraphicsWidget *widget)
00167 {
00168     if (d->currentWidget != widget) {
00169         return;
00170     }
00171 
00172     d->currentWidget = 0;
00173     d->showTimer->stop();  // stop the timer to show the tooltip
00174     d->delayedHide = false;
00175     d->tipWidget->hide();
00176 }
00177 
00178 void ToolTipManager::registerWidget(QGraphicsWidget *widget)
00179 {
00180     if (d->state == Deactivated || d->tooltips.contains(widget)) {
00181         return;
00182     }
00183 
00184     //the tooltip is not registered we add it in our map of tooltips
00185     d->tooltips.insert(widget, ToolTipContent());
00186     widget->installEventFilter(this);
00187     connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(onWidgetDestroyed(QObject*)));
00188 }
00189 
00190 void ToolTipManager::unregisterWidget(QGraphicsWidget *widget)
00191 {
00192     if (!d->tooltips.contains(widget)) {
00193         return;
00194     }
00195 
00196     widget->removeEventFilter(this);
00197     d->removeWidget(widget);
00198 }
00199 
00200 void ToolTipManager::setContent(QGraphicsWidget *widget, const ToolTipContent &data)
00201 {
00202     if (d->state == Deactivated || !widget) {
00203         return;
00204     }
00205 
00206     registerWidget(widget);
00207     d->tooltips.insert(widget, data);
00208 
00209     if (d->currentWidget == widget) {
00210         if (data.isEmpty()) {
00211             hide(widget);
00212         } else {
00213             d->delayedHide = data.autohide();
00214             if (d->delayedHide) {
00215                 //kDebug() << "starting authoide";
00216                 d->hideTimer->start(3000);
00217             } else {
00218                 d->hideTimer->stop();
00219             }
00220         }
00221 
00222         d->tipWidget->setContent(widget, data);
00223         d->tipWidget->prepareShowing();
00224         if (m_corona) {
00225             d->tipWidget->moveTo(m_corona->popupPosition(widget, d->tipWidget->size()));
00226         }
00227     }
00228 }
00229 
00230 void ToolTipManager::clearContent(QGraphicsWidget *widget)
00231 {
00232     setContent(widget, ToolTipContent());
00233 }
00234 
00235 void ToolTipManager::setState(ToolTipManager::State state)
00236 {
00237     d->state = state;
00238 
00239     switch (state) {
00240         case Activated:
00241             break;
00242         case Deactivated:
00243             d->clearTips();
00244             //fallthrough
00245         case Inhibited:
00246             d->resetShownState();
00247             break;
00248     }
00249 }
00250 
00251 ToolTipManager::State ToolTipManager::state() const
00252 {
00253     return d->state;
00254 }
00255 
00256 void ToolTipManagerPrivate::onWidgetDestroyed(QObject *object)
00257 {
00258     if (!object) {
00259         return;
00260     }
00261 
00262     // we do a static_cast here since it really isn't a QGraphicsWidget by this
00263     // point anymore since we are in the QObject dtor. we don't actually
00264     // try and do anything with it, we just need the value of the pointer
00265     // so this unsafe looking code is actually just fine.
00266     //
00267     // NOTE: DO NOT USE THE w VARIABLE FOR ANYTHING OTHER THAN COMPARING
00268     //       THE ADDRESS! ACTUALLY USING THE OBJECT WILL RESULT IN A CRASH!!!
00269     QGraphicsWidget *w = static_cast<QGraphicsWidget*>(object);
00270     removeWidget(w);
00271 }
00272 
00273 void ToolTipManagerPrivate::removeWidget(QGraphicsWidget *w)
00274 {
00275     // DO NOT ACCESS w HERE!! IT MAY BE IN THE PROCESS OF DELETION!
00276     if (currentWidget == w) {
00277         currentWidget = 0;
00278         showTimer->stop();  // stop the timer to show the tooltip
00279         tipWidget->setContent(0, ToolTipContent());
00280         tipWidget->hide();
00281         delayedHide = false;
00282     }
00283 
00284     tooltips.remove(w);
00285 }
00286 
00287 void ToolTipManagerPrivate::clearTips()
00288 {
00289     tooltips.clear();
00290 }
00291 
00292 void ToolTipManagerPrivate::resetShownState()
00293 {
00294     if (currentWidget) {
00295         if (!tipWidget->isVisible() || delayedHide) {
00296             //One might have moused out and back in again
00297             delayedHide = false;
00298             isShown = false;
00299             currentWidget = 0;
00300             tipWidget->hide();
00301         }
00302     }
00303 }
00304 
00305 void ToolTipManagerPrivate::showToolTip()
00306 {
00307     if (state != ToolTipManager::Activated ||
00308         !currentWidget ||
00309         QApplication::activePopupWidget() ||
00310         QApplication::activeModalWidget()) {
00311         return;
00312     }
00313 
00314     PopupApplet *popup = qobject_cast<PopupApplet*>(currentWidget);
00315     if (popup && popup->isPopupShowing()) {
00316         return;
00317     }
00318 
00319     // toolTipAboutToShow may call into methods such as setContent which play
00320     // with the current widget; so let's just pretend for a moment that we don't have
00321     // a current widget
00322     QGraphicsWidget *temp = currentWidget;
00323     currentWidget = 0;
00324     QMetaObject::invokeMethod(temp, "toolTipAboutToShow");
00325     currentWidget = temp;
00326 
00327     QHash<QGraphicsWidget *, ToolTipContent>::const_iterator tooltip = tooltips.constFind(currentWidget);
00328 
00329     if (tooltip == tooltips.constEnd() || tooltip.value().isEmpty()) {
00330         return;
00331     }
00332 
00333     Containment *c = dynamic_cast<Containment *>(currentWidget->topLevelItem());
00334     //kDebug() << "about to show" << (QObject*)c;
00335     if (c) {
00336         tipWidget->setDirection(Plasma::locationToDirection(c->location()));
00337     }
00338 
00339     tipWidget->setContent(currentWidget, tooltip.value());
00340     tipWidget->prepareShowing();
00341     if (q->m_corona) {
00342         tipWidget->moveTo(q->m_corona->popupPosition(currentWidget, tipWidget->size()));
00343     }
00344     tipWidget->show();
00345     isShown = true;  //ToolTip is visible
00346 
00347     delayedHide = tooltip.value().autohide();
00348     if (delayedHide) {
00349         //kDebug() << "starting authoide";
00350         hideTimer->start(3000);
00351     } else {
00352         hideTimer->stop();
00353     }
00354 }
00355 
00356 bool ToolTipManager::eventFilter(QObject *watched, QEvent *event)
00357 {
00358     QGraphicsWidget * widget = dynamic_cast<QGraphicsWidget *>(watched);
00359     if (d->state != Activated || !widget) {
00360         return QObject::eventFilter(watched, event);
00361     }
00362 
00363     switch (event->type()) {
00364         case QEvent::GraphicsSceneHoverMove:
00365             // If the tooltip isn't visible, run through showing the tooltip again
00366             // so that it only becomes visible after a stationary hover
00367             if (Plasma::ToolTipManager::self()->isVisible(widget)) {
00368                 break;
00369             }
00370 
00371             // Don't restart the show timer on a mouse move event if there hasn't
00372             // been an enter event or the current widget has been cleared by a click
00373             // or wheel event.
00374             if (!d->currentWidget) {
00375                 break;
00376             }
00377 
00378         case QEvent::GraphicsSceneHoverEnter:
00379         {
00380             // Check that there is a tooltip to show
00381             if (!d->tooltips.contains(widget)) {
00382                 break;
00383             }
00384 
00385             // If the mouse is in the widget's area at the time that it is being
00386             // created the widget can receive a hover event before it is fully
00387             // initialized, in which case view() will return 0.
00388             QGraphicsView *parentView = viewFor(widget);
00389             if (parentView) {
00390                 show(widget);
00391             }
00392 
00393             break;
00394         }
00395 
00396         case QEvent::GraphicsSceneHoverLeave:
00397             d->doDelayedHide();
00398             break;
00399 
00400         case QEvent::GraphicsSceneMousePress:
00401             hide(widget);
00402 
00403         case QEvent::GraphicsSceneWheel:
00404         default:
00405             break;
00406     }
00407 
00408     return QObject::eventFilter(watched, event);
00409 }
00410 
00411 } // Plasma namespace
00412 
00413 #include "tooltipmanager.moc"
00414 

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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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