File indexing completed on 2024-11-10 04:17:45
0001 /* 0002 SPDX-FileCopyrightText: 2012 Frederik Gladhorn <gladhorn@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "accessibleobject.h" 0008 #include "qaccessibilityclient_debug.h" 0009 0010 #include <QString> 0011 #include <QDebug> 0012 0013 #include "accessibleobject_p.h" 0014 #include "registry_p.h" 0015 0016 #include <atspi/atspi-constants.h> 0017 0018 using namespace QAccessibleClient; 0019 0020 AccessibleObject::AccessibleObject() 0021 :d(nullptr) 0022 { 0023 } 0024 0025 AccessibleObject::AccessibleObject(RegistryPrivate *registryPrivate, const QString &service, const QString &path) 0026 :d(nullptr) 0027 { 0028 Q_ASSERT(registryPrivate); 0029 Q_ASSERT(!service.isEmpty()); 0030 Q_ASSERT(!path.isEmpty()); 0031 if (registryPrivate->m_cache) { 0032 const QString id = path + service; 0033 d = registryPrivate->m_cache->get(id); 0034 if (!d) { 0035 d = QSharedPointer<AccessibleObjectPrivate>(new AccessibleObjectPrivate(registryPrivate, service, path)); 0036 registryPrivate->m_cache->add(id, d); 0037 } 0038 } else { 0039 d = QSharedPointer<AccessibleObjectPrivate>(new AccessibleObjectPrivate(registryPrivate, service, path)); 0040 } 0041 } 0042 0043 AccessibleObject::AccessibleObject(const QSharedPointer<AccessibleObjectPrivate> &dd) 0044 :d(dd) 0045 { 0046 } 0047 0048 AccessibleObject::AccessibleObject(const AccessibleObject &other) 0049 : d(other.d) 0050 { 0051 } 0052 0053 AccessibleObject::~AccessibleObject() 0054 { 0055 } 0056 0057 QString AccessibleObject::id() const 0058 { 0059 if (!d || !d->registryPrivate) 0060 return QString(); 0061 return d->path + d->service; 0062 } 0063 0064 QUrl AccessibleObject::url() const 0065 { 0066 if (!d || !d->registryPrivate) 0067 return QUrl(); 0068 QUrl u; 0069 u.setScheme(d->registryPrivate->ACCESSIBLE_OBJECT_SCHEME_STRING); 0070 u.setPath(d->path); 0071 u.setFragment(d->service); 0072 return u; 0073 } 0074 0075 bool AccessibleObject::isValid() const 0076 { 0077 return d && d->registryPrivate 0078 && (!d->service.isEmpty()) 0079 && (!d->path.isEmpty()) 0080 && (d->path != QLatin1String("/org/a11y/atspi/null")); 0081 } 0082 0083 AccessibleObject &AccessibleObject::operator=(const AccessibleObject &other) 0084 { 0085 d = other.d; 0086 return *this; 0087 } 0088 0089 bool AccessibleObject::operator==(const AccessibleObject &other) const 0090 { 0091 return (d == other.d) || (d && other.d && *d == *other.d); 0092 } 0093 0094 AccessibleObject AccessibleObject::parent() const 0095 { 0096 return d->registryPrivate->parentAccessible(*this); 0097 } 0098 0099 QList<AccessibleObject> AccessibleObject::children() const 0100 { 0101 return d->registryPrivate->children(*this); 0102 } 0103 0104 QVector< QList<AccessibleObject> > AccessibleObject::children(const QList<Role> &roles) const 0105 { 0106 QVector< QList<AccessibleObject> > result(roles.count()); 0107 const QList<AccessibleObject> all = children(); 0108 for(int i = 0; i < all.count(); ++i) { 0109 const AccessibleObject &child = all[i]; 0110 int index = roles.indexOf(child.role()); 0111 if (index < 0) continue; 0112 result[index].append(child); 0113 } 0114 return result; 0115 } 0116 0117 int AccessibleObject::childCount() const 0118 { 0119 return d->registryPrivate->childCount(*this); 0120 } 0121 0122 AccessibleObject AccessibleObject::child(int index) const 0123 { 0124 return d->registryPrivate->child(*this, index); 0125 } 0126 0127 int AccessibleObject::indexInParent() const 0128 { 0129 return d->registryPrivate->indexInParent(*this); 0130 } 0131 0132 QString AccessibleObject::accessibleId() const 0133 { 0134 return d->registryPrivate->accessibleId(*this); 0135 } 0136 0137 QString AccessibleObject::name() const 0138 { 0139 return d->registryPrivate->name(*this); 0140 } 0141 0142 QString AccessibleObject::description() const 0143 { 0144 return d->registryPrivate->description(*this); 0145 } 0146 0147 AccessibleObject::Role AccessibleObject::role() const 0148 { 0149 return d->registryPrivate->role(*this); 0150 } 0151 0152 QString AccessibleObject::roleName() const 0153 { 0154 return d->registryPrivate->roleName(*this); 0155 } 0156 0157 QString AccessibleObject::localizedRoleName() const 0158 { 0159 return d->registryPrivate->localizedRoleName(*this); 0160 } 0161 0162 int AccessibleObject::layer() const 0163 { 0164 return d->registryPrivate->layer(*this); 0165 } 0166 0167 int AccessibleObject::mdiZOrder() const 0168 { 0169 return d->registryPrivate->mdiZOrder(*this); 0170 } 0171 0172 double AccessibleObject::alpha() const 0173 { 0174 return d->registryPrivate->alpha(*this); 0175 } 0176 0177 QRect AccessibleObject::boundingRect() const 0178 { 0179 if( supportedInterfaces() & AccessibleObject::ComponentInterface ){ 0180 return d->registryPrivate->boundingRect(*this); 0181 } else { 0182 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "boundingRect called on accessible that does not implement component"; 0183 return QRect(); 0184 } 0185 } 0186 0187 QRect AccessibleObject::characterRect(int offset) const 0188 { 0189 if( supportedInterfaces() & AccessibleObject::TextInterface ){ 0190 return d->registryPrivate->characterRect(*this, offset); 0191 } else { 0192 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "characterRect called on accessible that does not implement text"; 0193 return QRect(); 0194 } 0195 } 0196 0197 AccessibleObject::Interfaces AccessibleObject::supportedInterfaces() const 0198 { 0199 return d->registryPrivate->supportedInterfaces(*this); 0200 } 0201 0202 int AccessibleObject::caretOffset() const 0203 { 0204 if( supportedInterfaces() & AccessibleObject::TextInterface ){ 0205 return d->registryPrivate->caretOffset(*this); 0206 } else { 0207 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "caretOffset called on accessible that does not implement text"; 0208 return 0; 0209 } 0210 } 0211 0212 int AccessibleObject::characterCount() const 0213 { 0214 if( supportedInterfaces() & AccessibleObject::TextInterface ){ 0215 return d->registryPrivate->characterCount(*this); 0216 } else { 0217 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "characterCount called on accessible that does not implement text"; 0218 return 0; 0219 } 0220 } 0221 0222 QString AccessibleObject::text(int startOffset, int endOffset) const 0223 { 0224 if( supportedInterfaces() & AccessibleObject::TextInterface ) 0225 return d->registryPrivate->text(*this, startOffset, endOffset); 0226 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "text called on accessible that does not implement text"; 0227 return QString(); 0228 } 0229 0230 QString AccessibleObject::textWithBoundary(int offset, TextBoundary boundary, int *startOffset, int *endOffset) const 0231 { 0232 if (supportedInterfaces() & AccessibleObject::TextInterface) 0233 return d->registryPrivate->textWithBoundary(*this, offset, boundary, startOffset, endOffset); 0234 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "text called on accessible that does not implement text"; 0235 return QString(); 0236 } 0237 0238 bool AccessibleObject::setText(const QString &text) 0239 { 0240 if( supportedInterfaces() & AccessibleObject::EditableTextInterface ) 0241 return d->registryPrivate->setText(*this, text); 0242 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "setText called on accessible that does not implement editableText"; 0243 return false; 0244 } 0245 0246 bool AccessibleObject::insertText(const QString &text, int position, int length) 0247 { 0248 if( supportedInterfaces() & AccessibleObject::EditableTextInterface ) 0249 return d->registryPrivate->insertText(*this, text, position, length); 0250 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "insertText called on accessible that does not implement editableText"; 0251 return false; 0252 } 0253 0254 bool AccessibleObject::copyText(int startPos, int endPos) 0255 { 0256 if( supportedInterfaces() & AccessibleObject::EditableTextInterface ) 0257 return d->registryPrivate->copyText(*this, startPos, endPos); 0258 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "copyText called on accessible that does not implement editableText"; 0259 return false; 0260 } 0261 0262 bool AccessibleObject::cutText(int startPos, int endPos) 0263 { 0264 if( supportedInterfaces() & AccessibleObject::EditableTextInterface ) 0265 return d->registryPrivate->cutText(*this, startPos, endPos); 0266 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "cutText called on accessible that does not implement editableText"; 0267 return false; 0268 } 0269 0270 bool AccessibleObject::deleteText(int startPos, int endPos) 0271 { 0272 if( supportedInterfaces() & AccessibleObject::EditableTextInterface ) 0273 return d->registryPrivate->deleteText(*this, startPos, endPos); 0274 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "deleteText called on accessible that does not implement editableText"; 0275 return false; 0276 } 0277 0278 bool AccessibleObject::pasteText(int position) 0279 { 0280 if( supportedInterfaces() & AccessibleObject::EditableTextInterface ) 0281 return d->registryPrivate->pasteText(*this, position); 0282 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "pasteText called on accessible that does not implement editableText"; 0283 return false; 0284 } 0285 0286 QList< QPair<int,int> > AccessibleObject::textSelections() const 0287 { 0288 if(supportedInterfaces() & AccessibleObject::Text) 0289 return d->registryPrivate->textSelections(*this); 0290 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "textSelections called on accessible that does not implement text"; 0291 return QList< QPair<int,int> >(); 0292 } 0293 0294 void AccessibleObject::setTextSelections(const QList< QPair<int,int> > &selections) 0295 { 0296 if(supportedInterfaces() & AccessibleObject::Text) 0297 return d->registryPrivate->setTextSelections(*this, selections); 0298 qCWarning(LIBQACCESSIBILITYCLIENT_LOG) << "setTextSelections called on accessible that does not implement text"; 0299 } 0300 0301 QPoint AccessibleObject::focusPoint() const 0302 { 0303 Interfaces ifaces = supportedInterfaces(); 0304 if (ifaces & TextInterface) { 0305 const int offset = caretOffset(); 0306 const QRect r = characterRect(offset); 0307 if (r.x() != 0 || r.y() != 0) 0308 return r.center(); 0309 } 0310 if (ifaces & ComponentInterface) { 0311 const QRect r = boundingRect(); 0312 if (!r.isNull()) 0313 return r.center(); 0314 } 0315 AccessibleObject p = parent(); 0316 if (p.isValid()) 0317 return p.focusPoint(); // recursive 0318 return QPoint(); 0319 } 0320 0321 AccessibleObject AccessibleObject::application() const 0322 { 0323 return d->registryPrivate->application(*this); 0324 } 0325 0326 QString AccessibleObject::appToolkitName() const 0327 { 0328 return d->registryPrivate->appToolkitName(*this); 0329 } 0330 0331 QString AccessibleObject::appVersion() const 0332 { 0333 return d->registryPrivate->appVersion(*this); 0334 } 0335 0336 int AccessibleObject::appId() const 0337 { 0338 return d->registryPrivate->appId(*this); 0339 } 0340 0341 QString AccessibleObject::appLocale(LocaleType lctype) const 0342 { 0343 return d->registryPrivate->appLocale(*this, lctype); 0344 } 0345 0346 QString AccessibleObject::appBusAddress() const 0347 { 0348 return d->registryPrivate->appBusAddress(*this); 0349 } 0350 0351 double AccessibleObject::minimumValue() const 0352 { 0353 return d->registryPrivate->minimumValue(*this); 0354 } 0355 0356 double AccessibleObject::maximumValue() const 0357 { 0358 return d->registryPrivate->maximumValue(*this); 0359 } 0360 0361 double AccessibleObject::minimumValueIncrement() const 0362 { 0363 return d->registryPrivate->minimumValueIncrement(*this); 0364 } 0365 0366 double AccessibleObject::currentValue() const 0367 { 0368 return d->registryPrivate->currentValue(*this); 0369 } 0370 0371 bool AccessibleObject::setCurrentValue(double value) 0372 { 0373 return d->registryPrivate->setCurrentValue(*this, value); 0374 } 0375 0376 QList<AccessibleObject> AccessibleObject::selection() const 0377 { 0378 return d->registryPrivate->selection(*this); 0379 } 0380 0381 QString AccessibleObject::imageDescription() const 0382 { 0383 return d->registryPrivate->imageDescription(*this); 0384 } 0385 0386 QString AccessibleObject::imageLocale() const 0387 { 0388 return d->registryPrivate->imageLocale(*this); 0389 } 0390 0391 QRect AccessibleObject::imageRect() const 0392 { 0393 return d->registryPrivate->imageRect(*this); 0394 } 0395 0396 QVector< QSharedPointer<QAction> > AccessibleObject::actions() const 0397 { 0398 // Actions in atspi are supposed to be static what means they cannot change in 0399 // between (e.g. actions removed or added or edited) so we can safely just 0400 // fetch them only once and store the result for the life-time of the object, 0401 if (!d->actionsFetched) { 0402 d->actionsFetched = true; 0403 d->actions = d->registryPrivate->actions(*this); 0404 } 0405 return d->actions; 0406 } 0407 0408 bool AccessibleObject::hasSelectableText() const 0409 { 0410 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_SELECTABLE_TEXT); 0411 } 0412 0413 bool AccessibleObject::hasToolTip() const 0414 { 0415 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_HAS_TOOLTIP); 0416 } 0417 0418 bool AccessibleObject::isActive() const 0419 { 0420 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_ACTIVE); 0421 } 0422 0423 bool AccessibleObject::isCheckable() const 0424 { 0425 //FIXME: Find better AccessibleObject::isCheckable 0426 //return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_); 0427 0428 Role role = d->registryPrivate->role(*this); 0429 if (role == AccessibleObject::CheckBox || 0430 role == AccessibleObject::CheckableMenuItem || 0431 role == AccessibleObject::RadioButton || 0432 role == AccessibleObject::RadioMenuItem || 0433 role == AccessibleObject::ToggleButton) 0434 return true; 0435 return false; 0436 } 0437 0438 bool AccessibleObject::isChecked() const 0439 { 0440 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_CHECKED); 0441 } 0442 0443 bool AccessibleObject::isDefunct() const 0444 { 0445 return d->defunct; 0446 } 0447 0448 bool AccessibleObject::isDefault() const 0449 { 0450 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_IS_DEFAULT); 0451 } 0452 0453 bool AccessibleObject::isEditable() const 0454 { 0455 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_EDITABLE); 0456 } 0457 0458 bool AccessibleObject::isEnabled() const 0459 { 0460 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_ENABLED); 0461 } 0462 0463 bool AccessibleObject::isExpandable() const 0464 { 0465 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_EXPANDABLE); 0466 } 0467 0468 bool AccessibleObject::isExpanded() const 0469 { 0470 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_EXPANDED); 0471 } 0472 0473 bool AccessibleObject::isFocusable() const 0474 { 0475 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_FOCUSABLE); 0476 } 0477 0478 bool AccessibleObject::isFocused() const 0479 { 0480 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_FOCUSED); 0481 } 0482 0483 bool AccessibleObject::isMultiLine() const 0484 { 0485 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_MULTI_LINE); 0486 } 0487 0488 bool AccessibleObject::isSelectable() const 0489 { 0490 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_SELECTABLE); 0491 } 0492 0493 bool AccessibleObject::isSelected() const 0494 { 0495 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_SELECTED); 0496 } 0497 0498 bool AccessibleObject::isSensitive() const 0499 { 0500 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_SENSITIVE); 0501 } 0502 0503 bool AccessibleObject::isSingleLine() const 0504 { 0505 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_SINGLE_LINE); 0506 } 0507 0508 QString AccessibleObject::stateString() const 0509 { 0510 QStringList s; 0511 if (isActive()) s << QStringLiteral("Active"); 0512 if (isCheckable()) s << QStringLiteral("Checkable"); 0513 if (isChecked()) s << QStringLiteral("Checked"); 0514 if (isEditable()) s << QStringLiteral("Editable"); 0515 if (isExpandable()) s << QStringLiteral("Expandable"); 0516 if (isExpanded()) s << QStringLiteral("Expanded"); 0517 if (isFocusable()) s << QStringLiteral("Focusable"); 0518 if (isFocused()) s << QStringLiteral("Focused"); 0519 if (isMultiLine()) s << QStringLiteral("MultiLine"); 0520 if (isSelectable()) s << QStringLiteral("Selectable"); 0521 if (isSelected()) s << QStringLiteral("Selected"); 0522 if (isSensitive()) s << QStringLiteral("Sensitive"); 0523 if (isSingleLine()) s << QStringLiteral("SingleLine"); 0524 if (isEnabled()) s << QStringLiteral("Enabled"); 0525 return s.join(QLatin1String(", ")); 0526 } 0527 0528 bool AccessibleObject::isVisible() const 0529 { 0530 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_VISIBLE); 0531 } 0532 0533 bool AccessibleObject::supportsAutocompletion() const 0534 { 0535 return d->registryPrivate->state(*this) & (quint64(1) << ATSPI_STATE_SUPPORTS_AUTOCOMPLETION); 0536 } 0537 0538 #ifndef QT_NO_DEBUG_STREAM 0539 QACCESSIBILITYCLIENT_EXPORT QDebug QAccessibleClient::operator<<(QDebug d, const AccessibleObject &object) 0540 { 0541 d.nospace(); 0542 d << "AccessibleObject("; 0543 if (object.d) { 0544 d << "service=" << object.d->service; 0545 d << " path=" << object.d->path; 0546 d << " name=" << object.name(); 0547 } else { 0548 d << "invalid"; 0549 } 0550 d << ")"; 0551 return d.space(); 0552 } 0553 #endif