dde-control-center
Deepin Control Center
载入中...
搜索中...
未找到
accessibleinterface.h
1//SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
2//
3//SPDX-License-Identifier: GPL-3.0-or-later
4#ifndef ACCESSIBLEINTERFACE_H
5#define ACCESSIBLEINTERFACE_H
6
7#include <QAccessible>
8#include <QAccessibleWidget>
9#include <QEvent>
10#include <QMap>
11#include <QString>
12#include <QWidget>
13#include <QObject>
14#include <QMetaEnum>
15#include <QMouseEvent>
16#include <QApplication>
17#include <QRect>
18
19#define SEPARATOR "_"
20
21inline QString getAccessibleName(QWidget *w, QAccessible::Role r, const QString &fallback)
22{
23 const QString lowerFallback = fallback.toLower();
24 // 避免重复生成
25 static QMap< QObject *, QString > objnameMap;
26 if (!objnameMap[w].isEmpty())
27 return objnameMap[w];
28
29 static QMap< QAccessible::Role, QList< QString > > accessibleMap;
30 QString oldAccessName = w->accessibleName().toLower();
31 oldAccessName.replace(SEPARATOR, "");
32
33 // 按照类型添加固定前缀
34 QMetaEnum metaEnum = QMetaEnum::fromType<QAccessible::Role>();
35 QByteArray prefix = metaEnum.valueToKeys(r);
36 switch (r) {
37 case QAccessible::Form: prefix = "Form"; break;
38 case QAccessible::Button: prefix = "Btn"; break;
39 case QAccessible::StaticText: prefix = "Label"; break;
40 case QAccessible::EditableText: prefix = "Editable"; break;
41 case QAccessible::Slider: prefix = "Slider"; break;
42 default: break;
43 }
44
45 // 再加上标识
46 QString accessibleName = QString::fromLatin1(prefix) + SEPARATOR;
47 accessibleName += oldAccessName.isEmpty() ? lowerFallback : oldAccessName;
48 // 检查名称是否唯一
49 if (accessibleMap[r].contains(accessibleName)) {
50 // 获取编号,然后+1
51 int pos = accessibleName.indexOf(SEPARATOR);
52 int id = accessibleName.mid(pos + 1).toInt();
53
54 QString newAccessibleName;
55 do {
56 // 一直找到一个不重复的名字
57 newAccessibleName = accessibleName + SEPARATOR + QString::number(++id);
58 } while (accessibleMap[r].contains(newAccessibleName));
59
60 accessibleMap[r].append(newAccessibleName);
61 objnameMap.insert(w, newAccessibleName);
62
63 QObject::connect(w, &QWidget::destroyed, [ = ] (QObject *obj) { // 对象销毁后移除占用名称
64 objnameMap.remove(obj);
65 accessibleMap[r].removeOne(newAccessibleName);
66 });
67 return newAccessibleName;
68 } else {
69 accessibleMap[r].append(accessibleName);
70 objnameMap.insert(w, accessibleName);
71
72 QObject::connect(w, &QWidget::destroyed, [ = ] (QObject *obj) { // 对象销毁后移除占用名称
73 objnameMap.remove(obj);
74 accessibleMap[r].removeOne(accessibleName);
75 });
76 return accessibleName;
77 }
78}
79
80// 公共的功能
81#define FUNC_CREATE(classname,accessibletype,accessdescription) Accessible##classname(classname *w) \
82 : QAccessibleWidget(w,accessibletype,#classname)\
83 , m_w(w)\
84 , m_description(accessdescription)\
85 {}\
86
87#define FUNC_TEXT(classname,accessiblename) inline QString Accessible##classname::text(QAccessible::Text t) const{\
88 switch (t) {\
89 case QAccessible::Name:\
90 return getAccessibleName(m_w, this->role(), accessiblename);\
91 case QAccessible::Description:\
92 return m_description;\
93 default:\
94 return QString();\
95 }\
96 }\
97
98// button控件特有功能
99#define FUNC_ACTIONNAMES(classname) inline QStringList Accessible##classname::actionNames() const{\
100 if(!m_w->isEnabled())\
101 return QStringList();\
102 return QStringList() << pressAction()<< showMenuAction();\
103 }\
104
105#define FUNC_DOACTION(classname) inline void Accessible##classname::doAction(const QString &actionName){\
106 if(actionName == pressAction())\
107 {\
108 QPointF localPos = m_w->geometry().center();\
109 QMouseEvent event(QEvent::MouseButtonPress,localPos,Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);\
110 qApp->sendEvent(m_w,&event);\
111 QMouseEvent eventr(QEvent::MouseButtonRelease,localPos,Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);\
112 qApp->sendEvent(m_w,&eventr);\
113 }\
114 else if(actionName == showMenuAction())\
115 {\
116 QPointF localPos = m_w->geometry().center();\
117 QMouseEvent event(QEvent::MouseButtonPress,localPos,Qt::RightButton,Qt::RightButton,Qt::NoModifier);\
118 qApp->sendEvent(m_w,&event);\
119 }\
120 }\
121
122// QLABEL控件特有功能
123#define FUNC_TEXT_(classname) inline QString Accessible##classname::text(int startOffset, int endOffset) const{\
124 Q_UNUSED(startOffset)\
125 Q_UNUSED(endOffset)\
126 return m_w->text();\
127 }\
128
129#define FUNC_CHILD_LABLE(classname) inline QAccessibleInterface *Accessible##classname::child(int index) const{\
130 return QAccessibleWidget::child(index);\
131 }\
132
133// EDITABLE控件特有功能
134#define FUNC_DELETETEXT(classname) inline void Accessible##classname::deleteText(int startOffset, int endOffset) {\
135 m_w->setText(m_w->text().remove(startOffset, endOffset - startOffset));\
136 }\
137
138#define FUNC_INSERTTEXT(classname) inline void Accessible##classname::insertText(int startOffset, const QString &text) {\
139 m_w->setText(m_w->text().insert(startOffset, text));\
140 }\
141
142#define FUNC_REPLACETEXT(classname) inline void Accessible##classname::replaceText(int startOffset, int endOffset, const QString &text) {\
143 m_w->setText(m_w->text().replace(startOffset, endOffset - startOffset, text));\
144 }\
145
146#define FUNC_CHILD_EDITABLE(classname) QAccessibleInterface *Accessible##classname::child(int index) const{\
147 return nullptr;\
148 }\
149
150#define FUNC_SELECTION(classname) inline void Accessible##classname::selection(int selectionIndex, int *startOffset, int *endOffset) const {\
151 m_w->setSelection(*startOffset, *endOffset);\
152 *startOffset = *endOffset = 0;\
153 if (selectionIndex != 0)\
154 return;\
155 *startOffset = m_w->selectionStart();\
156 *endOffset = *startOffset + m_w->selectedText().count();\
157 }\
158
159#define FUNC_SELECTIONCOUNT(classname) inline int Accessible##classname::selectionCount() const {\
160 return m_w->hasSelectedText() ? 1 : 0;\
161 }\
162
163#define FUNC_ADDSELECTION(classname) inline void Accessible##classname::addSelection(int startOffset, int endOffset) {\
164 setSelection(0, startOffset, endOffset);\
165 }\
166
167#define FUNC_REMOVESELECTION(classname) inline void Accessible##classname::removeSelection(int selectionIndex) {\
168 if (selectionIndex != 0)\
169 return;\
170 m_w->deselect();\
171 }\
172
173#define FUNC_SETSELECTION(classname) inline void Accessible##classname::setSelection(int selectionIndex, int startOffset, int endOffset) {\
174 if (selectionIndex != 0)\
175 return;\
176 m_w->setSelection(startOffset, endOffset - startOffset);\
177 }\
178
179#define FUNC_CURORPOSITION(classname) inline int Accessible##classname::cursorPosition() const {\
180 return m_w->cursorPosition();\
181 }\
182
183#define FUNC_SETCURORPOSITION(classname) inline void Accessible##classname::setCursorPosition(int position) {\
184 m_w->setCursorPosition(position);\
185 }\
186
187#define FUNC_TEXT_LineEdit(classname) inline QString Accessible##classname::text(int startOffset, int endOffset) const{\
188 if (startOffset > endOffset)\
189 return QString();\
190 if (m_w->echoMode() != QLineEdit::Normal)\
191 return QString();\
192 return m_w->text().mid(startOffset, endOffset - startOffset);\
193 }\
194
195#define FUNC_TEXTBEFOREOFFSET(classname) QString Accessible##classname::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const {\
196 if (m_w->echoMode() != QLineEdit::Normal) {\
197 *startOffset = *endOffset = -1;\
198 return QString();\
199 }\
200 if (offset == -2)\
201 offset = cursorPosition();\
202 return QAccessibleTextInterface::textBeforeOffset(offset, boundaryType, startOffset, endOffset);\
203 }\
204
205#define FUNC_TEXTAFTEROFFSET(classname) QString Accessible##classname::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const {\
206 if (lineEdit()->echoMode() != QLineEdit::Normal) {\
207 *startOffset = *endOffset = -1;\
208 return QString();\
209 }\
210 if (offset == -2)\
211 offset = cursorPosition();\
212 return QAccessibleTextInterface::textAfterOffset(offset, boundaryType, startOffset, endOffset);\
213 }\
214
215#define FUNC_TEXTATOFFSET(classname) QString Accessible##classname::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, int *startOffset, int *endOffset) const {\
216 if (m_w->echoMode() != QLineEdit::Normal) {\
217 *startOffset = *endOffset = -1;\
218 return QString();\
219 }\
220 if (offset == -2)\
221 offset = cursorPosition();\
222 return QAccessibleTextInterface::textAtOffset(offset, boundaryType, startOffset, endOffset);\
223 }\
224
225#define FUNC_CHARACTERCOUNT(classname) inline int Accessible##classname::characterCount() const {\
226 return m_w->text().count();\
227 }\
228
229#define FUNC_CHARACTERRECT(classname) inline QRect Accessible##classname::characterRect(int offset) const {\
230 Q_UNUSED(offset)\
231 return QRect();\
232 }\
233
234#define FUNC_OFFSETATPOINT(classname) inline int Accessible##classname::offsetAtPoint(const QPoint &point) const {\
235 QPoint p = m_w->mapFromGlobal(point);\
236 return m_w->cursorPositionAt(p);\
237 }\
238
239#define FUNC_SCROLLTOSUBSTRING(classname) inline void Accessible##classname::scrollToSubstring(int startIndex, int endIndex) {\
240 m_w->setCursorPosition(endIndex);\
241 m_w->setCursorPosition(startIndex);\
242 }\
243
244#define FUNC_ATTRIBUTES(classname) inline QString Accessible##classname::attributes(int offset, int *startOffset, int *endOffset) const {\
245 *startOffset = *endOffset = offset;\
246 return QString();\
247 }\
248
249// Slider控件特有功能
250#define FUNC_CURRENTVALUE(classname) inline QVariant Accessible##classname::currentValue() const{\
251 return m_w->value();\
252 }\
253
254#define FUNC_SETCURRENTVALUE(classname) inline void Accessible##classname::setCurrentValue(const QVariant &value){\
255 return m_w->setValue(value.toInt());\
256 }\
257
258#define FUNC_MAXMUMVALUE(classname) inline QVariant Accessible##classname::maximumValue() const{\
259 return QVariant(m_w->maximum());\
260 }\
261
262#define FUNC_FUNC_MINIMUMVALUE(classname) inline QVariant Accessible##classname::minimumValue() const{\
263 return QVariant(m_w->minimum());\
264 }\
265
266#define FUNC_FUNC_MINIMUMSTEPSIZE(classname) inline QVariant Accessible##classname::minimumStepSize() const{\
267 return QVariant(m_w->singleStep());\
268 }\
269
270#define SET_FORM_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,accessdescription) class Accessible##classname : public QAccessibleWidget\
271 {\
272 public:\
273 FUNC_CREATE(classname,QAccessible::Form,accessdescription)\
274 QString text(QAccessible::Text t) const override;\
275 void *interface_cast(QAccessible::InterfaceType t) override{\
276 switch (t) {\
277 case QAccessible::ActionInterface:\
278 return static_cast<QAccessibleActionInterface*>(this);\
279 default:\
280 return nullptr;\
281 }\
282 }\
283 private:\
284 classname *m_w;\
285 QString m_description;\
286 };\
287 FUNC_TEXT(classname,accessiblename)\
288
289#define SET_BUTTON_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,accessdescription) class Accessible##classname : public QAccessibleWidget\
290 {\
291 public:\
292 FUNC_CREATE(classname,QAccessible::Button,accessdescription)\
293 QString text(QAccessible::Text t) const override;\
294 void *interface_cast(QAccessible::InterfaceType t) override{\
295 switch (t) {\
296 case QAccessible::ActionInterface:\
297 return static_cast<QAccessibleActionInterface*>(this);\
298 default:\
299 return nullptr;\
300 }\
301 }\
302 QStringList actionNames() const override;\
303 void doAction(const QString &actionName) override;\
304 private:\
305 classname *m_w;\
306 QString m_description;\
307 };\
308 FUNC_TEXT(classname,accessiblename)\
309 FUNC_ACTIONNAMES(classname)\
310 FUNC_DOACTION(classname)\
311
312#define SET_LABEL_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,type,accessdescription) class Accessible##classname : public QAccessibleWidget, public QAccessibleTextInterface\
313 {\
314 public:\
315 FUNC_CREATE(classname,type,accessdescription)\
316 QString text(QAccessible::Text t) const override;\
317 void *interface_cast(QAccessible::InterfaceType t) override{\
318 switch (t) {\
319 case QAccessible::ActionInterface:\
320 return static_cast<QAccessibleActionInterface*>(this);\
321 case QAccessible::TextInterface:\
322 return static_cast<QAccessibleTextInterface*>(this);\
323 default:\
324 return nullptr;\
325 }\
326 }\
327 QAccessibleInterface *child(int index) const override;\
328 QString text(int startOffset, int endOffset) const override;\
329 void selection(int selectionIndex, int *startOffset, int *endOffset) const override {\
330 Q_UNUSED(selectionIndex)\
331 Q_UNUSED(startOffset)\
332 Q_UNUSED(endOffset)\
333 }\
334 int selectionCount() const override { return 0; }\
335 void addSelection(int startOffset, int endOffset) override {\
336 Q_UNUSED(startOffset)\
337 Q_UNUSED(endOffset)\
338 }\
339 void removeSelection(int selectionIndex) override {\
340 Q_UNUSED(selectionIndex)\
341 }\
342 void setSelection(int selectionIndex, int startOffset, int endOffset) override {\
343 Q_UNUSED(selectionIndex)\
344 Q_UNUSED(startOffset)\
345 Q_UNUSED(endOffset)\
346 }\
347 int cursorPosition() const override { return 0; }\
348 void setCursorPosition(int position) override {\
349 Q_UNUSED(position)\
350 }\
351 int characterCount() const override { return 0; }\
352 QRect characterRect(int offset) const override { \
353 Q_UNUSED(offset)\
354 return QRect();\
355 }\
356 int offsetAtPoint(const QPoint &point) const override { \
357 Q_UNUSED(point)\
358 return 0; \
359 }\
360 void scrollToSubstring(int startIndex, int endIndex) override {\
361 Q_UNUSED(startIndex)\
362 Q_UNUSED(endIndex)\
363 }\
364 QString attributes(int offset, int *startOffset, int *endOffset) const override {\
365 Q_UNUSED(startOffset)\
366 Q_UNUSED(offset)\
367 Q_UNUSED(endOffset)\
368 return QString(); \
369 }\
370 private:\
371 classname *m_w;\
372 QString m_description;\
373 };\
374 FUNC_TEXT(classname,accessiblename)\
375 FUNC_TEXT_(classname)\
376
377#define SET_SLIDER_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,accessdescription) class Accessible##classname : public QAccessibleWidget, public QAccessibleValueInterface\
378 {\
379 public:\
380 FUNC_CREATE(classname,QAccessible::Slider,accessdescription)\
381 QString text(QAccessible::Text t) const override;\
382 void *interface_cast(QAccessible::InterfaceType t) override{\
383 switch (t) {\
384 case QAccessible::ActionInterface:\
385 return static_cast<QAccessibleActionInterface*>(this);\
386 case QAccessible::ValueInterface:\
387 return static_cast<QAccessibleValueInterface*>(this);\
388 default:\
389 return nullptr;\
390 }\
391 }\
392 QVariant currentValue() const override;\
393 void setCurrentValue(const QVariant &value) override;\
394 QVariant maximumValue() const override;\
395 QVariant minimumValue() const override;\
396 QVariant minimumStepSize() const override { return QVariant(); }\
397 private:\
398 classname *m_w;\
399 QString m_description;\
400 };\
401 FUNC_TEXT(classname,accessiblename)\
402 FUNC_CURRENTVALUE(classname)\
403 FUNC_SETCURRENTVALUE(classname)\
404 FUNC_MAXMUMVALUE(classname)\
405 FUNC_FUNC_MINIMUMVALUE(classname)\
406
407#define SET_EDITABLE_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,accessdescription) class Accessible##classname : public QAccessibleWidget, public QAccessibleEditableTextInterface, public QAccessibleTextInterface\
408 {\
409 public:\
410 FUNC_CREATE(classname,QAccessible::EditableText,accessdescription)\
411 QString text(QAccessible::Text t) const override;\
412 QAccessibleInterface *child(int index) const override { \
413 Q_UNUSED(index) \
414 return nullptr; \
415 }\
416 void *interface_cast(QAccessible::InterfaceType t) override{\
417 switch (t) {\
418 case QAccessible::ActionInterface:\
419 return static_cast<QAccessibleActionInterface*>(this);\
420 case QAccessible::TextInterface:\
421 return static_cast<QAccessibleTextInterface*>(this);\
422 case QAccessible::EditableTextInterface:\
423 return static_cast<QAccessibleEditableTextInterface*>(this);\
424 default:\
425 return nullptr;\
426 }\
427 }\
428 QAccessible::State state() const override {\
429 QAccessible::State state;\
430 state.editable = 1;\
431 return state;\
432 }\
433 QString text(int startOffset, int endOffset) const override;\
434 void selection(int selectionIndex, int *startOffset, int *endOffset) const override;\
435 int selectionCount() const override;\
436 void addSelection(int startOffset, int endOffset) override;\
437 void removeSelection(int selectionIndex) override;\
438 void setSelection(int selectionIndex, int startOffset, int endOffset) override;\
439 int cursorPosition() const override;\
440 void setCursorPosition(int position) override;\
441 int characterCount() const override;\
442 QRect characterRect(int offset) const override;\
443 int offsetAtPoint(const QPoint &point) const override;\
444 void scrollToSubstring(int startIndex, int endIndex) override;\
445 QString attributes(int offset, int *startOffset, int *endOffset) const override;\
446 void insertText(int offset, const QString &text) override;\
447 void deleteText(int startOffset, int endOffset) override;\
448 void replaceText(int startOffset, int endOffset, const QString &text) override;\
449 private:\
450 classname *m_w;\
451 QString m_description;\
452 };\
453 FUNC_TEXT(classname,accessiblename)\
454 FUNC_TEXT_LineEdit(classname)\
455 FUNC_DELETETEXT(classname)\
456 FUNC_INSERTTEXT(classname)\
457 FUNC_REPLACETEXT(classname)\
458 FUNC_SELECTION(classname)\
459 FUNC_SELECTIONCOUNT(classname)\
460 FUNC_ADDSELECTION(classname)\
461 FUNC_REMOVESELECTION(classname)\
462 FUNC_SETSELECTION(classname)\
463 FUNC_CURORPOSITION(classname)\
464 FUNC_SETCURORPOSITION(classname)\
465 FUNC_CHARACTERCOUNT(classname)\
466 FUNC_CHARACTERRECT(classname)\
467 FUNC_OFFSETATPOINT(classname)\
468 FUNC_SCROLLTOSUBSTRING(classname)\
469 FUNC_ATTRIBUTES(classname)\
470
471#define USE_ACCESSIBLE(classnamestring,classname) if (classnamestring == QLatin1String(#classname) && object && object->isWidgetType())\
472 {\
473 interface = new Accessible##classname(static_cast<classname *>(object));\
474 }\
475
476// [指定objectname]---适用同一个类,但objectname不同的情况
477#define USE_ACCESSIBLE_BY_OBJECTNAME(classnamestring,classname,objectname) if (classnamestring == QLatin1String(#classname) && object && (object->objectName() == objectname) && object->isWidgetType())\
478 {\
479 interface = new Accessible##classname(static_cast<classname *>(object));\
480 }\
481
482/*******************************************简化使用*******************************************/
483
485{
486public:
487 explicit AccessibleFactoryBase() {}
488 virtual ~AccessibleFactoryBase() {}
489 virtual QAccessibleInterface* createObject(QObject *object) = 0;
490};
491
493{
494public:
495 static AccessibleFactoryBase * RegisterAccessibleFactory(const char *factoryName,AccessibleFactoryBase *factory);
496};
497
498#define FactoryMacro(Key,ClassName)\
499class FactoryAccessible##ClassName :public AccessibleFactoryBase\
500{\
501 private:\
502 static AccessibleFactoryBase* s_Accessible##ClassName##instance;\
503 public:\
504 virtual QAccessibleInterface* createObject(QObject *object) override\
505 { return new Accessible##ClassName(static_cast<ClassName *>(object));}\
506};\
507inline AccessibleFactoryBase* FactoryAccessible##ClassName::s_Accessible##ClassName##instance = AccessibleFactoryManager::RegisterAccessibleFactory(Key, new FactoryAccessible##ClassName());
508
510#define SET_FORM_ACCESSIBLE(classname,accessiblename) SET_FORM_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,"")\
511FactoryMacro(#classname, classname)
512
513#define SET_BUTTON_ACCESSIBLE(classname,accessiblename) SET_BUTTON_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,"")\
514FactoryMacro(#classname, classname)
515
516#define SET_LABEL_ACCESSIBLE(classname,accessiblename) SET_LABEL_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,QAccessible::StaticText,"") \
517FUNC_CHILD_LABLE(classname)\
518FactoryMacro(#classname, classname)
519
520#define SET_DTK_EDITABLE_ACCESSIBLE(classname,accessiblename) SET_LABEL_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,QAccessible::EditableText,"") \
521FUNC_CHILD_EDITABLE(classname)\
522FactoryMacro(#classname, classname)
523
524#define SET_SLIDER_ACCESSIBLE(classname,accessiblename) SET_SLIDER_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,"")\
525FactoryMacro(#classname, classname)
526
527#define SET_EDITABLE_ACCESSIBLE(classname,accessiblename) SET_EDITABLE_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,"")\
528FactoryMacro(#classname, classname)
530
531#endif // ACCESSIBLEINTERFACE_H
Definition accessibleinterface.h:485
Definition accessibleinterface.h:493