VirtualBox

Changeset 55477 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Apr 28, 2015 10:50:05 AM (10 years ago)
Author:
vboxsync
Message:

FE/Qt: 7720: Moving rich-text support object of the details-pane elements into separate files.

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
1 added
3 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r55095 r55477  
    153153        ./src/globals \
    154154        ./src/medium \
     155        ./src/objects \
    155156        ./src/platform \
    156157        ./src/platform/darwin \
     
    579580        src/medium/UIMediumEnumerator.cpp \
    580581        src/medium/UIMediumManager.cpp \
     582        src/objects/UIRichTextString.cpp \
    581583        src/runtime/UIActionPoolRuntime.cpp \
    582584        src/runtime/UIAddDiskEncryptionPasswordDialog.cpp \
  • trunk/src/VBox/Frontends/VirtualBox/src/objects/UIRichTextString.cpp

    r55476 r55477  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UIGraphicsTextPane and UITask class implementation.
     3 * VBox Qt GUI - UIRichTextString class implementation.
    44 */
    55
    66/*
    7  * Copyright (C) 2012-2014 Oracle Corporation
     7 * Copyright (C) 2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2121
    2222/* Qt includes: */
    23 # include <QStack>
    24 # include <QPainter>
    2523# include <QApplication>
    26 # include <QFontMetrics>
    27 # include <QGraphicsSceneHoverEvent>
     24# include <QPalette>
    2825
    2926/* GUI includes: */
    30 # include "UIGraphicsTextPane.h"
     27# include "UIRichTextString.h"
    3128
    3229/* Other VBox includes: */
     
    3431
    3532#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
    36 
    37 UIGraphicsTextPane::UIGraphicsTextPane(QIGraphicsWidget *pParent, QPaintDevice *pPaintDevice)
    38     : QIGraphicsWidget(pParent)
    39     , m_pPaintDevice(pPaintDevice)
    40     , m_iMargin(0)
    41     , m_iSpacing(10)
    42     , m_iMinimumTextColumnWidth(100)
    43     , m_fMinimumSizeHintInvalidated(true)
    44     , m_iMinimumTextWidth(0)
    45     , m_iMinimumTextHeight(0)
    46     , m_fAnchorCanBeHovered(true)
    47 {
    48     /* We do support hover-events: */
    49     setAcceptHoverEvents(true);
    50 }
    51 
    52 UIGraphicsTextPane::~UIGraphicsTextPane()
    53 {
    54     /* Clear text-layouts: */
    55     while (!m_leftList.isEmpty()) delete m_leftList.takeLast();
    56     while (!m_rightList.isEmpty()) delete m_rightList.takeLast();
    57 }
    58 
    59 void UIGraphicsTextPane::setText(const UITextTable &text)
    60 {
    61     /* Clear text: */
    62     m_text.clear();
    63 
    64     /* For each the line of the passed table: */
    65     foreach (const UITextTableLine &line, text)
    66     {
    67         /* Lines: */
    68         QString strLeftLine = line.first;
    69         QString strRightLine = line.second;
    70 
    71         /* If 2nd line is NOT empty: */
    72         if (!strRightLine.isEmpty())
    73         {
    74             /* Take both lines 'as is': */
    75             m_text << UITextTableLine(strLeftLine, strRightLine);
    76         }
    77         /* If 2nd line is empty: */
    78         else
    79         {
    80             /* Parse the 1st one to sub-lines: */
    81             QStringList subLines = strLeftLine.split(QRegExp("\\n"));
    82             foreach (const QString &strSubLine, subLines)
    83                 m_text << UITextTableLine(strSubLine, QString());
    84         }
    85     }
    86 
    87     /* Update text-layout: */
    88     updateTextLayout(true);
    89 
    90     /* Update minimum size-hint: */
    91     updateGeometry();
    92 }
    93 
    94 void UIGraphicsTextPane::setAnchorRoleRestricted(const QString &strAnchorRole, bool fRestricted)
    95 {
    96     /* Make sure something changed: */
    97     if (   (fRestricted && m_restrictedAnchorRoles.contains(strAnchorRole))
    98         || (!fRestricted && !m_restrictedAnchorRoles.contains(strAnchorRole)))
    99         return;
    100 
    101     /* Apply new value: */
    102     if (fRestricted)
    103         m_restrictedAnchorRoles << strAnchorRole;
    104     else
    105         m_restrictedAnchorRoles.remove(strAnchorRole);
    106 
    107     /* Reset hovered anchor: */
    108     m_strHoveredAnchor.clear();
    109     updateHoverStuff();
    110 }
    111 
    112 void UIGraphicsTextPane::updateTextLayout(bool fFull /* = false */)
    113 {
    114     /* Prepare variables: */
    115     QFontMetrics fm(font(), m_pPaintDevice);
    116     int iMaximumTextWidth = (int)size().width() - 2 * m_iMargin - m_iSpacing;
    117 
    118     /* Search for the maximum column widths: */
    119     int iMaximumLeftColumnWidth = 0;
    120     int iMaximumRightColumnWidth = 0;
    121     bool fSingleColumnText = true;
    122     foreach (const UITextTableLine &line, m_text)
    123     {
    124         bool fRightColumnPresent = !line.second.isEmpty();
    125         if (fRightColumnPresent)
    126             fSingleColumnText = false;
    127         QString strLeftLine = fRightColumnPresent ? line.first + ":" : line.first;
    128         QString strRightLine = line.second;
    129         iMaximumLeftColumnWidth = qMax(iMaximumLeftColumnWidth, fm.width(strLeftLine));
    130         iMaximumRightColumnWidth = qMax(iMaximumRightColumnWidth, fm.width(strRightLine));
    131     }
    132     iMaximumLeftColumnWidth += 1;
    133     iMaximumRightColumnWidth += 1;
    134 
    135     /* Calculate text attributes: */
    136     int iLeftColumnWidth = 0;
    137     int iRightColumnWidth = 0;
    138     /* Left column only: */
    139     if (fSingleColumnText)
    140     {
    141         /* Full update? */
    142         if (fFull)
    143         {
    144             /* Minimum width for left column: */
    145             int iMinimumLeftColumnWidth = qMin(m_iMinimumTextColumnWidth, iMaximumLeftColumnWidth);
    146             /* Minimum width for whole text: */
    147             m_iMinimumTextWidth = iMinimumLeftColumnWidth;
    148         }
    149 
    150         /* Current width for left column: */
    151         iLeftColumnWidth = qMax(m_iMinimumTextColumnWidth, iMaximumTextWidth);
    152     }
    153     /* Two columns: */
    154     else
    155     {
    156         /* Full update? */
    157         if (fFull)
    158         {
    159             /* Minimum width for left column: */
    160             int iMinimumLeftColumnWidth = iMaximumLeftColumnWidth;
    161             /* Minimum width for right column: */
    162             int iMinimumRightColumnWidth = qMin(m_iMinimumTextColumnWidth, iMaximumRightColumnWidth);
    163             /* Minimum width for whole text: */
    164             m_iMinimumTextWidth = iMinimumLeftColumnWidth + m_iSpacing + iMinimumRightColumnWidth;
    165         }
    166 
    167         /* Current width for left column: */
    168         iLeftColumnWidth = iMaximumLeftColumnWidth;
    169         /* Current width for right column: */
    170         iRightColumnWidth = iMaximumTextWidth - iLeftColumnWidth;
    171     }
    172 
    173     /* Clear old text-layouts: */
    174     while (!m_leftList.isEmpty()) delete m_leftList.takeLast();
    175     while (!m_rightList.isEmpty()) delete m_rightList.takeLast();
    176 
    177     /* Prepare new text-layouts: */
    178     int iTextX = m_iMargin;
    179     int iTextY = m_iMargin;
    180     /* Populate text-layouts: */
    181     m_iMinimumTextHeight = 0;
    182     foreach (const UITextTableLine &line, m_text)
    183     {
    184         /* Left layout: */
    185         int iLeftColumnHeight = 0;
    186         if (!line.first.isEmpty())
    187         {
    188             bool fRightColumnPresent = !line.second.isEmpty();
    189             m_leftList << buildTextLayout(font(), m_pPaintDevice,
    190                                           fRightColumnPresent ? line.first + ":" : line.first,
    191                                           iLeftColumnWidth, iLeftColumnHeight,
    192                                           m_strHoveredAnchor);
    193             m_leftList.last()->setPosition(QPointF(iTextX, iTextY));
    194         }
    195 
    196         /* Right layout: */
    197         int iRightColumnHeight = 0;
    198         if (!line.second.isEmpty())
    199         {
    200             m_rightList << buildTextLayout(font(), m_pPaintDevice,
    201                                            line.second,
    202                                            iRightColumnWidth, iRightColumnHeight,
    203                                            m_strHoveredAnchor);
    204             m_rightList.last()->setPosition(QPointF(iTextX + iLeftColumnWidth + m_iSpacing, iTextY));
    205         }
    206 
    207         /* Maximum colum height? */
    208         int iMaximumColumnHeight = qMax(iLeftColumnHeight, iRightColumnHeight);
    209 
    210         /* Indent Y: */
    211         iTextY += iMaximumColumnHeight;
    212         /* Append summary text height: */
    213         m_iMinimumTextHeight += iMaximumColumnHeight;
    214     }
    215 }
    216 
    217 void UIGraphicsTextPane::updateGeometry()
    218 {
    219     /* Discard cached minimum size-hint: */
    220     m_fMinimumSizeHintInvalidated = true;
    221 
    222     /* Call to base-class to notify layout if any: */
    223     QIGraphicsWidget::updateGeometry();
    224 
    225     /* And notify listeners which are not layouts: */
    226     emit sigGeometryChanged();
    227 }
    228 
    229 QSizeF UIGraphicsTextPane::sizeHint(Qt::SizeHint which, const QSizeF &constraint /* = QSizeF() */) const
    230 {
    231     /* For minimum size-hint: */
    232     if (which == Qt::MinimumSize)
    233     {
    234         /* If minimum size-hint invalidated: */
    235         if (m_fMinimumSizeHintInvalidated)
    236         {
    237             /* Recache minimum size-hint: */
    238             m_minimumSizeHint = QSizeF(2 * m_iMargin + m_iMinimumTextWidth,
    239                                        2 * m_iMargin + m_iMinimumTextHeight);
    240             m_fMinimumSizeHintInvalidated = false;
    241         }
    242         /* Return cached minimum size-hint: */
    243         return m_minimumSizeHint;
    244     }
    245     /* Call to base-class for other size-hints: */
    246     return QIGraphicsWidget::sizeHint(which, constraint);
    247 }
    248 
    249 void UIGraphicsTextPane::resizeEvent(QGraphicsSceneResizeEvent*)
    250 {
    251     /* Update text-layout: */
    252     updateTextLayout();
    253 
    254     /* Update minimum size-hint: */
    255     updateGeometry();
    256 }
    257 
    258 void UIGraphicsTextPane::hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent)
    259 {
    260     /* Redirect to common handler: */
    261     handleHoverEvent(pEvent);
    262 }
    263 
    264 void UIGraphicsTextPane::hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent)
    265 {
    266     /* Redirect to common handler: */
    267     handleHoverEvent(pEvent);
    268 }
    269 
    270 void UIGraphicsTextPane::handleHoverEvent(QGraphicsSceneHoverEvent *pEvent)
    271 {
    272     /* Ignore if anchor can't be hovered: */
    273     if (!m_fAnchorCanBeHovered)
    274         return;
    275 
    276     /* Prepare variables: */
    277     QPoint mousePosition = pEvent->pos().toPoint();
    278     QString strHoveredAnchor;
    279     QString strHoveredAnchorRole;
    280 
    281     /* Search for hovered-anchor in the left list: */
    282     strHoveredAnchor = searchForHoveredAnchor(m_pPaintDevice, m_leftList, mousePosition);
    283     strHoveredAnchorRole = strHoveredAnchor.section(',', 0, 0);
    284     if (!strHoveredAnchor.isNull() && !m_restrictedAnchorRoles.contains(strHoveredAnchorRole))
    285     {
    286         m_strHoveredAnchor = strHoveredAnchor;
    287         return updateHoverStuff();
    288     }
    289 
    290     /* Then search for hovered-anchor in the right one: */
    291     strHoveredAnchor = searchForHoveredAnchor(m_pPaintDevice, m_rightList, mousePosition);
    292     strHoveredAnchorRole = strHoveredAnchor.section(',', 0, 0);
    293     if (!strHoveredAnchor.isNull() && !m_restrictedAnchorRoles.contains(strHoveredAnchorRole))
    294     {
    295         m_strHoveredAnchor = strHoveredAnchor;
    296         return updateHoverStuff();
    297     }
    298 
    299     /* Finally clear it for good: */
    300     if (!m_strHoveredAnchor.isNull())
    301     {
    302         m_strHoveredAnchor.clear();
    303         return updateHoverStuff();
    304     }
    305 }
    306 
    307 void UIGraphicsTextPane::updateHoverStuff()
    308 {
    309     /* Update mouse-cursor: */
    310     if (m_strHoveredAnchor.isNull())
    311         unsetCursor();
    312     else
    313         setCursor(Qt::PointingHandCursor);
    314 
    315     /* Update text-layout: */
    316     updateTextLayout();
    317 
    318     /* Update tool-tip: */
    319     setToolTip(m_strHoveredAnchor.section(',', -1));
    320 
    321     /* Update text-pane: */
    322     update();
    323 }
    324 
    325 void UIGraphicsTextPane::mousePressEvent(QGraphicsSceneMouseEvent*)
    326 {
    327     /* Make sure some anchor hovered: */
    328     if (m_strHoveredAnchor.isNull())
    329         return;
    330 
    331     /* Restrict anchor hovering: */
    332     m_fAnchorCanBeHovered = false;
    333 
    334     /* Cache clicked anchor: */
    335     QString strClickedAnchor = m_strHoveredAnchor;
    336 
    337     /* Clear hovered anchor: */
    338     m_strHoveredAnchor.clear();
    339     updateHoverStuff();
    340 
    341     /* Notify listeners about anchor clicked: */
    342     emit sigAnchorClicked(strClickedAnchor);
    343 
    344     /* Allow anchor hovering again: */
    345     m_fAnchorCanBeHovered = true;
    346 }
    347 
    348 void UIGraphicsTextPane::paint(QPainter *pPainter, const QStyleOptionGraphicsItem*, QWidget*)
    349 {
    350     /* Draw all the text-layouts: */
    351     foreach (QTextLayout *pTextLayout, m_leftList)
    352         pTextLayout->draw(pPainter, QPoint(0, 0));
    353     foreach (QTextLayout *pTextLayout, m_rightList)
    354         pTextLayout->draw(pPainter, QPoint(0, 0));
    355 }
    356 
    357 /* static  */
    358 QTextLayout* UIGraphicsTextPane::buildTextLayout(const QFont &font, QPaintDevice *pPaintDevice,
    359                                                  const QString &strText, int iWidth, int &iHeight,
    360                                                  const QString &strHoveredAnchor)
    361 {
    362     /* Prepare variables: */
    363     QFontMetrics fm(font, pPaintDevice);
    364     int iLeading = fm.leading();
    365 
    366     /* Parse incoming string with UIRichTextString capabilities: */
    367     //printf("Text: {%s}\n", strText.toAscii().constData());
    368     UIRichTextString ms(strText);
    369     ms.setHoveredAnchor(strHoveredAnchor);
    370 
    371     /* Create layout; */
    372     QTextLayout *pTextLayout = new QTextLayout(ms.toString(), font, pPaintDevice);
    373     pTextLayout->setAdditionalFormats(ms.formatRanges());
    374 
    375     /* Configure layout: */
    376     QTextOption textOption;
    377     textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
    378     pTextLayout->setTextOption(textOption);
    379 
    380     /* Build layout: */
    381     pTextLayout->beginLayout();
    382     while (1)
    383     {
    384         QTextLine line = pTextLayout->createLine();
    385         if (!line.isValid())
    386             break;
    387 
    388         line.setLineWidth(iWidth);
    389         iHeight += iLeading;
    390         line.setPosition(QPointF(0, iHeight));
    391         iHeight += line.height();
    392     }
    393     pTextLayout->endLayout();
    394 
    395     /* Return layout: */
    396     return pTextLayout;
    397 }
    398 
    399 /* static */
    400 QString UIGraphicsTextPane::searchForHoveredAnchor(QPaintDevice *pPaintDevice, const QList<QTextLayout*> &list, const QPoint &mousePosition)
    401 {
    402     /* Analyze passed text-layouts: */
    403     foreach (QTextLayout *pTextLayout, list)
    404     {
    405         /* Prepare variables: */
    406         QFontMetrics fm(pTextLayout->font(), pPaintDevice);
    407 
    408         /* Text-layout attributes: */
    409         const QPoint layoutPosition = pTextLayout->position().toPoint();
    410         const QString strLayoutText = pTextLayout->text();
    411 
    412         /* Enumerate format ranges: */
    413         foreach (const QTextLayout::FormatRange &range, pTextLayout->additionalFormats())
    414         {
    415             /* Skip unrelated formats: */
    416             if (!range.format.isAnchor())
    417                 continue;
    418 
    419             /* Parse 'anchor' format: */
    420             const int iStart = range.start;
    421             const int iLength = range.length;
    422             QRegion formatRegion;
    423             for (int iTextPosition = iStart; iTextPosition < iStart + iLength; ++iTextPosition)
    424             {
    425                 QTextLine layoutLine = pTextLayout->lineForTextPosition(iTextPosition);
    426                 QPoint linePosition = layoutLine.position().toPoint();
    427                 int iSymbolX = (int)layoutLine.cursorToX(iTextPosition);
    428                 QRect symbolRect = QRect(layoutPosition.x() + linePosition.x() + iSymbolX,
    429                                          layoutPosition.y() + linePosition.y(),
    430                                          fm.width(strLayoutText[iTextPosition]) + 1, fm.height());
    431                 formatRegion += symbolRect;
    432             }
    433 
    434             /* Is that something we looking for? */
    435             if (formatRegion.contains(mousePosition))
    436                 return range.format.anchorHref();
    437         }
    438     }
    439 
    440     /* Null string by default: */
    441     return QString();
    442 }
    443 
    44433
    44534const QString UIRichTextString::m_sstrAny = QString("[\\s\\S]*");
     
    47564    /* Add own string first: */
    47665    QString strString = m_strString;
     66
    47767    /* Add all the strings of children finally: */
    47868    foreach (const int &iPosition, m_strings.keys())
    47969        strString.insert(iPosition, m_strings.value(iPosition)->toString());
     70
    48071    /* Return result: */
    48172    return strString;
     
    48677    /* Prepare format range list: */
    48778    QList<QTextLayout::FormatRange> ranges;
     79
    48880    /* Add own format range first: */
    48981    QTextLayout::FormatRange range;
     
    50092    }
    50193    ranges.append(range);
     94
    50295    /* Add all the format ranges of children finally: */
    50396    foreach (const int &iPosition, m_strings.keys())
    50497        ranges.append(m_strings.value(iPosition)->formatRanges(iShift + iPosition));
     98
    50599    /* Return result: */
    506100    return ranges;
     
    511105    /* Define own hovered anchor first: */
    512106    m_strHoveredAnchor = strHoveredAnchor;
     107
    513108    /* Propagate hovered anchor to children finally: */
    514109    foreach (const int &iPosition, m_strings.keys())
  • trunk/src/VBox/Frontends/VirtualBox/src/objects/UIRichTextString.h

    r55476 r55477  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UIGraphicsTextPane class declaration.
     3 * VBox Qt GUI - UIRichTextString class declaration.
    44 */
    55
    66/*
    7  * Copyright (C) 2012-2014 Oracle Corporation
     7 * Copyright (C) 2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1616 */
    1717
    18 #ifndef ___UIGraphicsTextPane_h___
    19 #define ___UIGraphicsTextPane_h___
     18#ifndef ___UIRichTextString_h___
     19#define ___UIRichTextString_h___
    2020
    2121/* Qt includes: */
    2222#include <QTextLayout>
    2323
    24 /* GUI includes: */
    25 #include "QIGraphicsWidget.h"
    26 
    27 /* Typedefs: */
    28 typedef QPair<QString, QString> UITextTableLine;
    29 typedef QList<UITextTableLine> UITextTable;
    30 Q_DECLARE_METATYPE(UITextTable);
    31 
    32 /** QIGraphicsWidget reimplementation to draw QTextLayout content. */
    33 class UIGraphicsTextPane : public QIGraphicsWidget
    34 {
    35     Q_OBJECT;
    36 
    37 signals:
    38 
    39     /** Notifies listeners about size-hint changes. */
    40     void sigGeometryChanged();
    41 
    42     /** Notifies listeners about anchor clicked. */
    43     void sigAnchorClicked(const QString &strAnchor);
    44 
    45 public:
    46 
    47     /** Graphics text-pane constructor. */
    48     UIGraphicsTextPane(QIGraphicsWidget *pParent, QPaintDevice *pPaintDevice);
    49     /** Graphics text-pane destructor. */
    50     ~UIGraphicsTextPane();
    51 
    52     /** Returns whether contained text is empty. */
    53     bool isEmpty() const { return m_text.isEmpty(); }
    54     /** Returns contained text. */
    55     const UITextTable& text() const { return m_text; }
    56     /** Defines contained text. */
    57     void setText(const UITextTable &text);
    58 
    59     /** Defines whether passed @a strAnchorRole is @a fRestricted. */
    60     void setAnchorRoleRestricted(const QString &strAnchorRole, bool fRestricted);
    61 
    62 private:
    63 
    64     /** Update text-layout. */
    65     void updateTextLayout(bool fFull = false);
    66 
    67     /** Notifies listeners about size-hint changes. */
    68     void updateGeometry();
    69     /** Returns the size-hint to constrain the content. */
    70     QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
    71 
    72     /** This event handler is delivered after the widget has been resized. */
    73     void resizeEvent(QGraphicsSceneResizeEvent *pEvent);
    74 
    75     /** This event handler called when mouse hovers widget. */
    76     void hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent);
    77     /** This event handler called when mouse leaves widget. */
    78     void hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent);
    79     /** Summarize two hover-event handlers above. */
    80     void handleHoverEvent(QGraphicsSceneHoverEvent *pEvent);
    81     /** Update hover stuff. */
    82     void updateHoverStuff();
    83 
    84     /** This event handler called when mouse press widget. */
    85     void mousePressEvent(QGraphicsSceneMouseEvent *pEvent);
    86 
    87     /** Paints the contents in local coordinates. */
    88     void paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget = 0);
    89 
    90     /** Builds new text-layout. */
    91     static QTextLayout* buildTextLayout(const QFont &font, QPaintDevice *pPaintDevice,
    92                                         const QString &strText, int iWidth, int &iHeight,
    93                                         const QString &strHoveredAnchor);
    94 
    95     /** Search for hovered anchor in passed text-layout @a list. */
    96     static QString searchForHoveredAnchor(QPaintDevice *pPaintDevice, const QList<QTextLayout*> &list, const QPoint &mousePosition);
    97 
    98     /** Paint-device to scale to. */
    99     QPaintDevice *m_pPaintDevice;
    100 
    101     /** Margin. */
    102     const int m_iMargin;
    103     /** Spacing. */
    104     const int m_iSpacing;
    105     /** Minimum text-column width: */
    106     const int m_iMinimumTextColumnWidth;
    107 
    108     /** Minimum size-hint invalidation flag. */
    109     mutable bool m_fMinimumSizeHintInvalidated;
    110     /** Minimum size-hint cache. */
    111     mutable QSizeF m_minimumSizeHint;
    112     /** Minimum text-width. */
    113     int m_iMinimumTextWidth;
    114     /** Minimum text-height. */
    115     int m_iMinimumTextHeight;
    116 
    117     /** Contained text. */
    118     UITextTable m_text;
    119     /** Left text-layout list. */
    120     QList<QTextLayout*> m_leftList;
    121     /** Right text-layout list. */
    122     QList<QTextLayout*> m_rightList;
    123 
    124     /** Holds whether anchor can be hovered. */
    125     bool m_fAnchorCanBeHovered;
    126     /** Holds restricted anchor roles. */
    127     QSet<QString> m_restrictedAnchorRoles;
    128     /** Holds currently hovered anchor. */
    129     QString m_strHoveredAnchor;
    130 };
    131 
    13224/** Rich text string implementation which parses the passed QString
    133   * and holds it as the tree of the formatted rich text blocks.
    134   * @todo: To be moved into separate files. */
     25  * and holds it as the tree of the formatted rich text blocks. */
    13526class UIRichTextString
    13627{
     
    15041
    15142    /** Constructor taking passed QString.
    152       * @param strString     holds the QString being parsed and held as tree of rich text blocks,
     43      * @param strString     holds the string being parsed and held as the tree of rich text blocks,
    15344      * @param type          holds the type of <i>this</i> rich text block,
    154       * @param strStringMeta holds the QString containing meta data describing <i>this</i> rich text block. */
     45      * @param strStringMeta holds the string containing meta data describing <i>this</i> rich text block. */
    15546    UIRichTextString(const QString &strString, Type type = Type_None, const QString &strStringMeta = QString());
    15647
     
    16253
    16354    /** Returns the list of existing format ranges appropriate for QTextLayout.
    164       * @param iShift holds the shift of <i>this</i> rich text block accordig to it's parent. */
     55      * @param iShift holds the shift of <i>this</i> rich text block accordig to it's root. */
    16556    QList<QTextLayout::FormatRange> formatRanges(int iShift = 0) const;
    16657
    167     /** Defines the hovered anchor for <i>this</i> rich text block. */
     58    /** Defines the anchor to highlight in <i>this</i> rich text block and in it's children. */
    16859    void setHoveredAnchor(const QString &strHoveredAnchor);
    16960
     
    212103    QString m_strHoveredAnchor;
    213104
    214     /** Holds the 'any' string pattern. */
     105    /** Holds the <i>any</i> string pattern. */
    215106    static const QString m_sstrAny;
    216107    /** Holds the map of known patterns. */
     
    220111};
    221112
    222 #endif /* !___UIGraphicsTextPane_h___ */
     113#endif /* !___UIRichTextString_h___ */
    223114
  • trunk/src/VBox/Frontends/VirtualBox/src/widgets/graphics/UIGraphicsTextPane.cpp

    r55476 r55477  
    11/* $Id$ */
    22/** @file
    3  * VBox Qt GUI - UIGraphicsTextPane and UITask class implementation.
     3 * VBox Qt GUI - UIGraphicsTextPane class implementation.
    44 */
    55
    66/*
    7  * Copyright (C) 2012-2014 Oracle Corporation
     7 * Copyright (C) 2012-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2121
    2222/* Qt includes: */
    23 # include <QStack>
    2423# include <QPainter>
     24# include <QTextLayout>
    2525# include <QApplication>
    2626# include <QFontMetrics>
     
    2929/* GUI includes: */
    3030# include "UIGraphicsTextPane.h"
    31 
    32 /* Other VBox includes: */
    33 # include "iprt/assert.h"
     31# include "UIRichTextString.h"
    3432
    3533#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
     
    442440}
    443441
    444 
    445 const QString UIRichTextString::m_sstrAny = QString("[\\s\\S]*");
    446 const QMap<UIRichTextString::Type, QString> UIRichTextString::m_sPatterns = populatePatterns();
    447 const QMap<UIRichTextString::Type, bool> UIRichTextString::m_sPatternHasMeta = populatePatternHasMeta();
    448 
    449 UIRichTextString::UIRichTextString(Type type /* = Type_None */)
    450     : m_type(type)
    451     , m_strString(QString())
    452     , m_strStringMeta(QString())
    453 {
    454 }
    455 
    456 UIRichTextString::UIRichTextString(const QString &strString, Type type /* = Type_None */, const QString &strStringMeta /* = QString() */)
    457     : m_type(type)
    458     , m_strString(strString)
    459     , m_strStringMeta(strStringMeta)
    460 {
    461     //printf("Creating new UIRichTextString with string=\"%s\" and string-meta=\"%s\"\n",
    462     //       m_strString.toAscii().constData(), m_strStringMeta.toAscii().constData());
    463     parse();
    464 }
    465 
    466 UIRichTextString::~UIRichTextString()
    467 {
    468     /* Erase the map: */
    469     qDeleteAll(m_strings.begin(), m_strings.end());
    470     m_strings.clear();
    471 }
    472 
    473 QString UIRichTextString::toString() const
    474 {
    475     /* Add own string first: */
    476     QString strString = m_strString;
    477     /* Add all the strings of children finally: */
    478     foreach (const int &iPosition, m_strings.keys())
    479         strString.insert(iPosition, m_strings.value(iPosition)->toString());
    480     /* Return result: */
    481     return strString;
    482 }
    483 
    484 QList<QTextLayout::FormatRange> UIRichTextString::formatRanges(int iShift /* = 0 */) const
    485 {
    486     /* Prepare format range list: */
    487     QList<QTextLayout::FormatRange> ranges;
    488     /* Add own format range first: */
    489     QTextLayout::FormatRange range;
    490     range.start = iShift;
    491     range.length = toString().size();
    492     range.format = textCharFormat(m_type);
    493     /* Enable anchor if present: */
    494     if (!m_strAnchor.isNull())
    495     {
    496         range.format.setAnchorHref(m_strAnchor);
    497         /* Highlight anchor if hovered: */
    498         if (range.format.anchorHref() == m_strHoveredAnchor)
    499             range.format.setForeground(qApp->palette().color(QPalette::Link));
    500     }
    501     ranges.append(range);
    502     /* Add all the format ranges of children finally: */
    503     foreach (const int &iPosition, m_strings.keys())
    504         ranges.append(m_strings.value(iPosition)->formatRanges(iShift + iPosition));
    505     /* Return result: */
    506     return ranges;
    507 }
    508 
    509 void UIRichTextString::setHoveredAnchor(const QString &strHoveredAnchor)
    510 {
    511     /* Define own hovered anchor first: */
    512     m_strHoveredAnchor = strHoveredAnchor;
    513     /* Propagate hovered anchor to children finally: */
    514     foreach (const int &iPosition, m_strings.keys())
    515         m_strings.value(iPosition)->setHoveredAnchor(m_strHoveredAnchor);
    516 }
    517 
    518 void UIRichTextString::parse()
    519 {
    520     /* Assign the meta to anchor directly for now,
    521      * will do a separate parsing when there will
    522      * be more than one type of meta: */
    523     if (!m_strStringMeta.isNull())
    524         m_strAnchor = m_strStringMeta;
    525 
    526     /* Parse the passed QString with all the known patterns: */
    527     foreach (const Type &enmPattern, m_sPatterns.keys())
    528     {
    529         /* Get the current pattern: */
    530         const QString strPattern = m_sPatterns.value(enmPattern);
    531 
    532         /* Recursively parse the string: */
    533         int iMaxLevel = 0;
    534         do
    535         {
    536             /* Search for the maximum level of the current pattern: */
    537             iMaxLevel = searchForMaxLevel(m_strString, strPattern, strPattern);
    538             //printf(" Maximum level for the pattern \"%s\" is %d.\n",
    539             //       strPattern.toAscii().constData(), iMaxLevel);
    540             /* If current pattern of at least level 1 is found: */
    541             if (iMaxLevel > 0)
    542             {
    543                 /* Compose full pattern of the corresponding level: */
    544                 const QString strFullPattern = composeFullPattern(strPattern, strPattern, iMaxLevel);
    545                 //printf("  Full pattern: %s\n", strFullPattern.toAscii().constData());
    546                 QRegExp regExp(strFullPattern);
    547                 regExp.setMinimal(true);
    548                 const int iPosition = regExp.indexIn(m_strString);
    549                 AssertReturnVoid(iPosition != -1);
    550                 if (iPosition != -1)
    551                 {
    552                     /* Cut the found string: */
    553                     m_strString.remove(iPosition, regExp.cap(0).size());
    554                     /* And paste that string as our child: */
    555                     const bool fPatterHasMeta = m_sPatternHasMeta.value(enmPattern);
    556                     const QString strSubString = !fPatterHasMeta ? regExp.cap(1) : regExp.cap(2);
    557                     const QString strSubMeta   = !fPatterHasMeta ? QString()     : regExp.cap(1);
    558                     m_strings.insert(iPosition, new UIRichTextString(strSubString, enmPattern, strSubMeta));
    559                 }
    560             }
    561         }
    562         while (iMaxLevel > 0);
    563     }
    564 }
    565 
    566 /* static */
    567 QMap<UIRichTextString::Type, QString> UIRichTextString::populatePatterns()
    568 {
    569     QMap<Type, QString> patterns;
    570     patterns.insert(Type_Anchor, QString("<a href=([^>]+)>(%1)</a>"));
    571     patterns.insert(Type_Bold,   QString("<b>(%1)</b>"));
    572     patterns.insert(Type_Italic, QString("<i>(%1)</i>"));
    573     return patterns;
    574 }
    575 
    576 /* static */
    577 QMap<UIRichTextString::Type, bool> UIRichTextString::populatePatternHasMeta()
    578 {
    579     QMap<Type, bool> patternHasMeta;
    580     patternHasMeta.insert(Type_Anchor, true);
    581     patternHasMeta.insert(Type_Bold,   false);
    582     patternHasMeta.insert(Type_Italic, false);
    583     return patternHasMeta;
    584 }
    585 
    586 /* static */
    587 int UIRichTextString::searchForMaxLevel(const QString &strString, const QString &strPattern,
    588                                         const QString &strCurrentPattern, int iCurrentLevel /* = 0 */)
    589 {
    590     QRegExp regExp(strCurrentPattern.arg(m_sstrAny));
    591     regExp.setMinimal(true);
    592     if (regExp.indexIn(strString) != -1)
    593         return searchForMaxLevel(strString, strPattern,
    594                                  strCurrentPattern.arg(m_sstrAny + strPattern + m_sstrAny),
    595                                  iCurrentLevel + 1);
    596     return iCurrentLevel;
    597 }
    598 
    599 /* static */
    600 QString UIRichTextString::composeFullPattern(const QString &strPattern,
    601                                              const QString &strCurrentPattern, int iCurrentLevel)
    602 {
    603     if (iCurrentLevel > 1)
    604         return composeFullPattern(strPattern,
    605                                   strCurrentPattern.arg(m_sstrAny + strPattern + m_sstrAny),
    606                                   iCurrentLevel - 1);
    607     return strCurrentPattern.arg(m_sstrAny);
    608 }
    609 
    610 /* static */
    611 QTextCharFormat UIRichTextString::textCharFormat(Type type)
    612 {
    613     QTextCharFormat format;
    614     switch (type)
    615     {
    616         case Type_Anchor:
    617         {
    618             format.setAnchor(true);
    619             break;
    620         }
    621         case Type_Bold:
    622         {
    623             QFont font = format.font();
    624             font.setBold(true);
    625             format.setFont(font);
    626             break;
    627         }
    628         case Type_Italic:
    629         {
    630             QFont font = format.font();
    631             font.setItalic(true);
    632             format.setFont(font);
    633             break;
    634         }
    635     }
    636     return format;
    637 }
    638 
  • trunk/src/VBox/Frontends/VirtualBox/src/widgets/graphics/UIGraphicsTextPane.h

    r55476 r55477  
    55
    66/*
    7  * Copyright (C) 2012-2014 Oracle Corporation
     7 * Copyright (C) 2012-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1919#define ___UIGraphicsTextPane_h___
    2020
    21 /* Qt includes: */
    22 #include <QTextLayout>
    23 
    2421/* GUI includes: */
    2522#include "QIGraphicsWidget.h"
     23
     24/* Forward declarations: */
     25class QTextLayout;
    2626
    2727/* Typedefs: */
     
    130130};
    131131
    132 /** Rich text string implementation which parses the passed QString
    133   * and holds it as the tree of the formatted rich text blocks.
    134   * @todo: To be moved into separate files. */
    135 class UIRichTextString
    136 {
    137 public:
    138 
    139     /** Rich text block types. */
    140     enum Type
    141     {
    142         Type_None,
    143         Type_Anchor,
    144         Type_Bold,
    145         Type_Italic,
    146     };
    147 
    148     /** Default (empty) constructor. */
    149     UIRichTextString(Type type = Type_None);
    150 
    151     /** Constructor taking passed QString.
    152       * @param strString     holds the QString being parsed and held as tree of rich text blocks,
    153       * @param type          holds the type of <i>this</i> rich text block,
    154       * @param strStringMeta holds the QString containing meta data describing <i>this</i> rich text block. */
    155     UIRichTextString(const QString &strString, Type type = Type_None, const QString &strStringMeta = QString());
    156 
    157     /** Destructor. */
    158     ~UIRichTextString();
    159 
    160     /** Returns the QString representation. */
    161     QString toString() const;
    162 
    163     /** Returns the list of existing format ranges appropriate for QTextLayout.
    164       * @param iShift holds the shift of <i>this</i> rich text block accordig to it's parent. */
    165     QList<QTextLayout::FormatRange> formatRanges(int iShift = 0) const;
    166 
    167     /** Defines the hovered anchor for <i>this</i> rich text block. */
    168     void setHoveredAnchor(const QString &strHoveredAnchor);
    169 
    170 private:
    171 
    172     /** Parses the string. */
    173     void parse();
    174 
    175     /** Used to populate const static map of known patterns.
    176       * @note Keep it sync with the method below - #populatePatternHasMeta(). */
    177     static QMap<Type, QString> populatePatterns();
    178     /** Used to populate const static map of meta flags for the known patterns.
    179       * @note Keep it sync with the method above - #populatePatterns(). */
    180     static QMap<Type, bool> populatePatternHasMeta();
    181 
    182     /** Recursively searching for the maximum level of the passed pattern.
    183       * @param strString         holds the string to check for the current (recursively advanced) pattern in,
    184       * @param strPattern        holds the etalon pattern to recursively advance the current pattern with,
    185       * @param strCurrentPattern holds the current (recursively advanced) pattern to check for the presence of,
    186       * @param iCurrentLevel     holds the current level of the recursively advanced pattern. */
    187     static int searchForMaxLevel(const QString &strString, const QString &strPattern,
    188                                  const QString &strCurrentPattern, int iCurrentLevel = 0);
    189 
    190     /** Recursively composing the pattern of the maximum level.
    191       * @param strPattern        holds the etalon pattern to recursively update the current pattern with,
    192       * @param strCurrentPattern holds the current (recursively advanced) pattern,
    193       * @param iCurrentLevel     holds the amount of the levels left to recursively advance current pattern. */
    194     static QString composeFullPattern(const QString &strPattern,
    195                                       const QString &strCurrentPattern, int iCurrentLevel);
    196 
    197     /** Composes the QTextCharFormat correpoding to passed @a type. */
    198     static QTextCharFormat textCharFormat(Type type);
    199 
    200     /** Holds the type of <i>this</i> rich text block. */
    201     Type m_type;
    202     /** Holds the string of <i>this</i> rich text block. */
    203     QString m_strString;
    204     /** Holds the string meta data of <i>this</i> rich text block. */
    205     QString m_strStringMeta;
    206     /** Holds the children of <i>this</i> rich text block. */
    207     QMap<int, UIRichTextString*> m_strings;
    208 
    209     /** Holds the anchor of <i>this</i> rich text block. */
    210     QString m_strAnchor;
    211     /** Holds the anchor to highlight in <i>this</i> rich text block and in it's children. */
    212     QString m_strHoveredAnchor;
    213 
    214     /** Holds the 'any' string pattern. */
    215     static const QString m_sstrAny;
    216     /** Holds the map of known patterns. */
    217     static const QMap<Type, QString> m_sPatterns;
    218     /** Holds the map of meta flags for the known patterns. */
    219     static const QMap<Type, bool> m_sPatternHasMeta;
    220 };
    221 
    222132#endif /* !___UIGraphicsTextPane_h___ */
    223133
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette