OSDN Git Service

20cb215dc454e0e0202701738be3aee9288a9825
[qt-creator-jp/qt-creator-jp.git] / src / plugins / texteditor / tooltip / tooltip.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "tooltip.h"
35 #include "tips.h"
36 #include "tipcontents.h"
37 #include "tipfactory.h"
38 #include "effects.h"
39 #include "reuse.h"
40
41 #include <QtCore/QString>
42 #include <QtGui/QColor>
43 #include <QtGui/QApplication>
44 #include <QtGui/QKeyEvent>
45 #include <QtGui/QMouseEvent>
46 #include <QtGui/QMenu>
47
48 #include <QtCore/QDebug>
49
50 using namespace TextEditor;
51 using namespace Internal;
52
53 ToolTip::ToolTip() : m_tipFactory(new TipFactory), m_tip(0), m_widget(0)
54 {
55     connect(&m_showTimer, SIGNAL(timeout()), this, SLOT(hideTipImmediately()));
56     connect(&m_hideDelayTimer, SIGNAL(timeout()), this, SLOT(hideTipImmediately()));
57 }
58
59 ToolTip::~ToolTip()
60 {
61     m_tip = 0;
62     delete m_tipFactory;
63 }
64
65 ToolTip *ToolTip::instance()
66 {
67     static ToolTip tooltip;
68     return &tooltip;
69 }
70
71 void ToolTip::show(const QPoint &pos, const TipContent &content, QWidget *w, const QRect &rect)
72 {
73     if (acceptShow(content, pos, w, rect)) {
74 #ifndef Q_WS_WIN
75         m_tip = m_tipFactory->createTip(content, w);
76 #else
77         m_tip = m_tipFactory->createTip(
78             content, QApplication::desktop()->screen(Internal::screenNumber(pos, w)));
79 #endif
80         setUp(pos, content, w, rect);
81         qApp->installEventFilter(this);
82         showTip();
83     }
84 }
85
86 void ToolTip::show(const QPoint &pos, const TipContent &content, QWidget *w)
87 {
88     show(pos, content, w, QRect());
89 }
90
91 bool ToolTip::acceptShow(const TipContent &content,
92                          const QPoint &pos,
93                          QWidget *w,
94                          const QRect &rect)
95 {
96     if (!validateContent(content))
97         return false;
98
99     if (isVisible()) {
100         if (m_tip->canHandleContentReplacement(content)) {
101             // Reuse current tip.
102             QPoint localPos = pos;
103             if (w)
104                 localPos = w->mapFromGlobal(pos);
105             if (tipChanged(localPos, content, w))
106                 setUp(pos, content, w, rect);
107             return false;
108         }
109         hideTipImmediately();
110     }
111 #if !defined(QT_NO_EFFECTS) && !defined(Q_WS_MAC)
112     // While the effect takes places it might be that although the widget is actually on
113     // screen the isVisible method doesn't return true.
114     else if (m_tip
115              && (QApplication::isEffectEnabled(Qt::UI_FadeTooltip)
116                  || QApplication::isEffectEnabled(Qt::UI_AnimateTooltip))) {
117         hideTipImmediately();
118     }
119 #endif
120     return true;
121 }
122
123 bool ToolTip::validateContent(const TipContent &content)
124 {
125     if (!content.isValid()) {
126         if (isVisible())
127             hideTipWithDelay();
128         return false;
129     }
130     return true;
131 }
132
133 void ToolTip::setUp(const QPoint &pos, const TipContent &content, QWidget *w, const QRect &rect)
134 {
135     m_tip->setContent(content);
136     m_tip->configure(pos, w);
137
138     placeTip(pos, w);
139     setTipRect(w, rect);
140
141     if (m_hideDelayTimer.isActive())
142         m_hideDelayTimer.stop();
143     m_showTimer.start(content.showTime());
144 }
145
146 bool ToolTip::tipChanged(const QPoint &pos, const TipContent &content, QWidget *w) const
147 {
148     if (!m_tip->content().equals(content) || m_widget != w)
149         return true;
150     if (!m_rect.isNull())
151         return !m_rect.contains(pos);
152     return false;
153 }
154
155 void ToolTip::setTipRect(QWidget *w, const QRect &rect)
156 {
157     if (!m_rect.isNull() && !w)
158         qWarning("ToolTip::show: Cannot pass null widget if rect is set");
159     else{
160         m_widget = w;
161         m_rect = rect;
162     }
163 }
164
165 bool ToolTip::isVisible() const
166 {
167     return m_tip && m_tip->isVisible();
168 }
169
170 void ToolTip::showTip()
171 {
172 #if !defined(QT_NO_EFFECTS) && !defined(Q_WS_MAC)
173     if (QApplication::isEffectEnabled(Qt::UI_FadeTooltip))
174         qFadeEffect(m_tip);
175     else if (QApplication::isEffectEnabled(Qt::UI_AnimateTooltip))
176         qScrollEffect(m_tip);
177     else
178         m_tip->show();
179 #else
180     m_tip->show();
181 #endif
182 }
183
184 void ToolTip::hide()
185 {
186     hideTipWithDelay();
187 }
188
189 void ToolTip::hideTipWithDelay()
190 {
191     if (!m_hideDelayTimer.isActive())
192         m_hideDelayTimer.start(300);
193 }
194
195 void ToolTip::hideTipImmediately()
196 {
197     if (m_tip) {
198         m_tip->close();
199         m_tip->deleteLater();
200         m_tip = 0;
201     }
202     m_showTimer.stop();
203     m_hideDelayTimer.stop();
204     qApp->removeEventFilter(this);
205 }
206
207 void ToolTip::placeTip(const QPoint &pos, QWidget *w)
208 {
209     QRect screen = Internal::screenGeometry(pos, w);
210     QPoint p = pos;
211     p += QPoint(2,
212 #ifdef Q_WS_WIN
213                 21
214 #else
215                 16
216 #endif
217                 );
218
219     if (p.x() + m_tip->width() > screen.x() + screen.width())
220         p.rx() -= 4 + m_tip->width();
221     if (p.y() + m_tip->height() > screen.y() + screen.height())
222         p.ry() -= 24 + m_tip->height();
223     if (p.y() < screen.y())
224         p.setY(screen.y());
225     if (p.x() + m_tip->width() > screen.x() + screen.width())
226         p.setX(screen.x() + screen.width() - m_tip->width());
227     if (p.x() < screen.x())
228         p.setX(screen.x());
229     if (p.y() + m_tip->height() > screen.y() + screen.height())
230         p.setY(screen.y() + screen.height() - m_tip->height());
231
232     m_tip->move(p);
233 }
234
235 bool ToolTip::eventFilter(QObject *o, QEvent *event)
236 {
237     if (!o->isWidgetType())
238         return false;
239
240     switch (event->type()) {
241 #ifdef Q_WS_MAC
242     case QEvent::KeyPress:
243     case QEvent::KeyRelease: {
244         int key = static_cast<QKeyEvent *>(event)->key();
245         Qt::KeyboardModifiers mody = static_cast<QKeyEvent *>(event)->modifiers();
246         if (!(mody & Qt::KeyboardModifierMask)
247             && key != Qt::Key_Shift && key != Qt::Key_Control
248             && key != Qt::Key_Alt && key != Qt::Key_Meta)
249             hideTipWithDelay();
250         break;
251     }
252 #endif
253     case QEvent::Leave:
254         if (o == m_tip) {
255             hideTipWithDelay();
256         }
257         break;
258     case QEvent::Enter:
259         // User moved cursor into tip and wants to interact.
260         if (m_tip && m_tip->isInteractive() && o == m_tip) {
261             if (m_hideDelayTimer.isActive())
262                 m_hideDelayTimer.stop();
263         }
264         break;
265     case QEvent::WindowActivate:
266     case QEvent::WindowDeactivate:
267     case QEvent::FocusOut:
268     case QEvent::FocusIn:
269         if (m_tip && !m_tip->isInteractive()) // Windows: A sequence of those occurs when interacting
270             hideTipImmediately();
271         break;
272     case QEvent::MouseButtonPress:
273     case QEvent::MouseButtonRelease:
274     case QEvent::MouseButtonDblClick:
275     case QEvent::Wheel:
276         if (m_tip) {
277             if (m_tip->isInteractive()) { // Do not close on interaction with the tooltip
278                 if (o != m_tip && !m_tip->isAncestorOf(static_cast<QWidget *>(o))) {
279                     hideTipImmediately();
280                 }
281             } else {
282                 hideTipImmediately();
283             }
284         }
285         break;
286     case QEvent::MouseMove:
287         if (o == m_widget &&
288             !m_rect.isNull() &&
289             !m_rect.contains(static_cast<QMouseEvent*>(event)->pos())) {
290             hideTipWithDelay();
291         }
292     default:
293         break;
294     }
295     return false;
296 }
297
298 QFont ToolTip::font() const
299 {
300     return QApplication::font("QTipLabel");
301 }
302
303 void ToolTip::setFont(const QFont &font)
304 {
305     QApplication::setFont(font, "QTipLabel");
306 }