~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to systemsettings/app/ToolTips/tooltipmanager.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*******************************************************************************
 
2
 *   Copyright (C) 2008 by Konstantin Heil <konst.heil@stud.uni-heidelberg.de> *
 
3
 *                                                                             *
 
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.                                       *
 
8
 *                                                                             *
 
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.                              *
 
13
 *                                                                             *
 
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
 *******************************************************************************/
 
19
 
 
20
#include "tooltipmanager.h"
 
21
 
 
22
#include "MenuItem.h"
 
23
 
 
24
#include "ktooltip.h"
 
25
 
 
26
#include <QRect>
 
27
#include <QLabel>
 
28
#include <QTimer>
 
29
#include <QPainter>
 
30
#include <QHelpEvent>
 
31
#include <QScrollBar>
 
32
#include <QGridLayout>
 
33
#include <QApplication>
 
34
#include <QDesktopWidget>
 
35
#include <QAbstractItemView>
 
36
 
 
37
#ifdef Q_WS_X11
 
38
#include <QX11Info>
 
39
#endif
 
40
 
 
41
#include <KIcon>
 
42
#include <KColorScheme>
 
43
 
 
44
class ToolTipManager::Private
 
45
{
 
46
public:
 
47
    Private() :
 
48
        view(0),
 
49
        timer(0)
 
50
        { }
 
51
 
 
52
    QAbstractItemView* view;
 
53
    QTimer* timer;
 
54
    QModelIndex item;
 
55
    QRect itemRect;
 
56
};
 
57
 
 
58
ToolTipManager::ToolTipManager(QAbstractItemView* parent)
 
59
    : QObject(parent)
 
60
    , d(new ToolTipManager::Private)
 
61
{
 
62
    d->view = parent;
 
63
 
 
64
    connect(parent, SIGNAL(viewportEntered()), this, SLOT(hideToolTip()));
 
65
    connect(parent, SIGNAL(entered(const QModelIndex&)), this, SLOT(requestToolTip(const QModelIndex&)));
 
66
            
 
67
    d->timer = new QTimer(this);
 
68
    d->timer->setSingleShot(true);
 
69
    connect(d->timer, SIGNAL(timeout()), this, SLOT(prepareToolTip()));
 
70
 
 
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()));
 
76
 
 
77
    d->view->viewport()->installEventFilter(this);
 
78
}
 
79
 
 
80
ToolTipManager::~ToolTipManager()
 
81
{
 
82
    delete d;
 
83
}
 
84
 
 
85
bool ToolTipManager::eventFilter(QObject* watched, QEvent* event)
 
86
{
 
87
    if ( watched == d->view->viewport() ) {
 
88
        switch ( event->type() ) {
 
89
            case QEvent::Leave:
 
90
            case QEvent::MouseButtonPress:
 
91
                hideToolTip();
 
92
                break;
 
93
            case QEvent::ToolTip:
 
94
                return true;
 
95
            default:
 
96
                break;
 
97
        }
 
98
    }
 
99
    
 
100
    return QObject::eventFilter(watched, event);
 
101
}
 
102
 
 
103
void ToolTipManager::requestToolTip(const QModelIndex& index)
 
104
{
 
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) ) {
 
108
        KToolTip::hideTip();
 
109
        
 
110
        d->itemRect = d->view->visualRect(index);
 
111
        const QPoint pos = d->view->viewport()->mapToGlobal(d->itemRect.topLeft());
 
112
        d->itemRect.moveTo(pos);
 
113
        d->item = index;
 
114
        d->timer->start(300);
 
115
    } else {
 
116
        hideToolTip();
 
117
    }
 
118
}
 
119
 
 
120
void ToolTipManager::hideToolTip()
 
121
{
 
122
    d->timer->stop();
 
123
    KToolTip::hideTip();
 
124
}
 
125
 
 
126
void ToolTipManager::prepareToolTip()
 
127
{
 
128
    showToolTip( d->item );
 
129
}
 
130
 
 
131
void ToolTipManager::showToolTip( QModelIndex menuItem )
 
132
{
 
133
    if (QApplication::mouseButtons() & Qt::LeftButton) {
 
134
        return;
 
135
    }
 
136
 
 
137
    QWidget * tip = createTipContent( menuItem );
 
138
 
 
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() );
 
142
 
 
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) {
 
154
        delete tip;
 
155
        tip = 0;
 
156
        return;
 
157
    }
 
158
 
 
159
    int x = 0;
 
160
    int y = 0;
 
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();
 
165
        }
 
166
 
 
167
        y = hasRoomBelow ? d->itemRect.bottom() + margin : d->itemRect.top() - size.height() - margin;
 
168
    } else {
 
169
        Q_ASSERT(hasRoomToLeft || hasRoomToRight);
 
170
        x = hasRoomToRight ? d->itemRect.right() + margin : d->itemRect.left() - size.width() - margin;
 
171
 
 
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();
 
175
    }
 
176
 
 
177
    // the ownership of tip is transferred to KToolTip
 
178
    KToolTip::showTip(QPoint(x, y), tip);
 
179
}
 
180
 
 
181
QWidget * ToolTipManager::createTipContent( QModelIndex item )
 
182
{
 
183
    QWidget * tipContent = new QWidget();
 
184
    QGridLayout* tipLayout = new QGridLayout();
 
185
 
 
186
    QLayout * primaryLine = generateToolTipLine( &item, tipContent, QSize(32,32), true );
 
187
    tipLayout->addLayout( primaryLine, 0, 0 );
 
188
 
 
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 );
 
193
    }
 
194
 
 
195
    tipLayout->setVerticalSpacing( 0 );
 
196
    tipContent->setLayout( tipLayout );
 
197
 
 
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 );
 
202
    }
 
203
 
 
204
    return tipContent;
 
205
}
 
206
 
 
207
QLayout * ToolTipManager::generateToolTipLine( QModelIndex * item, QWidget * toolTip, QSize iconSize, bool comment )
 
208
{
 
209
    // Get MenuItem
 
210
    MenuItem * menuItem = d->view->model()->data( *item, Qt::UserRole ).value<MenuItem*>();
 
211
 
 
212
    QString text = menuItem->name(); 
 
213
    if ( comment ) {
 
214
        text = QString( "<b>%1</b>" ).arg( menuItem->name() );
 
215
    }
 
216
 
 
217
    // Generate text
 
218
    if ( comment ) {
 
219
        text += "<br />";
 
220
        if ( !menuItem->service()->comment().isEmpty() ) {
 
221
            text += menuItem->service()->comment();
 
222
        } else {
 
223
            int childCount = d->view->model()->rowCount( *item );
 
224
            text += i18np( "<i>Contains 1 item</i>", "<i>Contains %1 items</i>", childCount );
 
225
        }
 
226
    }
 
227
    QLabel * textLabel = new QLabel( toolTip );
 
228
    textLabel->setForegroundRole(QPalette::ToolTipText);
 
229
    textLabel->setText( text );
 
230
    
 
231
    // Get icon
 
232
    KIcon icon( menuItem->service()->icon() );
 
233
    QLabel * iconLabel = new QLabel( toolTip );
 
234
    iconLabel->setPixmap( icon.pixmap(iconSize) );
 
235
    iconLabel->setMaximumSize( iconSize );
 
236
    
 
237
    // Generate layout
 
238
    QHBoxLayout * layout = new QHBoxLayout();
 
239
    layout->addWidget( iconLabel );
 
240
    layout->addWidget( textLabel );
 
241
    
 
242
    return layout;
 
243
}
 
244
 
 
245
#include "tooltipmanager.moc"