Fix clicking on links in aligned or elided Text.
authorAndrew den Exter <andrew.den-exter@nokia.com>
Tue, 19 Jun 2012 01:30:59 +0000 (11:30 +1000)
committerQt by Nokia <qt-info@nokia.com>
Mon, 25 Jun 2012 06:57:36 +0000 (08:57 +0200)
Adjust the mouse position to compensate for any alignment offsets
and test the elided text layout for anchors if none is found in
the normal layout.

Change-Id: Idfda3f7e372d0f2d6c1b7bb5f22d7015d52e8239
Reviewed-by: Yann Bodson <yann.bodson@nokia.com>
src/quick/items/qquicktext.cpp
src/quick/items/qquicktext_p_p.h
src/quick/items/qquicktextutil.cpp
src/quick/items/qquicktextutil_p.h
tests/auto/quick/qquicktext/tst_qquicktext.cpp

index f03afd6..b19b13f 100644 (file)
@@ -47,6 +47,8 @@
 #include <private/qsgadaptationlayer_p.h>
 #include "qquicktextnode_p.h"
 #include "qquickimage_p_p.h"
+#include "qquicktextutil_p.h"
+
 #include <QtQuick/private/qsgtexture_p.h>
 
 #include <QtQml/qqmlinfo.h>
@@ -2011,36 +2013,13 @@ QRectF QQuickText::boundingRect() const
     Q_D(const QQuickText);
 
     QRectF rect = d->layedOutTextRect;
+    rect.moveLeft(QQuickTextUtil::alignedX(rect, width(), d->hAlign));
+    rect.moveTop(QQuickTextUtil::alignedY(rect, height(), d->vAlign));
+
     if (d->style != Normal)
         rect.adjust(-1, 0, 1, 2);
-
     // Could include font max left/right bearings to either side of rectangle.
 
-    qreal w = width();
-    switch (d->hAlign) {
-    case AlignLeft:
-    case AlignJustify:
-        break;
-    case AlignRight:
-        rect.moveLeft(w - rect.width());
-        break;
-    case AlignHCenter:
-        rect.moveLeft((w - rect.width()) / 2);
-        break;
-    }
-
-    qreal h = height();
-    switch (d->vAlign) {
-    case AlignTop:
-        break;
-    case AlignBottom:
-        rect.moveTop(h - rect.height());
-        break;
-    case AlignVCenter:
-        rect.moveTop((h - rect.height()) / 2);
-        break;
-    }
-
     return rect;
 }
 
@@ -2131,7 +2110,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
 
     d->updateType = QQuickTextPrivate::UpdateNone;
 
-    QRectF bounds = boundingRect();
+    const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect, height(), d->vAlign);
 
     // We need to make sure the layout is done in the current thread
 #if defined(Q_OS_MAC)
@@ -2156,27 +2135,28 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data
 
     if (d->richText) {
         d->ensureDoc();
-        node->addTextDocument(bounds.topLeft(), d->extra->doc, color, d->style, styleColor, linkColor);
-    } else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) {
+        const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect, width(), d->hAlign);
+        node->addTextDocument(QPointF(dx, dy), d->extra->doc, color, d->style, styleColor, linkColor);
+    } else if (d->elideMode == QQuickText::ElideNone || d->layedOutTextRect.width() > 0.) {
         int unelidedLineCount = d->lineCount;
         if (d->elideLayout)
             unelidedLineCount -= 1;
         if (unelidedLineCount > 0) {
             node->addTextLayout(
-                        QPoint(0, bounds.y()),
+                        QPoint(0, dy),
                         &d->layout,
                         color, d->style, styleColor, linkColor,
                         QColor(), QColor(), -1, -1,
                         0, unelidedLineCount);
         }
         if (d->elideLayout)
-            node->addTextLayout(QPoint(0, bounds.y()), d->elideLayout, color, d->style, styleColor, linkColor);
+            node->addTextLayout(QPoint(0, dy), d->elideLayout, color, d->style, styleColor, linkColor);
     }
 
     foreach (QQuickStyledTextImgTag *img, d->visibleImgTags) {
         QQuickPixmap *pix = img->pix;
         if (pix && pix->isReady())
-            node->addImage(QRectF(img->pos.x(), img->pos.y() + bounds.y(), pix->width(), pix->height()), pix->image());
+            node->addImage(QRectF(img->pos.x(), img->pos.y() + dy, pix->width(), pix->height()), pix->image());
     }
     return node;
 }
