Commit e8396f4c authored by hjk's avatar hjk
Browse files

Utils: Simplify tooltip architecture and cleanup



This mainly merges TipContents into the the actual
tooltip labels.

Change-Id: I64b576c987bce034842f7e3f324b81595dae0713
Reviewed-by: default avatarChristian Stenger <christian.stenger@theqtcompany.com>
parent 88159909
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "tipcontents.h"
#include "tooltip.h"
#include "tips.h"
#include <utils/qtcassert.h>
#include <QtGlobal>
namespace Utils {
TipContent::TipContent()
: m_typeId(0), m_widget(0), m_interactive(false)
{
}
TipContent::TipContent(const QString &text)
: m_typeId(TEXT_CONTENT_ID), m_text(text), m_widget(0), m_interactive(false)
{
}
TipContent::TipContent(const QColor &color)
: m_typeId(COLOR_CONTENT_ID), m_color(color), m_widget(0), m_interactive(false)
{
}
TipContent::TipContent(QWidget *w, bool interactive)
: m_typeId(WIDGET_CONTENT_ID), m_widget(w), m_interactive(interactive)
{
}
bool TipContent::isValid() const
{
if (m_typeId == TEXT_CONTENT_ID)
return !m_text.isEmpty();
if (m_typeId == COLOR_CONTENT_ID)
return m_color.isValid();
return m_widget;
}
int TipContent::showTime() const
{
if (m_typeId == TEXT_CONTENT_ID)
return 10000 + 40 * qMax(0, m_text.length() - 100);
if (m_typeId == COLOR_CONTENT_ID)
return 4000;
return 30000;
}
bool TipContent::equals(const TipContent &other) const
{
return m_typeId == other.m_typeId
&& m_text == other.m_text
&& m_widget == other.m_widget;
}
bool TipContent::pinToolTip(QWidget *w, QWidget *parent)
{
QTC_ASSERT(w, return false);
// Find the parent WidgetTip, tell it to pin/release the
// widget and close.
for (QWidget *p = w->parentWidget(); p ; p = p->parentWidget()) {
if (Internal::WidgetTip *wt = qobject_cast<Internal::WidgetTip *>(p)) {
wt->pinToolTipWidget(parent);
ToolTip::hide();
return true;
}
}
return false;
}
} // namespace Utils
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef TIPCONTENTS_H
#define TIPCONTENTS_H
#include "../utils_global.h"
#include <QString>
#include <QColor>
#include <QWidget>
namespace Utils {
class QTCREATOR_UTILS_EXPORT TipContent
{
public:
TipContent();
explicit TipContent(const QString &text);
explicit TipContent(const QColor &color);
explicit TipContent(QWidget *w, bool interactive);
int typeId() const { return m_typeId; }
bool isValid() const;
bool isInteractive() const { return m_interactive; }
int showTime() const;
bool equals(const TipContent &other) const;
const QString &text() const { return m_text; }
const QColor &color() const { return m_color; }
QWidget *widget() const { return m_widget; }
enum {
COLOR_CONTENT_ID = 0,
TEXT_CONTENT_ID = 1,
WIDGET_CONTENT_ID = 42
};
void setInteractive(bool i) { m_interactive = i; }
// Helper to 'pin' (show as real window) a tooltip shown
// using WidgetContent
static bool pinToolTip(QWidget *w, QWidget *parent);
private:
int m_typeId;
QString m_text;
QColor m_color;
QWidget *m_widget;
bool m_interactive;
};
} // namespace Utils
#endif // TIPCONTENTS_H
......@@ -29,7 +29,7 @@
****************************************************************************/
#include "tips.h"
#include "tipcontents.h"
#include "tooltip.h"
#include "reuse.h"
#include <utils/qtcassert.h>
......@@ -49,50 +49,32 @@
#include <QVBoxLayout>
namespace Utils {
namespace Internal {
// @todo: Reuse...
static QPixmap tilePixMap(int size)
{
const int checkerbordSize= size;
QPixmap tilePixmap(checkerbordSize * 2, checkerbordSize * 2);
tilePixmap.fill(Qt::white);
QPainter tilePainter(&tilePixmap);
QColor color(220, 220, 220);
tilePainter.fillRect(0, 0, checkerbordSize, checkerbordSize, color);
tilePainter.fillRect(checkerbordSize, checkerbordSize, checkerbordSize, checkerbordSize, color);
return tilePixmap;
}
namespace Internal {
QTipLabel::QTipLabel(QWidget *parent) :
QLabel(parent, Qt::ToolTip | Qt::BypassGraphicsProxyWidget)
{}
QTipLabel::~QTipLabel()
{
}
bool QTipLabel::isInteractive() const
{
return m_tipContent.isInteractive();
}
void QTipLabel::setContent(const TipContent &content)
ColorTip::ColorTip(QWidget *parent)
: QTipLabel(parent)
{
m_tipContent = content;
resize(40, 40);
}
ColorTip::ColorTip(QWidget *parent) : QTipLabel(parent)
void ColorTip::setContent(const QVariant &content)
{
resize(QSize(40, 40));
m_tilePixMap = tilePixMap(10);
m_color = content.value<QColor>();
const int size = 10;
m_tilePixmap = QPixmap(size * 2, size * 2);
m_tilePixmap.fill(Qt::white);
QPainter tilePainter(&m_tilePixmap);
QColor col(220, 220, 220);
tilePainter.fillRect(0, 0, size, size, col);
tilePainter.fillRect(size, size, size, size, col);
}
ColorTip::~ColorTip()
{}
void ColorTip::configure(const QPoint &pos, QWidget *w)
{
Q_UNUSED(pos)
......@@ -101,29 +83,32 @@ void ColorTip::configure(const QPoint &pos, QWidget *w)
update();
}
bool ColorTip::canHandleContentReplacement(const TipContent &content) const
bool ColorTip::canHandleContentReplacement(int typeId) const
{
return content.typeId() == TipContent::COLOR_CONTENT_ID;
return typeId == ToolTip::ColorContent;
}
bool ColorTip::equals(int typeId, const QVariant &other) const
{
return typeId == ToolTip::ColorContent && other == m_color;
}
void ColorTip::paintEvent(QPaintEvent *event)
{
QTipLabel::paintEvent(event);
const QColor &color = content().color();
QPen pen;
pen.setWidth(1);
if (color.value() > 100)
pen.setColor(color.darker());
if (m_color.value() > 100)
pen.setColor(m_color.darker());
else
pen.setColor(color.lighter());
pen.setColor(m_color.lighter());
QPainter painter(this);
painter.setPen(pen);
painter.setBrush(color);
painter.setBrush(m_color);
QRect r(0, 0, rect().width() - 1, rect().height() - 1);
painter.drawTiledPixmap(r, m_tilePixMap);
painter.drawTiledPixmap(r, m_tilePixmap);
painter.drawRect(r);
}
......@@ -139,12 +124,14 @@ TextTip::TextTip(QWidget *parent) : QTipLabel(parent)
setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / 255.0);
}
TextTip::~TextTip()
{}
void TextTip::setContent(const QVariant &content)
{
m_text = content.toString();
}
void TextTip::configure(const QPoint &pos, QWidget *w)
{
setText(content().text());
setText(m_text);
// Make it look good with the default ToolTip font on Mac, which has a small descent.
QFontMetrics fm(font());
......@@ -169,9 +156,19 @@ void TextTip::configure(const QPoint &pos, QWidget *w)
resize(tipWidth, heightForWidth(tipWidth) + extraHeight);
}
bool TextTip::canHandleContentReplacement(const TipContent &content) const
bool TextTip::canHandleContentReplacement(int typeId) const
{
return typeId == ToolTip::TextContent;
}
int TextTip::showTime() const
{
return 10000 + 40 * qMax(0, m_text.size() - 100);
}
bool TextTip::equals(int typeId, const QVariant &other) const
{
return content.typeId() == TipContent::TEXT_CONTENT_ID;
return typeId == ToolTip::TextContent && other.toString() == m_text;
}
void TextTip::paintEvent(QPaintEvent *event)
......@@ -203,14 +200,17 @@ WidgetTip::WidgetTip(QWidget *parent) :
setLayout(m_layout);
}
void WidgetTip::configure(const QPoint &pos, QWidget *)
void WidgetTip::setContent(const QVariant &content)
{
QWidget *widget = content().widget();
m_widget = content.value<QWidget *>();
}
QTC_ASSERT(widget && m_layout->count() == 0, return);
void WidgetTip::configure(const QPoint &pos, QWidget *)
{
QTC_ASSERT(m_widget && m_layout->count() == 0, return);
move(pos);
m_layout->addWidget(widget);
m_layout->addWidget(m_widget);
m_layout->setSizeConstraint(QLayout::SetFixedSize);
adjustSize();
}
......@@ -238,12 +238,18 @@ void WidgetTip::pinToolTipWidget(QWidget *parent)
widget->setAttribute(Qt::WA_DeleteOnClose);
}
bool WidgetTip::canHandleContentReplacement(const TipContent & ) const
bool WidgetTip::canHandleContentReplacement(int typeId) const
{
// Always create a new widget.
Q_UNUSED(typeId);
return false;
}
bool WidgetTip::equals(int typeId, const QVariant &other) const
{
return typeId == ToolTip::WidgetContent && other.value<QWidget *>() == m_widget;
}
// need to include it here to force it to be inside the namespaces
#include "moc_tips.cpp"
......
......@@ -31,13 +31,13 @@
#ifndef TIPS_H
#define TIPS_H
#include "tipcontents.h"
#include "../utils_global.h"
#include <QSharedPointer>
#include <QLabel>
#include <QPixmap>
QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
#include <QSharedPointer>
#include <QVariant>
#include <QVBoxLayout>
#ifndef Q_MOC_RUN
namespace Utils {
......@@ -48,68 +48,68 @@ namespace Internal {
class QTipLabel : public QLabel
{
Q_OBJECT
protected:
QTipLabel(QWidget *parent);
public:
virtual ~QTipLabel();
void setContent(const TipContent &content);
const TipContent &content() const { return m_tipContent; }
QTipLabel(QWidget *parent);
virtual void setContent(const QVariant &content) = 0;
virtual bool isInteractive() const { return false; }
virtual int showTime() const = 0;
virtual void configure(const QPoint &pos, QWidget *w) = 0;
virtual bool canHandleContentReplacement(const TipContent &content) const = 0;
bool isInteractive() const;
private:
TipContent m_tipContent;
virtual bool canHandleContentReplacement(int typeId) const = 0;
virtual bool equals(int typeId, const QVariant &other) const = 0;
};
class TextTip : public QTipLabel
{
Q_OBJECT
public:
TextTip(QWidget *parent);
virtual ~TextTip();
virtual void setContent(const QVariant &content);
virtual void configure(const QPoint &pos, QWidget *w);
virtual bool canHandleContentReplacement(const TipContent &content) const;
private:
virtual bool canHandleContentReplacement(int typeId) const;
virtual int showTime() const;
virtual bool equals(int typeId, const QVariant &other) const;
virtual void paintEvent(QPaintEvent *event);
virtual void resizeEvent(QResizeEvent *event);
private:
QString m_text;
};
class ColorTip : public QTipLabel
{
Q_OBJECT
public:
ColorTip(QWidget *parent);
virtual ~ColorTip();
virtual void setContent(const QVariant &content);
virtual void configure(const QPoint &pos, QWidget *w);
virtual bool canHandleContentReplacement(const TipContent &content) const;
private:
virtual bool canHandleContentReplacement(int typeId) const;
virtual int showTime() const { return 4000; }
virtual bool equals(int typeId, const QVariant &other) const;
virtual void paintEvent(QPaintEvent *event);
QPixmap m_tilePixMap;
private:
QColor m_color;
QPixmap m_tilePixmap;
};
class WidgetTip : public QTipLabel
{
Q_OBJECT
public:
explicit WidgetTip(QWidget *parent = 0);
void pinToolTipWidget(QWidget *parent);
virtual void setContent(const QVariant &content);
virtual void configure(const QPoint &pos, QWidget *w);
virtual bool canHandleContentReplacement(const TipContent &content) const;
public slots:
void pinToolTipWidget(QWidget *parent);
virtual bool canHandleContentReplacement(int typeId) const;
virtual int showTime() const { return 30000; }
virtual bool equals(int typeId, const QVariant &other) const;
virtual bool isInteractive() const { return true; }
private:
QWidget *m_widget;
QVBoxLayout *m_layout;
};
......
......@@ -30,11 +30,11 @@
#include "tooltip.h"
#include "tips.h"
#include "tipcontents.h"
#include "effects.h"
#include "reuse.h"
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <QString>
#include <QColor>
......@@ -68,17 +68,26 @@ ToolTip *ToolTip::instance()
void ToolTip::show(const QPoint &pos, const QString &content, QWidget *w, const QRect &rect)
{
instance()->showInternal(pos, TipContent(content), w, rect);
if (content.isEmpty())
instance()->hideTipWithDelay();
else
instance()->showInternal(pos, QVariant(content), TextContent, w, rect);
}
void ToolTip::show(const QPoint &pos, const QColor &color, QWidget *w, const QRect &rect)
{
instance()->showInternal(pos, TipContent(color), w, rect);
if (!color.isValid())
instance()->hideTipWithDelay();
else
instance()->showInternal(pos, QVariant(color), ColorContent, w, rect);
}
void ToolTip::show(const QPoint &pos, QWidget *content, QWidget *w, const QRect &rect)
{
instance()->showInternal(pos, TipContent(content, true), w, rect);
if (!content)
instance()->hideTipWithDelay();
else
instance()->showInternal(pos, QVariant::fromValue(content), WidgetContent, w, rect);
}
void ToolTip::move(const QPoint &pos, QWidget *w)
......@@ -87,22 +96,37 @@ void ToolTip::move(const QPoint &pos, QWidget *w)
instance()->placeTip(pos, w);
}
bool ToolTip::acceptShow(const TipContent &content,
bool ToolTip::pinToolTip(QWidget *w, QWidget *parent)
{
QTC_ASSERT(w, return false);
// Find the parent WidgetTip, tell it to pin/release the
// widget and close.
for (QWidget *p = w->parentWidget(); p ; p = p->parentWidget()) {
if (Internal::WidgetTip *wt = qobject_cast<Internal::WidgetTip *>(p)) {
wt->pinToolTipWidget(parent);
ToolTip::hide();
return true;
}
}
return false;
}
bool ToolTip::acceptShow(const QVariant &content,
int typeId,
const QPoint &pos,
QWidget *w,
const QRect &rect)
{
if (!validateContent(content))
return false;
if (isVisible()) {
if (m_tip->canHandleContentReplacement(content)) {
if (m_tip->canHandleContentReplacement(typeId)) {
// Reuse current tip.
QPoint localPos = pos;
if (w)
localPos = w->mapFromGlobal(pos);
if (tipChanged(localPos, content, w))
setUp(pos, content, w, rect);
if (tipChanged(localPos, content, typeId, w)) {
m_tip->setContent(content);
setUp(pos, w, rect);
}
return false;
}
hideTipImmediately();
......@@ -119,19 +143,8 @@ bool ToolTip::acceptShow(const TipContent &content,
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)
void ToolTip::setUp(const QPoint &pos, QWidget *w, const QRect &rect)
{
m_tip->setContent(content);
m_tip->configure(pos, w);
placeTip(pos, w);
......@@ -139,12 +152,12 @@ void ToolTip::setUp(const QPoint &pos, const TipContent &content, QWidget *w, co
if (m_hideDelayTimer.isActive())
m_hideDelayTimer.stop();
m_showTimer.start(content.showTime());