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(QLatin1String("toggled(bool)"));
124 else
125 addControllingSignal(QLatin1String("clicked()"));
126}
127
128/*! Returns the button. */
129QAbstractButton *QAccessibleButton::button() const
130{
131 return qobject_cast<QAbstractButton*>(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());
143 if (pb && pb->isDefault())
144 str = QKeySequence(Qt::Key_Enter).toString(QKeySequence::NativeText);
145#endif
146 if (str.isEmpty())
147 str = qt_accHotKey(button()->text());
148 }
149 break;
150 case QAccessible::Name:
151 str = widget()->accessibleName();
152 if (str.isEmpty())
153 str = qt_accStripAmp(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 *>(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*>(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 *>(ab)) {
204 QPoint wpos = cb->mapToGlobal(QPoint(0, 0));
205 QStyleOptionButton opt;
206 cb->initStyleOption(&opt);
207 return cb->style()->subElementRect(QStyle::SE_CheckBoxClickRect, &opt, cb).translated(wpos);
208 }
209#endif
210#if QT_CONFIG(radiobutton)
211 else if (QRadioButton *rb = qobject_cast<QRadioButton *>(ab)) {
212 QPoint wpos = rb->mapToGlobal(QPoint(0, 0));
213 QStyleOptionButton opt;
214 rb->initStyleOption(&opt);
215 return rb->style()->subElementRect(QStyle::SE_RadioButtonClickRect, &opt, rb).translated(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*>(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());
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());
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*>(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());
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())) {
449 return QAccessible::ProgressBar;
450#endif
451#if QT_CONFIG(statusbar)
452 } else if (qobject_cast<QStatusBar*>(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())) {
477 QLabel *label = qobject_cast<QLabel*>(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(str);
490#endif
491#endif // QT_CONFIG(label)
492#if QT_CONFIG(lcdnumber)
493 } else if (qobject_cast<QLCDNumber*>(object())) {
494 QLCDNumber *l = qobject_cast<QLCDNumber*>(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())) {
502 return qobject_cast<QStatusBar*>(object())->currentMessage();
503#endif
504 }
505 }
506 break;
507 case QAccessible::Value:
508#if QT_CONFIG(progressbar)
509 if (qobject_cast<QProgressBar*>(object()))
510 str = QString::number(qobject_cast<QProgressBar*>(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 */
522QList<QPair<QAccessibleInterface *, QAccessible::Relation>>
523QAccessibleDisplay::relations(QAccessible::Relation match /* = QAccessible::AllRelations */) const
524{
525 QList<QPair<QAccessibleInterface *, QAccessible::Relation>> rels =
526 QAccessibleWidget::relations(match);
527# if QT_CONFIG(shortcut) && QT_CONFIG(label)
528 if (match & QAccessible::Labelled) {
529 if (QLabel *label = qobject_cast<QLabel*>(object())) {
530 const QAccessible::Relation rel = QAccessible::Labelled;
531 if (QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(label->buddy()))
532 rels.append(qMakePair(iface, rel));
533 }
534 }
535#endif
536 return rels;
537}
538
539void *QAccessibleDisplay::interface_cast(QAccessible::InterfaceType t)
540{
541 if (t == QAccessible::ImageInterface)
542 return static_cast<QAccessibleImageInterface*>(this);
543 return QAccessibleWidget::interface_cast(t);
544}
545
546/*! \internal */
547QString QAccessibleDisplay::imageDescription() const
548{
549#if QT_CONFIG(tooltip)
550 return widget()->toolTip();
551#else
552 return QString();
553#endif
554}
555
556/*! \internal */
557QSize QAccessibleDisplay::imageSize() const
558{
559#if QT_CONFIG(label)
560 QLabel *label = qobject_cast<QLabel *>(widget());
561 if (!label)
562#endif
563 return QSize();
564#if QT_CONFIG(label)
565 return label->pixmap(Qt::ReturnByValue).size();
566#endif
567}
568
569/*! \internal */
570QPoint QAccessibleDisplay::imagePosition() const
571{
572#if QT_CONFIG(label)
573 QLabel *label = qobject_cast<QLabel *>(widget());
574 if (!label)
575#endif
576 return QPoint();
577#if QT_CONFIG(label)
578 if (label->pixmap(Qt::ReturnByValue).isNull())
579 return QPoint();
580
581 return QPoint(label->mapToGlobal(label->pos()));
582#endif
583}
584
585#if QT_CONFIG(groupbox)
586QAccessibleGroupBox::QAccessibleGroupBox(QWidget *w)
587: QAccessibleWidget(w)
588{
589}
590
591QGroupBox* QAccessibleGroupBox::groupBox() const
592{
593 return static_cast<QGroupBox *>(widget());
594}
595
596QString QAccessibleGroupBox::text(QAccessible::Text t) const
597{
598 QString txt = QAccessibleWidget::text(t);
599
600 if (txt.isEmpty()) {
601 switch (t) {
602 case QAccessible::Name:
603 txt = qt_accStripAmp(groupBox()->title());
604 break;
605#if QT_CONFIG(tooltip)
606 case QAccessible::Description:
607 txt = groupBox()->toolTip();
608 break;
609#endif
610 case QAccessible::Accelerator:
611 txt = qt_accHotKey(groupBox()->title());
612 break;
613 default:
614 break;
615 }
616 }
617
618 return txt;
619}
620
621QAccessible::State QAccessibleGroupBox::state() const
622{
623 QAccessible::State st = QAccessibleWidget::state();
624 st.checkable = groupBox()->isCheckable();
625 st.checked = groupBox()->isChecked();
626 return st;
627}
628
629QAccessible::Role QAccessibleGroupBox::role() const
630{
631 return groupBox()->isCheckable() ? QAccessible::CheckBox : QAccessible::Grouping;
632}
633
634QList<QPair<QAccessibleInterface *, QAccessible::Relation>>
635QAccessibleGroupBox::relations(QAccessible::Relation match /* = QAccessible::AllRelations */) const
636{
637 QList<QPair<QAccessibleInterface *, QAccessible::Relation>> rels =
638 QAccessibleWidget::relations(match);
639
640 if ((match & QAccessible::Labelled) && (!groupBox()->title().isEmpty())) {
641 const QList<QWidget*> kids = childWidgets(widget());
642 for (QWidget *kid : kids) {
643 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(kid);
644 if (iface)
645 rels.append(qMakePair(iface, QAccessible::Relation(QAccessible::Labelled)));
646 }
647 }
648 return rels;
649}
650
651QStringList QAccessibleGroupBox::actionNames() const
652{
653 QStringList actions = QAccessibleWidget::actionNames();
654
655 if (groupBox()->isCheckable()) {
656 actions.prepend(QAccessibleActionInterface::toggleAction());
657 }
658 return actions;
659}
660
661void QAccessibleGroupBox::doAction(const QString &actionName)
662{
663 if (actionName == QAccessibleActionInterface::toggleAction())
664 groupBox()->setChecked(!groupBox()->isChecked());
665}
666
667QStringList QAccessibleGroupBox::keyBindingsForAction(const QString &) const
668{
669 return QStringList();
670}
671
672#endif
673
674#if QT_CONFIG(lineedit)
675/*!
676 \class QAccessibleLineEdit
677 \brief The QAccessibleLineEdit class implements the QAccessibleInterface for widgets with editable text
678 \internal
679
680 \ingroup accessibility
681*/
682
683/*!
684 Constructs a QAccessibleLineEdit object for \a w.
685 \a name is propagated to the QAccessibleWidget constructor.
686*/
687QAccessibleLineEdit::QAccessibleLineEdit(QWidget *w, const QString &name)
688: QAccessibleWidget(w, QAccessible::EditableText, name)
689{
690 addControllingSignal(QLatin1String("textChanged(const QString&)"));
691 addControllingSignal(QLatin1String("returnPressed()"));
692}
693
694/*! Returns the line edit. */
695QLineEdit *QAccessibleLineEdit::lineEdit() const
696{
697 return qobject_cast<QLineEdit*>(object());
698}
699
700QString QAccessibleLineEdit::text(QAccessible::Text t) const
701{
702 QString str;
703 switch (t) {
704 case QAccessible::Value:
705 if (lineEdit()->echoMode() == QLineEdit::Normal)
706 str = lineEdit()->text();
707 else if (lineEdit()->echoMode() != QLineEdit::NoEcho)
708 str = QString(lineEdit()->text().length(), QChar::fromLatin1('*'));
709 break;
710 default:
711 break;
712 }
713 if (str.isEmpty())
714 str = QAccessibleWidget::text(t);
715 if (str.isEmpty() && t == QAccessible::Description)
716 str = lineEdit()->placeholderText();
717 return str;
718}
719
720void QAccessibleLineEdit::setText(QAccessible::Text t, const QString &text)
721{
722 if (t != QAccessible::Value) {
723 QAccessibleWidget::setText(t, text);
724 return;
725 }
726
727 QString newText = text;
728#if QT_CONFIG(validator)
729 if (lineEdit()->validator()) {
730 int pos = 0;
731 if (lineEdit()->validator()->validate(newText, pos) != QValidator::Acceptable)
732 return;
733 }
734#endif
735 lineEdit()->setText(newText);
736}
737
738QAccessible::State QAccessibleLineEdit::state() const
739{
740 QAccessible::State state = QAccessibleWidget::state();
741
742 QLineEdit *l = lineEdit();
743 state.editable = true;
744 if (l->isReadOnly())
745 state.readOnly = true;
746
747 if (l->echoMode() != QLineEdit::Normal)
748 state.passwordEdit = true;
749
750 state.selectableText = true;
751 return state;
752}
753
754void *QAccessibleLineEdit::interface_cast(QAccessible::InterfaceType t)
755{
756 if (t == QAccessible::TextInterface)
757 return static_cast<QAccessibleTextInterface*>(this);
758 if (t == QAccessible::EditableTextInterface)
759 return static_cast<QAccessibleEditableTextInterface*>(this);
760 return QAccessibleWidget::interface_cast(t);
761}
762
763void QAccessibleLineEdit::addSelection(int startOffset, int endOffset)
764{
765 setSelection(0, startOffset, endOffset);
766}
767
768QString QAccessibleLineEdit::attributes(int offset, int *startOffset, int *endOffset) const
769{
770 // QLineEdit doesn't have text attributes
771 *startOffset = *endOffset = offset;
772 return QString();
773}
774
775int QAccessibleLineEdit::cursorPosition() const
776{
777 return lineEdit()->cursorPosition();
778}
779
780QRect QAccessibleLineEdit::characterRect(int offset) const
781{
782 int x = lineEdit()->d_func()->control->cursorToX(offset);
783 int y = lineEdit()->textMargins().top();
784 QFontMetrics fm(lineEdit()->font());
785 const QString ch = text(offset, offset + 1);
786 if (ch.isEmpty())
787 return QRect();
788 int w = fm.horizontalAdvance(ch);
789 int h = fm.height();
790 QRect r(x, y, w, h);
791 r.moveTo(lineEdit()->mapToGlobal(r.topLeft()));
792 return r;
793}
794
795int QAccessibleLineEdit::selectionCount() const
796{
797 return lineEdit()->hasSelectedText() ? 1 : 0;
798}
799
800int QAccessibleLineEdit::offsetAtPoint(const QPoint &point) const
801{
802 QPoint p = lineEdit()->mapFromGlobal(point);
803
804 return lineEdit()->cursorPositionAt(p);
805}
806
807void QAccessibleLineEdit::selection(int selectionIndex, int *startOffset, int *endOffset) const
808{
809 *startOffset = *endOffset = 0;
810 if (selectionIndex != 0)
811 return;
812
813 *startOffset = lineEdit()->selectionStart();
814 *endOffset = *startOffset + lineEdit()->selectedText().count();
815}
816
817QString QAccessibleLineEdit::text(int startOffset, int endOffset) const
818{
819 if (startOffset > endOffset)
820 return QString();
821
822 if (lineEdit()->echoMode() != QLineEdit::Normal)
823 return QString();
824
825 return lineEdit()->text().mid(startOffset, endOffset - startOffset);
826}
827
828QString QAccessibleLineEdit::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType,
829 int *startOffset, int *endOffset) const
830{
831 if (lineEdit()->echoMode() != QLineEdit::Normal) {
832 *startOffset = *endOffset = -1;
833 return QString();
834 }
835 if (offset == -2)
836 offset = cursorPosition();
837 return QAccessibleTextInterface::textBeforeOffset(offset, boundaryType, startOffset, endOffset);
838}
839
840QString QAccessibleLineEdit::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType,
841 int *startOffset, int *endOffset) const
842{
843 if (lineEdit()->echoMode() != QLineEdit::Normal) {
844 *startOffset = *endOffset = -1;
845 return QString();
846 }
847 if (offset == -2)
848 offset = cursorPosition();
849 return QAccessibleTextInterface::textAfterOffset(offset, boundaryType, startOffset, endOffset);
850}
851
852QString QAccessibleLineEdit::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType,
853 int *startOffset, int *endOffset) const
854{
855 if (lineEdit()->echoMode() != QLineEdit::Normal) {
856 *startOffset = *endOffset = -1;
857 return QString();
858 }
859 if (offset == -2)
860 offset = cursorPosition();
861 return QAccessibleTextInterface::textAtOffset(offset, boundaryType, startOffset, endOffset);
862}
863
864void QAccessibleLineEdit::removeSelection(int selectionIndex)
865{
866 if (selectionIndex != 0)
867 return;
868
869 lineEdit()->deselect();
870}
871
872void QAccessibleLineEdit::setCursorPosition(int position)
873{
874 lineEdit()->setCursorPosition(position);
875}
876
877void QAccessibleLineEdit::setSelection(int selectionIndex, int startOffset, int endOffset)
878{
879 if (selectionIndex != 0)
880 return;
881
882 lineEdit()->setSelection(startOffset, endOffset - startOffset);
883}
884
885int QAccessibleLineEdit::characterCount() const
886{
887 return lineEdit()->text().count();
888}
889
890void QAccessibleLineEdit::scrollToSubstring(int startIndex, int endIndex)
891{
892 lineEdit()->setCursorPosition(endIndex);
893 lineEdit()->setCursorPosition(startIndex);
894}
895
896void QAccessibleLineEdit::deleteText(int startOffset, int endOffset)
897{
898 lineEdit()->setText(lineEdit()->text().remove(startOffset, endOffset - startOffset));
899}
900
901void QAccessibleLineEdit::insertText(int offset, const QString &text)
902{
903 lineEdit()->setText(lineEdit()->text().insert(offset, text));
904}
905
906void QAccessibleLineEdit::replaceText(int startOffset, int endOffset, const QString &text)
907{
908 lineEdit()->setText(lineEdit()->text().replace(startOffset, endOffset - startOffset, text));
909}
910
911#endif // QT_CONFIG(lineedit)
912
913#if QT_CONFIG(progressbar)
914QAccessibleProgressBar::QAccessibleProgressBar(QWidget *o)
915 : QAccessibleDisplay(o)
916{
917 Q_ASSERT(progressBar());
918}
919
920void *QAccessibleProgressBar::interface_cast(QAccessible::InterfaceType t)
921{
922 if (t == QAccessible::ValueInterface)
923 return static_cast<QAccessibleValueInterface*>(this);
924 return QAccessibleDisplay::interface_cast(t);
925}
926
927QVariant QAccessibleProgressBar::currentValue() const
928{
929 return progressBar()->value();
930}
931
932QVariant QAccessibleProgressBar::maximumValue() const
933{
934 return progressBar()->maximum();
935}
936
937QVariant QAccessibleProgressBar::minimumValue() const
938{
939 return progressBar()->minimum();
940}
941
942QVariant QAccessibleProgressBar::minimumStepSize() const
943{
944 // This is arbitrary since any value between min and max is valid.
945 // Some screen readers (orca use it to calculate how many digits to display though,
946 // so it makes sense to return a "sensible" value. Providing 100 increments seems ok.
947 return (progressBar()->maximum() - progressBar()->minimum()) / 100.0;
948}
949
950QProgressBar *QAccessibleProgressBar::progressBar() const
951{
952 return qobject_cast<QProgressBar *>(object());
953}
954#endif
955
956
957QAccessibleWindowContainer::QAccessibleWindowContainer(QWidget *w)
958 : QAccessibleWidget(w)
959{
960}
961
962int QAccessibleWindowContainer::childCount() const
963{
964 if (container()->containedWindow() && QAccessible::queryAccessibleInterface(container()->containedWindow()))
965 return 1;
966 return 0;
967}
968
969int QAccessibleWindowContainer::indexOfChild(const QAccessibleInterface *child) const
970{
971 if (child->object() == container()->containedWindow())
972 return 0;
973 return -1;
974}
975
976QAccessibleInterface *QAccessibleWindowContainer::child(int i) const
977{
978 if (i == 0)
979 return QAccessible::queryAccessibleInterface(container()->containedWindow());
980 return nullptr;
981}
982
983QWindowContainer *QAccessibleWindowContainer::container() const
984{
985 return static_cast<QWindowContainer *>(widget());
986}
987
988#endif // QT_NO_ACCESSIBILITY
989
990QT_END_NAMESPACE
991