1
/*******************************************************************************
2
* Copyright (C) 2008 by Konstantin Heil <konst.heil@stud.uni-heidelberg.de> *
4
* This program is free software; you can redistribute it and/or modify *
5
* it under the terms of the GNU General Public License as published by *
6
* the Free Software Foundation; either version 2 of the License, or *
7
* (at your option) any later version. *
9
* This program is distributed in the hope that it will be useful, *
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12
* GNU General Public License for more details. *
14
* You should have received a copy of the GNU General Public License *
15
* along with this program; if not, write to the *
16
* Free Software Foundation, Inc., *
17
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18
*******************************************************************************/
20
#include "tooltipmanager.h"
32
#include <QGridLayout>
33
#include <QApplication>
34
#include <QDesktopWidget>
35
#include <QAbstractItemView>
42
#include <KColorScheme>
44
class ToolTipManager::Private
52
QAbstractItemView* view;
58
ToolTipManager::ToolTipManager(QAbstractItemView* parent)
60
, d(new ToolTipManager::Private)
64
connect(parent, SIGNAL(viewportEntered()), this, SLOT(hideToolTip()));
65
connect(parent, SIGNAL(entered(const QModelIndex&)), this, SLOT(requestToolTip(const QModelIndex&)));
67
d->timer = new QTimer(this);
68
d->timer->setSingleShot(true);
69
connect(d->timer, SIGNAL(timeout()), this, SLOT(prepareToolTip()));
71
// When the mousewheel is used, the items don't get a hovered indication
72
// (Qt-issue #200665). To assure that the tooltip still gets hidden,
73
// the scrollbars are observed.
74
connect(parent->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(hideToolTip()));
75
connect(parent->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(hideToolTip()));
77
d->view->viewport()->installEventFilter(this);
80
ToolTipManager::~ToolTipManager()
85
bool ToolTipManager::eventFilter(QObject* watched, QEvent* event)
87
if ( watched == d->view->viewport() ) {
88
switch ( event->type() ) {
90
case QEvent::MouseButtonPress:
100
return QObject::eventFilter(watched, event);
103
void ToolTipManager::requestToolTip(const QModelIndex& index)
105
// only request a tooltip for the name column and when no selection or
106
// drag & drop operation is done (indicated by the left mouse button)
107
if ( !(QApplication::mouseButtons() & Qt::LeftButton) ) {
110
d->itemRect = d->view->visualRect(index);
111
const QPoint pos = d->view->viewport()->mapToGlobal(d->itemRect.topLeft());
112
d->itemRect.moveTo(pos);
114
d->timer->start(300);
120
void ToolTipManager::hideToolTip()
126
void ToolTipManager::prepareToolTip()
128
showToolTip( d->item );
131
void ToolTipManager::showToolTip( QModelIndex menuItem )
133
if (QApplication::mouseButtons() & Qt::LeftButton) {
137
QWidget * tip = createTipContent( menuItem );
139
// calculate the x- and y-position of the tooltip
140
const QSize size = tip->sizeHint();
141
const QRect desktop = QApplication::desktop()->screenGeometry( d->itemRect.bottomRight() );
143
// d->itemRect defines the area of the item, where the tooltip should be
144
// shown. Per default the tooltip is shown in the bottom right corner.
145
// If the tooltip content exceeds the desktop borders, it must be assured that:
146
// - the content is fully visible
147
// - the content is not drawn inside d->itemRect
148
const int margin = 3;
149
const bool hasRoomToLeft = (d->itemRect.left() - size.width() - margin >= desktop.left());
150
const bool hasRoomToRight = (d->itemRect.right() + size.width() + margin <= desktop.right());
151
const bool hasRoomAbove = (d->itemRect.top() - size.height() - margin >= desktop.top());
152
const bool hasRoomBelow = (d->itemRect.bottom() + size.height() + margin <= desktop.bottom());
153
if (!hasRoomAbove && !hasRoomBelow && !hasRoomToLeft && !hasRoomToRight) {
161
if (hasRoomBelow || hasRoomAbove) {
162
x = qMax(desktop.left(), d->itemRect.center().x() - size.width() / 2);
163
if (x + size.width() / 2 >= desktop.right()) {
164
x = desktop.right() - size.width();
167
y = hasRoomBelow ? d->itemRect.bottom() + margin : d->itemRect.top() - size.height() - margin;
169
Q_ASSERT(hasRoomToLeft || hasRoomToRight);
170
x = hasRoomToRight ? d->itemRect.right() + margin : d->itemRect.left() - size.width() - margin;
172
// Put the tooltip at the bottom of the screen. The x-coordinate has already
173
// been adjusted, so that no overlapping with d->itemRect occurs.
174
y = desktop.bottom() - size.height();
177
// the ownership of tip is transferred to KToolTip
178
KToolTip::showTip(QPoint(x, y), tip);
181
QWidget * ToolTipManager::createTipContent( QModelIndex item )
183
QWidget * tipContent = new QWidget();
184
QGridLayout* tipLayout = new QGridLayout();
186
QLayout * primaryLine = generateToolTipLine( &item, tipContent, QSize(32,32), true );
187
tipLayout->addLayout( primaryLine, 0, 0 );
189
for ( int done = 0; d->view->model()->rowCount( item ) > done; done = 1 + done ) {
190
QModelIndex childItem = d->view->model()->index( done, 0, item );
191
QLayout * subLine = generateToolTipLine( &childItem, tipContent, QSize(24,24), false );
192
tipLayout->addLayout( subLine, done + 2, 0 );
195
tipLayout->setVerticalSpacing( 0 );
196
tipContent->setLayout( tipLayout );
198
if( d->view->model()->rowCount( item ) > 0 ) {
199
QFrame * separatorLine = new QFrame( tipContent );
200
separatorLine->setFrameStyle( QFrame::HLine );
201
tipLayout->addWidget( separatorLine, 1, 0 );
207
QLayout * ToolTipManager::generateToolTipLine( QModelIndex * item, QWidget * toolTip, QSize iconSize, bool comment )
210
MenuItem * menuItem = d->view->model()->data( *item, Qt::UserRole ).value<MenuItem*>();
212
QString text = menuItem->name();
214
text = QString( "<b>%1</b>" ).arg( menuItem->name() );
220
if ( !menuItem->service()->comment().isEmpty() ) {
221
text += menuItem->service()->comment();
223
int childCount = d->view->model()->rowCount( *item );
224
text += i18np( "<i>Contains 1 item</i>", "<i>Contains %1 items</i>", childCount );
227
QLabel * textLabel = new QLabel( toolTip );
228
textLabel->setForegroundRole(QPalette::ToolTipText);
229
textLabel->setText( text );
232
KIcon icon( menuItem->service()->icon() );
233
QLabel * iconLabel = new QLabel( toolTip );
234
iconLabel->setPixmap( icon.pixmap(iconSize) );
235
iconLabel->setMaximumSize( iconSize );
238
QHBoxLayout * layout = new QHBoxLayout();
239
layout->addWidget( iconLabel );
240
layout->addWidget( textLabel );
245
#include "tooltipmanager.moc"