VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/extensions/QILabel.cpp@ 82781

Last change on this file since 82781 was 76606, checked in by vboxsync, 5 years ago

FE/Qt: Cleaning out old precompiled header experiment.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1/* $Id: QILabel.cpp 76606 2019-01-02 05:40:39Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - Qt extensions: QILabel class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*
19 * This class is based on the original QLabel implementation.
20 */
21
22/* Qt includes: */
23#include <QApplication>
24#include <QClipboard>
25#include <QContextMenuEvent>
26#include <QDrag>
27#include <QFocusEvent>
28#include <QMenu>
29#include <QMimeData>
30#include <QMouseEvent>
31#include <QPainter>
32#include <QStyleOptionFocusRect>
33
34/* GUI includes: */
35#include "QILabel.h"
36
37/* Type definitions: */
38#define HOR_PADDING 1
39
40
41/* static */
42const QRegExp QILabel::s_regExpCopy = QRegExp("<[^>]*>");
43QRegExp QILabel::s_regExpElide = QRegExp("(<compact\\s+elipsis=\"(start|middle|end)\"?>([^<]*)</compact>)");
44
45QILabel::QILabel(QWidget *pParent /* = 0 */, Qt::WindowFlags enmFlags /* = 0 */)
46 : QLabel(pParent, enmFlags)
47{
48 init();
49}
50
51QILabel::QILabel(const QString &strText, QWidget *pParent /* = 0 */, Qt::WindowFlags enmFlags /* = 0 */)
52 : QLabel(pParent, enmFlags)
53{
54 init();
55 setFullText(strText);
56}
57
58void QILabel::setFullSizeSelection(bool fEnabled)
59{
60 /* Remember new value: */
61 m_fFullSizeSelection = fEnabled;
62 if (m_fFullSizeSelection)
63 {
64 /* Enable mouse interaction only */
65 setTextInteractionFlags(Qt::LinksAccessibleByMouse);
66 /* The label should be able to get the focus */
67 setFocusPolicy(Qt::StrongFocus);
68 /* Change the appearance in the focus state a little bit.
69 * Note: Unfortunately QLabel, precisely the text of a QLabel isn't
70 * styleable. The trolls have forgotten the simplest case ... So this
71 * is done by changing the currently used palette in the In/Out-focus
72 * events below. Next broken feature is drawing a simple dotted line
73 * around the label. So this is done manually in the paintEvent. Not
74 * sure if the stylesheet stuff is ready for production environments. */
75 setStyleSheet(QString("QLabel::focus {\
76 background-color: palette(highlight);\
77 }\
78 QLabel {\
79 padding: 0px %1px 0px %1px;\
80 }").arg(HOR_PADDING));
81 }
82 else
83 {
84 /* Text should be selectable/copyable */
85 setTextInteractionFlags(Qt::TextBrowserInteraction);
86 /* No Focus an the label */
87 setFocusPolicy(Qt::NoFocus);
88 /* No focus style change */
89 setStyleSheet("");
90 }
91}
92
93void QILabel::useSizeHintForWidth(int iWidthHint) const
94{
95 /* Remember new value: */
96 m_iWidthHint = iWidthHint;
97 updateSizeHint();
98}
99
100QSize QILabel::sizeHint() const
101{
102 /* Update size-hint if it's invalid: */
103 if (!m_fHintValid)
104 updateSizeHint();
105
106 /* If there is an updated sizeHint() present - using it: */
107 return m_ownSizeHint.isValid() ? m_ownSizeHint : QLabel::sizeHint();
108}
109
110QSize QILabel::minimumSizeHint() const
111{
112 /* Update size-hint if it's invalid: */
113 if (!m_fHintValid)
114 updateSizeHint();
115
116 /* If there is an updated minimumSizeHint() present - using it. */
117 return m_ownSizeHint.isValid() ? m_ownSizeHint : QLabel::minimumSizeHint();
118}
119
120void QILabel::clear()
121{
122 QLabel::clear();
123 setFullText("");
124}
125
126void QILabel::setText(const QString &strText)
127{
128 /* Call to wrapper below: */
129 setFullText(strText);
130
131 /* If QILabel forced to be fixed vertically */
132 if (minimumHeight() == maximumHeight())
133 {
134 /* Check if new text requires label growing */
135 QSize sh(width(), heightForWidth(width()));
136 if (sh.height() > minimumHeight())
137 setFixedHeight(sh.height());
138 }
139}
140
141void QILabel::copy()
142{
143 /* Strip the text of all HTML subsets: */
144 QString strText = removeHtmlTags(m_strText);
145 /* Copy the current text to the global and selection clipboard. */
146 QApplication::clipboard()->setText(strText, QClipboard::Clipboard);
147 QApplication::clipboard()->setText(strText, QClipboard::Selection);
148}
149
150void QILabel::resizeEvent(QResizeEvent *pEvent)
151{
152 /* Call to base-class: */
153 QLabel::resizeEvent(pEvent);
154 /* Recalculate the elipsis of the text after every resize. */
155 updateText();
156}
157
158void QILabel::mousePressEvent(QMouseEvent *pEvent)
159{
160 /* Start dragging: */
161 if (pEvent->button() == Qt::LeftButton && geometry().contains(pEvent->pos()) && m_fFullSizeSelection)
162 m_fStartDragging = true;
163 /* Call to base-class: */
164 else
165 QLabel::mousePressEvent(pEvent);
166}
167
168void QILabel::mouseReleaseEvent(QMouseEvent *pEvent)
169{
170 /* Reset dragging: */
171 m_fStartDragging = false;
172 /* Call to base-class: */
173 QLabel::mouseReleaseEvent(pEvent);
174}
175
176void QILabel::mouseMoveEvent(QMouseEvent *pEvent)
177{
178 /* If we have an order to start dragging: */
179 if (m_fStartDragging)
180 {
181 /* Reset dragging: */
182 m_fStartDragging = false;
183 /* Create a drag object out of the given data: */
184 QDrag *pDrag = new QDrag(this);
185 QMimeData *pMimeData = new QMimeData;
186 pMimeData->setText(removeHtmlTags(m_strText));
187 pDrag->setMimeData(pMimeData);
188 /* Start the dragging finally: */
189 pDrag->exec();
190 }
191 /* Call to base-class: */
192 else
193 QLabel::mouseMoveEvent(pEvent);
194}
195
196void QILabel::contextMenuEvent(QContextMenuEvent *pEvent)
197{
198 /* If we have an order for full-size selection: */
199 if (m_fFullSizeSelection)
200 {
201 /* Create a context menu for the copy to clipboard action: */
202 QMenu menu;
203 m_pCopyAction->setText(tr("&Copy"));
204 menu.addAction(m_pCopyAction);
205 menu.exec(pEvent->globalPos());
206 }
207 /* Call to base-class: */
208 else
209 QLabel::contextMenuEvent(pEvent);
210}
211
212void QILabel::focusInEvent(QFocusEvent *)
213{
214 /* If we have an order for full-size selection: */
215 if (m_fFullSizeSelection)
216 {
217 /* Set the text color to the current used highlight text color: */
218 QPalette pal = qApp->palette();
219 pal.setBrush(QPalette::WindowText, pal.brush(QPalette::HighlightedText));
220 setPalette(pal);
221 }
222}
223
224void QILabel::focusOutEvent(QFocusEvent *pEvent)
225{
226 /* Reset to the default palette: */
227 if (m_fFullSizeSelection && pEvent->reason() != Qt::PopupFocusReason)
228 setPalette(qApp->palette());
229}
230
231void QILabel::paintEvent(QPaintEvent *pEvent)
232{
233 /* Call to base-class: */
234 QLabel::paintEvent(pEvent);
235
236 /* If we have an order for full-size selection and have focus: */
237 if (m_fFullSizeSelection && hasFocus())
238 {
239 /* Paint a focus rect based on the current style: */
240 QPainter painter(this);
241 QStyleOptionFocusRect option;
242 option.initFrom(this);
243 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this);
244 }
245}
246
247void QILabel::init()
248{
249 /* Initial setup: */
250 m_fHintValid = false;
251 m_iWidthHint = -1;
252 m_fStartDragging = false;
253 setFullSizeSelection(false);
254 setOpenExternalLinks(true);
255
256 /* Create invisible copy action: */
257 m_pCopyAction = new QAction(this);
258 if (m_pCopyAction)
259 {
260 /* Configure action: */
261 m_pCopyAction->setShortcut(QKeySequence(QKeySequence::Copy));
262 m_pCopyAction->setShortcutContext(Qt::WidgetShortcut);
263 connect(m_pCopyAction, &QAction::triggered, this, &QILabel::copy);
264 /* Add action to label: */
265 addAction(m_pCopyAction);
266 }
267}
268
269void QILabel::updateSizeHint() const
270{
271 /* Recalculate size-hint if necessary: */
272 m_ownSizeHint = m_iWidthHint == -1 ? QSize() : QSize(m_iWidthHint, heightForWidth(m_iWidthHint));
273 m_fHintValid = true;
274}
275
276void QILabel::setFullText(const QString &strText)
277{
278 /* Reapply size-policy: */
279 QSizePolicy sp = sizePolicy();
280 sp.setHeightForWidth(wordWrap());
281 setSizePolicy(sp);
282
283 /* Reset size-hint validity: */
284 m_fHintValid = false;
285
286 /* Remember new value: */
287 m_strText = strText;
288 updateText();
289}
290
291void QILabel::updateText()
292{
293 /* Compress text: */
294 const QString strCompText = compressText(m_strText);
295
296 /* Assign it: */
297 QLabel::setText(strCompText);
298
299 /* Only set the tool-tip if the text is shortened in any way: */
300 if (removeHtmlTags(strCompText) != removeHtmlTags(m_strText))
301 setToolTip(removeHtmlTags(m_strText));
302 else
303 setToolTip("");
304}
305
306QString QILabel::compressText(const QString &strText) const
307{
308 /* Prepare result: */
309 QStringList result;
310 QFontMetrics fm = fontMetrics();
311 /* Split up any multi-line text: */
312 foreach (QString strLine, strText.split(QRegExp("<br */?>")))
313 {
314 /* Search for the compact tag: */
315 if (s_regExpElide.indexIn(strLine) > -1)
316 {
317 /* USe the untouchable text to work on: */
318 const QString strWork = strLine;
319 /* Grep out the necessary info of the regexp: */
320 const QString strCompact = s_regExpElide.cap(1);
321 const QString strElideMode = s_regExpElide.cap(2);
322 const QString strElide = s_regExpElide.cap(3);
323 /* Remove the whole compact tag (also the text): */
324 const QString strFlat = removeHtmlTags(QString(strWork).remove(strCompact));
325 /* What size will the text have without the compact text: */
326 const int iFlatWidth = fm.width(strFlat);
327 /* Create the shortened text: */
328 const QString strNew = fm.elidedText(strElide, toTextElideMode(strElideMode), width() - (2 * HOR_PADDING) - iFlatWidth);
329 /* Replace the compact part with the shortened text in the initial string: */
330 strLine = QString(strWork).replace(strCompact, strNew);
331 }
332 /* Append the line: */
333 result << strLine;
334 }
335 /* Return result: */
336 return result.join("<br />");
337}
338
339/* static */
340QString QILabel::removeHtmlTags(const QString &strText)
341{
342 /* Remove all HTML tags from the text and return it: */
343 return QString(strText).remove(s_regExpCopy);
344}
345
346/* static */
347Qt::TextElideMode QILabel::toTextElideMode(const QString &strType)
348{
349 /* Converts a string-represented type to a Qt elide mode: */
350 Qt::TextElideMode enmMode = Qt::ElideNone;
351 if (strType == "start")
352 enmMode = Qt::ElideLeft;
353 else if (strType == "middle")
354 enmMode = Qt::ElideMiddle;
355 else if (strType == "end")
356 enmMode = Qt::ElideRight;
357 return enmMode;
358}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use