Files
qt-creator/src/plugins/texteditor/tooltip/tooltip.cpp
Friedemann Kleint cbafc50acc Debugger: Make tooltips use standard text editor tooltips.
Extend text editor tooltips by a 'widget content', making
it possible to show any widget utilizing the fact that the
QTipLabel actually is a frame (and thus a container).
Introduce concept of 'interactive' tooltips and modify
the tooltip-closing mechanism such that simple interaction
is possible. Emit the base text editor's tooltip signals
with the correct position and add API to calculate the tooltip
position from the cursor position.
Add API for pinning tooltips to the text editor (by removing
them from the QTipLabel layout).
Modify the Debugger's tooltipmanager not to manage tooltips
under TextEditor control and to take over control only once
tooltips are pinned.

Rubber-stamped-by: Leandro T. C. Melo <leandro.melo@nokia.com>
2011-02-21 16:51:00 +01:00

307 lines
8.3 KiB
C++

/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "tooltip.h"
#include "tips.h"
#include "tipcontents.h"
#include "tipfactory.h"
#include "effects.h"
#include "reuse.h"
#include <QtCore/QString>
#include <QtGui/QColor>
#include <QtGui/QApplication>
#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
#include <QtGui/QMenu>
#include <QtCore/QDebug>
using namespace TextEditor;
using namespace Internal;
ToolTip::ToolTip() : m_tipFactory(new TipFactory), m_tip(0), m_widget(0)
{
connect(&m_showTimer, SIGNAL(timeout()), this, SLOT(hideTipImmediately()));
connect(&m_hideDelayTimer, SIGNAL(timeout()), this, SLOT(hideTipImmediately()));
}
ToolTip::~ToolTip()
{
m_tip = 0;
delete m_tipFactory;
}
ToolTip *ToolTip::instance()
{
static ToolTip tooltip;
return &tooltip;
}
void ToolTip::show(const QPoint &pos, const TipContent &content, QWidget *w, const QRect &rect)
{
if (acceptShow(content, pos, w, rect)) {
#ifndef Q_WS_WIN
m_tip = m_tipFactory->createTip(content, w);
#else
m_tip = m_tipFactory->createTip(
content, QApplication::desktop()->screen(Internal::screenNumber(pos, w)));
#endif
setUp(pos, content, w, rect);
qApp->installEventFilter(this);
showTip();
}
}
void ToolTip::show(const QPoint &pos, const TipContent &content, QWidget *w)
{
show(pos, content, w, QRect());
}
bool ToolTip::acceptShow(const TipContent &content,
const QPoint &pos,
QWidget *w,
const QRect &rect)
{
if (!validateContent(content))
return false;
if (isVisible()) {
if (m_tip->canHandleContentReplacement(content)) {
// Reuse current tip.
QPoint localPos = pos;
if (w)
localPos = w->mapFromGlobal(pos);
if (tipChanged(localPos, content, w))
setUp(pos, content, w, rect);
return false;
}
hideTipImmediately();
}
#if !defined(QT_NO_EFFECTS) && !defined(Q_WS_MAC)
// While the effect takes places it might be that although the widget is actually on
// screen the isVisible method doesn't return true.
else if (m_tip
&& (QApplication::isEffectEnabled(Qt::UI_FadeTooltip)
|| QApplication::isEffectEnabled(Qt::UI_AnimateTooltip))) {
hideTipImmediately();
}
#endif
return true;
}
bool ToolTip::validateContent(const TipContent &content)
{
if (!content.isValid()) {
if (isVisible())
hideTipWithDelay();
return false;
}
return true;
}
void ToolTip::setUp(const QPoint &pos, const TipContent &content, QWidget *w, const QRect &rect)
{
m_tip->setContent(content);
m_tip->configure(pos, w);
placeTip(pos, w);
setTipRect(w, rect);
if (m_hideDelayTimer.isActive())
m_hideDelayTimer.stop();
m_showTimer.start(content.showTime());
}
bool ToolTip::tipChanged(const QPoint &pos, const TipContent &content, QWidget *w) const
{
if (!m_tip->content().equals(content) || m_widget != w)
return true;
if (!m_rect.isNull())
return !m_rect.contains(pos);
return false;
}
void ToolTip::setTipRect(QWidget *w, const QRect &rect)
{
if (!m_rect.isNull() && !w)
qWarning("ToolTip::show: Cannot pass null widget if rect is set");
else{
m_widget = w;
m_rect = rect;
}
}
bool ToolTip::isVisible() const
{
return m_tip && m_tip->isVisible();
}
void ToolTip::showTip()
{
#if !defined(QT_NO_EFFECTS) && !defined(Q_WS_MAC)
if (QApplication::isEffectEnabled(Qt::UI_FadeTooltip))
qFadeEffect(m_tip);
else if (QApplication::isEffectEnabled(Qt::UI_AnimateTooltip))
qScrollEffect(m_tip);
else
m_tip->show();
#else
m_tip->show();
#endif
}
void ToolTip::hide()
{
hideTipWithDelay();
}
void ToolTip::hideTipWithDelay()
{
if (!m_hideDelayTimer.isActive())
m_hideDelayTimer.start(300);
}
void ToolTip::hideTipImmediately()
{
if (m_tip) {
m_tip->close();
m_tip->deleteLater();
m_tip = 0;
}
m_showTimer.stop();
m_hideDelayTimer.stop();
qApp->removeEventFilter(this);
}
void ToolTip::placeTip(const QPoint &pos, QWidget *w)
{
QRect screen = Internal::screenGeometry(pos, w);
QPoint p = pos;
p += QPoint(2,
#ifdef Q_WS_WIN
21
#else
16
#endif
);
if (p.x() + m_tip->width() > screen.x() + screen.width())
p.rx() -= 4 + m_tip->width();
if (p.y() + m_tip->height() > screen.y() + screen.height())
p.ry() -= 24 + m_tip->height();
if (p.y() < screen.y())
p.setY(screen.y());
if (p.x() + m_tip->width() > screen.x() + screen.width())
p.setX(screen.x() + screen.width() - m_tip->width());
if (p.x() < screen.x())
p.setX(screen.x());
if (p.y() + m_tip->height() > screen.y() + screen.height())
p.setY(screen.y() + screen.height() - m_tip->height());
m_tip->move(p);
}
bool ToolTip::eventFilter(QObject *o, QEvent *event)
{
if (!o->isWidgetType())
return false;
switch (event->type()) {
#ifdef Q_WS_MAC
case QEvent::KeyPress:
case QEvent::KeyRelease: {
int key = static_cast<QKeyEvent *>(event)->key();
Qt::KeyboardModifiers mody = static_cast<QKeyEvent *>(event)->modifiers();
if (!(mody & Qt::KeyboardModifierMask)
&& key != Qt::Key_Shift && key != Qt::Key_Control
&& key != Qt::Key_Alt && key != Qt::Key_Meta)
hideTipWithDelay();
break;
}
#endif
case QEvent::Leave:
if (o == m_tip) {
hideTipWithDelay();
}
break;
case QEvent::Enter:
// User moved cursor into tip and wants to interact.
if (m_tip && m_tip->isInteractive() && o == m_tip) {
if (m_hideDelayTimer.isActive())
m_hideDelayTimer.stop();
}
break;
case QEvent::WindowActivate:
case QEvent::WindowDeactivate:
case QEvent::FocusOut:
case QEvent::FocusIn:
if (m_tip && !m_tip->isInteractive()) // Windows: A sequence of those occurs when interacting
hideTipImmediately();
break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::Wheel:
if (m_tip) {
if (m_tip->isInteractive()) { // Do not close on interaction with the tooltip
if (o != m_tip && !m_tip->isAncestorOf(static_cast<QWidget *>(o))) {
hideTipImmediately();
}
} else {
hideTipImmediately();
}
}
break;
case QEvent::MouseMove:
if (o == m_widget &&
!m_rect.isNull() &&
!m_rect.contains(static_cast<QMouseEvent*>(event)->pos())) {
hideTipWithDelay();
}
default:
break;
}
return false;
}
QFont ToolTip::font() const
{
return QApplication::font("QTipLabel");
}
void ToolTip::setFont(const QFont &font)
{
QApplication::setFont(font, "QTipLabel");
}