Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qaccessiblewidgets.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
6#include "qapplication.h"
7#include "qclipboard.h"
8#include "qtextdocument.h"
9#include "qtextobject.h"
10#if QT_CONFIG(textedit)
11#include "qplaintextedit.h"
12#include "qtextedit.h"
13#include "private/qtextedit_p.h"
14#endif
15#include "qtextboundaryfinder.h"
16#if QT_CONFIG(scrollbar)
17#include "qscrollbar.h"
18#endif
19#include "qdebug.h"
20#include <QApplication>
21#if QT_CONFIG(stackedwidget)
22#include <QStackedWidget>
23#endif
24#if QT_CONFIG(toolbox)
25#include <QToolBox>
26#endif
27#if QT_CONFIG(mdiarea)
28#include <QMdiArea>
29#include <QMdiSubWindow>
30#endif
31#if QT_CONFIG(dialogbuttonbox)
32#include <QDialogButtonBox>
33#endif
34#include <limits.h>
35#if QT_CONFIG(rubberband)
36#include <QRubberBand>
37#endif
38#if QT_CONFIG(textbrowser)
39#include <QTextBrowser>
40#endif
41#if QT_CONFIG(calendarwidget)
42#include <QCalendarWidget>
43#endif
44#if QT_CONFIG(itemviews)
45#include <QAbstractItemView>
46#endif
47#if QT_CONFIG(dockwidget)
48#include <QDockWidget>
49#include <private/qdockwidget_p.h>
50#endif
51#if QT_CONFIG(mainwindow)
52#include <QMainWindow>
53#endif
54#include <QFocusFrame>
55#if QT_CONFIG(menu)
56#include <QMenu>
57#endif
58
59#if QT_CONFIG(accessibility)
60
62
63using namespace Qt::StringLiterals;
64
65QString qt_accStripAmp(const QString &text);
66QString qt_accHotKey(const QString &text);
67
68QWidgetList _q_ac_childWidgets(const QWidget *widget)
69{
71 if (!widget)
72 return widgets;
73 for (QObject *o : widget->children()) {
75 if (!w)
76 continue;
77 QString objectName = w->objectName();
78 if (!w->isWindow()
79 && !qobject_cast<QFocusFrame*>(w)
80#if QT_CONFIG(menu)
81 && !qobject_cast<QMenu*>(w)
82#endif
83 // Exclude widgets used as implementation details
84 && objectName != "qt_rubberband"_L1
85 && objectName != "qt_qmainwindow_extended_splitter"_L1
86 && objectName != "qt_spinbox_lineedit"_L1) {
88 }
89 }
90 return widgets;
91}
92
93#if QT_CONFIG(textedit) && !defined(QT_NO_CURSOR)
94
95QAccessiblePlainTextEdit::QAccessiblePlainTextEdit(QWidget* o)
96 :QAccessibleTextWidget(o)
97{
98 Q_ASSERT(widget()->inherits("QPlainTextEdit"));
99}
100
101QPlainTextEdit* QAccessiblePlainTextEdit::plainTextEdit() const
102{
103 return static_cast<QPlainTextEdit *>(widget());
104}
105
106QString QAccessiblePlainTextEdit::text(QAccessible::Text t) const
107{
108 if (t == QAccessible::Value)
109 return plainTextEdit()->toPlainText();
110
111 return QAccessibleWidget::text(t);
112}
113
114void QAccessiblePlainTextEdit::setText(QAccessible::Text t, const QString &text)
115{
116 if (t != QAccessible::Value) {
117 QAccessibleWidget::setText(t, text);
118 return;
119 }
120 if (plainTextEdit()->isReadOnly())
121 return;
122
123 plainTextEdit()->setPlainText(text);
124}
125
126QAccessible::State QAccessiblePlainTextEdit::state() const
127{
128 QAccessible::State st = QAccessibleTextWidget::state();
129 if (plainTextEdit()->isReadOnly())
130 st.readOnly = true;
131 else
132 st.editable = true;
133 return st;
134}
135
136void *QAccessiblePlainTextEdit::interface_cast(QAccessible::InterfaceType t)
137{
138 if (t == QAccessible::TextInterface)
139 return static_cast<QAccessibleTextInterface*>(this);
140 else if (t == QAccessible::EditableTextInterface)
141 return static_cast<QAccessibleEditableTextInterface*>(this);
142 return QAccessibleWidget::interface_cast(t);
143}
144
145QPoint QAccessiblePlainTextEdit::scrollBarPosition() const
146{
148 result.setX(plainTextEdit()->horizontalScrollBar() ? plainTextEdit()->horizontalScrollBar()->sliderPosition() : 0);
149 result.setY(plainTextEdit()->verticalScrollBar() ? plainTextEdit()->verticalScrollBar()->sliderPosition() : 0);
150 return result;
151}
152
153QTextCursor QAccessiblePlainTextEdit::textCursor() const
154{
155 return plainTextEdit()->textCursor();
156}
157
158void QAccessiblePlainTextEdit::setTextCursor(const QTextCursor &textCursor)
159{
160 plainTextEdit()->setTextCursor(textCursor);
161}
162
163QTextDocument* QAccessiblePlainTextEdit::textDocument() const
164{
165 return plainTextEdit()->document();
166}
167
168QWidget* QAccessiblePlainTextEdit::viewport() const
169{
170 return plainTextEdit()->viewport();
171}
172
173void QAccessiblePlainTextEdit::scrollToSubstring(int startIndex, int endIndex)
174{
175 //TODO: Not implemented
176 Q_UNUSED(startIndex);
177 Q_UNUSED(endIndex);
178}
179
180
192QAccessibleTextEdit::QAccessibleTextEdit(QWidget *o)
193: QAccessibleTextWidget(o, QAccessible::EditableText)
194{
195 Q_ASSERT(widget()->inherits("QTextEdit"));
196}
197
199QTextEdit *QAccessibleTextEdit::textEdit() const
200{
201 return static_cast<QTextEdit *>(widget());
202}
203
204QTextCursor QAccessibleTextEdit::textCursor() const
205{
206 return textEdit()->textCursor();
207}
208
209QTextDocument *QAccessibleTextEdit::textDocument() const
210{
211 return textEdit()->document();
212}
213
214void QAccessibleTextEdit::setTextCursor(const QTextCursor &textCursor)
215{
216 textEdit()->setTextCursor(textCursor);
217}
218
219QWidget *QAccessibleTextEdit::viewport() const
220{
221 return textEdit()->viewport();
222}
223
224QPoint QAccessibleTextEdit::scrollBarPosition() const
225{
227 result.setX(textEdit()->horizontalScrollBar() ? textEdit()->horizontalScrollBar()->sliderPosition() : 0);
228 result.setY(textEdit()->verticalScrollBar() ? textEdit()->verticalScrollBar()->sliderPosition() : 0);
229 return result;
230}
231
232QString QAccessibleTextEdit::text(QAccessible::Text t) const
233{
234 if (t == QAccessible::Value)
235 return textEdit()->toPlainText();
236
237 return QAccessibleWidget::text(t);
238}
239
240void QAccessibleTextEdit::setText(QAccessible::Text t, const QString &text)
241{
242 if (t != QAccessible::Value) {
243 QAccessibleWidget::setText(t, text);
244 return;
245 }
246 if (textEdit()->isReadOnly())
247 return;
248
249 textEdit()->setText(text);
250}
251
252QAccessible::State QAccessibleTextEdit::state() const
253{
254 QAccessible::State st = QAccessibleTextWidget::state();
255 if (textEdit()->isReadOnly())
256 st.readOnly = true;
257 else
258 st.editable = true;
259 return st;
260}
261
262void *QAccessibleTextEdit::interface_cast(QAccessible::InterfaceType t)
263{
264 if (t == QAccessible::TextInterface)
265 return static_cast<QAccessibleTextInterface*>(this);
266 else if (t == QAccessible::EditableTextInterface)
267 return static_cast<QAccessibleEditableTextInterface*>(this);
268 return QAccessibleWidget::interface_cast(t);
269}
270
271void QAccessibleTextEdit::scrollToSubstring(int startIndex, int endIndex)
272{
274
276 cursor.setPosition(startIndex);
278
279 cursor.setPosition(endIndex);
280 r.setBottomRight(edit->cursorRect(cursor).bottomRight());
281
282 r.moveTo(r.x() + edit->horizontalScrollBar()->value(),
283 r.y() + edit->verticalScrollBar()->value());
284
285 // E V I L, but ensureVisible is not public
286 if (Q_UNLIKELY(!QMetaObject::invokeMethod(edit, "_q_ensureVisible", Q_ARG(QRectF, r))))
287 qWarning("AccessibleTextEdit::scrollToSubstring failed!");
288}
289
290#endif // QT_CONFIG(textedit) && QT_NO_CURSOR
291
292#if QT_CONFIG(stackedwidget)
293// ======================= QAccessibleStackedWidget ======================
294QAccessibleStackedWidget::QAccessibleStackedWidget(QWidget *widget)
295 : QAccessibleWidget(widget, QAccessible::LayeredPane)
296{
297 Q_ASSERT(qobject_cast<QStackedWidget *>(widget));
298}
299
300QAccessibleInterface *QAccessibleStackedWidget::childAt(int x, int y) const
301{
302 if (!stackedWidget()->isVisible())
303 return nullptr;
304 QWidget *currentWidget = stackedWidget()->currentWidget();
305 if (!currentWidget)
306 return nullptr;
307 QPoint position = currentWidget->mapFromGlobal(QPoint(x, y));
308 if (currentWidget->rect().contains(position))
309 return child(stackedWidget()->currentIndex());
310 return nullptr;
311}
312
313int QAccessibleStackedWidget::childCount() const
314{
315 return stackedWidget()->count();
316}
317
318int QAccessibleStackedWidget::indexOfChild(const QAccessibleInterface *child) const
319{
320 if (!child)
321 return -1;
322
324 return stackedWidget()->indexOf(widget);
325}
326
327QAccessibleInterface *QAccessibleStackedWidget::child(int index) const
328{
329 if (index < 0 || index >= stackedWidget()->count())
330 return nullptr;
331 return QAccessible::queryAccessibleInterface(stackedWidget()->widget(index));
332}
333
334QStackedWidget *QAccessibleStackedWidget::stackedWidget() const
335{
336 return static_cast<QStackedWidget *>(object());
337}
338#endif // QT_CONFIG(stackedwidget)
339
340#if QT_CONFIG(toolbox)
341// ======================= QAccessibleToolBox ======================
342QAccessibleToolBox::QAccessibleToolBox(QWidget *widget)
343 : QAccessibleWidget(widget, QAccessible::LayeredPane)
344{
345 Q_ASSERT(qobject_cast<QToolBox *>(widget));
346}
347
348QToolBox * QAccessibleToolBox::toolBox() const
349{
350 return static_cast<QToolBox *>(object());
351}
352#endif // QT_CONFIG(toolbox)
353
354// ======================= QAccessibleMdiArea ======================
355#if QT_CONFIG(mdiarea)
356QAccessibleMdiArea::QAccessibleMdiArea(QWidget *widget)
357 : QAccessibleWidget(widget, QAccessible::LayeredPane)
358{
359 Q_ASSERT(qobject_cast<QMdiArea *>(widget));
360}
361
362int QAccessibleMdiArea::childCount() const
363{
364 return mdiArea()->subWindowList().size();
365}
366
367QAccessibleInterface *QAccessibleMdiArea::child(int index) const
368{
369 QList<QMdiSubWindow *> subWindows = mdiArea()->subWindowList();
370 QWidget *targetObject = subWindows.value(index);
371 if (!targetObject)
372 return nullptr;
373 return QAccessible::queryAccessibleInterface(targetObject);
374}
375
376
377int QAccessibleMdiArea::indexOfChild(const QAccessibleInterface *child) const
378{
379 if (!child || !child->object() || mdiArea()->subWindowList().isEmpty())
380 return -1;
381 if (QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(child->object())) {
382 return mdiArea()->subWindowList().indexOf(window);
383 }
384 return -1;
385}
386
387QMdiArea *QAccessibleMdiArea::mdiArea() const
388{
389 return static_cast<QMdiArea *>(object());
390}
391
392// ======================= QAccessibleMdiSubWindow ======================
393QAccessibleMdiSubWindow::QAccessibleMdiSubWindow(QWidget *widget)
394 : QAccessibleWidget(widget, QAccessible::Window)
395{
396 Q_ASSERT(qobject_cast<QMdiSubWindow *>(widget));
397}
398
399QString QAccessibleMdiSubWindow::text(QAccessible::Text textType) const
400{
401 if (textType == QAccessible::Name) {
402 QString title = mdiSubWindow()->windowTitle();
403 title.remove("[*]"_L1);
404 return title;
405 }
406 return QAccessibleWidget::text(textType);
407}
408
409void QAccessibleMdiSubWindow::setText(QAccessible::Text textType, const QString &text)
410{
411 if (textType == QAccessible::Name)
412 mdiSubWindow()->setWindowTitle(text);
413 else
414 QAccessibleWidget::setText(textType, text);
415}
416
417QAccessible::State QAccessibleMdiSubWindow::state() const
418{
420 state.focusable = true;
421 if (!mdiSubWindow()->isMaximized()) {
422 state.movable = true;
423 state.sizeable = true;
424 }
425 if (mdiSubWindow()->isAncestorOf(QApplication::focusWidget())
426 || QApplication::focusWidget() == mdiSubWindow())
427 state.focused = true;
428 if (!mdiSubWindow()->isVisible())
429 state.invisible = true;
430 if (const QWidget *parent = mdiSubWindow()->parentWidget())
431 if (!parent->contentsRect().contains(mdiSubWindow()->geometry()))
432 state.offscreen = true;
433 if (!mdiSubWindow()->isEnabled())
434 state.disabled = true;
435 return state;
436}
437
438int QAccessibleMdiSubWindow::childCount() const
439{
440 if (mdiSubWindow()->widget())
441 return 1;
442 return 0;
443}
444
445QAccessibleInterface *QAccessibleMdiSubWindow::child(int index) const
446{
447 QMdiSubWindow *source = mdiSubWindow();
448 if (index != 0 || !source->widget())
449 return nullptr;
450
451 return QAccessible::queryAccessibleInterface(source->widget());
452}
453
454int QAccessibleMdiSubWindow::indexOfChild(const QAccessibleInterface *child) const
455{
456 if (child && child->object() && child->object() == mdiSubWindow()->widget())
457 return 0;
458 return -1;
459}
460
461QRect QAccessibleMdiSubWindow::rect() const
462{
463 if (mdiSubWindow()->isHidden())
464 return QRect();
465 if (!mdiSubWindow()->parent())
466 return QAccessibleWidget::rect();
467 const QPoint pos = mdiSubWindow()->mapToGlobal(QPoint(0, 0));
468 return QRect(pos, mdiSubWindow()->size());
469}
470
471QMdiSubWindow *QAccessibleMdiSubWindow::mdiSubWindow() const
472{
473 return static_cast<QMdiSubWindow *>(object());
474}
475#endif // QT_CONFIG(mdiarea)
476
477#if QT_CONFIG(dialogbuttonbox)
478// ======================= QAccessibleDialogButtonBox ======================
479QAccessibleDialogButtonBox::QAccessibleDialogButtonBox(QWidget *widget)
480 : QAccessibleWidget(widget, QAccessible::Grouping)
481{
482 Q_ASSERT(qobject_cast<QDialogButtonBox*>(widget));
483}
484
485#endif // QT_CONFIG(dialogbuttonbox)
486
487#if QT_CONFIG(textbrowser) && !defined(QT_NO_CURSOR)
488QAccessibleTextBrowser::QAccessibleTextBrowser(QWidget *widget)
489 : QAccessibleTextEdit(widget)
490{
491 Q_ASSERT(qobject_cast<QTextBrowser *>(widget));
492}
493
494QAccessible::Role QAccessibleTextBrowser::role() const
495{
496 return QAccessible::StaticText;
497}
498#endif // QT_CONFIG(textbrowser) && QT_NO_CURSOR
499
500#if QT_CONFIG(calendarwidget)
501// ===================== QAccessibleCalendarWidget ========================
502QAccessibleCalendarWidget::QAccessibleCalendarWidget(QWidget *widget)
503 : QAccessibleWidget(widget, QAccessible::Table)
504{
505 Q_ASSERT(qobject_cast<QCalendarWidget *>(widget));
506}
507
508int QAccessibleCalendarWidget::childCount() const
509{
510 return calendarWidget()->isNavigationBarVisible() ? 2 : 1;
511}
512
513int QAccessibleCalendarWidget::indexOfChild(const QAccessibleInterface *child) const
514{
515 if (!child || !child->object() || childCount() <= 0)
516 return -1;
517 if (qobject_cast<QAbstractItemView *>(child->object()))
518 return childCount() - 1; // FIXME
519 return 0;
520}
521
522QAccessibleInterface *QAccessibleCalendarWidget::child(int index) const
523{
524 if (index < 0 || index >= childCount())
525 return nullptr;
526
527 if (childCount() > 1 && index == 0)
528 return QAccessible::queryAccessibleInterface(navigationBar());
529
530 return QAccessible::queryAccessibleInterface(calendarView());
531}
532
533QCalendarWidget *QAccessibleCalendarWidget::calendarWidget() const
534{
535 return static_cast<QCalendarWidget *>(object());
536}
537
538QAbstractItemView *QAccessibleCalendarWidget::calendarView() const
539{
540 for (QObject *child : calendarWidget()->children()) {
541 if (child->objectName() == "qt_calendar_calendarview"_L1)
542 return static_cast<QAbstractItemView *>(child);
543 }
544 return nullptr;
545}
546
547QWidget *QAccessibleCalendarWidget::navigationBar() const
548{
549 for (QObject *child : calendarWidget()->children()) {
550 if (child->objectName() == "qt_calendar_navigationbar"_L1)
551 return static_cast<QWidget *>(child);
552 }
553 return nullptr;
554}
555#endif // QT_CONFIG(calendarwidget)
556
557#if QT_CONFIG(dockwidget)
558
559// Dock Widget - order of children:
560// - Content widget
561// - Float button
562// - Close button
563// If there is a custom title bar widget, that one becomes child 1, after the content 0
564// (in that case the buttons are ignored)
565QAccessibleDockWidget::QAccessibleDockWidget(QWidget *widget)
566 : QAccessibleWidget(widget, QAccessible::Window)
567{
568}
569
570QDockWidgetLayout *QAccessibleDockWidget::dockWidgetLayout() const
571{
572 return qobject_cast<QDockWidgetLayout*>(dockWidget()->layout());
573}
574
575int QAccessibleDockWidget::childCount() const
576{
577 if (dockWidget()->titleBarWidget()) {
578 return dockWidget()->widget() ? 2 : 1;
579 }
580 return dockWidgetLayout()->count();
581}
582
583QAccessibleInterface *QAccessibleDockWidget::child(int index) const
584{
585 if (dockWidget()->titleBarWidget()) {
586 if ((!dockWidget()->widget() && index == 0) || (index == 1))
587 return QAccessible::queryAccessibleInterface(dockWidget()->titleBarWidget());
588 if (index == 0)
589 return QAccessible::queryAccessibleInterface(dockWidget()->widget());
590 } else {
591 QLayoutItem *item = dockWidgetLayout()->itemAt(index);
592 if (item)
593 return QAccessible::queryAccessibleInterface(item->widget());
594 }
595 return nullptr;
596}
597
598int QAccessibleDockWidget::indexOfChild(const QAccessibleInterface *child) const
599{
600 if (!child || !child->object() || child->object()->parent() != object())
601 return -1;
602
603 if (dockWidget()->titleBarWidget() == child->object()) {
604 return dockWidget()->widget() ? 1 : 0;
605 }
606
607 return dockWidgetLayout()->indexOf(qobject_cast<QWidget*>(child->object()));
608}
609
610QRect QAccessibleDockWidget::rect() const
611{
612 QRect rect;
613
614 if (dockWidget()->isFloating()) {
616 } else {
617 rect = dockWidget()->rect();
618 rect.moveTopLeft(dockWidget()->mapToGlobal(rect.topLeft()));
619 }
620
621 return rect;
622}
623
624QDockWidget *QAccessibleDockWidget::dockWidget() const
625{
626 return static_cast<QDockWidget *>(object());
627}
628
629QString QAccessibleDockWidget::text(QAccessible::Text t) const
630{
631 if (t == QAccessible::Name) {
632 return qt_accStripAmp(dockWidget()->windowTitle());
633 } else if (t == QAccessible::Accelerator) {
634 return qt_accHotKey(dockWidget()->windowTitle());
635 }
636 return QString();
637}
638#endif // QT_CONFIG(dockwidget)
639
640#ifndef QT_NO_CURSOR
641
642QAccessibleTextWidget::QAccessibleTextWidget(QWidget *o, QAccessible::Role r, const QString &name):
643 QAccessibleWidget(o, r, name)
644{
645
646}
647
648QAccessible::State QAccessibleTextWidget::state() const
649{
650 QAccessible::State s = QAccessibleWidget::state();
651 s.selectableText = true;
652 s.multiLine = true;
653 return s;
654}
655
656QRect QAccessibleTextWidget::characterRect(int offset) const
657{
659 if (!block.isValid())
660 return QRect();
661
662 QTextLayout *layout = block.layout();
663 QPointF layoutPosition = layout->position();
664 int relativeOffset = offset - block.position();
665 QTextLine line = layout->lineForTextPosition(relativeOffset);
666
667 QRect r;
668
669 if (line.isValid()) {
670 qreal x = line.cursorToX(relativeOffset);
671
674 if (iter.atEnd())
675 format = block.charFormat();
676 else {
677 while (!iter.atEnd() && !iter.fragment().contains(offset))
678 ++iter;
679 if (iter.atEnd()) // newline should have same format as preceding character
680 --iter;
681 format = iter.fragment().charFormat();
682 }
683
684 QFontMetrics fm(format.font());
685 const QString ch = text(offset, offset + 1);
686 if (!ch.isEmpty()) {
687 int w = fm.horizontalAdvance(ch);
688 int h = fm.height();
689 r = QRect(layoutPosition.x() + x, layoutPosition.y() + line.y() + line.ascent() + fm.descent() - h,
690 w, h);
691 r.moveTo(viewport()->mapToGlobal(r.topLeft()));
692 }
693 r.translate(-scrollBarPosition());
694 }
695
696 return r;
697}
698
699int QAccessibleTextWidget::offsetAtPoint(const QPoint &point) const
700{
701 QPoint p = viewport()->mapFromGlobal(point);
702 // convert to document coordinates
703 p += scrollBarPosition();
705}
706
707int QAccessibleTextWidget::selectionCount() const
708{
709 return textCursor().hasSelection() ? 1 : 0;
710}
711
712namespace {
724class AttributeFormatterRef {
726 const char *key;
727 friend class AttributeFormatter;
728 AttributeFormatterRef(QString &string, const char *key) : string(string), key(key) {}
729public:
730 template <typename RHS>
731 void operator=(RHS &&rhs)
732 { string += QLatin1StringView(key) + u':' + std::forward<RHS>(rhs) + u';'; }
733};
734
749class AttributeFormatter {
751public:
752 AttributeFormatterRef operator[](const char *key)
753 { return AttributeFormatterRef(string, key); }
754
755 QString toFormatted() const { return string; }
756};
757} // unnamed namespace
758
759QString QAccessibleTextWidget::attributes(int offset, int *startOffset, int *endOffset) const
760{
761 /* The list of attributes can be found at:
762 http://linuxfoundation.org/collaborate/workgroups/accessibility/iaccessible2/textattributes
763 */
764
765 // IAccessible2 defines -1 as length and -2 as cursor position
766 if (offset == -2)
767 offset = cursorPosition();
768
769 const int charCount = characterCount();
770
771 // -1 doesn't make much sense here, but it's better to return something
772 // screen readers may ask for text attributes at the cursor pos which may be equal to length
773 if (offset == -1 || offset == charCount)
774 offset = charCount - 1;
775
776 if (offset < 0 || offset > charCount) {
777 *startOffset = -1;
778 *endOffset = -1;
779 return QString();
780 }
781
782
784 cursor.setPosition(offset);
785 QTextBlock block = cursor.block();
786
787 int blockStart = block.position();
788 int blockEnd = blockStart + block.length();
789
791 int lastFragmentIndex = blockStart;
792 while (!iter.atEnd()) {
793 QTextFragment f = iter.fragment();
794 if (f.contains(offset))
795 break;
796 lastFragmentIndex = f.position() + f.length();
797 ++iter;
798 }
799
800 QTextCharFormat charFormat;
801 if (!iter.atEnd()) {
802 QTextFragment fragment = iter.fragment();
803 charFormat = fragment.charFormat();
804 int pos = fragment.position();
805 // text block and fragment may overlap, use the smallest common range
806 *startOffset = qMax(pos, blockStart);
807 *endOffset = qMin(pos + fragment.length(), blockEnd);
808 } else {
809 charFormat = block.charFormat();
810 *startOffset = lastFragmentIndex;
811 *endOffset = blockEnd;
812 }
813 Q_ASSERT(*startOffset <= offset);
814 Q_ASSERT(*endOffset >= offset);
815
816 QTextBlockFormat blockFormat = cursor.blockFormat();
817
818 const QFont charFormatFont = charFormat.font();
819
820 AttributeFormatter attrs;
821 QString family = charFormatFont.families().value(0, QString());
822 if (!family.isEmpty()) {
823 family = family.replace(u'\\', "\\\\"_L1);
824 family = family.replace(u':', "\\:"_L1);
825 family = family.replace(u',', "\\,"_L1);
826 family = family.replace(u'=', "\\="_L1);
827 family = family.replace(u';', "\\;"_L1);
828 family = family.replace(u'\"', "\\\""_L1);
829 attrs["font-family"] = u'"' + family + u'"';
830 }
831
832 int fontSize = int(charFormatFont.pointSize());
833 if (fontSize)
834 attrs["font-size"] = QString::fromLatin1("%1pt").arg(fontSize);
835
836 //Different weight values are not handled
837 attrs["font-weight"] = QString::fromLatin1(charFormatFont.weight() > QFont::Normal ? "bold" : "normal");
838
839 QFont::Style style = charFormatFont.style();
840 attrs["font-style"] = QString::fromLatin1((style == QFont::StyleItalic) ? "italic" : ((style == QFont::StyleOblique) ? "oblique": "normal"));
841
842 QTextCharFormat::UnderlineStyle underlineStyle = charFormat.underlineStyle();
843 if (underlineStyle == QTextCharFormat::NoUnderline && charFormatFont.underline()) // underline could still be set in the default font
844 underlineStyle = QTextCharFormat::SingleUnderline;
845 QString underlineStyleValue;
846 switch (underlineStyle) {
848 break;
850 underlineStyleValue = QStringLiteral("solid");
851 break;
853 underlineStyleValue = QStringLiteral("dash");
854 break;
856 underlineStyleValue = QStringLiteral("dash");
857 break;
859 underlineStyleValue = QStringLiteral("dot-dash");
860 break;
862 underlineStyleValue = QStringLiteral("dot-dot-dash");
863 break;
865 underlineStyleValue = QStringLiteral("wave");
866 break;
868 underlineStyleValue = QStringLiteral("wave"); // this is not correct, but provides good approximation at least
869 break;
870 default:
871 qWarning() << "Unknown QTextCharFormat::​UnderlineStyle value " << underlineStyle << " could not be translated to IAccessible2 value";
872 break;
873 }
874 if (!underlineStyleValue.isNull()) {
875 attrs["text-underline-style"] = underlineStyleValue;
876 attrs["text-underline-type"] = QStringLiteral("single"); // if underlineStyleValue is set, there is an underline, and Qt does not support other than single ones
877 } // else both are "none" which is the default - no need to set them
878
879 if (block.textDirection() == Qt::RightToLeft)
880 attrs["writing-mode"] = QStringLiteral("rl");
881
883 attrs["text-position"] = QString::fromLatin1((alignment == QTextCharFormat::AlignSubScript) ? "sub" : ((alignment == QTextCharFormat::AlignSuperScript) ? "super" : "baseline" ));
884
885 QBrush background = charFormat.background();
886 if (background.style() == Qt::SolidPattern) {
887 attrs["background-color"] = QString::fromLatin1("rgb(%1,%2,%3)").arg(background.color().red()).arg(background.color().green()).arg(background.color().blue());
888 }
889
890 QBrush foreground = charFormat.foreground();
891 if (foreground.style() == Qt::SolidPattern) {
892 attrs["color"] = QString::fromLatin1("rgb(%1,%2,%3)").arg(foreground.color().red()).arg(foreground.color().green()).arg(foreground.color().blue());
893 }
894
896 case Qt::AlignLeft:
897 attrs["text-align"] = QStringLiteral("left");
898 break;
899 case Qt::AlignRight:
900 attrs["text-align"] = QStringLiteral("right");
901 break;
902 case Qt::AlignHCenter:
903 attrs["text-align"] = QStringLiteral("center");
904 break;
905 case Qt::AlignJustify:
906 attrs["text-align"] = QStringLiteral("justify");
907 break;
908 }
909
910 return attrs.toFormatted();
911}
912
913int QAccessibleTextWidget::cursorPosition() const
914{
915 return textCursor().position();
916}
917
918void QAccessibleTextWidget::selection(int selectionIndex, int *startOffset, int *endOffset) const
919{
920 *startOffset = *endOffset = 0;
922
923 if (selectionIndex != 0 || !cursor.hasSelection())
924 return;
925
926 *startOffset = cursor.selectionStart();
927 *endOffset = cursor.selectionEnd();
928}
929
930QString QAccessibleTextWidget::text(int startOffset, int endOffset) const
931{
933
934 cursor.setPosition(startOffset, QTextCursor::MoveAnchor);
935 cursor.setPosition(endOffset, QTextCursor::KeepAnchor);
936
937 return cursor.selectedText().replace(QChar(QChar::ParagraphSeparator), u'\n');
938}
939
940QPoint QAccessibleTextWidget::scrollBarPosition() const
941{
942 return QPoint(0, 0);
943}
944
945
946QString QAccessibleTextWidget::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType,
947 int *startOffset, int *endOffset) const
948{
949 Q_ASSERT(startOffset);
950 Q_ASSERT(endOffset);
951
953 cursor.setPosition(offset);
954 QPair<int, int> boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
955 cursor.setPosition(boundaries.first - 1);
956 boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
957
958 *startOffset = boundaries.first;
959 *endOffset = boundaries.second;
960
961 return text(boundaries.first, boundaries.second);
962 }
963
964
965QString QAccessibleTextWidget::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType,
966 int *startOffset, int *endOffset) const
967{
968 Q_ASSERT(startOffset);
969 Q_ASSERT(endOffset);
970
972 cursor.setPosition(offset);
973 QPair<int, int> boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
974 cursor.setPosition(boundaries.second);
975 boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
976
977 *startOffset = boundaries.first;
978 *endOffset = boundaries.second;
979
980 return text(boundaries.first, boundaries.second);
981}
982
983QString QAccessibleTextWidget::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType,
984 int *startOffset, int *endOffset) const
985{
986 Q_ASSERT(startOffset);
987 Q_ASSERT(endOffset);
988
990 cursor.setPosition(offset);
991 QPair<int, int> boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
992
993 *startOffset = boundaries.first;
994 *endOffset = boundaries.second;
995
996 return text(boundaries.first, boundaries.second);
997}
998
999void QAccessibleTextWidget::setCursorPosition(int position)
1000{
1002 cursor.setPosition(position);
1003 setTextCursor(cursor);
1004}
1005
1006void QAccessibleTextWidget::addSelection(int startOffset, int endOffset)
1007{
1008 setSelection(0, startOffset, endOffset);
1009}
1010
1011void QAccessibleTextWidget::removeSelection(int selectionIndex)
1012{
1013 if (selectionIndex != 0)
1014 return;
1015
1017 cursor.clearSelection();
1018 setTextCursor(cursor);
1019}
1020
1021void QAccessibleTextWidget::setSelection(int selectionIndex, int startOffset, int endOffset)
1022{
1023 if (selectionIndex != 0)
1024 return;
1025
1027 cursor.setPosition(startOffset, QTextCursor::MoveAnchor);
1028 cursor.setPosition(endOffset, QTextCursor::KeepAnchor);
1029 setTextCursor(cursor);
1030}
1031
1032int QAccessibleTextWidget::characterCount() const
1033{
1035 cursor.movePosition(QTextCursor::End);
1036 return cursor.position();
1037}
1038
1039QTextCursor QAccessibleTextWidget::textCursorForRange(int startOffset, int endOffset) const
1040{
1042 cursor.setPosition(startOffset, QTextCursor::MoveAnchor);
1043 cursor.setPosition(endOffset, QTextCursor::KeepAnchor);
1044
1045 return cursor;
1046}
1047
1048void QAccessibleTextWidget::deleteText(int startOffset, int endOffset)
1049{
1050 QTextCursor cursor = textCursorForRange(startOffset, endOffset);
1051 cursor.removeSelectedText();
1052}
1053
1054void QAccessibleTextWidget::insertText(int offset, const QString &text)
1055{
1057 cursor.setPosition(offset);
1058 cursor.insertText(text);
1059}
1060
1061void QAccessibleTextWidget::replaceText(int startOffset, int endOffset, const QString &text)
1062{
1063 QTextCursor cursor = textCursorForRange(startOffset, endOffset);
1064 cursor.removeSelectedText();
1065 cursor.insertText(text);
1066}
1067#endif // QT_NO_CURSOR
1068
1069
1070#if QT_CONFIG(mainwindow)
1071QAccessibleMainWindow::QAccessibleMainWindow(QWidget *widget)
1072 : QAccessibleWidget(widget, QAccessible::Window) { }
1073
1074QAccessibleInterface *QAccessibleMainWindow::child(int index) const
1075{
1076 QList<QWidget*> kids = _q_ac_childWidgets(mainWindow());
1077 if (index >= 0 && index < kids.size()) {
1078 return QAccessible::queryAccessibleInterface(kids.at(index));
1079 }
1080 return nullptr;
1081}
1082
1083int QAccessibleMainWindow::childCount() const
1084{
1085 QList<QWidget*> kids = _q_ac_childWidgets(mainWindow());
1086 return kids.size();
1087}
1088
1089int QAccessibleMainWindow::indexOfChild(const QAccessibleInterface *iface) const
1090{
1091 QList<QWidget*> kids = _q_ac_childWidgets(mainWindow());
1092 return kids.indexOf(static_cast<QWidget*>(iface->object()));
1093}
1094
1095QAccessibleInterface *QAccessibleMainWindow::childAt(int x, int y) const
1096{
1097 QWidget *w = widget();
1098 if (!w->isVisible())
1099 return nullptr;
1100 QPoint gp = w->mapToGlobal(QPoint(0, 0));
1101 if (!QRect(gp.x(), gp.y(), w->width(), w->height()).contains(x, y))
1102 return nullptr;
1103
1104 const QWidgetList kids = _q_ac_childWidgets(mainWindow());
1106 for (QWidget *child : kids) {
1107 if (!child->isWindow() && !child->isHidden() && child->geometry().contains(rp)) {
1108 return QAccessible::queryAccessibleInterface(child);
1109 }
1110 }
1111 return nullptr;
1112}
1113
1114QMainWindow *QAccessibleMainWindow::mainWindow() const
1115{
1116 return qobject_cast<QMainWindow *>(object());
1117}
1118
1119#endif // QT_CONFIG(mainwindow)
1120
1122
1123#endif // QT_CONFIG(accessibility)
The QAbstractItemView class provides the basic functionality for item view classes.
virtual int hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const =0
Returns the cursor position for the given point with the specified accuracy.
\inmodule QtGui
The QAccessible class provides enums and static functions related to accessibility.
static QWidget * focusWidget()
Returns the application widget that has the keyboard input focus, or \nullptr if no widget in this ap...
\inmodule QtGui
Definition qbrush.h:30
const QColor & color() const
Returns the brush color.
Definition qbrush.h:121
Qt::BrushStyle style() const
Returns the brush style.
Definition qbrush.h:120
The QCalendarWidget class provides a monthly based calendar widget allowing the user to select a date...
\inmodule QtCore
Definition qchar.h:48
@ ParagraphSeparator
Definition qchar.h:63
int red() const noexcept
Returns the red color component of this color.
Definition qcolor.cpp:1528
int blue() const noexcept
Returns the blue color component of this color.
Definition qcolor.cpp:1583
int green() const noexcept
Returns the green color component of this color.
Definition qcolor.cpp:1555
The QDockWidget class provides a widget that can be docked inside a QMainWindow or floated as a top-l...
Definition qdockwidget.h:20
QWidget * widget() const
Returns the widget for the dock widget.
\reentrant \inmodule QtGui
\reentrant
Definition qfont.h:20
bool underline() const
Returns true if underline has been set; otherwise returns false.
Definition qfont.cpp:1236
QStringList families() const
Definition qfont.cpp:2469
Weight weight() const
Returns the weight of the font, using the same scale as the \l{QFont::Weight} enumeration.
Definition qfont.cpp:1118
int pointSize() const
Returns the point size of the font.
Definition qfont.cpp:863
Style style() const
Returns the style of the font.
Definition qfont.cpp:1090
@ Normal
Definition qfont.h:64
Style
This enum describes the different styles of glyphs that are used to display text.
Definition qfont.h:73
@ StyleItalic
Definition qfont.h:75
The QLayoutItem class provides an abstract item that a QLayout manipulates.
Definition qlayoutitem.h:25
virtual QRect geometry() const =0
Returns the rectangle covered by this layout item.
QRect cursorRect() const
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
T value(qsizetype i) const
Definition qlist.h:661
void append(parameter_type t)
Definition qlist.h:441
The QMainWindow class provides a main application window.
Definition qmainwindow.h:25
The QMdiArea widget provides an area in which MDI windows are displayed.
Definition qmdiarea.h:21
The QMdiSubWindow class provides a subwindow class for QMdiArea.
\inmodule QtCore
Definition qobject.h:90
The QPlainTextEdit class provides a widget that is used to edit and display plain text.
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:338
\inmodule QtCore\reentrant
Definition qpoint.h:23
\inmodule QtCore\reentrant
Definition qrect.h:483
\inmodule QtCore\reentrant
Definition qrect.h:30
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qrect.cpp:851
constexpr QPoint bottomRight() const noexcept
Returns the position of the rectangle's bottom-right corner.
Definition qrect.h:223
The QStackedWidget class provides a stack of widgets where only one widget is visible at a time.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:898
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3435
Qt::Alignment alignment() const
Returns the paragraph's alignment.
\reentrant
iterator begin() const
Returns a text block iterator pointing to the beginning of the text block.
int length() const
Returns the length of the block in characters.
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
QTextLayout * layout() const
Returns the QTextLayout that is used to lay out and display the block's contents.
int position() const
Returns the index of the block's first character within the document.
Qt::LayoutDirection textDirection() const
QTextCharFormat charFormat() const
Returns the QTextCharFormat that describes the block's character format.
VerticalAlignment
This enum describes the ways that adjacent characters can be vertically aligned.
UnderlineStyle underlineStyle() const
UnderlineStyle
This enum describes the different ways drawing underlined text.
VerticalAlignment verticalAlignment() const
Returns the vertical alignment used for characters with this format.
QFont font() const
Returns the font for this character format.
\reentrant \inmodule QtGui
Definition qtextcursor.h:30
\reentrant \inmodule QtGui
QAbstractTextDocumentLayout * documentLayout() const
Returns the document layout for this document.
QTextBlock findBlock(int pos) const
Returns the text block that contains the {pos}-th character.
The QTextEdit class provides a widget that is used to edit and display both plain and rich text.
Definition qtextedit.h:27
QBrush background() const
Returns the brush used to paint the document's background.
QBrush foreground() const
Returns the brush used to render foreground details, such as text, frame outlines,...
\reentrant
QTextCharFormat charFormat() const
Returns the text fragment's character format.
int length() const
Returns the number of characters in the text fragment.
int position() const
Returns the position of this text fragment in the document.
\reentrant
Definition qtextlayout.h:70
\reentrant
The QToolBox class provides a column of tabbed widget items.
Definition qtoolbox.h:18
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
QRect rect
the internal geometry of the widget excluding any window frame
Definition qwidget.h:116
int y
the y coordinate of the widget relative to its parent and including any window frame
Definition qwidget.h:110
QRect frameGeometry
geometry of the widget relative to its parent including any window frame
Definition qwidget.h:107
QPointF mapFromGlobal(const QPointF &) const
Translates the global screen coordinate pos to widget coordinates.
[Window class with invokable method]
Definition window.h:11
QOpenGLWidget * widget
[1]
QString text
QCursor cursor
rect
[4]
uint alignment
else opt state
[0]
Combined button and popup list for selecting options.
bool isEnabled()
constexpr QBindableInterface iface
Definition qproperty.h:664
@ AlignRight
Definition qnamespace.h:145
@ AlignJustify
Definition qnamespace.h:148
@ AlignHCenter
Definition qnamespace.h:147
@ AlignLeft
Definition qnamespace.h:143
@ RightToLeft
@ ExactHit
Definition qnamespace.h:202
@ SolidPattern
static jboolean setSelection(JNIEnv *, jobject, jint start, jint end)
#define Q_UNLIKELY(x)
std::pair< T1, T2 > QPair
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
static struct AttrInfo attrs[]
#define qWarning
Definition qlogging.h:162
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define Q_ARG(Type, data)
Definition qobjectdefs.h:62
GLint GLint GLint GLint GLint x
[0]
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLenum GLenum GLsizei count
GLuint object
[3]
GLfloat GLfloat f
GLenum GLsizeiptr fontSize
GLenum GLuint GLintptr offset
GLuint name
GLint GLsizei GLsizei GLenum format
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLsizei const GLchar *const * string
[0]
Definition qopenglext.h:694
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
#define gp
#define QT_CONFIG(feature)
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:92
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition qwidget.h:786
static QT_BEGIN_NAMESPACE QString windowTitle(HWND hwnd)
QList< QWidget * > widgets
[11]
QVBoxLayout * layout
QString title
[35]
timer inherits("QTimer")
QGraphicsWidget * textEdit
QGraphicsItem * item
view viewport() -> scroll(dx, dy, deviceRect)
edit isVisible()
QLayoutItem * child
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QDockWidget * dockWidget
[0]
QMenu menu
[5]
edit textCursor().insertText(text)
[0]
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:955
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent