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