Index: /trunk/src/VBox/Frontends/VirtualBox/src/widgets/graphics/UIGraphicsTextPane.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/widgets/graphics/UIGraphicsTextPane.cpp	(revision 50867)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/widgets/graphics/UIGraphicsTextPane.cpp	(revision 50868)
@@ -17,7 +17,9 @@
 
 /* Qt includes: */
+#include <QApplication>
 #include <QFontMetrics>
 #include <QTextLayout>
 #include <QPainter>
+#include <QGraphicsSceneHoverEvent>
 
 /* GUI includes: */
@@ -33,5 +35,8 @@
     , m_iMinimumTextWidth(0)
     , m_iMinimumTextHeight(0)
-{
+    , m_fAnchorCanBeHovered(true)
+{
+    /* We do support hover-events: */
+    setAcceptHoverEvents(true);
 }
 
@@ -157,5 +162,6 @@
             m_leftList << buildTextLayout(font(), m_pPaintDevice,
                                           fRightColumnPresent ? line.first + ":" : line.first,
-                                          iLeftColumnWidth, iLeftColumnHeight);
+                                          iLeftColumnWidth, iLeftColumnHeight,
+                                          m_strHoveredAnchor);
             m_leftList.last()->setPosition(QPointF(iTextX, iTextY));
         }
@@ -167,5 +173,6 @@
             m_rightList << buildTextLayout(font(), m_pPaintDevice,
                                            line.second,
-                                           iRightColumnWidth, iRightColumnHeight);
+                                           iRightColumnWidth, iRightColumnHeight,
+                                           m_strHoveredAnchor);
             m_rightList.last()->setPosition(QPointF(iTextX + iLeftColumnWidth + m_iSpacing, iTextY));
         }
@@ -220,4 +227,99 @@
     /* Update minimum size-hint: */
     updateGeometry();
+}
+
+void UIGraphicsTextPane::hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent)
+{
+    /* Redirect to common handler: */
+    handleHoverEvent(pEvent);
+}
+
+void UIGraphicsTextPane::hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent)
+{
+    /* Redirect to common handler: */
+    handleHoverEvent(pEvent);
+}
+
+void UIGraphicsTextPane::handleHoverEvent(QGraphicsSceneHoverEvent *pEvent)
+{
+    /* Ignore if anchor can't be hovered: */
+    if (!m_fAnchorCanBeHovered)
+        return;
+
+    /* Prepare variables: */
+    QPoint mousePosition = pEvent->pos().toPoint();
+
+    /* If we currently have no anchor hovered: */
+    if (m_strHoveredAnchor.isNull())
+    {
+        /* Search it in the left list: */
+        m_strHoveredAnchor = searchForHoveredAnchor(m_pPaintDevice, m_leftList, mousePosition);
+        if (!m_strHoveredAnchor.isNull())
+            return updateHoverStuff();
+        /* Then search it in the right one: */
+        m_strHoveredAnchor = searchForHoveredAnchor(m_pPaintDevice, m_rightList, mousePosition);
+        if (!m_strHoveredAnchor.isNull())
+            return updateHoverStuff();
+    }
+    /* If we currently have some anchor hovered: */
+    else
+    {
+        QString strHoveredAnchorName;
+        /* Validate it through the left list: */
+        strHoveredAnchorName = searchForHoveredAnchor(m_pPaintDevice, m_leftList, mousePosition);
+        if (!strHoveredAnchorName.isNull())
+        {
+            m_strHoveredAnchor = strHoveredAnchorName;
+            return updateHoverStuff();
+        }
+        /* Then validate it through the right one: */
+        strHoveredAnchorName = searchForHoveredAnchor(m_pPaintDevice, m_rightList, mousePosition);
+        if (!strHoveredAnchorName.isNull())
+        {
+            m_strHoveredAnchor = strHoveredAnchorName;
+            return updateHoverStuff();
+        }
+        /* Finally clear it for good: */
+        m_strHoveredAnchor.clear();
+        return updateHoverStuff();
+    }
+}
+
+void UIGraphicsTextPane::updateHoverStuff()
+{
+    /* Update mouse-cursor: */
+    if (m_strHoveredAnchor.isNull())
+        unsetCursor();
+    else
+        setCursor(Qt::PointingHandCursor);
+
+    /* Update text-layout: */
+    updateTextLayout();
+
+    /* Update text-pane: */
+    update();
+}
+
+void UIGraphicsTextPane::mousePressEvent(QGraphicsSceneMouseEvent*)
+{
+    /* Make sure some anchor hovered: */
+    if (m_strHoveredAnchor.isNull())
+        return;
+
+    /* Restrict anchor hovering: */
+    m_fAnchorCanBeHovered = false;
+
+    /* Cache clicked anchor: */
+    QString strClickedAnchor = m_strHoveredAnchor;
+
+    /* Clear hovered anchor: */
+    m_strHoveredAnchor.clear();
+    updateHoverStuff();
+
+    /* Notify listeners about anchor clicked: */
+    emit sigAnchorClicked(strClickedAnchor);
+
+    /* Allow anchor hovering again: */
+    m_fAnchorCanBeHovered = true;
 }
 
