Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
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{
70 QList<QWidget*> widgets;
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(qobject_cast<QPlainTextEdit *>(widget()));
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(qobject_cast<QTextEdit *>(widget()));
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 attrs["text-line-through-type"] = charFormatFont.strikeOut() ? "single"_L1 : "none"_L1;
843
844 QTextCharFormat::UnderlineStyle underlineStyle = charFormat.underlineStyle();
845 if (underlineStyle == QTextCharFormat::NoUnderline && charFormatFont.underline()) // underline could still be set in the default font
846 underlineStyle = QTextCharFormat::SingleUnderline;
847 QString underlineStyleValue;
848 switch (underlineStyle) {
850 break;
852 underlineStyleValue = QStringLiteral("solid");
853 break;
855 underlineStyleValue = QStringLiteral("dash");
856 break;
858 underlineStyleValue = QStringLiteral("dash");
859 break;
861 underlineStyleValue = QStringLiteral("dot-dash");
862 break;
864 underlineStyleValue = QStringLiteral("dot-dot-dash");
865 break;
867 underlineStyleValue = QStringLiteral("wave");
868 break;
870 underlineStyleValue = QStringLiteral("wave"); // this is not correct, but provides good approximation at least
871 break;
872 default:
873 qWarning() << "Unknown QTextCharFormat::UnderlineStyle value " << underlineStyle << " could not be translated to IAccessible2 value";
874 break;
875 }
876 if (!underlineStyleValue.isNull()) {
877 attrs["text-underline-style"] = underlineStyleValue;
878 attrs["text-underline-type"] = QStringLiteral("single"); // if underlineStyleValue is set, there is an underline, and Qt does not support other than single ones
879 } // else both are "none" which is the default - no need to set them
880
881 if (block.textDirection() == Qt::RightToLeft)
882 attrs["writing-mode"] = QStringLiteral("rl");
883
885 attrs["text-position"] = QString::fromLatin1((alignment == QTextCharFormat::AlignSubScript) ? "sub" : ((alignment == QTextCharFormat::AlignSuperScript) ? "super" : "baseline" ));
886
887 QBrush background = charFormat.background();
888 if (background.style() == Qt::SolidPattern) {
889 attrs["background-color"] = QString::fromLatin1("rgb(%1,%2,%3)").arg(background.color().red()).arg(background.color().green()).arg(background.color().blue());
890 }
891
892 QBrush foreground = charFormat.foreground();
893 if (foreground.style() == Qt::SolidPattern) {
894 attrs["color"] = QString::fromLatin1("rgb(%1,%2,%3)").arg(foreground.color().red()).arg(foreground.color().green()).arg(foreground.color().blue());
895 }
896
898 case Qt::AlignLeft:
899 attrs["text-align"] = QStringLiteral("left");
900 break;
901 case Qt::AlignRight:
902 attrs["text-align"] = QStringLiteral("right");
903 break;
904 case Qt::AlignHCenter:
905 attrs["text-align"] = QStringLiteral("center");
906 break;
907 case Qt::AlignJustify:
908 attrs["text-align"] = QStringLiteral("justify");
909 break;
910 }
911
912 return attrs.toFormatted();
913}
914
915int QAccessibleTextWidget::cursorPosition() const
916{
917 return textCursor().position();
918}
919
920void QAccessibleTextWidget::selection(int selectionIndex, int *startOffset, int *endOffset) const
921{
922 *startOffset = *endOffset = 0;
924
925 if (selectionIndex != 0 || !cursor.hasSelection())
926 return;
927
928 *startOffset = cursor.selectionStart();
929 *endOffset = cursor.selectionEnd();
930}
931
932QString QAccessibleTextWidget::text(int startOffset, int endOffset) const
933{
935
936 cursor.setPosition(startOffset, QTextCursor::MoveAnchor);
937 cursor.setPosition(endOffset, QTextCursor::KeepAnchor);
938
939 return cursor.selectedText().replace(QChar(QChar::ParagraphSeparator), u'\n');
940}
941
942QPoint QAccessibleTextWidget::scrollBarPosition() const
943{
944 return QPoint(0, 0);
945}
946
947
948QString QAccessibleTextWidget::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType,
949 int *startOffset, int *endOffset) const
950{
951 Q_ASSERT(startOffset);
952 Q_ASSERT(endOffset);
953
955 cursor.setPosition(offset);
956 QPair<int, int> boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
957 cursor.setPosition(boundaries.first - 1);
958 boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
959
960 *startOffset = boundaries.first;
961 *endOffset = boundaries.second;
962
963 return text(boundaries.first, boundaries.second);
964 }
965
966
967QString QAccessibleTextWidget::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType,
968 int *startOffset, int *endOffset) const
969{
970 Q_ASSERT(startOffset);
971 Q_ASSERT(endOffset);
972
974 cursor.setPosition(offset);
975 QPair<int, int> boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
976 cursor.setPosition(boundaries.second);
977 boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
978
979 *startOffset = boundaries.first;
980 *endOffset = boundaries.second;
981
982 return text(boundaries.first, boundaries.second);
983}
984
985QString QAccessibleTextWidget::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType,
986 int *startOffset, int *endOffset) const
987{
988 Q_ASSERT(startOffset);
989 Q_ASSERT(endOffset);
990
992 cursor.setPosition(offset);
993 QPair<int, int> boundaries = QAccessible::qAccessibleTextBoundaryHelper(cursor, boundaryType);
994
995 *startOffset = boundaries.first;
996 *endOffset = boundaries.second;
997
998 return text(boundaries.first, boundaries.second);
999}
1000
1001void QAccessibleTextWidget::setCursorPosition(int position)
1002{
1004 cursor.setPosition(position);
1005 setTextCursor(cursor);
1006}
1007
1008void QAccessibleTextWidget::addSelection(int startOffset, int endOffset)
1009{
1010 setSelection(0, startOffset, endOffset);
1011}
1012
1013void QAccessibleTextWidget::removeSelection(int selectionIndex)
1014{
1015 if (selectionIndex != 0)
1016 return;
1017
1019 cursor.clearSelection();
1020 setTextCursor(cursor);
1021}
1022
1023void QAccessibleTextWidget::setSelection(int selectionIndex, int startOffset, int endOffset)
1024{
1025 if (selectionIndex != 0)
1026 return;
1027
1029 cursor.setPosition(startOffset, QTextCursor::MoveAnchor);
1030 cursor.setPosition(endOffset, QTextCursor::KeepAnchor);
1031 setTextCursor(cursor);
1032}
1033
1034int QAccessibleTextWidget::characterCount() const
1035{
1037 cursor.movePosition(QTextCursor::End);
1038 return cursor.position();
1039}
1040
1041QTextCursor QAccessibleTextWidget::textCursorForRange(int startOffset, int endOffset) const
1042{
1044 cursor.setPosition(startOffset, QTextCursor::MoveAnchor);
1045 cursor.setPosition(endOffset, QTextCursor::KeepAnchor);
1046
1047 return cursor;
1048}
1049
1050void QAccessibleTextWidget::deleteText(int startOffset, int endOffset)
1051{
1052 QTextCursor cursor = textCursorForRange(startOffset, endOffset);
1053 cursor.removeSelectedText();
1054}
1055
1056void QAccessibleTextWidget::insertText(int offset, const QString &text)
1057{
1059 cursor.setPosition(offset);
1060 cursor.insertText(text);
1061}
1062
1063void QAccessibleTextWidget::replaceText(int startOffset, int endOffset, const QString &text)
1064{
1065 QTextCursor cursor = textCursorForRange(startOffset, endOffset);
1066 cursor.removeSelectedText();
1067 cursor.insertText(text);
1068}
1069#endif // QT_NO_CURSOR
1070
1071
1072#if QT_CONFIG(mainwindow)
1073QAccessibleMainWindow::QAccessibleMainWindow(QWidget *widget)
1074 : QAccessibleWidget(widget, QAccessible::Window) { }
1075
1076QAccessibleInterface *QAccessibleMainWindow::child(int index) const
1077{
1078 QList<QWidget*> kids = _q_ac_childWidgets(mainWindow());
1079 if (index >= 0 && index < kids.size()) {
1080 return QAccessible::queryAccessibleInterface(kids.at(index));
1081 }
1082 return nullptr;
1083}
1084
1085int QAccessibleMainWindow::childCount() const
1086{
1087 QList<QWidget*> kids = _q_ac_childWidgets(mainWindow());
1088 return kids.size();
1089}
1090
1091int QAccessibleMainWindow::indexOfChild(const QAccessibleInterface *iface) const
1092{
1093 QList<QWidget*> kids = _q_ac_childWidgets(mainWindow());
1094 return kids.indexOf(static_cast<QWidget*>(iface->object()));
1095}
1096
1097QAccessibleInterface *QAccessibleMainWindow::childAt(int x, int y) const
1098{
1099 QWidget *w = widget();
1100 if (!w->isVisible())
1101 return nullptr;
1102 QPoint gp = w->mapToGlobal(QPoint(0, 0));
1103 if (!QRect(gp.x(), gp.y(), w->width(), w->height()).contains(x, y))
1104 return nullptr;
1105
1106 const QWidgetList kids = _q_ac_childWidgets(mainWindow());
1108 for (QWidget *child : kids) {
1109 if (!child->isWindow() && !child->isHidden() && child->geometry().contains(rp)) {
1110 return QAccessible::queryAccessibleInterface(child);
1111 }
1112 }
1113 return nullptr;
1114}
1115
1116QMainWindow *QAccessibleMainWindow::mainWindow() const
1117{
1118 return qobject_cast<QMainWindow *>(object());
1119}
1120
1121#endif // QT_CONFIG(mainwindow)
1122
1124
1125#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
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:22
@ Normal
Definition qfont.h:67
Style
This enum describes the different styles of glyphs that are used to display text.
Definition qfont.h:76
@ StyleItalic
Definition qfont.h:78
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
void append(parameter_type t)
Definition qlist.h:458
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:103
The QPlainTextEdit class provides a widget that is used to edit and display plain text.
\inmodule QtCore\reentrant
Definition qpoint.h:217
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr void setX(int x) noexcept
Sets the x coordinate of this point to the given x coordinate.
Definition qpoint.h:140
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr void moveTopLeft(const QPoint &p) noexcept
Moves the rectangle, leaving the top-left corner at the given position.
Definition qrect.h:304
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:855
constexpr QPoint bottomRight() const noexcept
Returns the position of the rectangle's bottom-right corner.
Definition qrect.h:224
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:129
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
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:3466
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:666
@ AlignRight
Definition qnamespace.h:146
@ AlignJustify
Definition qnamespace.h:149
@ AlignHCenter
Definition qnamespace.h:148
@ AlignLeft
Definition qnamespace.h:144
@ RightToLeft
@ ExactHit
Definition qnamespace.h:203
@ SolidPattern
static jboolean setSelection(JNIEnv *, jobject, jint start, jint end)
#define Q_UNLIKELY(x)
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:166
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:63
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 s
[6]
Definition qopenglext.h:235
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
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:187
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition qwidget.h:786
static QString windowTitle(HWND hwnd)
QList< QWidget * > widgets
[11]
QVBoxLayout * layout
QString title
[35]
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]
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...