VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/extensions/QILineEdit.cpp

Last change on this file was 104041, checked in by vboxsync, 8 weeks ago

FE/Qt: bugref:6899: Accessibility improvement for UIMarkableLineEdit; This wrapper should now redirect tool-tip assigned to wrapped line-edit, VoiceOver likes that one.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
Line 
1/* $Id: QILineEdit.cpp 104041 2024-03-25 14:24:04Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - Qt extensions: QILineEdit class implementation.
4 */
5
6/*
7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QApplication>
30#include <QClipboard>
31#include <QContextMenuEvent>
32#include <QHBoxLayout>
33#include <QLabel>
34#include <QMenu>
35#include <QStyleOptionFrame>
36
37/* GUI includes: */
38#include "QILineEdit.h"
39#include "UIDesktopWidgetWatchdog.h"
40#include "UIIconPool.h"
41
42/* Other VBox includes: */
43#include "iprt/assert.h"
44
45
46QILineEdit::QILineEdit(QWidget *pParent /* = 0 */)
47 : QLineEdit(pParent)
48 , m_fAllowToCopyContentsWhenDisabled(false)
49 , m_pCopyAction(0)
50 , m_pIconLabel(0)
51 , m_fMarkForError(false)
52{
53 prepare();
54}
55
56QILineEdit::QILineEdit(const QString &strText, QWidget *pParent /* = 0 */)
57 : QLineEdit(strText, pParent)
58 , m_fAllowToCopyContentsWhenDisabled(false)
59 , m_pCopyAction(0)
60 , m_pIconLabel(0)
61 , m_fMarkForError(false)
62{
63 prepare();
64}
65
66void QILineEdit::setAllowToCopyContentsWhenDisabled(bool fAllow)
67{
68 m_fAllowToCopyContentsWhenDisabled = fAllow;
69}
70
71void QILineEdit::setMinimumWidthByText(const QString &strText)
72{
73 setMinimumWidth(fitTextWidth(strText).width());
74}
75
76void QILineEdit::setFixedWidthByText(const QString &strText)
77{
78 setFixedWidth(fitTextWidth(strText).width());
79}
80
81void QILineEdit::mark(bool fError, const QString &strErrorMessage /* = QString() */)
82{
83 /* Check if something really changed: */
84 if (fError == m_fMarkForError && m_strErrorMessage == strErrorMessage)
85 return;
86
87 /* Save new values: */
88 m_fMarkForError = fError;
89 m_strErrorMessage = strErrorMessage;
90
91 /* Update accordingly: */
92 if (m_fMarkForError)
93 {
94 /* Create label if absent: */
95 if (!m_pIconLabel)
96 m_pIconLabel = new QLabel(this);
97
98 /* Update label content, visibility & position: */
99 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) * .625;
100 const int iShift = height() > iIconMetric ? (height() - iIconMetric) / 2 : 0;
101 const qreal fDevicePixelRatio = window() && window()->windowHandle() ? window()->windowHandle()->devicePixelRatio() : 1;
102 m_pIconLabel->setPixmap(m_markIcon.pixmap(QSize(iIconMetric, iIconMetric), fDevicePixelRatio));
103 m_pIconLabel->setToolTip(m_strErrorMessage);
104 m_pIconLabel->move(width() - iIconMetric - iShift, iShift);
105 m_pIconLabel->show();
106 }
107 else
108 {
109 /* Hide label: */
110 if (m_pIconLabel)
111 m_pIconLabel->hide();
112 }
113}
114
115bool QILineEdit::event(QEvent *pEvent)
116{
117 switch (pEvent->type())
118 {
119 case QEvent::ContextMenu:
120 {
121 /* For disabled widget if requested: */
122 if (!isEnabled() && m_fAllowToCopyContentsWhenDisabled)
123 {
124 /* Create a context menu for the copy to clipboard action: */
125 QContextMenuEvent *pContextMenuEvent = static_cast<QContextMenuEvent*>(pEvent);
126 QMenu menu;
127 m_pCopyAction->setText(tr("&Copy"));
128 menu.addAction(m_pCopyAction);
129 menu.exec(pContextMenuEvent->globalPos());
130 pEvent->accept();
131 }
132 break;
133 }
134 default:
135 break;
136 }
137 return QLineEdit::event(pEvent);
138}
139
140void QILineEdit::resizeEvent(QResizeEvent *pResizeEvent)
141{
142 /* Call to base-class: */
143 QLineEdit::resizeEvent(pResizeEvent);
144
145 /* Update error label position: */
146 if (m_pIconLabel)
147 {
148 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) * .625;
149 const int iShift = height() > iIconMetric ? (height() - iIconMetric) / 2 : 0;
150 m_pIconLabel->move(width() - iIconMetric - iShift, iShift);
151 }
152}
153
154void QILineEdit::copy()
155{
156 /* Copy the current text to the global and selection clipboards: */
157 QApplication::clipboard()->setText(text(), QClipboard::Clipboard);
158 QApplication::clipboard()->setText(text(), QClipboard::Selection);
159}
160
161void QILineEdit::prepare()
162{
163 /* Prepare invisible copy action: */
164 m_pCopyAction = new QAction(this);
165 if (m_pCopyAction)
166 {
167 m_pCopyAction->setShortcut(QKeySequence(QKeySequence::Copy));
168 m_pCopyAction->setShortcutContext(Qt::WidgetShortcut);
169 connect(m_pCopyAction, &QAction::triggered, this, &QILineEdit::copy);
170 addAction(m_pCopyAction);
171 }
172
173 /* Prepare warning icon: */
174 m_markIcon = UIIconPool::iconSet(":/status_error_16px.png");
175}
176
177QSize QILineEdit::fitTextWidth(const QString &strText) const
178{
179 QStyleOptionFrame sof;
180 sof.initFrom(this);
181 sof.rect = contentsRect();
182 sof.lineWidth = hasFrame() ? style()->pixelMetric(QStyle::PM_DefaultFrameWidth) : 0;
183 sof.midLineWidth = 0;
184 sof.state |= QStyle::State_Sunken;
185
186 /** @todo make it wise.. */
187 // WORKAROUND:
188 // The margins are based on qlineedit.cpp of Qt.
189 // Maybe they where changed at some time in the future.
190#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
191 QSize sc(fontMetrics().horizontalAdvance(strText) + 2 * 2,
192 fontMetrics().xHeight() + 2 * 1);
193#else
194 QSize sc(fontMetrics().width(strText) + 2 * 2,
195 fontMetrics().xHeight() + 2 * 1);
196#endif
197 const QSize sa = style()->sizeFromContents(QStyle::CT_LineEdit, &sof, sc, this);
198
199 return sa;
200}
201
202UIMarkableLineEdit::UIMarkableLineEdit(QWidget *pParent /* = 0 */)
203 :QWidget(pParent)
204 , m_pLineEdit(0)
205 , m_pIconLabel(0)
206{
207 prepare();
208}
209
210void UIMarkableLineEdit::setText(const QString &strText)
211{
212 if (m_pLineEdit)
213 m_pLineEdit->setText(strText);
214}
215
216void UIMarkableLineEdit::setToolTip(const QString &strText)
217{
218 if (m_pLineEdit)
219 m_pLineEdit->setToolTip(strText);
220}
221
222QString UIMarkableLineEdit::text() const
223{
224 if (!m_pLineEdit)
225 return QString();
226 return m_pLineEdit->text();
227}
228
229void UIMarkableLineEdit::setValidator(const QValidator *pValidator)
230{
231 if (m_pLineEdit)
232 m_pLineEdit->setValidator(pValidator);
233}
234
235bool UIMarkableLineEdit::hasAcceptableInput() const
236{
237 if (!m_pLineEdit)
238 return false;
239 return m_pLineEdit->hasAcceptableInput();
240}
241
242void UIMarkableLineEdit::setPlaceholderText(const QString &strText)
243{
244 if (m_pLineEdit)
245 m_pLineEdit->setPlaceholderText(strText);
246}
247
248void UIMarkableLineEdit::mark(bool fError, const QString &strErrorMessage /* = QString() */)
249{
250 AssertPtrReturnVoid(m_pIconLabel);
251 m_pIconLabel->setVisible(true);
252 const QIcon icon = fError ? UIIconPool::iconSet(":/status_error_16px.png") : UIIconPool::iconSet(":/status_check_16px.png");
253 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
254 const qreal fDevicePixelRatio = gpDesktop->devicePixelRatio(m_pIconLabel);
255 m_pIconLabel->setPixmap(icon.pixmap(QSize(iIconMetric, iIconMetric), fDevicePixelRatio));
256 m_pIconLabel->setToolTip(strErrorMessage);
257}
258
259void UIMarkableLineEdit::prepare()
260{
261 QHBoxLayout *pMainLayout = new QHBoxLayout(this);
262 AssertReturnVoid(pMainLayout);
263 pMainLayout->setContentsMargins(0, 0, 0, 0);
264 m_pLineEdit = new QILineEdit;
265 AssertReturnVoid(m_pLineEdit);
266 m_pIconLabel = new QLabel;
267 AssertReturnVoid(m_pIconLabel);
268 /* Show the icon label only if line edit is marked for error/no error.*/
269 m_pIconLabel->hide();
270 pMainLayout->addWidget(m_pLineEdit);
271 pMainLayout->addWidget(m_pIconLabel);
272 setFocusProxy(m_pLineEdit);
273 connect(m_pLineEdit, &QILineEdit::textChanged, this, &UIMarkableLineEdit::textChanged);
274}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use