File indexing completed on 2023-12-03 11:41:02

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