@@ -2397,28 +2377,42 @@ void QQuickText::componentComplete()
         d->updateLayout();
 }
 
-
-QString QQuickTextPrivate::anchorAt(const QPointF &mousePos)
+QString QQuickTextPrivate::anchorAt(const QTextLayout *layout, const QPointF &mousePos)
 {
-    if (styledText) {
-        for (int i = 0; i < layout.lineCount(); ++i) {
-            QTextLine line = layout.lineAt(i);
-            if (line.naturalTextRect().contains(mousePos)) {
-                int charPos = line.xToCursor(mousePos.x());
-                foreach (const QTextLayout::FormatRange &formatRange, layout.additionalFormats()) {
-                    if (formatRange.format.isAnchor()
-                            && charPos >= formatRange.start
-                            && charPos <= formatRange.start + formatRange.length) {
-                        return formatRange.format.anchorHref();
-                    }
+    for (int i = 0; i < layout->lineCount(); ++i) {
+        QTextLine line = layout->lineAt(i);
+        if (line.naturalTextRect().contains(mousePos)) {
+            int charPos = line.xToCursor(mousePos.x(), QTextLine::CursorOnCharacter);
+            foreach (const QTextLayout::FormatRange &formatRange, layout->additionalFormats()) {
+                if (formatRange.format.isAnchor()
+                        && charPos >= formatRange.start
+                        && charPos < formatRange.start + formatRange.length) {
+                    return formatRange.format.anchorHref();
                 }
-                break;
             }
+            break;
         }
     }
     return QString();
 }
 
+QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const
+{
+    Q_Q(const QQuickText);
+    QPointF translatedMousePos = mousePos;
+    translatedMousePos.ry() -= QQuickTextUtil::alignedY(layedOutTextRect, q->height(), vAlign);
+    if (styledText) {
+        QString link = anchorAt(&layout, translatedMousePos);
+        if (link.isEmpty() && elideLayout)
+            link = anchorAt(elideLayout, translatedMousePos);
+        return link;
+    } else if (richText && extra.isAllocated() && extra->doc) {
+        translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect, q->width(), hAlign);
+        return extra->doc->documentLayout()->anchorAt(translatedMousePos);
+    }
+    return QString();
+}
+
 bool QQuickTextPrivate::isLinkActivatedConnected()
 {
     Q_Q(QQuickText);
@@ -2431,14 +2425,8 @@ void QQuickText::mousePressEvent(QMouseEvent *event)
     Q_D(QQuickText);
 
     QString link;
-    if (d->isLinkActivatedConnected()) {
-        if (d->styledText)
-            link = d->anchorAt(event->localPos());
-        else if (d->richText) {
-            d->ensureDoc();
-            link = d->extra->doc->documentLayout()->anchorAt(event->localPos());
-        }
-    }
+    if (d->isLinkActivatedConnected())
+        link = d->anchorAt(event->localPos());
 
     if (link.isEmpty()) {
         event->setAccepted(false);
@@ -2450,9 +2438,9 @@ void QQuickText::mousePressEvent(QMouseEvent *event)
 
     if (!event->isAccepted())
         QQuickItem::mousePressEvent(event);
-
 }
 
+
 /*! \internal */
 void QQuickText::mouseReleaseEvent(QMouseEvent *event)
 {
@@ -2461,14 +2449,8 @@ void QQuickText::mouseReleaseEvent(QMouseEvent *event)
     // ### confirm the link, and send a signal out
 
     QString link;
-    if (d->isLinkActivatedConnected()) {
-        if (d->styledText)
-            link = d->anchorAt(event->localPos());
-        else if (d->richText) {
-            d->ensureDoc();
-            link = d->extra->doc->documentLayout()->anchorAt(event->localPos());
-        }
-    }
+    if (d->isLinkActivatedConnected())
+        link = d->anchorAt(event->localPos());
 
     if (!link.isEmpty() && d->extra.isAllocated() && d->extra->activeLink == link)
         emit linkActivated(d->extra->activeLink);
index 2afcd8f..985b1e1 100644 (file)
@@ -166,7 +166,8 @@ public:
     QRectF setupTextLayout(qreal *const naturalWidth,  qreal * const baseline);
     void setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset = 0);
     bool isLinkActivatedConnected();
-    QString anchorAt(const QPointF &pos);
+    static QString anchorAt(const QTextLayout *layout, const QPointF &mousePos);
+    QString anchorAt(const QPointF &pos) const;
 
     inline qreal lineHeight() const { return extra.isAllocated() ? extra->lineHeight : 1.0; }
     inline int maximumLineCount() const { return extra.isAllocated() ? extra->maximumLineCount : INT_MAX; }
index c2c11b3..176301d 100644 (file)
@@ -78,4 +78,37 @@ QQuickItem *QQuickTextUtil::createCursor(
     return item;
 }
 
+qreal QQuickTextUtil::alignedX(const QRectF &rect, qreal width, int alignment)
+{
+    qreal x = 0;
+    switch (alignment) {
+    case Qt::AlignLeft:
+    case Qt::AlignJustify:
+        break;
+    case Qt::AlignRight:
+        x = width - rect.width();
+        break;
+    case Qt::AlignHCenter:
+        x = (width - rect.width()) / 2;
+        break;
+    }
+    return x;
+}
+
+qreal QQuickTextUtil::alignedY(const QRectF &rect, const qreal height, int alignment)
+{
+    qreal y = 0;
+    switch (alignment) {
+    case Qt::AlignTop:
+        break;
+    case Qt::AlignBottom:
+        y = height - rect.height();
+        break;
+    case Qt::AlignVCenter:
+        y = (height - rect.height()) / 2;
+        break;
+    }
+    return y;
+}
+
 QT_END_NAMESPACE
index 91ef40b..d6c05aa 100644 (file)
@@ -66,12 +66,16 @@ public:
     template <typename Private> static void setCursorDelegate(Private *d, QQmlComponent *delegate);
     template <typename Private> static void createCursor(Private *d);
 
+    static qreal alignedX(const QRectF &rect, qreal width, int alignment);
+    static qreal alignedY(const QRectF &rect, qreal height, int alignment);
+
 private:
     static QQuickItem *createCursor(
             QQmlComponent *component,
             QQuickItem *parent,
             const QRectF &cursorRectangle,
             const char *className);
+
 };
 
 template <typename Private>
index 7d24de6..2bdf4a9 100644 (file)
@@ -105,6 +105,7 @@ private slots:
     void letterSpacing();
     void wordSpacing();
 
+    void clickLink_data();
     void clickLink();
 
     void implicitSize_data();
@@ -1438,6 +1439,8 @@ public:
             mousePressEvent(event);
         else if (event->type() == QEvent::MouseButtonRelease)
             mouseReleaseEvent(event);
+        else if (event->type() == QEvent::MouseMove)
+            mouseMoveEvent(event);
         else
             qWarning() << "Trying to send unsupported event type";
     }
@@ -1455,36 +1458,339 @@ public slots:
     void linkClicked(QString l) { link = l; }
 };
 
-void tst_qquicktext::clickLink()
+class TextMetrics
 {
+public:
+    TextMetrics(const QString &text, Qt::TextElideMode elideMode = Qt::ElideNone)
     {
-        QString componentStr = "import QtQuick 2.0\nText { text: \"<a href=\\\"http://qt.nokia.com\\\">Hello world!</a>\" }";
-        QQmlComponent textComponent(&engine);
-        textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
-        QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
-
-        QVERIFY(textObject != 0);
+        QString adjustedText = text;
+        adjustedText.replace(QLatin1Char('\n'), QChar(QChar::LineSeparator));
+        if (elideMode == Qt::ElideLeft)
+            adjustedText = QChar(0x2026) + adjustedText;
+        else if (elideMode == Qt::ElideRight)
+            adjustedText = adjustedText + QChar(0x2026);
+
+        layout.setText(adjustedText);
+        QTextOption option;
+        option.setUseDesignMetrics(true);
+        layout.setTextOption(option);
 
-        LinkTest test;
-        QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
+        layout.beginLayout();
+        qreal height = 0;
+        QTextLine line = layout.createLine();
+        while (line.isValid()) {
+            line.setLineWidth(FLT_MAX);
+            line.setPosition(QPointF(0, height));
+            height += line.height();
+            line = layout.createLine();
+        }
+        layout.endLayout();
+    }
 
-        {
-            QMouseEvent me(QEvent::MouseButtonPress,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
-            static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+    qreal width() const { return layout.maximumWidth(); }
 
+    QRectF characterRectangle(
+            int position,
+            int hAlign = Qt::AlignLeft,
+            int vAlign = Qt::AlignTop,
+            const QSizeF &bounds = QSizeF(240, 320)) const
+    {
+        qreal dy = 0;
+        switch (vAlign) {
+        case Qt::AlignBottom:
+            dy = bounds.height() - layout.boundingRect().height();
+            break;
+        case Qt::AlignVCenter:
+            dy = (bounds.height() - layout.boundingRect().height()) / 2;
+            break;
+        default:
+            break;
         }
 
-        {
-            QMouseEvent me(QEvent::MouseButtonRelease,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
-            static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+        for (int i = 0; i < layout.lineCount(); ++i) {
+            QTextLine line = layout.lineAt(i);
+            if (position >= line.textStart() + line.textLength())
+                continue;
+            qreal dx = 0;
+            switch (hAlign) {
+            case Qt::AlignRight:
+                dx = bounds.width() - line.naturalTextWidth();
+                break;
+            case Qt::AlignHCenter:
+                dx = (bounds.width() - line.naturalTextWidth()) / 2;
+                break;
+            default:
+                break;
+            }
 
+            QRectF rect;
+            rect.setLeft(dx + line.cursorToX(position, QTextLine::Leading));
+            rect.setRight(dx + line.cursorToX(position, QTextLine::Trailing));
+            rect.setTop(dy + line.y());
+            rect.setBottom(dy + line.y() + line.height());
+
+            return rect;
         }
+        return QRectF();
+    }
 
+    QTextLayout layout;
+};
 
-        QCOMPARE(test.link, QLatin1String("http://qt.nokia.com"));
 
-        delete textObject;
+typedef QVector<QPointF> PointVector;
+Q_DECLARE_METATYPE(PointVector);
+
+void tst_qquicktext::clickLink_data()
+{
+    QTest::addColumn<QString>("text");
+    QTest::addColumn<qreal>("width");
+    QTest::addColumn<QString>("bindings");
+    QTest::addColumn<PointVector>("mousePositions");
+    QTest::addColumn<QString>("link");
+
+    const QString singleLineText = "this text has a <a href=\\\"http://qt-project.org/single\\\">link</a> in it";
+    const QString singleLineLink = "http://qt-project.org/single";
+    const QString multipleLineText = "this text<br/>has <a href=\\\"http://qt-project.org/multiple\\\">multiple<br/>lines</a> in it";
+    const QString multipleLineLink = "http://qt-project.org/multiple";
+    const QString nestedText = "this text has a <a href=\\\"http://qt-project.org/outer\\\">nested <a href=\\\"http://qt-project.org/inner\\\">link</a> in it</a>";
+    const QString outerLink = "http://qt-project.org/outer";
+    const QString innerLink = "http://qt-project.org/inner";
+
+    {
+        const TextMetrics metrics("this text has a link in it");
+
+        QTest::newRow("click on link")
+                << singleLineText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(18).center())
+                << singleLineLink;
+        QTest::newRow("click on text")
+                << singleLineText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(13).center())
+                << QString();
+        QTest::newRow("drag within link")
+                << singleLineText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(17).center()
+                    << metrics.characterRectangle(19).center())
+                << singleLineLink;
+        QTest::newRow("drag away from link")
+                << singleLineText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(18).center()
+                    << metrics.characterRectangle(13).center())
+                << QString();
+        QTest::newRow("drag on to link")
+                << singleLineText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(13).center()
+                    << metrics.characterRectangle(18).center())
+                << QString();
+        QTest::newRow("click on bottom right aligned link")
+                << singleLineText << 240.
+                << "horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
+                << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
+                << singleLineLink;
+        QTest::newRow("click on center aligned link")
+                << singleLineText << 240.
+                << "horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
+                << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
+                << singleLineLink;
+        QTest::newRow("click on rich text link")
+                << singleLineText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(18).center())
+                << singleLineLink;
+        QTest::newRow("click on rich text")
+                << singleLineText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(13).center())
+                << QString();
+        QTest::newRow("click on bottom right aligned rich text link")
+                << singleLineText << 240.
+                << "textFormat: Text.RichText; horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
+                << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
+                << singleLineLink;
+        QTest::newRow("click on center aligned rich text link")
+                << singleLineText << 240.
+                << "textFormat: Text.RichText; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
+                << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
+                << singleLineLink;
+    } {
+        const TextMetrics metrics("this text has a li", Qt::ElideRight);
+        QTest::newRow("click on right elided link")
+                << singleLineText << metrics.width() +  2
+                << "elide: Text.ElideRight"
+                << (PointVector() << metrics.characterRectangle(17).center())
+                << singleLineLink;
+    } {
+        const TextMetrics metrics("ink in it", Qt::ElideLeft);
+        QTest::newRow("click on left elided link")
+                << singleLineText << metrics.width() +  2
+                << "elide: Text.ElideLeft"
+                << (PointVector() << metrics.characterRectangle(2).center())
+                << singleLineLink;
+    } {
+        const TextMetrics metrics("this text\nhas multiple\nlines in it");
+        QTest::newRow("click on second line")
+                << multipleLineText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(18).center())
+                << multipleLineLink;
+        QTest::newRow("click on third line")
+                << multipleLineText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(25).center())
+                << multipleLineLink;
+        QTest::newRow("drag from second line to third")
+                << multipleLineText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(18).center()
+                    << metrics.characterRectangle(25).center())
+                << multipleLineLink;
+        QTest::newRow("click on rich text second line")
+                << multipleLineText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(18).center())
+                << multipleLineLink;
+        QTest::newRow("click on rich text third line")
+                << multipleLineText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(25).center())
+                << multipleLineLink;
+        QTest::newRow("drag rich text from second line to third")
+                << multipleLineText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector()
+                    << metrics.characterRectangle(18).center()
+                    << metrics.characterRectangle(25).center())
+                << multipleLineLink;
+    } {
+        const TextMetrics metrics("this text has a nested link in it");
+        QTest::newRow("click on left outer link")
+                << nestedText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(22).center())
+                << outerLink;
+        QTest::newRow("click on right outer link")
+                << nestedText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(27).center())
+                << outerLink;
+        QTest::newRow("click on inner link left")
+                << nestedText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(23).center())
+                << innerLink;
+        QTest::newRow("click on inner link right")
+                << nestedText << 240.
+                << ""
+                << (PointVector() << metrics.characterRectangle(26).center())
+                << innerLink;
+        QTest::newRow("drag from inner to outer link")
+                << nestedText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(25).center()
+                    << metrics.characterRectangle(30).center())
+                << QString();
+        QTest::newRow("drag from outer to inner link")
+                << nestedText << 240.
+                << ""
+                << (PointVector()
+                    << metrics.characterRectangle(30).center()
+                    << metrics.characterRectangle(25).center())
+                << QString();
+        QTest::newRow("click on left outer rich text link")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(22).center())
+                << outerLink;
+        QTest::newRow("click on right outer rich text link")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(27).center())
+                << outerLink;
+        QTest::newRow("click on inner rich text link left")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(23).center())
+                << innerLink;
+        QTest::newRow("click on inner rich text link right")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector() << metrics.characterRectangle(26).center())
+                << innerLink;
+        QTest::newRow("drag from inner to outer rich text link")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector()
+                    << metrics.characterRectangle(25).center()
+                    << metrics.characterRectangle(30).center())
+                << QString();
+        QTest::newRow("drag from outer to inner rich text link")
+                << nestedText << 240.
+                << "textFormat: Text.RichText"
+                << (PointVector()
+                    << metrics.characterRectangle(30).center()
+                    << metrics.characterRectangle(25).center())
+                << QString();
+    }
+}
+
+void tst_qquicktext::clickLink()
+{
+    QFETCH(QString, text);
+    QFETCH(qreal, width);
+    QFETCH(QString, bindings);
+    QFETCH(PointVector, mousePositions);
+    QFETCH(QString, link);
+
+    QString componentStr =
+            "import QtQuick 2.0\nText {\n"
+                "width: " + QString::number(width) + "\n"
+                "height: 320\n"
+                "text: \"" + text + "\"\n"
+                "" + bindings + "\n"
+            "}";
+    QQmlComponent textComponent(&engine);
+    textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+    QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+
+    QVERIFY(textObject != 0);
+
+    LinkTest test;
+    QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
+
+    QVERIFY(mousePositions.count() > 0);
+
+    QPointF mousePosition = mousePositions.first();
+    {
+        QMouseEvent me(QEvent::MouseButtonPress, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+        static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
     }
+
+    for (int i = 1; i < mousePositions.count(); ++i) {
+        mousePosition = mousePositions.at(i);
+
+        QMouseEvent me(QEvent::MouseMove, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+        static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+    }
+
+    {
+        QMouseEvent me(QEvent::MouseButtonRelease, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+        static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
+    }
+
+    QCOMPARE(test.link, link);
+
+    delete textObject;
 }
 
 void tst_qquicktext::baseUrl()