src/hbcore/gui/hbtooltiplabel_p.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbcore/gui/hbtooltiplabel_p.cpp	Mon Apr 19 14:02:13 2010 +0300
@@ -0,0 +1,430 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (developer.feedback@nokia.com)
+**
+** This file is part of the HbCore module of the UI Extensions for Mobile.
+**
+** GNU Lesser General Public License Usage
+** 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 developer.feedback@nokia.com.
+**
+****************************************************************************/
+
+#include "hbtooltiplabel_p.h"
+#include "hbtooltiplabel_p_p.h"
+#include "hbtooltip.h"
+#include "hbtextitem.h"
+#include "hbnamespace_p.h"
+#include "hbfontspec.h"
+#ifdef HB_EFFECTS
+#include "hbeffectinternal_p.h"
+#endif
+
+#include <QGraphicsWidget>
+#include <QPointer>
+#include <QGraphicsSceneMouseEvent>
+#include <QGraphicsScene>
+#include <QStyle> // krazy:exclude=qclasses
+#include <QGraphicsLinearLayout>
+
+
+
+
+namespace {
+    static const int TOOLTIP_DELAY = 150;
+    static const int TOOLTIP_HIDE_DELAY = 300;
+}
+
+HbToolTipLabelPrivate::HbToolTipLabelPrivate():
+        label(0),aboutToHide(false)
+{
+}
+
+void HbToolTipLabelPrivate::init()
+{
+    Q_Q(HbToolTipLabel);
+    q->setBackgroundItem(HbStyle::P_ToolTip_background);
+
+    q->setFocusPolicy(Qt::NoFocus);
+    q->setTimeout(HbPopup::NoTimeout);
+    q->setBackgroundFaded(false);
+    q->setDismissPolicy(HbPopup::TapAnywhere);
+    q->setModal(false);
+}
+
+void HbToolTipLabelPrivate::addPopupEffects()
+{
+#ifdef HB_EFFECTS
+    Q_Q(HbToolTipLabel);
+    hasEffects = HbEffectInternal::add(q,"tooltip_appear", "appear");
+    if (hasEffects) {
+        //We load the disappear effect only if appear effect was also loaded
+        hasEffects = HbEffectInternal::add(q,"tooltip_disappear", "disappear");
+    }
+#endif
+}
+
+/*
+  Checks if there is an item under scenePos that has tooltip. If it finds an item it sends an
+  QGraphicsSceneHelpEvent event to it. If the event is not handled by the item it uses default implementation
+  to display tooltip.
+*/
+void HbToolTipLabelPrivate::checkForToolTip(const QPointF& scenePos, const QPoint& screenPos)
+{
+    Q_Q(HbToolTipLabel);
+
+    if (q->scene()) {
+        // Find pressed item having tooltip
+        QGraphicsItem *toolTipItem = 0;
+
+        foreach(QGraphicsItem *item, q->scene()->items(scenePos)) {
+            if (toolTipBlockItem(item)) {
+                break;
+            }
+            if (!item->toolTip().isEmpty()) {
+                toolTipItem = item;
+                break;
+            }
+        }
+
+        if (toolTipItem) {
+            QGraphicsSceneHelpEvent helpEvent(QEvent::GraphicsSceneHelp);
+            helpEvent.setScenePos(scenePos);
+            helpEvent.setScreenPos(screenPos);
+            helpEvent.setAccepted(false);
+
+            static_cast<GraphicsItem*>(toolTipItem)->sceneEvent(&helpEvent);
+
+            // if event is not processed display tooltip
+            if (!helpEvent.isAccepted()) {
+                // Note: Intentionally public API is used to get same behavior
+                HbToolTip::showText(toolTipItem->toolTip(),toolTipItem,toolTipItem->boundingRect());
+            }
+        }
+    }
+}
+
+void HbToolTipLabelPrivate::mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent)
+{
+    Q_Q(HbToolTipLabel);
+    pressPointScreenPos = mouseEvent->screenPos();
+    pressPointScenePos = mouseEvent->scenePos();
+
+    tooltipTimer.start(TOOLTIP_DELAY, q);
+    hideTimer.stop();
+}
+
+void HbToolTipLabelPrivate::mouseReleaseEvent (QGraphicsSceneMouseEvent* mouseEvent)
+{
+    Q_UNUSED(mouseEvent)
+    tooltipTimer.stop();
+    hideTimer.stop();
+}
+
+void HbToolTipLabelPrivate::mouseMoveEvent (QGraphicsSceneMouseEvent* mouseEvent)
+{
+    Q_Q(HbToolTipLabel);
+
+    if (aboutToHide) {
+        checkForToolTip(mouseEvent->scenePos(),mouseEvent->screenPos());
+    } else {
+        if (!rect.isNull() && !rect.contains(static_cast<QGraphicsSceneMouseEvent*>(mouseEvent)->scenePos())) {
+            q->hideText();
+        }
+    }
+}
+
+void HbToolTipLabelPrivate::showText(QGraphicsItem *item, Qt::Alignment preferredAlignment)
+{
+    Q_Q(HbToolTipLabel);    
+    QRectF itemSceneRect = item->sceneBoundingRect();    
+    QRectF toolTipBoundingRect = QRectF(qreal(0.0), qreal(0.0), q->preferredSize().width(), q->preferredSize().height()); //q->boundingRect();
+    QRectF screenRect(QPointF(qreal(0.0), qreal(0.0)), HbDeviceProfile::profile(q).logicalSize());
+
+    Qt::Alignment currentAlignment = (preferredAlignment & Qt::AlignHorizontal_Mask)?
+                                     QStyle::visualAlignment(q->layoutDirection(), preferredAlignment ): // krazy:exclude=qclasses
+                                     preferredAlignment;
+    Qt::AlignmentFlag nextAlignmentFlag;
+    Qt::Alignment nextAlignment;
+    Qt::Alignment visitedAlignment;
+    bool matchingFinished = false;
+
+    forever {
+
+        toolTipBoundingRect.moveCenter(itemSceneRect.center());
+
+        if (currentAlignment & Qt::AlignTop) {            
+            visitedAlignment |= Qt::AlignTop;
+            if (currentAlignment & Qt::AlignRight) {
+                visitedAlignment |= Qt::AlignRight;
+                toolTipBoundingRect.moveBottomLeft(itemSceneRect.topRight());
+
+                nextAlignment = Qt::AlignTop;
+                nextAlignmentFlag = Qt::AlignLeft;
+                nextAlignment |= nextAlignmentFlag;
+
+            } else if (currentAlignment & Qt::AlignLeft) {
+                visitedAlignment |= Qt::AlignLeft;
+                toolTipBoundingRect.moveBottomRight(itemSceneRect.topLeft());
+
+                nextAlignment = Qt::AlignTop;
+                nextAlignmentFlag = Qt::AlignRight;
+                nextAlignment |= nextAlignmentFlag;
+
+            } else {
+                toolTipBoundingRect.moveBottom(itemSceneRect.top());
+
+                // Find out next alignment
+                nextAlignment = Qt::AlignRight | (preferredAlignment & Qt::AlignAbsolute);
+                nextAlignment = QStyle::visualAlignment(q->layoutDirection(), nextAlignment ); // krazy:exclude=qclasses
+                nextAlignmentFlag = ((nextAlignment & Qt::AlignRight)?Qt::AlignRight:Qt::AlignLeft);
+            }
+
+        } else if (currentAlignment & Qt::AlignRight) {
+
+            visitedAlignment |= Qt::AlignRight;
+            toolTipBoundingRect.moveLeft(itemSceneRect.right());
+            nextAlignment = nextAlignmentFlag = Qt::AlignLeft;
+
+        } else if (currentAlignment & Qt::AlignLeft ) {
+
+            visitedAlignment |= Qt::AlignLeft;
+            toolTipBoundingRect.moveRight(itemSceneRect.left());
+            nextAlignment = nextAlignmentFlag = Qt::AlignRight;
+
+        } else {
+            currentAlignment = Qt::AlignTop;
+            continue;
+        }
+
+        // Respect screen boundaries
+        toolTipBoundingRect.moveBottom(qMin(toolTipBoundingRect.bottom(),screenRect.bottom()));
+        toolTipBoundingRect.moveLeft(qMax(toolTipBoundingRect.left(),screenRect.left()));
+        toolTipBoundingRect.moveRight(qMin(toolTipBoundingRect.right(),screenRect.right()));
+        toolTipBoundingRect.moveTop(qMax(toolTipBoundingRect.top(),screenRect.top()));
+
+        // Check if a match is found or if matching was finished
+        if (!toolTipBoundingRect.intersects(itemSceneRect) || matchingFinished) {
+            break;
+        }
+        else { // move to the next alignment
+
+            // Check if every supported alignment was tried
+            if (visitedAlignment & nextAlignmentFlag) {
+                   currentAlignment = Qt::AlignTop;
+                   matchingFinished = true;
+            } else {
+                currentAlignment = nextAlignment;
+            }
+        }
+    }
+
+    q->setPos(toolTipBoundingRect.topLeft());
+    q->show();
+}
+
+/*
+  Returns true if item is a tooltip blocking item.
+  For example HbPopup background item is tooltip blocking for modal popups.
+*/
+bool HbToolTipLabelPrivate::toolTipBlockItem(QGraphicsItem *item)
+{
+    if (item->type() == HbPrivate::ItemType_FadeItem) {
+        return true;
+    } else if (item->type() == HbPrivate::ItemType_PopupBackGround) {
+        return static_cast<HbPopupBackGround *>(item)->isModal();
+    }
+    return false;
+}
+
+/*
+    \class HbToolTipLabel
+    \brief HbToolTipLabel is a convenience widget that displays a small message box.
+    Compared to traditional popup, a tooltip does not dim the background.
+    It disappears automatically after 3 seconds.
+*/
+HbToolTipLabel::HbToolTipLabel(QGraphicsWidget *parent) :
+    HbPopup(*new HbToolTipLabelPrivate, parent)
+{
+    Q_D(HbToolTipLabel);
+    d->q_ptr = this;
+    d->init();
+}
+
+HbToolTipLabel::~HbToolTipLabel()
+{
+}
+
+/*
+  This method can be used to eventHook tool tip triggering and dismissal logic to a scene event
+  flow.
+ */
+
+void HbToolTipLabel::eventHook(QEvent *event)
+{
+    Q_D(HbToolTipLabel);
+
+    if (isVisible()) {
+        switch (event->type()) {
+                case QEvent::WindowActivate:
+                case QEvent::WindowDeactivate:
+                case QEvent::GraphicsSceneMousePress:
+                case QEvent::GraphicsSceneMouseRelease:
+                case QEvent::GraphicsSceneMouseDoubleClick:
+                case QEvent::GraphicsSceneHoverEnter:
+                case QEvent::GraphicsSceneHoverLeave:
+                case QEvent::GraphicsSceneHoverMove:
+                case QEvent::KeyPress:
+                case QEvent::KeyRelease:
+                case QEvent::FocusIn:
+                case QEvent::FocusOut:
+
+                hideTextImmediately();
+                break;
+            case QEvent::GraphicsSceneMouseMove:
+                d->mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
+                break;
+            default:
+                break;
+        }
+    } else if (event->type() == QEvent::GraphicsSceneMousePress){
+        d->mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
+    } else if (event->type() == QEvent::GraphicsSceneMouseRelease){
+        d->mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
+    }
+}
+
+
+/*
+    Returns the text of the tooltip.
+
+    \sa setText()
+*/
+
+QString HbToolTipLabel::text() const
+{
+    Q_D(const HbToolTipLabel);
+    if (!d->label) {
+        return QString();
+    } else {
+        return d->label->text();
+    }
+}
+
+/*
+    Sets the text of the tooltip.
+
+    \sa text()
+*/
+void HbToolTipLabel::setText(const QString &newText)
+{
+    Q_D(HbToolTipLabel);
+    if (!d->label) {
+        d->label = new HbTextItem(this);
+        HbStyle::setItemName(d->label, "label");
+        repolish();
+    }
+    d->label->setText(newText);
+}
+
+/*
+    If you specify a non-empty rect the tip will be hidden as soon
+    as you move your cursor out of this area.
+
+    The \a rect is in the coordinates of the scene
+*/
+void HbToolTipLabel::setRect(const QRectF& rect)
+{
+    Q_D(HbToolTipLabel);
+    d->rect = rect;
+}
+
+
+/*
+    Displays tooltip using preferredAlignment regarding item.
+
+    \sa hideText()
+*/
+void HbToolTipLabel::showText(QGraphicsItem *item, Qt::Alignment preferredAlignment)
+{
+    Q_D(HbToolTipLabel);
+    d->aboutToHide = false;
+    d->tooltipTimer.stop();
+    d->hideTimer.stop();
+
+    d->showText(item, preferredAlignment);
+    d->mPreferredAlignment = preferredAlignment;
+    d->mItem = item;
+}
+
+/*
+    Hides tooltip
+
+    \sa hideText()
+*/
+void HbToolTipLabel::hideText()
+{
+    Q_D(HbToolTipLabel);
+    d->aboutToHide = true;
+    d->hideTimer.start(TOOLTIP_HIDE_DELAY, this);
+}
+
+
+void HbToolTipLabel::hideTextImmediately()
+{
+    Q_D(HbToolTipLabel);
+    d->aboutToHide = false;
+    d->hideTimer.stop();
+    d->tooltipTimer.stop();
+    close();
+}
+
+/*
+    Timer event to show tooltip or hide the tool tip immediately
+*/
+void HbToolTipLabel::timerEvent(QTimerEvent *event)
+{
+    Q_D(HbToolTipLabel);
+    if (event->timerId() == d->hideTimer.timerId()){
+        hideTextImmediately();
+    } else if (event->timerId() == d->tooltipTimer.timerId()) {        
+        d->tooltipTimer.stop();
+        d->checkForToolTip(d->pressPointScenePos,d->pressPointScreenPos);
+    }
+}
+
+/*
+    reimp
+*/
+bool HbToolTipLabel::event(QEvent *event)
+{
+    Q_D(HbToolTipLabel);
+    if (event->type() == QEvent::FontChange) {
+        if (d->label) {
+            d->label->setFont(font());
+        }
+    } else if (event->type() == QEvent::LayoutRequest) {        
+        if (d->label) {
+            resize(preferredSize());
+            d->label->resize(d->label->preferredSize());
+        }
+        if (isVisible()) {
+            showText(d->mItem, d->mPreferredAlignment);
+        }
+    }
+    return HbPopup::event(event);
+}
+