• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDevelop Platform Libraries
  • Sitemap
  • Contact Us
 

util

activetooltip.cpp

00001 /* This file is part of the KDE project
00002    Copyright 2007 Vladimir Prus
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "activetooltip.h"
00021 
00022 #include <QPoint>
00023 #include <QPalette>
00024 #include <QApplication>
00025 #include <QEvent>
00026 #include <QMouseEvent>
00027 #include <limits>
00028 #include <kdebug.h>
00029 #include <QPointer>
00030 #include <qdesktopwidget.h>
00031 #include <qmenu.h>
00032 
00033 namespace KDevelop
00034 {
00035 
00036 class ActiveToolTipPrivate
00037 {
00038 public:
00039     uint previousDistance_;
00040     QRect rect_;
00041     QRegion rectExtensions_;
00042     QList<QPointer<QObject> > friendWidgets_;
00043     int mouseOut_;
00044 };
00045 
00046 ActiveToolTip::ActiveToolTip(QWidget *parent, const QPoint& position)
00047     : QWidget(parent, Qt::ToolTip), d(new ActiveToolTipPrivate)
00048 {
00049     d->mouseOut_ = 0;
00050     d->previousDistance_ = std::numeric_limits<uint>::max();
00051     setMouseTracking(true);
00052     d->rect_ = QRect(position, position);
00053     d->rect_.adjust(-10, -10, 10, 10);
00054     move(position);
00055 
00056     QPalette p;
00057     p.setColor(backgroundRole(), p.color(QPalette::ToolTipBase));
00058     p.setColor(QPalette::Base, p.color(QPalette::ToolTipBase));
00059     setPalette(p);
00060 
00061     qApp->installEventFilter(this);
00062 }
00063 
00064 ActiveToolTip::~ActiveToolTip()
00065 {
00066     delete d;
00067 }
00068 
00069 bool ActiveToolTip::eventFilter(QObject *object, QEvent *e)
00070 {
00071     switch (e->type()) {
00072 
00073     case QEvent::WindowActivate:
00074     case QEvent::WindowDeactivate:
00075     {
00076         if(insideThis(object))
00077             return false;
00078         kDebug() << "closing because of window activation";
00079         close();
00080     }
00081     case QEvent::MouseButtonPress:
00082     case QEvent::MouseButtonRelease:
00083     case QEvent::MouseButtonDblClick:
00084     case QEvent::Wheel:
00085         /* If the click is within tooltip, it's fine.
00086            Clicks outside close it.  */
00087         {
00088             //Do not close the widget when NoFocus widgets are used
00089             QWidget* widget = dynamic_cast<QWidget*>(object);
00090             if(widget && widget->focusPolicy() == Qt::NoFocus)
00091                 return false;
00092         }
00093         if (!insideThis(object)) {
00094             kDebug() << "closing because of click into" << object;
00095             close();
00096         }
00097 
00098     // FIXME: revisit this code later.
00099 #if 0
00100     case QEvent::FocusIn:
00101     case QEvent::FocusOut:
00102         close();
00103         break;
00104 #endif
00105     case QEvent::MouseMove:
00106         {
00107             QPoint globalPos = static_cast<QMouseEvent*>(e)->globalPos();
00108             if (!d->rect_.isNull() 
00109                 && !d->rect_.contains(globalPos) && !d->rectExtensions_.contains(globalPos) && !insideThis(object)) {
00110                 
00111                 int distance = (d->rect_.center() - static_cast<QMouseEvent*>(e)->globalPos()).manhattanLength();
00112                 
00113                 // On X, when the cursor leaves the tooltip and enters
00114                 // the parent, we sometimes get some wrong Y coordinate.
00115                 // Don't know why, so wait for two out-of-range mouse
00116                 // positions before closing.
00117                 
00118                 //Additional test: When the cursor has been moved towards the tooltip, don't close it.
00119                 if(distance > d->previousDistance_)
00120                     ++d->mouseOut_;
00121                 else
00122                     d->previousDistance_ = distance;
00123             } else               
00124                 d->mouseOut_ = 0;
00125             if (d->mouseOut_ == 2) {
00126                 kDebug() << "closing because of mouse move";
00127                 close();
00128             }
00129         }
00130     default:
00131         break;
00132     }
00133     return false;
00134 }
00135 
00136 void ActiveToolTip::addFriendWidget(QWidget* widget)
00137 {
00138     d->friendWidgets_.append((QObject*)widget);
00139 }
00140 
00141 bool ActiveToolTip::insideThis(QObject* object)
00142 {
00143     while (object)
00144     {
00145         if(dynamic_cast<QMenu*>(object))
00146             return true;
00147         if (object == this || d->friendWidgets_.contains(object))
00148         {
00149             return true;
00150         }
00151         object = object->parent();
00152     }
00153     return false;
00154 }
00155 
00156 void ActiveToolTip::showEvent(QShowEvent*)
00157 {        
00158     adjustRect();
00159 }
00160 
00161 void ActiveToolTip::updateMouseDistance()
00162 {
00163     d->previousDistance_ = (d->rect_.center() - QCursor::pos()).manhattanLength();
00164 }
00165 
00166 void ActiveToolTip::moveEvent(QMoveEvent* ev)
00167 {
00168     QWidget::moveEvent(ev);
00169     
00170     updateMouseDistance();
00171 }
00172 
00173 void ActiveToolTip::resizeEvent(QResizeEvent*)
00174 {
00175     adjustRect();
00176     
00177     emit resized();
00178 
00179     updateMouseDistance();
00180 }
00181 
00182 void ActiveToolTip::addExtendRect(QRect rect)
00183 {
00184     d->rectExtensions_ += rect;
00185 }
00186 
00187 void ActiveToolTip::adjustRect()
00188 {
00189     // For tooltip widget, geometry() returns global coordinates.
00190     QRect r = geometry();
00191     r.adjust(-10, -10, 10, 10);
00192     d->rect_ = r;
00193     updateMouseDistance();
00194 }
00195 
00196 void ActiveToolTip::setBoundingGeometry(QRect r) {
00197     r.adjust(-10, -10, 10, 10);
00198     d->rect_ = r;
00199 }
00200 
00201 namespace {
00202     typedef QMultiMap<float, QPair<QPointer<ActiveToolTip>, QString> > ToolTipPriorityMap;
00203     static ToolTipPriorityMap registeredToolTips;
00204     ActiveToolTipManager manager;
00205 }
00206 
00207 void ActiveToolTipManager::doVisibility() {
00208     bool hideAll = false;
00209     int lastBottomPosition = -1;
00210     int lastLeftPosition = -1;
00211     QRect fullGeometry; //Geometry of all visible tooltips together
00212     
00213     for(ToolTipPriorityMap::const_iterator it = registeredToolTips.constBegin(); it != registeredToolTips.constEnd(); ++it) {
00214         QPointer< ActiveToolTip > w = (*it).first;
00215         if(w) {
00216             if(hideAll) {
00217                 (w)->hide();
00218             }else{
00219                 QRect geom = (w)->geometry();
00220                 if((w)->geometry().top() < lastBottomPosition) {
00221                     geom.moveTop(lastBottomPosition);
00222                 }
00223                 if(lastLeftPosition != -1)
00224                     geom.moveLeft(lastLeftPosition);
00225                 
00226                 (w)->setGeometry(geom);
00227 //                 (w)->show();
00228                     
00229                 lastBottomPosition = (w)->geometry().bottom();
00230                 lastLeftPosition = (w)->geometry().left();
00231                 
00232                 if(it == registeredToolTips.constBegin())
00233                     fullGeometry = (w)->geometry();
00234                 else
00235                     fullGeometry = fullGeometry.united((w)->geometry());
00236             }
00237             if(it.key() == 0) {
00238                 hideAll = true;
00239             }
00240         }
00241     }
00242     if(!fullGeometry.isEmpty()) {
00243         QRect oldFullGeometry = fullGeometry;
00244         QRect screenGeometry = QApplication::desktop()->screenGeometry(fullGeometry.topLeft());
00245         if(fullGeometry.bottom() > screenGeometry.bottom()) {
00246             //Move up, avoiding the mouse-cursor
00247             fullGeometry.moveBottom(fullGeometry.top()-10);
00248             if(fullGeometry.bottom() > QCursor::pos().y() - 20)
00249                 fullGeometry.moveBottom(QCursor::pos().y() - 20);
00250         }
00251         if(fullGeometry.right() > screenGeometry.right()) {
00252             //Move to left, avoiding the mouse-cursor
00253             fullGeometry.moveRight(fullGeometry.left()-10);
00254             if(fullGeometry.right() > QCursor::pos().x() - 20)
00255                 fullGeometry.moveRight(QCursor::pos().x() - 20);
00256         }
00257         
00258         QPoint offset = fullGeometry.topLeft() - oldFullGeometry.topLeft();
00259         if(!offset.isNull()) {
00260             for(ToolTipPriorityMap::const_iterator it = registeredToolTips.constBegin(); it != registeredToolTips.constEnd(); ++it)
00261                 if((*it).first) {
00262                     (*it).first->move((*it).first->pos() + offset);
00263                 }
00264         }
00265     }
00266 
00267     //Set bounding geometry, and remove old tooltips
00268     for(ToolTipPriorityMap::iterator it = registeredToolTips.begin(); it != registeredToolTips.end(); ) {
00269         if(!(*it).first) {
00270             it = registeredToolTips.erase(it);
00271         }else{
00272             (*it).first->setBoundingGeometry(fullGeometry);
00273             ++it;
00274         }
00275     }
00276 
00277     //Final step: Show all tooltips
00278     if(!hideAll) {
00279         for(ToolTipPriorityMap::const_iterator it = registeredToolTips.constBegin(); it != registeredToolTips.constEnd(); ++it)
00280             if(it->first)
00281                 (*it).first->show();
00282     }
00283 }
00284 
00285 void ActiveToolTip::showToolTip(KDevelop::ActiveToolTip* tooltip, float priority, QString uniqueId) {
00286     
00287     if(!uniqueId.isEmpty()) {
00288         for(QMap< float, QPair< QPointer< ActiveToolTip >, QString > >::const_iterator it = registeredToolTips.begin(); it != registeredToolTips.end(); ++it) {
00289             if((*it).second == uniqueId)
00290                 delete (*it).first;
00291         }
00292     }
00293 
00294     registeredToolTips.insert(priority, qMakePair(QPointer<KDevelop::ActiveToolTip>(tooltip), uniqueId));
00295 
00296     connect(tooltip, SIGNAL(resized()), &manager, SLOT(doVisibility()));
00297     QMetaObject::invokeMethod(&manager, "doVisibility", Qt::QueuedConnection);
00298 }
00299 
00300 
00301 void ActiveToolTip::closeEvent(QCloseEvent* event)
00302 {
00303     QWidget::closeEvent(event);
00304     deleteLater();
00305 }
00306 
00307 }
00308 
00309 
00310 
00311 #include "activetooltip.moc"

util

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

KDevelop Platform Libraries

Skip menu "KDevelop Platform Libraries"
  • interfaces
  • language
  •   codegen
  •   duchain
  •   editor
  • outputview
  • project
  • shell
  • sublime
  • util
  • vcs
Generated for KDevelop Platform Libraries by doxygen 1.5.9-20090814
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