Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
complexwidgets.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "complexwidgets_p.h"
5
6#include <qaccessible.h>
7#include <qapplication.h>
8#include <qevent.h>
9#if QT_CONFIG(itemviews)
10#include <qheaderview.h>
11#endif
12#if QT_CONFIG(tabbar)
13#include <qtabbar.h>
14#include <private/qtabbar_p.h>
15#endif
16#if QT_CONFIG(combobox)
17#include <qcombobox.h>
18#endif
19#if QT_CONFIG(lineedit)
20#include <qlineedit.h>
21#endif
22#include <qstyle.h>
23#include <qstyleoption.h>
24#if QT_CONFIG(tooltip)
25#include <qtooltip.h>
26#endif
27#if QT_CONFIG(whatsthis)
28#include <qwhatsthis.h>
29#endif
30#include <QAbstractScrollArea>
31#if QT_CONFIG(scrollarea)
32#include <QScrollArea>
33#endif
34#if QT_CONFIG(scrollbar)
35#include <QScrollBar>
36#endif
37#include <QDebug>
38
39#if QT_CONFIG(accessibility)
40
42
43using namespace Qt::StringLiterals;
44
45QString qt_accStripAmp(const QString &text);
46QString qt_accHotKey(const QString &text);
47
48#if QT_CONFIG(tabbar)
57class QAccessibleTabButton: public QAccessibleInterface, public QAccessibleActionInterface
58{
59public:
60 QAccessibleTabButton(QTabBar *parent, int index)
61 : m_parent(parent), m_index(index)
62 {}
63
64 void *interface_cast(QAccessible::InterfaceType t) override {
65 if (t == QAccessible::ActionInterface) {
66 return static_cast<QAccessibleActionInterface*>(this);
67 }
68 return nullptr;
69 }
70
71 QObject *object() const override { return nullptr; }
72 QAccessible::Role role() const override { return QAccessible::PageTab; }
73 QAccessible::State state() const override {
74 if (!isValid()) {
76 s.invalid = true;
77 return s;
78 }
79
80 QAccessible::State s = parent()->state();
81 s.selectable = true;
82 s.focused = (m_index == m_parent->currentIndex());
83 s.selected = s.focused;
84 return s;
85 }
86 QRect rect() const override {
87 if (!isValid())
88 return QRect();
89
90 QPoint tp = m_parent->mapToGlobal(QPoint(0,0));
91 QRect rec = m_parent->tabRect(m_index);
92 rec = QRect(tp.x() + rec.x(), tp.y() + rec.y(), rec.width(), rec.height());
93 return rec;
94 }
95
96 bool isValid() const override {
97 if (m_parent) {
98 if (static_cast<QWidget *>(m_parent.data())->d_func()->data.in_destructor)
99 return false;
100 return m_parent->count() > m_index;
101 }
102 return false;
103 }
104
105 QAccessibleInterface *childAt(int, int) const override { return nullptr; }
106 int childCount() const override { return 0; }
107 int indexOfChild(const QAccessibleInterface *) const override { return -1; }
108
109 QString text(QAccessible::Text t) const override
110 {
111 if (!isValid())
112 return QString();
113 QString str;
114 switch (t) {
115 case QAccessible::Name:
116 str = m_parent->accessibleTabName(m_index);
117 if (str.isEmpty())
118 str = qt_accStripAmp(m_parent->tabText(m_index));
119 break;
120 case QAccessible::Accelerator:
121 str = qt_accHotKey(m_parent->tabText(m_index));
122 break;
123#if QT_CONFIG(tooltip)
124 case QAccessible::Description:
125 str = m_parent->tabToolTip(m_index);
126 break;
127#endif
128#if QT_CONFIG(whatsthis)
129 case QAccessible::Help:
130 str = m_parent->tabWhatsThis(m_index);
131 break;
132#endif
133 default:
134 break;
135 }
136 return str;
137 }
138
139 void setText(QAccessible::Text, const QString &) override {}
140
141 QAccessibleInterface *parent() const override {
142 return QAccessible::queryAccessibleInterface(m_parent.data());
143 }
144 QAccessibleInterface *child(int) const override { return nullptr; }
145
146 // action interface
147 QStringList actionNames() const override
148 {
149 return QStringList(pressAction());
150 }
151
152 void doAction(const QString &actionName) override
153 {
154 if (isValid() && actionName == pressAction())
155 m_parent->setCurrentIndex(m_index);
156 }
157
158 QStringList keyBindingsForAction(const QString &) const override
159 {
160 return QStringList();
161 }
162
163 int index() const { return m_index; }
164
165private:
166 QPointer<QTabBar> m_parent;
167 int m_index;
168
169};
170
174QAccessibleTabBar::QAccessibleTabBar(QWidget *w)
175: QAccessibleWidget(w, QAccessible::PageTabList)
176{
177 Q_ASSERT(tabBar());
178}
179
180QAccessibleTabBar::~QAccessibleTabBar()
181{
182 for (QAccessible::Id id : std::as_const(m_childInterfaces))
183 QAccessible::deleteAccessibleInterface(id);
184}
185
186void *QAccessibleTabBar::interface_cast(QAccessible::InterfaceType t)
187{
188 if (t == QAccessible::SelectionInterface) {
189 return static_cast<QAccessibleSelectionInterface*>(this);
190 }
191 return QAccessibleWidget::interface_cast(t);
192}
193
195QTabBar *QAccessibleTabBar::tabBar() const
196{
197 return qobject_cast<QTabBar*>(object());
198}
199
200QAccessibleInterface* QAccessibleTabBar::focusChild() const
201{
202 for (int i = 0; i < childCount(); ++i) {
203 if (child(i)->state().focused)
204 return child(i);
205 }
206
207 return nullptr;
208}
209
210QAccessibleInterface* QAccessibleTabBar::child(int index) const
211{
212 if (QAccessible::Id id = m_childInterfaces.value(index))
213 return QAccessible::accessibleInterface(id);
214
215 // first the tabs, then 2 buttons
216 if (index < tabBar()->count()) {
217 QAccessibleTabButton *button = new QAccessibleTabButton(tabBar(), index);
218 QAccessible::registerAccessibleInterface(button);
219 m_childInterfaces.insert(index, QAccessible::uniqueId(button));
220 return button;
221 } else if (index >= tabBar()->count()) {
222 // left button
223 if (index - tabBar()->count() == 0) {
224 return QAccessible::queryAccessibleInterface(tabBar()->d_func()->leftB);
225 }
226 // right button
227 if (index - tabBar()->count() == 1) {
228 return QAccessible::queryAccessibleInterface(tabBar()->d_func()->rightB);
229 }
230 }
231 return nullptr;
232}
233
234int QAccessibleTabBar::indexOfChild(const QAccessibleInterface *child) const
235{
236 if (child->object() && child->object() == tabBar()->d_func()->leftB)
237 return tabBar()->count();
238 if (child->object() && child->object() == tabBar()->d_func()->rightB)
239 return tabBar()->count() + 1;
240 if (child->role() == QAccessible::PageTab) {
241 QAccessibleInterface *parent = child->parent();
242 if (parent == this) {
243 const QAccessibleTabButton *tabButton = static_cast<const QAccessibleTabButton *>(child);
244 return tabButton->index();
245 }
246 }
247 return -1;
248}
249
250int QAccessibleTabBar::childCount() const
251{
252 // tabs + scroll buttons
253 return tabBar()->count() + 2;
254}
255
256QString QAccessibleTabBar::text(QAccessible::Text t) const
257{
258 if (t == QAccessible::Name) {
259 const QTabBar *tBar = tabBar();
260 int idx = tBar->currentIndex();
261 QString str = tBar->accessibleTabName(idx);
262 if (str.isEmpty())
263 str = qt_accStripAmp(tBar->tabText(idx));
264 return str;
265 } else if (t == QAccessible::Accelerator) {
266 return qt_accHotKey(tabBar()->tabText(tabBar()->currentIndex()));
267 }
268 return QString();
269}
270
271int QAccessibleTabBar::selectedItemCount() const
272{
273 if (tabBar()->currentIndex() >= 0)
274 return 1;
275 return 0;
276}
277
278QList<QAccessibleInterface*> QAccessibleTabBar::selectedItems() const
279{
280 QList<QAccessibleInterface*> items;
281 QAccessibleInterface *selected = selectedItem(0);
282 if (selected)
283 items.push_back(selected);
284 return items;
285}
286
287QAccessibleInterface* QAccessibleTabBar::selectedItem(int selectionIndex) const
288{
289 const int currentIndex = tabBar()->currentIndex();
290 if (selectionIndex != 0 || currentIndex < 0)
291 return nullptr;
292 return child(currentIndex);
293}
294
295bool QAccessibleTabBar::isSelected(QAccessibleInterface *childItem) const
296{
297 return childItem && selectedItem(0) == childItem;
298}
299
300bool QAccessibleTabBar::select(QAccessibleInterface *childItem)
301{
302 const int childIndex = indexOfChild(childItem);
303 if (childIndex >= 0) {
304 tabBar()->setCurrentIndex(childIndex);
305 return true;
306 }
307 return false;
308}
309
310bool QAccessibleTabBar::unselect(QAccessibleInterface *)
311{
312 return false;
313}
314
315bool QAccessibleTabBar::selectAll()
316{
317 return false;
318}
319
320bool QAccessibleTabBar::clear()
321{
322 return false;
323}
324
325#endif // QT_CONFIG(tabbar)
326
327#if QT_CONFIG(combobox)
339QAccessibleComboBox::QAccessibleComboBox(QWidget *w)
340: QAccessibleWidget(w, QAccessible::ComboBox)
341{
342 Q_ASSERT(comboBox());
343}
344
348QComboBox *QAccessibleComboBox::comboBox() const
349{
350 return qobject_cast<QComboBox *>(object());
351}
352
353QAccessibleInterface *QAccessibleComboBox::child(int index) const
354{
355 if (QComboBox *cBox = comboBox()) {
356 if (index == 0) {
357 QAbstractItemView *view = cBox->view();
358 //QWidget *parent = view ? view->parentWidget() : 0;
359 return QAccessible::queryAccessibleInterface(view);
360 } else if (index == 1 && cBox->isEditable()) {
361 return QAccessible::queryAccessibleInterface(cBox->lineEdit());
362 }
363 }
364 return nullptr;
365}
366
367int QAccessibleComboBox::childCount() const
368{
369 // list and text edit
370 if (QComboBox *cBox = comboBox())
371 return (cBox->isEditable()) ? 2 : 1;
372 return 0;
373}
374
375QAccessibleInterface *QAccessibleComboBox::childAt(int x, int y) const
376{
377 if (QComboBox *cBox = comboBox()) {
378 if (cBox->isEditable() && cBox->lineEdit()->rect().contains(x, y))
379 return child(1);
380 }
381 return nullptr;
382}
383
384int QAccessibleComboBox::indexOfChild(const QAccessibleInterface *child) const
385{
386 if (QComboBox *cBox = comboBox()) {
387 if (cBox->view() == child->object())
388 return 0;
389 if (cBox->isEditable() && cBox->lineEdit() == child->object())
390 return 1;
391 }
392 return -1;
393}
394
395QAccessibleInterface *QAccessibleComboBox::focusChild() const
396{
397 // The editable combobox is the focus proxy of its lineedit, so the
398 // lineedit itself never gets focus. But it is the accessible focus
399 // child of an editable combobox.
400 if (QComboBox *cBox = comboBox()) {
401 if (cBox->isEditable())
402 return child(1);
403 }
404 return nullptr;
405}
406
408QString QAccessibleComboBox::text(QAccessible::Text t) const
409{
410 QString str;
411 if (QComboBox *cBox = comboBox()) {
412 switch (t) {
413 case QAccessible::Name:
414#ifndef Q_OS_UNIX // on Linux we use relations for this, name is text (fall through to Value)
415 str = QAccessibleWidget::text(t);
416 break;
417#endif
418 case QAccessible::Value:
419 if (cBox->isEditable())
420 str = cBox->lineEdit()->text();
421 else
422 str = cBox->currentText();
423 break;
424#ifndef QT_NO_SHORTCUT
425 case QAccessible::Accelerator:
427 break;
428#endif
429 default:
430 break;
431 }
432 if (str.isEmpty())
433 str = QAccessibleWidget::text(t);
434 }
435 return str;
436}
437
438QAccessible::State QAccessibleComboBox::state() const
439{
440 QAccessible::State s = QAccessibleWidget::state();
441
442 if (QComboBox *cBox = comboBox()) {
443 s.expandable = true;
444 s.expanded = isValid() && cBox->view()->isVisible();
445 s.editable = cBox->isEditable();
446 }
447 return s;
448}
449
450QStringList QAccessibleComboBox::actionNames() const
451{
452 return QStringList() << showMenuAction() << pressAction();
453}
454
455QString QAccessibleComboBox::localizedActionDescription(const QString &actionName) const
456{
457 if (actionName == showMenuAction() || actionName == pressAction())
458 return QComboBox::tr("Open the combo box selection popup");
459 return QString();
460}
461
462void QAccessibleComboBox::doAction(const QString &actionName)
463{
464 if (QComboBox *cBox = comboBox()) {
465 if (actionName == showMenuAction() || actionName == pressAction()) {
466 if (cBox->view()->isVisible()) {
467#if defined(Q_OS_ANDROID)
468 const auto list = child(0)->tableInterface();
469 if (list && list->selectedRowCount() > 0) {
470 cBox->setCurrentIndex(list->selectedRows().at(0));
471 }
472 cBox->setFocus();
473#endif
474 cBox->hidePopup();
475 } else {
476 cBox->showPopup();
477#if defined(Q_OS_ANDROID)
478 const auto list = child(0)->tableInterface();
479 if (list && list->selectedRowCount() > 0) {
480 auto selectedCells = list->selectedCells();
481 QAccessibleEvent ev(selectedCells.at(0),QAccessible::Focus);
482 QAccessible::updateAccessibility(&ev);
483 }
484#endif
485 }
486 }
487 }
488}
489
490QStringList QAccessibleComboBox::keyBindingsForAction(const QString &/*actionName*/) const
491{
492 return QStringList();
493}
494
495#endif // QT_CONFIG(combobox)
496
497#if QT_CONFIG(scrollarea)
498// ======================= QAccessibleAbstractScrollArea =======================
499QAccessibleAbstractScrollArea::QAccessibleAbstractScrollArea(QWidget *widget)
500 : QAccessibleWidget(widget, QAccessible::Client)
501{
502 Q_ASSERT(qobject_cast<QAbstractScrollArea *>(widget));
503}
504
505QAccessibleInterface *QAccessibleAbstractScrollArea::child(int index) const
506{
507 return QAccessible::queryAccessibleInterface(accessibleChildren().at(index));
508}
509
510int QAccessibleAbstractScrollArea::childCount() const
511{
512 return accessibleChildren().size();
513}
514
515int QAccessibleAbstractScrollArea::indexOfChild(const QAccessibleInterface *child) const
516{
517 if (!child || !child->object())
518 return -1;
519 return accessibleChildren().indexOf(qobject_cast<QWidget *>(child->object()));
520}
521
522bool QAccessibleAbstractScrollArea::isValid() const
523{
524 return (QAccessibleWidget::isValid() && abstractScrollArea() && abstractScrollArea()->viewport());
525}
526
527QAccessibleInterface *QAccessibleAbstractScrollArea::childAt(int x, int y) const
528{
529 if (!abstractScrollArea()->isVisible())
530 return nullptr;
531
532 for (int i = 0; i < childCount(); ++i) {
533 QPoint wpos = accessibleChildren().at(i)->mapToGlobal(QPoint(0, 0));
534 QRect rect = QRect(wpos, accessibleChildren().at(i)->size());
535 if (rect.contains(x, y))
536 return child(i);
537 }
538 return nullptr;
539}
540
541QAbstractScrollArea *QAccessibleAbstractScrollArea::abstractScrollArea() const
542{
543 return static_cast<QAbstractScrollArea *>(object());
544}
545
546QWidgetList QAccessibleAbstractScrollArea::accessibleChildren() const
547{
548 QWidgetList children;
549
550 // Viewport.
551 QWidget * viewport = abstractScrollArea()->viewport();
552 if (viewport)
553 children.append(viewport);
554
555 // Horizontal scrollBar container.
556 QScrollBar *horizontalScrollBar = abstractScrollArea()->horizontalScrollBar();
557 if (horizontalScrollBar && horizontalScrollBar->isVisible()) {
558 QWidget *scrollBarParent = horizontalScrollBar->parentWidget();
559 // Add container only if scroll bar is in the container
560 if (elementType(scrollBarParent) == HorizontalContainer)
561 children.append(scrollBarParent);
562 }
563
564 // Vertical scrollBar container.
565 QScrollBar *verticalScrollBar = abstractScrollArea()->verticalScrollBar();
566 if (verticalScrollBar && verticalScrollBar->isVisible()) {
567 QWidget *scrollBarParent = verticalScrollBar->parentWidget();
568 // Add container only if scroll bar is in the container
569 if (elementType(scrollBarParent) == VerticalContainer)
570 children.append(scrollBarParent);
571 }
572
573 // CornerWidget.
574 QWidget *cornerWidget = abstractScrollArea()->cornerWidget();
575 if (cornerWidget && cornerWidget->isVisible())
576 children.append(cornerWidget);
577
578 return children;
579}
580
581QAccessibleAbstractScrollArea::AbstractScrollAreaElement
582QAccessibleAbstractScrollArea::elementType(QWidget *widget) const
583{
584 if (!widget)
585 return Undefined;
586
587 if (widget == abstractScrollArea())
588 return Self;
589 if (widget == abstractScrollArea()->viewport())
590 return Viewport;
591 if (widget->objectName() == "qt_scrollarea_hcontainer"_L1)
592 return HorizontalContainer;
593 if (widget->objectName() == "qt_scrollarea_vcontainer"_L1)
594 return VerticalContainer;
595 if (widget == abstractScrollArea()->cornerWidget())
596 return CornerWidget;
597
598 return Undefined;
599}
600
601bool QAccessibleAbstractScrollArea::isLeftToRight() const
602{
603 return abstractScrollArea()->isLeftToRight();
604}
605
606// ======================= QAccessibleScrollArea ===========================
607QAccessibleScrollArea::QAccessibleScrollArea(QWidget *widget)
608 : QAccessibleAbstractScrollArea(widget)
609{
610 Q_ASSERT(qobject_cast<QScrollArea *>(widget));
611}
612#endif // QT_CONFIG(scrollarea)
613
615
616#endif // QT_CONFIG(accessibility)
The QAbstractItemView class provides the basic functionality for item view classes.
\inmodule QtGui
The QAccessible class provides enums and static functions related to accessibility.
The QComboBox widget combines a button with a dropdown list.
Definition qcombobox.h:24
The QKeySequence class encapsulates a key sequence as used by shortcuts.
QString toString(SequenceFormat format=PortableText) const
void push_back(parameter_type t)
Definition qlist.h:675
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qobject.h:103
QString objectName
the name of this object
Definition qobject.h:107
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
constexpr int y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:135
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:188
The QScrollBar widget provides a vertical or horizontal scroll bar.
Definition qscrollbar.h:20
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
The QTabBar class provides a tab bar, e.g.
Definition qtabbar.h:19
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
QWidget * parentWidget() const
Returns the parent of this widget, or \nullptr if it does not have any parent widget.
Definition qwidget.h:904
bool isVisible() const
Definition qwidget.h:874
QOpenGLWidget * widget
[1]
QString str
[2]
QString text
QPushButton * button
[2]
rect
[4]
else opt state
[0]
Combined button and popup list for selecting options.
@ Key_Down
Definition qnamespace.h:680
QList< QString > QStringList
Constructs a string list that contains the given string, str.
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLenum GLuint id
[7]
GLenum GLenum GLsizei count
GLuint object
[3]
GLint y
GLdouble s
[6]
Definition qopenglext.h:235
GLdouble GLdouble t
Definition qopenglext.h:243
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QList< int > list
[14]
view viewport() -> scroll(dx, dy, deviceRect)
edit isVisible()
QList< QTreeWidgetItem * > items
QLayoutItem * child
[0]
insertRed setText("insert red text")
QAction * at
QQuickView * view
[0]