mirror of
https://github.com/linuxdeepin/dde-dock.git
synced 2025-06-01 07:05:48 +00:00
406 lines
15 KiB
C
406 lines
15 KiB
C
// Copyright (C) 2018 ~ 2020 Deepin Technology Co., Ltd.
|
||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||
//
|
||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||
|
||
// 为了方便使用,把相关定义独立出来,如有需要,直接包含这个头文件,然后使用SET_*的宏去设置,USE_*宏开启即可
|
||
// 注意:对项目中出现的所有的QWidget的派生类都要再启用一次accessiblity,包括qt的原生控件[qt未限制其标记名称为空的情况]
|
||
// 注意:使用USE_ACCESSIBLE_BY_OBJECTNAME开启accessiblity的时候,一定要再对这个类用一下USE_ACCESSIBLE,否则标记可能会遗漏
|
||
|
||
#ifndef ACCESSIBLEINTERFACE_H
|
||
#define ACCESSIBLEINTERFACE_H
|
||
|
||
#include <QAccessible>
|
||
#include <QAccessibleWidget>
|
||
#include <QEvent>
|
||
#include <QMap>
|
||
#include <QString>
|
||
#include <QWidget>
|
||
#include <QObject>
|
||
#include <QMetaEnum>
|
||
#include <QMouseEvent>
|
||
#include <QApplication>
|
||
|
||
#define SEPARATOR "_"
|
||
|
||
inline QString getAccessibleName(QWidget *w, QAccessible::Role r, const QString &fallback)
|
||
{
|
||
const QString lowerFallback = fallback.toLower();
|
||
// 避免重复生成
|
||
static QMap< QObject *, QString > objnameMap;
|
||
if (!objnameMap[w].isEmpty())
|
||
return objnameMap[w];
|
||
|
||
static QMap< QAccessible::Role, QList< QString > > accessibleMap;
|
||
QString oldAccessName = w->accessibleName().toLower();
|
||
oldAccessName.replace(SEPARATOR, "");
|
||
|
||
// 按照类型添加固定前缀
|
||
QMetaEnum metaEnum = QMetaEnum::fromType<QAccessible::Role>();
|
||
QByteArray prefix = metaEnum.valueToKeys(r);
|
||
switch (r) {
|
||
case QAccessible::Button: prefix = "Btn"; break;
|
||
case QAccessible::StaticText: prefix = "Label"; break;
|
||
default: break;
|
||
}
|
||
|
||
// 再加上标识
|
||
QString accessibleName = QString::fromLatin1(prefix) + SEPARATOR;
|
||
QString objectName = w->objectName().toLower();
|
||
accessibleName += oldAccessName.isEmpty() ? (objectName.isEmpty() ?lowerFallback : objectName) : oldAccessName;
|
||
// 检查名称是否唯一
|
||
if (accessibleMap[r].contains(accessibleName)) {
|
||
if (!objnameMap.key(accessibleName)) {
|
||
objnameMap.remove(objnameMap.key(accessibleName));
|
||
objnameMap.insert(w, accessibleName);
|
||
return accessibleName;
|
||
}
|
||
// 获取编号,然后+1
|
||
int pos = accessibleName.indexOf(SEPARATOR);
|
||
int id = accessibleName.mid(pos + 1).toInt();
|
||
|
||
QString newAccessibleName;
|
||
do {
|
||
// 一直找到一个不重复的名字
|
||
newAccessibleName = accessibleName + SEPARATOR + QString::number(++id);
|
||
} while (accessibleMap[r].contains(newAccessibleName));
|
||
|
||
accessibleMap[r].append(newAccessibleName);
|
||
objnameMap.insert(w, newAccessibleName);
|
||
|
||
// 对象销毁后移除占用名称
|
||
QObject::connect(w, &QWidget::destroyed, [ = ] (QObject *obj) {
|
||
objnameMap.remove(obj);
|
||
accessibleMap[r].removeOne(newAccessibleName);
|
||
});
|
||
return newAccessibleName;
|
||
} else {
|
||
accessibleMap[r].append(accessibleName);
|
||
objnameMap.insert(w, accessibleName);
|
||
|
||
// 对象销毁后移除占用名称
|
||
QObject::connect(w, &QWidget::destroyed, [ = ] (QObject *obj) {
|
||
objnameMap.remove(obj);
|
||
accessibleMap[r].removeOne(accessibleName);
|
||
});
|
||
return accessibleName;
|
||
}
|
||
}
|
||
|
||
// 公共的功能
|
||
#define FUNC_CREATE(classname,accessibletype,accessdescription) explicit Accessible##classname(classname *w) \
|
||
: QAccessibleWidget(w,accessibletype,#classname)\
|
||
, m_w(w)\
|
||
, m_description(accessdescription)\
|
||
{}\
|
||
|
||
#define FUNC_TEXT(classname,accessiblename) QString Accessible##classname::text(QAccessible::Text t) const{\
|
||
switch (t) {\
|
||
case QAccessible::Name:\
|
||
return getAccessibleName(m_w, this->role(), accessiblename);\
|
||
case QAccessible::Description:\
|
||
return m_description;\
|
||
default:\
|
||
return QString();\
|
||
}\
|
||
}\
|
||
|
||
// button控件特有功能
|
||
#define FUNC_ACTIONNAMES(classname) QStringList Accessible##classname::actionNames() const{\
|
||
if(!m_w->isEnabled())\
|
||
return QStringList();\
|
||
return QStringList() << pressAction()<< showMenuAction();\
|
||
}\
|
||
|
||
#define FUNC_DOACTION(classname) void Accessible##classname::doAction(const QString &actionName){\
|
||
if(actionName == pressAction())\
|
||
{\
|
||
QPointF localPos = m_w->geometry().center();\
|
||
QMouseEvent event(QEvent::MouseButtonPress,localPos,Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);\
|
||
qApp->sendEvent(m_w,&event);\
|
||
}\
|
||
else if(actionName == showMenuAction())\
|
||
{\
|
||
QPointF localPos = m_w->geometry().center();\
|
||
QMouseEvent event(QEvent::MouseButtonPress,localPos,Qt::RightButton,Qt::RightButton,Qt::NoModifier);\
|
||
qApp->sendEvent(m_w,&event);\
|
||
}\
|
||
}\
|
||
|
||
// Label控件特有功能
|
||
#define FUNC_TEXT_(classname) QString Accessible##classname::text(int startOffset, int endOffset) const{\
|
||
Q_UNUSED(startOffset)\
|
||
Q_UNUSED(endOffset)\
|
||
return m_w->text();\
|
||
}\
|
||
|
||
// Slider控件特有功能
|
||
#define FUNC_CURRENTVALUE(classname) QVariant Accessible##classname::currentValue() const{\
|
||
return m_w->value();\
|
||
}\
|
||
|
||
#define FUNC_SETCURRENTVALUE(classname) void Accessible##classname::setCurrentValue(const QVariant &value){\
|
||
return m_w->setValue(value.toInt());\
|
||
}\
|
||
|
||
#define FUNC_MAXMUMVALUE(classname) QVariant Accessible##classname::maximumValue() const{\
|
||
return QVariant(m_w->maximum());\
|
||
}\
|
||
|
||
#define FUNC_FUNC_MINIMUMVALUE(classname) QVariant Accessible##classname::minimumValue() const{\
|
||
return QVariant(m_w->minimum());\
|
||
}\
|
||
|
||
// DSlider控件特有功能函数
|
||
#define FUNC_FUNC_MINIMUMSTEPSIZE(classname) QVariant Accessible##classname::minimumStepSize() const{\
|
||
return QVariant(m_w->pageStep());\
|
||
}\
|
||
|
||
#define SET_FORM_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,accessdescription) class Accessible##classname : public QAccessibleWidget\
|
||
{\
|
||
public:\
|
||
FUNC_CREATE(classname,QAccessible::Form,accessdescription)\
|
||
QString text(QAccessible::Text t) const override;\
|
||
void *interface_cast(QAccessible::InterfaceType t) override{\
|
||
switch (t) {\
|
||
case QAccessible::ActionInterface:\
|
||
return static_cast<QAccessibleActionInterface*>(this);\
|
||
default:\
|
||
return nullptr;\
|
||
}\
|
||
}\
|
||
private:\
|
||
classname *m_w;\
|
||
QString m_description;\
|
||
};\
|
||
FUNC_TEXT(classname,accessiblename)\
|
||
|
||
#define SET_BUTTON_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,accessdescription) class Accessible##classname : public QAccessibleWidget\
|
||
{\
|
||
public:\
|
||
FUNC_CREATE(classname,QAccessible::Button,accessdescription)\
|
||
QString text(QAccessible::Text t) const override;\
|
||
void *interface_cast(QAccessible::InterfaceType t) override{\
|
||
switch (t) {\
|
||
case QAccessible::ActionInterface:\
|
||
return static_cast<QAccessibleActionInterface*>(this);\
|
||
default:\
|
||
return nullptr;\
|
||
}\
|
||
}\
|
||
QStringList actionNames() const override;\
|
||
void doAction(const QString &actionName) override;\
|
||
private:\
|
||
classname *m_w;\
|
||
QString m_description;\
|
||
};\
|
||
FUNC_TEXT(classname,accessiblename)\
|
||
FUNC_ACTIONNAMES(classname)\
|
||
FUNC_DOACTION(classname)\
|
||
|
||
#define SET_LABEL_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,accessdescription) class Accessible##classname : public QAccessibleWidget, public QAccessibleTextInterface\
|
||
{\
|
||
public:\
|
||
FUNC_CREATE(classname,QAccessible::StaticText,accessdescription)\
|
||
QString text(QAccessible::Text t) const override;\
|
||
void *interface_cast(QAccessible::InterfaceType t) override{\
|
||
switch (t) {\
|
||
case QAccessible::ActionInterface:\
|
||
return static_cast<QAccessibleActionInterface*>(this);\
|
||
case QAccessible::TextInterface:\
|
||
return static_cast<QAccessibleTextInterface*>(this);\
|
||
default:\
|
||
return nullptr;\
|
||
}\
|
||
}\
|
||
QString text(int startOffset, int endOffset) const override;\
|
||
void selection(int selectionIndex, int *startOffset, int *endOffset) const override {\
|
||
Q_UNUSED(selectionIndex)\
|
||
Q_UNUSED(startOffset)\
|
||
Q_UNUSED(endOffset)\
|
||
}\
|
||
int selectionCount() const override { return 0; }\
|
||
void addSelection(int startOffset, int endOffset) override {\
|
||
Q_UNUSED(startOffset)\
|
||
Q_UNUSED(endOffset)\
|
||
}\
|
||
void removeSelection(int selectionIndex) override {\
|
||
Q_UNUSED(selectionIndex)\
|
||
}\
|
||
void setSelection(int selectionIndex, int startOffset, int endOffset) override {\
|
||
Q_UNUSED(selectionIndex)\
|
||
Q_UNUSED(startOffset)\
|
||
Q_UNUSED(endOffset)\
|
||
}\
|
||
int cursorPosition() const override { return 0; }\
|
||
void setCursorPosition(int position) override {\
|
||
Q_UNUSED(position)\
|
||
}\
|
||
int characterCount() const override { return 0; }\
|
||
QRect characterRect(int offset) const override {\
|
||
Q_UNUSED(offset)\
|
||
return QRect();\
|
||
}\
|
||
int offsetAtPoint(const QPoint &point) const override {\
|
||
Q_UNUSED(point)\
|
||
return 0;\
|
||
}\
|
||
void scrollToSubstring(int startIndex, int endIndex) override {\
|
||
Q_UNUSED(startIndex)\
|
||
Q_UNUSED(endIndex)\
|
||
}\
|
||
QString attributes(int offset, int *startOffset, int *endOffset) const override {\
|
||
Q_UNUSED(offset)\
|
||
Q_UNUSED(startOffset)\
|
||
Q_UNUSED(endOffset)\
|
||
return QString();\
|
||
}\
|
||
private:\
|
||
classname *m_w;\
|
||
QString m_description;\
|
||
};\
|
||
FUNC_TEXT(classname,accessiblename)\
|
||
FUNC_TEXT_(classname)\
|
||
|
||
#define SET_SLIDER_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,accessdescription) class Accessible##classname : public QAccessibleWidget, public QAccessibleValueInterface\
|
||
{\
|
||
public:\
|
||
FUNC_CREATE(classname,QAccessible::Slider,accessdescription)\
|
||
QString text(QAccessible::Text t) const override;\
|
||
void *interface_cast(QAccessible::InterfaceType t) override{\
|
||
switch (t) {\
|
||
case QAccessible::ActionInterface:\
|
||
return static_cast<QAccessibleActionInterface*>(this);\
|
||
case QAccessible::ValueInterface:\
|
||
return static_cast<QAccessibleValueInterface*>(this);\
|
||
default:\
|
||
return nullptr;\
|
||
}\
|
||
}\
|
||
QVariant currentValue() const override;\
|
||
void setCurrentValue(const QVariant &value) override;\
|
||
QVariant maximumValue() const override;\
|
||
QVariant minimumValue() const override;\
|
||
QVariant minimumStepSize() const override;\
|
||
private:\
|
||
classname *m_w;\
|
||
QString m_description;\
|
||
};\
|
||
FUNC_TEXT(classname,accessiblename)\
|
||
FUNC_CURRENTVALUE(classname)\
|
||
FUNC_SETCURRENTVALUE(classname)\
|
||
FUNC_MAXMUMVALUE(classname)\
|
||
FUNC_FUNC_MINIMUMVALUE(classname)\
|
||
FUNC_FUNC_MINIMUMSTEPSIZE(classname)\
|
||
|
||
#define SET_EDITABLE_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,accessdescription) class Accessible##classname : public QAccessibleWidget, public QAccessibleEditableTextInterface, public QAccessibleTextInterface\
|
||
{\
|
||
public:\
|
||
FUNC_CREATE(classname,QAccessible::EditableText,accessdescription)\
|
||
QString text(QAccessible::Text t) const override;\
|
||
QAccessibleInterface *child(int index) const override { Q_UNUSED(index); return nullptr; }\
|
||
void *interface_cast(QAccessible::InterfaceType t) override{\
|
||
switch (t) {\
|
||
case QAccessible::ActionInterface:\
|
||
return static_cast<QAccessibleActionInterface*>(this);\
|
||
case QAccessible::TextInterface:\
|
||
return static_cast<QAccessibleTextInterface*>(this);\
|
||
case QAccessible::EditableTextInterface:\
|
||
return static_cast<QAccessibleEditableTextInterface*>(this);\
|
||
default:\
|
||
return nullptr;\
|
||
}\
|
||
}\
|
||
QString text(int startOffset, int endOffset) const override;\
|
||
void selection(int selectionIndex, int *startOffset, int *endOffset) const override {\
|
||
Q_UNUSED(selectionIndex)\
|
||
Q_UNUSED(startOffset)\
|
||
Q_UNUSED(endOffset)\
|
||
}\
|
||
int selectionCount() const override { return 0; }\
|
||
void addSelection(int startOffset, int endOffset) override {\
|
||
Q_UNUSED(startOffset)\
|
||
Q_UNUSED(endOffset)\
|
||
}\
|
||
void removeSelection(int selectionIndex) override { Q_UNUSED(selectionIndex);}\
|
||
void setSelection(int selectionIndex, int startOffset, int endOffset) override {\
|
||
Q_UNUSED(selectionIndex)\
|
||
Q_UNUSED(startOffset)\
|
||
Q_UNUSED(endOffset)\
|
||
}\
|
||
int cursorPosition() const override { return 0; }\
|
||
void setCursorPosition(int position) override {\
|
||
Q_UNUSED(position)\
|
||
}\
|
||
int characterCount() const override { return 0; }\
|
||
QRect characterRect(int offset) const override { \
|
||
Q_UNUSED(offset)\
|
||
return QRect(); }\
|
||
int offsetAtPoint(const QPoint &point) const override {\
|
||
Q_UNUSED(point)\
|
||
return 0; }\
|
||
void scrollToSubstring(int startIndex, int endIndex) override {\
|
||
Q_UNUSED(startIndex)\
|
||
Q_UNUSED(endIndex)\
|
||
}\
|
||
QString attributes(int offset, int *startOffset, int *endOffset) const override {\
|
||
Q_UNUSED(offset)\
|
||
Q_UNUSED(startOffset)\
|
||
Q_UNUSED(endOffset)\
|
||
return QString(); }\
|
||
void insertText(int offset, const QString &text) override {\
|
||
Q_UNUSED(offset)\
|
||
Q_UNUSED(text)\
|
||
}\
|
||
void deleteText(int startOffset, int endOffset) override {\
|
||
Q_UNUSED(startOffset)\
|
||
Q_UNUSED(endOffset)\
|
||
}\
|
||
void replaceText(int startOffset, int endOffset, const QString &text) override {\
|
||
Q_UNUSED(startOffset)\
|
||
Q_UNUSED(endOffset)\
|
||
Q_UNUSED(text)\
|
||
}\
|
||
private:\
|
||
classname *m_w;\
|
||
QString m_description;\
|
||
};\
|
||
FUNC_TEXT(classname,accessiblename)\
|
||
FUNC_TEXT_(classname)\
|
||
|
||
#define USE_ACCESSIBLE(classnamestring,classname) if (classnamestring == QLatin1String(#classname) && object && object->isWidgetType())\
|
||
{\
|
||
interface = new Accessible##classname(static_cast<classname *>(object));\
|
||
}\
|
||
|
||
#define ELSE_USE_ACCESSIBLE(classnamestring,classname) else if (classnamestring == QLatin1String(#classname) && object && object->isWidgetType())\
|
||
{\
|
||
interface = new Accessible##classname(static_cast<classname *>(object));\
|
||
}\
|
||
|
||
|
||
// [指定objectname]---适用同一个类,但objectname不同的情况
|
||
#define USE_ACCESSIBLE_BY_OBJECTNAME(classnamestring,classname,objectname) if (classnamestring == QLatin1String(#classname) && object && (object->objectName() == objectname) && object->isWidgetType())\
|
||
{\
|
||
interface = new Accessible##classname(static_cast<classname *>(object));\
|
||
}\
|
||
|
||
#define ELSE_USE_ACCESSIBLE_BY_OBJECTNAME(classnamestring,classname,objectname) else if (classnamestring == QLatin1String(#classname) && object && (object->objectName() == objectname) && object->isWidgetType())\
|
||
{\
|
||
interface = new Accessible##classname(static_cast<classname *>(object));\
|
||
}\
|
||
|
||
/*******************************************简化使用*******************************************/
|
||
#define SET_FORM_ACCESSIBLE(classname,accessiblename) SET_FORM_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,"")
|
||
|
||
#define SET_BUTTON_ACCESSIBLE(classname,accessiblename) SET_BUTTON_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,"")
|
||
|
||
#define SET_LABEL_ACCESSIBLE(classname,accessiblename) SET_LABEL_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,"")
|
||
|
||
#define SET_SLIDER_ACCESSIBLE(classname,accessiblename) SET_SLIDER_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,"")
|
||
|
||
#define SET_EDITABLE_ACCESSIBLE(classname,accessiblename) SET_EDITABLE_ACCESSIBLE_WITH_DESCRIPTION(classname,accessiblename,"")
|
||
/************************************************************************************************/
|
||
|
||
#endif // ACCESSIBLEINTERFACE_H
|