1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "simplewidgets_p.h"
41
42#if QT_CONFIG(abstractbutton)
43#include <qabstractbutton.h>
44#endif
45#if QT_CONFIG(checkbox)
46#include <qcheckbox.h>
47#endif
48#if QT_CONFIG(pushbutton)
49#include <qpushbutton.h>
50#endif
51#if QT_CONFIG(progressbar)
52#include <qprogressbar.h>
53#endif
54#if QT_CONFIG(statusbar)
55#include <qstatusbar.h>
56#endif
57#if QT_CONFIG(radiobutton)
58#include <qradiobutton.h>
59#endif
60#if QT_CONFIG(toolbutton)
61#include <qtoolbutton.h>
62#endif
63#if QT_CONFIG(menu)
64#include <qmenu.h>
65#endif
66#if QT_CONFIG(label)
67#include <qlabel.h>
68#endif
69#if QT_CONFIG(groupbox)
70#include <qgroupbox.h>
71#endif
72#if QT_CONFIG(lcdnumber)
73#include <qlcdnumber.h>
74#endif
75#if QT_CONFIG(lineedit)
76#include <qlineedit.h>
77#include <private/qlineedit_p.h>
78#endif
79#ifndef QT_NO_PICTURE
80#include <QtGui/qpicture.h>
81#endif
82#include <qstyle.h>
83#include <qstyleoption.h>
84#include <qtextdocument.h>
85#include <qwindow.h>
86#include <private/qwindowcontainer_p.h>
87#include <QtCore/qvarlengtharray.h>
88#include <QtGui/qvalidator.h>
89
90#ifdef Q_OS_MAC
91#include <qfocusframe.h>
92#endif
93
94QT_BEGIN_NAMESPACE
95
96#ifndef QT_NO_ACCESSIBILITY
97
98extern QList<QWidget*> childWidgets(const QWidget *widget);
99
100QString qt_accStripAmp(const QString &text);
101QString qt_accHotKey(const QString &text);
102
103#if QT_CONFIG(abstractbutton)
104/*!
105 \class QAccessibleButton
106 \brief The QAccessibleButton class implements the QAccessibleInterface for button type widgets.
107 \internal
108
109 \ingroup accessibility
110*/
111
112/*!
113 Creates a QAccessibleButton object for \a w.
114*/
115QAccessibleButton::QAccessibleButton(QWidget *w)
116: QAccessibleWidget(w)
117{
118 Q_ASSERT(button());
119
120 // FIXME: The checkable state of the button is dynamic,
121 // while we only update the controlling signal once :(
122 if (button()->isCheckable())
123 addControllingSignal(signal: QLatin1String("toggled(bool)"));
124 else
125 addControllingSignal(signal: QLatin1String("clicked()"));
126}
127
128/*! Returns the button. */
129QAbstractButton *QAccessibleButton::button() const
130{
131 return qobject_cast<QAbstractButton*>(object: object());
132}
133
134/*! \reimp */
135QString QAccessibleButton::text(QAccessible::Text t) const
136{
137 QString str;
138 switch (t) {
139 case QAccessible::Accelerator:
140 {
141#if QT_CONFIG(shortcut) && QT_CONFIG(pushbutton)
142 QPushButton *pb = qobject_cast<QPushButton*>(object: object());
143 if (pb && pb->isDefault())
144 str = QKeySequence(Qt::Key_Enter).toString(format: QKeySequence::NativeText);
145#endif
146 if (str.isEmpty())
147 str = qt_accHotKey(text: button()->text());
148 }
149 break;
150 case QAccessible::Name:
151 str = widget()->accessibleName();
152 if (str.isEmpty())
153 str = qt_accStripAmp(text: button()->text());
154 break;
155 default:
156 break;
157 }
158 if (str.isEmpty())
159 str = QAccessibleWidget::text(t);
160 return str;
161}
162
163QAccessible::State QAccessibleButton::state() const
164{
165 QAccessible::State state = QAccessibleWidget::state();
166
167 QAbstractButton *b = button();
168#if QT_CONFIG(checkbox)
169 QCheckBox *cb = qobject_cast<QCheckBox *>(object: b);
170#endif
171 if (b->isCheckable())
172 state.checkable = true;
173 if (b->isChecked())
174 state.checked = true;
175#if QT_CONFIG(checkbox)
176 if (cb && cb->checkState() == Qt::PartiallyChecked)
177 state.checkStateMixed = true;
178#endif
179 if (b->isDown())
180 state.pressed = true;
181#if QT_CONFIG(pushbutton)
182 QPushButton *pb = qobject_cast<QPushButton*>(object: b);
183 if (pb) {
184 if (pb->isDefault())
185 state.defaultButton = true;
186#if QT_CONFIG(menu)
187 if (pb->menu())
188 state.hasPopup = true;
189#endif
190 }
191#endif
192
193 return state;
194}
195
196QRect QAccessibleButton::rect() const
197{
198 QAbstractButton *ab = button();
199 if (!ab->isVisible())
200 return QRect();
201
202#if QT_CONFIG(checkbox)
203 if (QCheckBox *cb = qobject_cast<QCheckBox *>(object: ab)) {
204 QPoint wpos = cb->mapToGlobal(QPoint(0, 0));
205 QStyleOptionButton opt;
206 cb->initStyleOption(option: &opt);
207 return cb->style()->subElementRect(subElement: QStyle::SE_CheckBoxClickRect, option: &opt, widget: cb).translated(p: wpos);
208 }
209#endif
210#if QT_CONFIG(radiobutton)
211 else if (QRadioButton *rb = qobject_cast<QRadioButton *>(object: ab)) {
212 QPoint wpos = rb->mapToGlobal(QPoint(0, 0));
213 QStyleOptionButton opt;
214 rb->initStyleOption(button: &opt);
215 return rb->style()->subElementRect(subElement: QStyle::SE_RadioButtonClickRect, option: &opt, widget: rb).translated(p: wpos);
216 }
217#endif
218 return QAccessibleWidget::rect();
219}
220
221QAccessible::Role QAccessibleButton::role() const
222{
223 QAbstractButton *ab = button();
224
225#if QT_CONFIG(menu)
226 if (QPushButton *pb = qobject_cast<QPushButton*>(object: ab)) {
227 if (pb->menu())
228 return QAccessible::ButtonMenu;
229 }
230#endif
231
232 if (ab->isCheckable())
233 return ab->autoExclusive() ? QAccessible::RadioButton : QAccessible::CheckBox;
234
235 return QAccessible::Button;
236}
237
238QStringList QAccessibleButton::actionNames() const
239{
240 QStringList names;
241 if (widget()->isEnabled()) {
242 switch (role()) {
243 case QAccessible::ButtonMenu:
244 names << showMenuAction();
245 break;
246 case QAccessible::RadioButton:
247 names << toggleAction();
248 break;
249 default:
250 if (button()->isCheckable()) {
251 names << toggleAction();
252 } else {
253 names << pressAction();
254 }
255 break;
256 }
257 }
258 names << QAccessibleWidget::actionNames();
259 return names;
260}
261
262void QAccessibleButton::doAction(const QString &actionName)
263{
264 if (!widget()->isEnabled())
265 return;
266 if (actionName == pressAction() ||
267 actionName == showMenuAction()) {
268#if QT_CONFIG(menu)
269 QPushButton *pb = qobject_cast<QPushButton*>(object: object());
270 if (pb && pb->menu())
271 pb->showMenu();
272 else
273#endif
274 button()->animateClick();
275 } else if (actionName == toggleAction()) {
276 button()->toggle();
277 } else {
278 QAccessibleWidget::doAction(actionName);
279 }
280}
281
282QStringList QAccessibleButton::keyBindingsForAction(const QString &actionName) const
283{
284 if (actionName == pressAction()) {
285#ifndef QT_NO_SHORTCUT
286 return QStringList() << button()->shortcut().toString();
287#endif
288 }
289 return QStringList();
290}
291#endif // QT_CONFIG(abstractbutton)
292
293#if QT_CONFIG(toolbutton)
294/*!
295 \class QAccessibleToolButton
296 \brief The QAccessibleToolButton class implements the QAccessibleInterface for tool buttons.
297 \internal
298
299 \ingroup accessibility
300*/
301
302/*!
303 Creates a QAccessibleToolButton object for \a w.
304*/
305QAccessibleToolButton::QAccessibleToolButton(QWidget *w)
306: QAccessibleButton(w)
307{
308 Q_ASSERT(toolButton());
309}
310
311/*! Returns the button. */
312QToolButton *QAccessibleToolButton::toolButton() const
313{
314 return qobject_cast<QToolButton*>(object: object());
315}
316
317/*!
318 Returns \c true if this tool button is a split button.
319*/
320bool QAccessibleToolButton::isSplitButton() const
321{
322#if QT_CONFIG(menu)
323 return toolButton()->menu() && toolButton()->popupMode() == QToolButton::MenuButtonPopup;
324#else
325 return false;
326#endif
327}
328
329QAccessible::State QAccessibleToolButton::state() const
330{
331 QAccessible::State st = QAccessibleButton::state();
332 if (toolButton()->autoRaise())
333 st.hotTracked = true;
334#if QT_CONFIG(menu)
335 if (toolButton()->menu())
336 st.hasPopup = true;
337#endif
338 return st;
339}
340
341int QAccessibleToolButton::childCount() const
342{
343 return isSplitButton() ? 1 : 0;
344}
345
346QAccessible::Role QAccessibleToolButton::role() const
347{
348#if QT_CONFIG(menu)
349 QAbstractButton *ab = button();
350 QToolButton *tb = qobject_cast<QToolButton*>(object: ab);
351 if (!tb->menu())
352 return tb->isCheckable() ? QAccessible::CheckBox : QAccessible::PushButton;
353 else if (tb->popupMode() == QToolButton::DelayedPopup)
354 return QAccessible::ButtonDropDown;
355#endif
356
357 return QAccessible::ButtonMenu;
358}
359
360QAccessibleInterface *QAccessibleToolButton::child(int index) const
361{
362#if QT_CONFIG(menu)
363 if (index == 0 && toolButton()->menu())
364 {
365 return QAccessible::queryAccessibleInterface(toolButton()->menu());
366 }
367#else
368 Q_UNUSED(index)
369#endif
370 return nullptr;
371}
372
373/*
374 The three different tool button types can have the following actions:
375| DelayedPopup | ShowMenuAction + (PressedAction || CheckedAction) |
376| MenuButtonPopup | ShowMenuAction + (PressedAction || CheckedAction) |
377| InstantPopup | ShowMenuAction |
378*/
379QStringList QAccessibleToolButton::actionNames() const
380{
381 QStringList names;
382 if (widget()->isEnabled()) {
383#if QT_CONFIG(menu)
384 if (toolButton()->menu())
385 names << showMenuAction();
386 if (toolButton()->popupMode() != QToolButton::InstantPopup)
387 names << QAccessibleButton::actionNames();
388#endif
389 }
390 return names;
391}
392
393void QAccessibleToolButton::doAction(const QString &actionName)
394{
395 if (!widget()->isEnabled())
396 return;
397
398 if (actionName == pressAction()) {
399 button()->click();
400 } else if (actionName == showMenuAction()) {
401#if QT_CONFIG(menu)
402 if (toolButton()->popupMode() != QToolButton::InstantPopup) {
403 toolButton()->setDown(true);
404 toolButton()->showMenu();
405 }
406#endif
407 } else {
408 QAccessibleButton::doAction(actionName);
409 }
410
411}
412
413#endif // QT_CONFIG(toolbutton)
414
415/*!
416 \class QAccessibleDisplay
417 \brief The QAccessibleDisplay class implements the QAccessibleInterface for widgets that display information.
418 \internal
419
420 \ingroup accessibility
421*/
422
423/*!
424 Constructs a QAccessibleDisplay object for \a w.
425 \a role is propagated to the QAccessibleWidget constructor.
426*/
427QAccessibleDisplay::QAccessibleDisplay(QWidget *w, QAccessible::Role role)
428: QAccessibleWidget(w, role)
429{
430}
431
432QAccessible::Role QAccessibleDisplay::role() const
433{
434#if QT_CONFIG(label)
435 QLabel *l = qobject_cast<QLabel*>(object: object());
436 if (l) {
437 if (!l->pixmap(Qt::ReturnByValue).isNull())
438 return QAccessible::Graphic;
439#ifndef QT_NO_PICTURE
440 if (!l->picture(Qt::ReturnByValue).isNull())
441 return QAccessible::Graphic;
442#endif
443#if QT_CONFIG(movie)
444 if (l->movie())
445 return QAccessible::Animation;
446#endif
447#if QT_CONFIG(progressbar)
448 } else if (qobject_cast<QProgressBar*>(object: object())) {
449 return QAccessible::ProgressBar;
450#endif
451#if QT_CONFIG(statusbar)
452 } else if (qobject_cast<QStatusBar*>(object: object())) {
453 return QAccessible::StatusBar;
454#endif
455 }
456#endif
457 return QAccessibleWidget::role();
458}
459
460QAccessible::State QAccessibleDisplay::state() const
461{
462 QAccessible::State s = QAccessibleWidget::state();
463 s.readOnly = true;
464 return s;
465}
466
467QString QAccessibleDisplay::text(QAccessible::Text t) const
468{
469 QString str;
470 switch (t) {
471 case QAccessible::Name:
472 str = widget()->accessibleName();
473 if (str.isEmpty()) {
474 if (false) {
475#if QT_CONFIG(label)
476 } else if (qobject_cast<QLabel*>(object: object())) {
477 QLabel *label = qobject_cast<QLabel*>(object: object());
478 str = label->text();
479#ifndef QT_NO_TEXTHTMLPARSER
480 if (label->textFormat() == Qt::RichText
481 || (label->textFormat() == Qt::AutoText && Qt::mightBeRichText(str))) {
482 QTextDocument doc;
483 doc.setHtml(str);
484 str = doc.toPlainText();
485 }
486#endif
487#ifndef QT_NO_SHORTCUT
488 if (label->buddy())
489 str = qt_accStripAmp(text: str);
490#endif
491#endif // QT_CONFIG(label)
492#if QT_CONFIG(lcdnumber)
493 } else if (qobject_cast<QLCDNumber*>(object: object())) {
494 QLCDNumber *l = qobject_cast<QLCDNumber*>(object: object());
495 if (l->digitCount())
496 str = QString::number(l->value());
497 else
498 str = QString::number(l->intValue());
499#endif
500#if QT_CONFIG(statusbar)
501 } else if (qobject_cast<QStatusBar*>(object: object())) {
502 return qobject_cast<QStatusBar*>(object: object())->currentMessage();
503#endif
504 }
505 }
506 break;
507 case QAccessible::Value:
508#if QT_CONFIG(progressbar)
509 if (qobject_cast<QProgressBar*>(object: object()))
510 str = QString::number(qobject_cast<QProgressBar*>(object: object())->value());
511#endif
512 break;
513 default:
514 break;
515 }
516 if (str.isEmpty())
517 str = QAccessibleWidget::text(t);
518 return str;
519}
520
521/*! \reimp */
522QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >
523QAccessibleDisplay::relations(QAccessible::Relation match /* = QAccessible::AllRelations */) const
524{
525 QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > rels = QAccessibleWidget::relations(match);
526#if QT_CONFIG(shortcut) && QT_CONFIG(label)
527 if (match & QAccessible::Labelled) {
528 if (QLabel *label = qobject_cast<QLabel*>(object: object())) {
529 const QAccessible::Relation rel = QAccessible::Labelled;
530 if (QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(label->buddy()))
531 rels.append(t: qMakePair(x: iface, y: rel));
532 }
533 }
534#endif
535 return rels;
536}
537
538void *QAccessibleDisplay::interface_cast(QAccessible::InterfaceType t)
539{
540 if (t == QAccessible::ImageInterface)
541 return static_cast<QAccessibleImageInterface*>(this);
542 return QAccessibleWidget::interface_cast(t);
543}
544
545/*! \internal */
546QString QAccessibleDisplay::imageDescription() const
547{
548#ifndef QT_NO_TOOLTIP
549 return widget()->toolTip();
550#else
551 return QString();
552#endif
553}
554
555/*! \internal */
556QSize QAccessibleDisplay::imageSize() const
557{
558#if QT_CONFIG(label)
559 QLabel *label = qobject_cast<QLabel *>(object: widget());
560 if (!label)
561#endif
562 return QSize();
563#if QT_CONFIG(label)
564 return label->pixmap(Qt::ReturnByValue).size();
565#endif
566}
567
568/*! \internal */
569QPoint QAccessibleDisplay::imagePosition() const
570{
571#if QT_CONFIG(label)
572 QLabel *label = qobject_cast<QLabel *>(object: widget());
573 if (!label)
574#endif
575 return QPoint();
576#if QT_CONFIG(label)
577 if (label->pixmap(Qt::ReturnByValue).isNull())
578 return QPoint();
579
580 return QPoint(label->mapToGlobal(label->pos()));
581#endif
582}
583
584#if QT_CONFIG(groupbox)
585QAccessibleGroupBox::QAccessibleGroupBox(QWidget *w)
586: QAccessibleWidget(w)
587{
588}
589
590QGroupBox* QAccessibleGroupBox::groupBox() const
591{
592 return static_cast<QGroupBox *>(widget());
593}
594
595QString QAccessibleGroupBox::text(QAccessible::Text t) const
596{
597 QString txt = QAccessibleWidget::text(t);
598
599 if (txt.isEmpty()) {
600 switch (t) {
601 case QAccessible::Name:
602 txt = qt_accStripAmp(text: groupBox()->title());
603 break;
604#if QT_CONFIG(tooltip)
605 case QAccessible::Description:
606 txt = groupBox()->toolTip();
607 break;
608#endif
609 case QAccessible::Accelerator:
610 txt = qt_accHotKey(text: groupBox()->title());
611 break;
612 default:
613 break;
614 }
615 }
616
617 return txt;
618}
619
620QAccessible::State QAccessibleGroupBox::state() const
621{
622 QAccessible::State st = QAccessibleWidget::state();
623 st.checkable = groupBox()->isCheckable();
624 st.checked = groupBox()->isChecked();
625 return st;
626}
627
628QAccessible::Role QAccessibleGroupBox::role() const
629{
630 return groupBox()->isCheckable() ? QAccessible::CheckBox : QAccessible::Grouping;
631}
632
633QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >
634QAccessibleGroupBox::relations(QAccessible::Relation match /* = QAccessible::AllRelations */) const
635{
636 QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > rels = QAccessibleWidget::relations(match);
637
638 if ((match & QAccessible::Labelled) && (!groupBox()->title().isEmpty())) {
639 const QList<QWidget*> kids = childWidgets(widget: widget());
640 for (QWidget *kid : kids) {
641 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(kid);
642 if (iface)
643 rels.append(t: qMakePair(x: iface, y: QAccessible::Relation(QAccessible::Labelled)));
644 }
645 }
646 return rels;
647}
648
649QStringList QAccessibleGroupBox::actionNames() const
650{
651 QStringList actions = QAccessibleWidget::actionNames();
652
653 if (groupBox()->isCheckable()) {
654 actions.prepend(t: QAccessibleActionInterface::toggleAction());
655 }
656 return actions;
657}
658
659void QAccessibleGroupBox::doAction(const QString &actionName)
660{
661 if (actionName == QAccessibleActionInterface::toggleAction())
662 groupBox()->setChecked(!groupBox()->isChecked());
663}
664
665QStringList QAccessibleGroupBox::keyBindingsForAction(const QString &) const
666{
667 return QStringList();
668}
669
670#endif
671
672#if QT_CONFIG(lineedit)
673/*!
674 \class QAccessibleLineEdit
675 \brief The QAccessibleLineEdit class implements the QAccessibleInterface for widgets with editable text
676 \internal
677
678 \ingroup accessibility
679*/
680
681/*!
682 Constructs a QAccessibleLineEdit object for \a w.
683 \a name is propagated to the QAccessibleWidget constructor.
684*/
685QAccessibleLineEdit::QAccessibleLineEdit(QWidget *w, const QString &name)
686: QAccessibleWidget(w, QAccessible::EditableText, name)
687{
688 addControllingSignal(signal: QLatin1String("textChanged(const QString&)"));
689 addControllingSignal(signal: QLatin1String("returnPressed()"));
690}
691
692/*! Returns the line edit. */
693QLineEdit *QAccessibleLineEdit::lineEdit() const
694{
695 return qobject_cast<QLineEdit*>(object: object());
696}
697
698QString QAccessibleLineEdit::text(QAccessible::Text t) const
699{
700 QString str;
701 switch (t) {
702 case QAccessible::Value:
703 if (lineEdit()->echoMode() == QLineEdit::Normal)
704 str = lineEdit()->text();
705 else if (lineEdit()->echoMode() != QLineEdit::NoEcho)
706 str = QString(lineEdit()->text().length(), QChar::fromLatin1(c: '*'));
707 break;
708 default:
709 break;
710 }
711 if (str.isEmpty())
712 str = QAccessibleWidget::text(t);
713 if (str.isEmpty() && t == QAccessible::Description)
714 str = lineEdit()->placeholderText();
715 return str;
716}
717
718void QAccessibleLineEdit::setText(QAccessible::Text t, const QString &text)
719{
720 if (t != QAccessible::Value) {
721 QAccessibleWidget::setText(t, text);
722 return;
723 }
724
725 QString newText = text;
726#if QT_CONFIG(validator)
727 if (lineEdit()->validator()) {
728 int pos = 0;
729 if (lineEdit()->validator()->validate(newText, pos) != QValidator::Acceptable)
730 return;
731 }
732#endif
733 lineEdit()->setText(newText);
734}
735
736QAccessible::State QAccessibleLineEdit::state() const
737{
738 QAccessible::State state = QAccessibleWidget::state();
739
740 QLineEdit *l = lineEdit();
741 state.editable = true;
742 if (l->isReadOnly())
743 state.readOnly = true;
744
745 if (l->echoMode() != QLineEdit::Normal)
746 state.passwordEdit = true;
747
748 state.selectableText = true;
749 return state;
750}
751
752void *QAccessibleLineEdit::interface_cast(QAccessible::InterfaceType t)
753{
754 if (t == QAccessible::TextInterface)
755 return static_cast<QAccessibleTextInterface*>(this);
756 if (t == QAccessible::EditableTextInterface)
757 return static_cast<QAccessibleEditableTextInterface*>(this);
758 return QAccessibleWidget::interface_cast(t);
759}
760
761void QAccessibleLineEdit::addSelection(int startOffset, int endOffset)
762{
763 setSelection(selectionIndex: 0, startOffset, endOffset);
764}
765
766QString QAccessibleLineEdit::attributes(int offset, int *startOffset, int *endOffset) const
767{
768 // QLineEdit doesn't have text attributes
769 *startOffset = *endOffset = offset;
770 return QString();
771}
772
773int QAccessibleLineEdit::cursorPosition() const
774{
775 return lineEdit()->cursorPosition();
776}
777
778QRect QAccessibleLineEdit::characterRect(int offset) const
779{
780 int x = lineEdit()->d_func()->control->cursorToX(cursor: offset);
781 int y = lineEdit()->textMargins().top();
782 QFontMetrics fm(lineEdit()->font());
783 const QString ch = text(startOffset: offset, endOffset: offset + 1);
784 if (ch.isEmpty())
785 return QRect();
786 int w = fm.horizontalAdvance(ch);
787 int h = fm.height();
788 QRect r(x, y, w, h);
789 r.moveTo(p: lineEdit()->mapToGlobal(r.topLeft()));
790 return r;
791}
792
793int QAccessibleLineEdit::selectionCount() const
794{
795 return lineEdit()->hasSelectedText() ? 1 : 0;
796}
797
798int QAccessibleLineEdit::offsetAtPoint(const QPoint &point) const
799{
800 QPoint p = lineEdit()->mapFromGlobal(point);
801
802 return lineEdit()->cursorPositionAt(pos: p);
803}
804
805void QAccessibleLineEdit::selection(int selectionIndex, int *startOffset, int *endOffset) const
806{
807 *startOffset = *endOffset = 0;
808 if (selectionIndex != 0)
809 return;
810
811 *startOffset = lineEdit()->selectionStart();
812 *endOffset = *startOffset + lineEdit()->selectedText().count();
813}
814
815QString QAccessibleLineEdit::text(int startOffset, int endOffset) const
816{
817 if (startOffset > endOffset)
818 return QString();
819
820 if (lineEdit()->echoMode() != QLineEdit::Normal)
821 return QString();
822
823 return lineEdit()->text().mid(position: startOffset, n: endOffset - startOffset);
824}
825
826QString QAccessibleLineEdit::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType,
827 int *startOffset, int *endOffset) const
828{
829 if (lineEdit()->echoMode() != QLineEdit::Normal) {
830 *startOffset = *endOffset = -1;
831 return QString();
832 }
833 if (offset == -2)
834 offset = cursorPosition();
835 return QAccessibleTextInterface::textBeforeOffset(offset, boundaryType, startOffset, endOffset);
836}
837
838QString QAccessibleLineEdit::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType,
839 int *startOffset, int *endOffset) const
840{
841 if (lineEdit()->echoMode() != QLineEdit::Normal) {
842 *startOffset = *endOffset = -1;
843 return QString();
844 }
845 if (offset == -2)
846 offset = cursorPosition();
847 return QAccessibleTextInterface::textAfterOffset(offset, boundaryType, startOffset, endOffset);
848}
849
850QString QAccessibleLineEdit::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType,
851 int *startOffset, int *endOffset) const
852{
853 if (lineEdit()->echoMode() != QLineEdit::Normal) {
854 *startOffset = *endOffset = -1;
855 return QString();
856 }
857 if (offset == -2)
858 offset = cursorPosition();
859 return QAccessibleTextInterface::textAtOffset(offset, boundaryType, startOffset, endOffset);
860}
861
862void QAccessibleLineEdit::removeSelection(int selectionIndex)
863{
864 if (selectionIndex != 0)
865 return;
866
867 lineEdit()->deselect();
868}
869
870void QAccessibleLineEdit::setCursorPosition(int position)
871{
872 lineEdit()->setCursorPosition(position);
873}
874
875void QAccessibleLineEdit::setSelection(int selectionIndex, int startOffset, int endOffset)
876{
877 if (selectionIndex != 0)
878 return;
879
880 lineEdit()->setSelection(startOffset, endOffset - startOffset);
881}
882
883int QAccessibleLineEdit::characterCount() const
884{
885 return lineEdit()->text().count();
886}
887
888void QAccessibleLineEdit::scrollToSubstring(int startIndex, int endIndex)
889{
890 lineEdit()->setCursorPosition(endIndex);
891 lineEdit()->setCursorPosition(startIndex);
892}
893
894void QAccessibleLineEdit::deleteText(int startOffset, int endOffset)
895{
896 lineEdit()->setText(lineEdit()->text().remove(i: startOffset, len: endOffset - startOffset));
897}
898
899void QAccessibleLineEdit::insertText(int offset, const QString &text)
900{
901 lineEdit()->setText(lineEdit()->text().insert(i: offset, s: text));
902}
903
904void QAccessibleLineEdit::replaceText(int startOffset, int endOffset, const QString &text)
905{
906 lineEdit()->setText(lineEdit()->text().replace(i: startOffset, len: endOffset - startOffset, after: text));
907}
908
909#endif // QT_CONFIG(lineedit)
910
911#if QT_CONFIG(progressbar)
912QAccessibleProgressBar::QAccessibleProgressBar(QWidget *o)
913 : QAccessibleDisplay(o)
914{
915 Q_ASSERT(progressBar());
916}
917
918void *QAccessibleProgressBar::interface_cast(QAccessible::InterfaceType t)
919{
920 if (t == QAccessible::ValueInterface)
921 return static_cast<QAccessibleValueInterface*>(this);
922 return QAccessibleDisplay::interface_cast(t);
923}
924
925QVariant QAccessibleProgressBar::currentValue() const
926{
927 return progressBar()->value();
928}
929
930QVariant QAccessibleProgressBar::maximumValue() const
931{
932 return progressBar()->maximum();
933}
934
935QVariant QAccessibleProgressBar::minimumValue() const
936{
937 return progressBar()->minimum();
938}
939
940QVariant QAccessibleProgressBar::minimumStepSize() const
941{
942 // This is arbitrary since any value between min and max is valid.
943 // Some screen readers (orca use it to calculate how many digits to display though,
944 // so it makes sense to return a "sensible" value. Providing 100 increments seems ok.
945 return (progressBar()->maximum() - progressBar()->minimum()) / 100.0;
946}
947
948QProgressBar *QAccessibleProgressBar::progressBar() const
949{
950 return qobject_cast<QProgressBar *>(object: object());
951}
952#endif
953
954
955QAccessibleWindowContainer::QAccessibleWindowContainer(QWidget *w)
956 : QAccessibleWidget(w)
957{
958}
959
960int QAccessibleWindowContainer::childCount() const
961{
962 if (container()->containedWindow() && QAccessible::queryAccessibleInterface(container()->containedWindow()))
963 return 1;
964 return 0;
965}
966
967int QAccessibleWindowContainer::indexOfChild(const QAccessibleInterface *child) const
968{
969 if (child->object() == container()->containedWindow())
970 return 0;
971 return -1;
972}
973
974QAccessibleInterface *QAccessibleWindowContainer::child(int i) const
975{
976 if (i == 0)
977 return QAccessible::queryAccessibleInterface(container()->containedWindow());
978 return nullptr;
979}
980
981QWindowContainer *QAccessibleWindowContainer::container() const
982{
983 return static_cast<QWindowContainer *>(widget());
984}
985
986#endif // QT_NO_ACCESSIBILITY
987
988QT_END_NAMESPACE
989

source code of qtbase/src/widgets/accessible/simplewidgets.cpp