// 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 #include #include #include #include #include #include #include #include #include #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(); 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(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(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(this);\ case QAccessible::TextInterface:\ return static_cast(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(this);\ case QAccessible::ValueInterface:\ return static_cast(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(this);\ case QAccessible::TextInterface:\ return static_cast(this);\ case QAccessible::EditableTextInterface:\ return static_cast(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(object));\ }\ #define ELSE_USE_ACCESSIBLE(classnamestring,classname) else if (classnamestring == QLatin1String(#classname) && object && object->isWidgetType())\ {\ interface = new Accessible##classname(static_cast(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(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(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