Changeset 55477 in vbox for trunk/src/VBox
- Timestamp:
- Apr 28, 2015 10:50:05 AM (10 years ago)
- 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 153 153 ./src/globals \ 154 154 ./src/medium \ 155 ./src/objects \ 155 156 ./src/platform \ 156 157 ./src/platform/darwin \ … … 579 580 src/medium/UIMediumEnumerator.cpp \ 580 581 src/medium/UIMediumManager.cpp \ 582 src/objects/UIRichTextString.cpp \ 581 583 src/runtime/UIActionPoolRuntime.cpp \ 582 584 src/runtime/UIAddDiskEncryptionPasswordDialog.cpp \ -
trunk/src/VBox/Frontends/VirtualBox/src/objects/UIRichTextString.cpp
r55476 r55477 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UI GraphicsTextPane and UITaskclass implementation.3 * VBox Qt GUI - UIRichTextString class implementation. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 201 2-2014Oracle Corporation7 * Copyright (C) 2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 21 21 22 22 /* Qt includes: */ 23 # include <QStack>24 # include <QPainter>25 23 # include <QApplication> 26 # include <QFontMetrics> 27 # include <QGraphicsSceneHoverEvent> 24 # include <QPalette> 28 25 29 26 /* GUI includes: */ 30 # include "UI GraphicsTextPane.h"27 # include "UIRichTextString.h" 31 28 32 29 /* Other VBox includes: */ … … 34 31 35 32 #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 else79 {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 else105 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 else155 {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() */) const230 {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 else313 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 444 33 445 34 const QString UIRichTextString::m_sstrAny = QString("[\\s\\S]*"); … … 475 64 /* Add own string first: */ 476 65 QString strString = m_strString; 66 477 67 /* Add all the strings of children finally: */ 478 68 foreach (const int &iPosition, m_strings.keys()) 479 69 strString.insert(iPosition, m_strings.value(iPosition)->toString()); 70 480 71 /* Return result: */ 481 72 return strString; … … 486 77 /* Prepare format range list: */ 487 78 QList<QTextLayout::FormatRange> ranges; 79 488 80 /* Add own format range first: */ 489 81 QTextLayout::FormatRange range; … … 500 92 } 501 93 ranges.append(range); 94 502 95 /* Add all the format ranges of children finally: */ 503 96 foreach (const int &iPosition, m_strings.keys()) 504 97 ranges.append(m_strings.value(iPosition)->formatRanges(iShift + iPosition)); 98 505 99 /* Return result: */ 506 100 return ranges; … … 511 105 /* Define own hovered anchor first: */ 512 106 m_strHoveredAnchor = strHoveredAnchor; 107 513 108 /* Propagate hovered anchor to children finally: */ 514 109 foreach (const int &iPosition, m_strings.keys()) -
trunk/src/VBox/Frontends/VirtualBox/src/objects/UIRichTextString.h
r55476 r55477 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UI GraphicsTextPaneclass declaration.3 * VBox Qt GUI - UIRichTextString class declaration. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 201 2-2014Oracle Corporation7 * Copyright (C) 2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 16 16 */ 17 17 18 #ifndef ___UI GraphicsTextPane_h___19 #define ___UI GraphicsTextPane_h___18 #ifndef ___UIRichTextString_h___ 19 #define ___UIRichTextString_h___ 20 20 21 21 /* Qt includes: */ 22 22 #include <QTextLayout> 23 23 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 QIGraphicsWidget34 {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 132 24 /** 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. */ 135 26 class UIRichTextString 136 27 { … … 150 41 151 42 /** Constructor taking passed QString. 152 * @param strString holds the QString being parsed and held astree of rich text blocks,43 * @param strString holds the string being parsed and held as the tree of rich text blocks, 153 44 * @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. */ 155 46 UIRichTextString(const QString &strString, Type type = Type_None, const QString &strStringMeta = QString()); 156 47 … … 162 53 163 54 /** 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. */ 165 56 QList<QTextLayout::FormatRange> formatRanges(int iShift = 0) const; 166 57 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. */ 168 59 void setHoveredAnchor(const QString &strHoveredAnchor); 169 60 … … 212 103 QString m_strHoveredAnchor; 213 104 214 /** Holds the 'any'string pattern. */105 /** Holds the <i>any</i> string pattern. */ 215 106 static const QString m_sstrAny; 216 107 /** Holds the map of known patterns. */ … … 220 111 }; 221 112 222 #endif /* !___UI GraphicsTextPane_h___ */113 #endif /* !___UIRichTextString_h___ */ 223 114 -
trunk/src/VBox/Frontends/VirtualBox/src/widgets/graphics/UIGraphicsTextPane.cpp
r55476 r55477 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UIGraphicsTextPane and UITaskclass implementation.3 * VBox Qt GUI - UIGraphicsTextPane class implementation. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2012-201 4Oracle Corporation7 * Copyright (C) 2012-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 21 21 22 22 /* Qt includes: */ 23 # include <QStack>24 23 # include <QPainter> 24 # include <QTextLayout> 25 25 # include <QApplication> 26 26 # include <QFontMetrics> … … 29 29 /* GUI includes: */ 30 30 # include "UIGraphicsTextPane.h" 31 32 /* Other VBox includes: */ 33 # include "iprt/assert.h" 31 # include "UIRichTextString.h" 34 32 35 33 #endif /* !VBOX_WITH_PRECOMPILED_HEADERS */ … … 442 440 } 443 441 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() const474 {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 */) const485 {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 will522 * 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 do535 {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 5 5 6 6 /* 7 * Copyright (C) 2012-201 4Oracle Corporation7 * Copyright (C) 2012-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 19 19 #define ___UIGraphicsTextPane_h___ 20 20 21 /* Qt includes: */22 #include <QTextLayout>23 24 21 /* GUI includes: */ 25 22 #include "QIGraphicsWidget.h" 23 24 /* Forward declarations: */ 25 class QTextLayout; 26 26 27 27 /* Typedefs: */ … … 130 130 }; 131 131 132 /** Rich text string implementation which parses the passed QString133 * and holds it as the tree of the formatted rich text blocks.134 * @todo: To be moved into separate files. */135 class UIRichTextString136 {137 public:138 139 /** Rich text block types. */140 enum Type141 {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 222 132 #endif /* !___UIGraphicsTextPane_h___ */ 223 133
Note:
See TracChangeset
for help on using the changeset viewer.