util
activetooltip.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
00086
00087 {
00088
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
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
00114
00115
00116
00117
00118
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
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;
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
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
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
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
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
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"