@@ -233,14 +335,16 @@
 /* static  */
 QTextLayout* UIGraphicsTextPane::buildTextLayout(const QFont &font, QPaintDevice *pPaintDevice,
-                                                 const QString &strText, int iWidth, int &iHeight)
+                                                 const QString &strText, int iWidth, int &iHeight,
+                                                 const QString &strHoveredAnchor)
 {
     /* Prepare variables: */
     QFontMetrics fm(font, pPaintDevice);
     int iLeading = fm.leading();
-
-    /* Only bold sub-strings are currently handled: */
     QString strModifiedText(strText);
+    QList<QTextLayout::FormatRange> formatRangeList;
+
+    /* Handle bold sub-strings: */
     QRegExp boldRegExp("<b>([\\s\\S]+)</b>");
-    QList<QTextLayout::FormatRange> formatRangeList;
+    boldRegExp.setMinimal(true);
     while (boldRegExp.indexIn(strModifiedText) != -1)
     {
@@ -258,4 +362,23 @@
     }
 
+    /* Handle anchored sub-strings: */
+    QRegExp anchoredRegExp("<a href=([^>]+)>([^<>]+)</a>");
+    anchoredRegExp.setMinimal(true);
+    while (anchoredRegExp.indexIn(strModifiedText) != -1)
+    {
+        /* Prepare format: */
+        QTextLayout::FormatRange formatRange;
+        formatRange.format.setAnchor(true);
+        formatRange.format.setAnchorHref(anchoredRegExp.cap(1));
+        if (formatRange.format.anchorHref() == strHoveredAnchor)
+            formatRange.format.setForeground(qApp->palette().color(QPalette::Link));
+        formatRange.start = anchoredRegExp.pos(0);
+        formatRange.length = anchoredRegExp.cap(2).size();
+        /* Add format range to list: */
+        formatRangeList << formatRange;
+        /* Replace sub-string: */
+        strModifiedText.replace(anchoredRegExp.cap(0), anchoredRegExp.cap(2));
+    }
+
     /* Create layout; */
     QTextLayout *pTextLayout = new QTextLayout(strModifiedText, font, pPaintDevice);
@@ -286,2 +409,47 @@
 }
 
+/* static */
+QString UIGraphicsTextPane::searchForHoveredAnchor(QPaintDevice *pPaintDevice, const QList<QTextLayout*> &list, const QPoint &mousePosition)
+{
+    /* Analyze passed text-layouts: */
+    foreach (QTextLayout *pTextLayout, list)
+    {
+        /* Prepare variables: */
+        QFontMetrics fm(pTextLayout->font(), pPaintDevice);
+
+        /* Text-layout attributes: */
+        const QPoint layoutPosition = pTextLayout->position().toPoint();
+        const QString strLayoutText = pTextLayout->text();
+
+        /* Enumerate format ranges: */
+        foreach (const QTextLayout::FormatRange &range, pTextLayout->additionalFormats())
+        {
+            /* Skip unrelated formats: */
+            if (!range.format.isAnchor())
+                continue;
+
+            /* Parse 'anchor' format: */
+            const int iStart = range.start;
+            const int iLength = range.length;
+            QRegion formatRegion;
+            for (int iTextPosition = iStart; iTextPosition < iStart + iLength; ++iTextPosition)
+            {
+                QTextLine layoutLine = pTextLayout->lineForTextPosition(iTextPosition);
+                QPoint linePosition = layoutLine.position().toPoint();
+                int iSymbolX = (int)layoutLine.cursorToX(iTextPosition);
+                QRect symbolRect = QRect(layoutPosition.x() + linePosition.x() + iSymbolX,
+                                         layoutPosition.y() + linePosition.y(),
+                                         fm.width(strLayoutText[iTextPosition]) + 1, fm.height());
+                formatRegion += symbolRect;
+            }
+
+            /* Is that something we looking for? */
+            if (formatRegion.contains(mousePosition))
+                return range.format.anchorHref();
+        }
+    }
+
+    /* Null string by default: */
+    return QString();
+}
+
Index: /trunk/src/VBox/Frontends/VirtualBox/src/widgets/graphics/UIGraphicsTextPane.h
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/widgets/graphics/UIGraphicsTextPane.h	(revision 50867)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/widgets/graphics/UIGraphicsTextPane.h	(revision 50868)
@@ -39,4 +39,7 @@
     void sigGeometryChanged();
 
+    /** Notifies listeners about anchor clicked. */
+    void sigAnchorClicked(const QString &strAnchor);
+
 public:
 
@@ -66,4 +69,16 @@
     void resizeEvent(QGraphicsSceneResizeEvent *pEvent);
 
+    /** This event handler called when mouse hovers widget. */
+    void hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent);
+    /** This event handler called when mouse leaves widget. */
+    void hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent);
+    /** Summarize two hover-event handlers above. */
+    void handleHoverEvent(QGraphicsSceneHoverEvent *pEvent);
+    /** Update hover stuff. */
+    void updateHoverStuff();
+
+    /** This event handler called when mouse press widget. */
+    void mousePressEvent(QGraphicsSceneMouseEvent *pEvent);
+
     /** Paints the contents in local coordinates. */
     void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget = 0);
@@ -71,5 +86,9 @@
     /** Builds new text-layout. */
     static QTextLayout* buildTextLayout(const QFont &font, QPaintDevice *pPaintDevice,
-                                        const QString &strText, int iWidth, int &iHeight);
+                                        const QString &strText, int iWidth, int &iHeight,
+                                        const QString &strHoveredAnchor);
+
+    /** Search for hovered anchor in passed text-layout @a list. */
+    static QString searchForHoveredAnchor(QPaintDevice *pPaintDevice, const QList<QTextLayout*> &list, const QPoint &mousePosition);
 
     /** Paint-device to scale to. */
@@ -98,4 +117,9 @@
     /** Right text-layout list. */
     QList<QTextLayout*> m_rightList;
+
+    /** Holds whether anchor can be hovered. */
+    bool m_fAnchorCanBeHovered;
+    /** Holds currently hovered anchor. */
+    QString m_strHoveredAnchor;
 };
 
