File indexing completed on 2025-01-26 03:28:30
0001 /* 0002 SPDX-FileCopyrightText: 2012 Sebastian Sauer <sebastian.sauer@kdab.com> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "accessiblepropertiesmodel.h" 0008 0009 #include <KLocalizedString> 0010 0011 #include <qaccessibilityclient/registry.h> 0012 0013 using namespace QAccessibleClient; 0014 0015 ObjectPropertiesModel::ObjectPropertiesModel(QObject *parent) 0016 : QStandardItemModel(parent) 0017 { 0018 connect(this, &ObjectPropertiesModel::itemChanged, this, &ObjectPropertiesModel::slotDataChanged); 0019 } 0020 0021 ObjectPropertiesModel::~ObjectPropertiesModel() = default; 0022 0023 int ObjectPropertiesModel::columnCount(const QModelIndex &parent) const 0024 { 0025 Q_UNUSED(parent) 0026 constexpr int val = static_cast<int>(ObjectPropertiesModelRoles::LastColumn) + 1; 0027 return val; 0028 } 0029 0030 void ObjectPropertiesModel::slotDataChanged(QStandardItem *item) 0031 { 0032 if (item == mTextItem) { 0033 QString newText = item->data(Qt::EditRole).toString(); 0034 mAccessibleObject.setText(newText); 0035 } else if (item == mValueItem) { 0036 bool couldConvert; 0037 const double value = item->data(Qt::EditRole).toDouble(&couldConvert); 0038 if (couldConvert) { 0039 mAccessibleObject.setCurrentValue(value); 0040 } 0041 0042 mValueItem = nullptr; // Prevent recursion 0043 item->setData(mAccessibleObject.currentValue(), Qt::DisplayRole); 0044 mValueItem = item; 0045 } 0046 } 0047 0048 QVariant ObjectPropertiesModel::headerData(int section, Qt::Orientation orientation, int role) const 0049 { 0050 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { 0051 switch (static_cast<ObjectPropertiesModelRoles>(section)) { 0052 case Name: 0053 return i18n("Property"); 0054 case Value: 0055 return i18n("Value"); 0056 } 0057 } 0058 return {}; 0059 } 0060 0061 QHash<int, QByteArray> ObjectPropertiesModel::roleNames() const 0062 { 0063 QHash<int, QByteArray> roles; 0064 roles[Name] = "name"; 0065 roles[Value] = "value"; 0066 return roles; 0067 } 0068 0069 void ObjectPropertiesModel::setFontBold(QStandardItem *item) 0070 { 0071 QFont font = item->font(); 0072 font.setBold(true); 0073 item->setFont(font); 0074 } 0075 0076 void ObjectPropertiesModel::setAccessibleObject(const QAccessibleClient::AccessibleObject &acc) 0077 { 0078 beginResetModel(); 0079 mAccessibleObject = acc; 0080 mTextItem = nullptr; 0081 mValueItem = nullptr; 0082 clear(); 0083 0084 if (!acc.isValid()) { 0085 endResetModel(); 0086 return; 0087 } 0088 0089 QAccessibleClient::AccessibleObject::Interfaces interfaces = acc.supportedInterfaces(); 0090 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::AccessibleInterface)) { 0091 QStandardItem *item = append(i18n("Accessible")); 0092 setFontBold(item); 0093 append(i18n("Name"), acc.name(), item); 0094 append(i18n("Description"), acc.description(), item); 0095 append(i18n("Role"), acc.roleName(), item); 0096 append(i18n("LocalizedRole"), acc.localizedRoleName(), item); 0097 append(i18n("Visible"), acc.isVisible(), item); 0098 append(i18n("Default"), acc.isDefault(), item); 0099 append(i18n("State"), acc.stateString(), item); 0100 append(i18n("AccessibleId"), acc.accessibleId(), item); 0101 append(i18n("Url"), acc.url(), item); 0102 AccessibleObject parent = acc.parent(); 0103 if (parent.isValid()) 0104 append(i18n("Parent"), parent.url(), item); 0105 int childCount = acc.childCount(); 0106 QStandardItem *children = append(i18n("Children"), acc.childCount(), item); 0107 for (int i = 0; i < childCount; ++i) { 0108 AccessibleObject child = acc.child(i); 0109 if (!child.isValid()) { 0110 append(i18n("Broken child"), QString::number(i), children); 0111 } else { 0112 append(child.name().isEmpty() ? QStringLiteral("[%1]").arg(child.roleName()) : child.name(), child.url(), children); 0113 } 0114 } 0115 // GetAttributes 0116 } 0117 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::ComponentInterface)) { 0118 QStandardItem *item = append(i18n("Component")); 0119 setFontBold(item); 0120 append(i18n("BoundingRect"), acc.boundingRect(), item); 0121 append(i18n("Layer"), acc.layer(), item); 0122 append(i18n("MDIZOrder"), acc.mdiZOrder(), item); 0123 append(i18n("Alpha"), acc.alpha(), item); 0124 } 0125 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::CollectionInterface)) { 0126 QStandardItem *item = append(i18n("Collection")); 0127 setFontBold(item); 0128 Q_UNUSED(item); 0129 } 0130 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::ApplicationInterface)) { 0131 QStandardItem *item = append(i18n("Application")); 0132 setFontBold(item); 0133 append(i18n("ToolkitName"), acc.appToolkitName(), item); 0134 append(i18n("Version"), acc.appVersion(), item); 0135 append(i18n("Id"), acc.appId(), item); 0136 append(i18n("Locale"), acc.appLocale(), item); 0137 append(i18n("BusAddress"), acc.appBusAddress(), item); 0138 } 0139 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::DocumentInterface)) { 0140 QStandardItem *item = append(i18n("Document")); 0141 setFontBold(item); 0142 Q_UNUSED(item); 0143 // GetLocale 0144 // GetAttributeValue 0145 // GetAttributes 0146 } 0147 0148 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::EditableTextInterface)) { 0149 QStandardItem *item = append(i18n("Editable Text")); 0150 setFontBold(item); 0151 Q_UNUSED(item); 0152 } 0153 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::HyperlinkInterface)) { 0154 QStandardItem *item = append(i18n("Hyperlink")); 0155 setFontBold(item); 0156 Q_UNUSED(item); 0157 /* 0158 <property name="NAnchors" type="n" access="read"/> 0159 <property name="StartIndex" type="i" access="read"/> 0160 <property name="EndIndex" type="i" access="read"/> 0161 <method name="GetObject"> 0162 <arg direction="in" name="i" type="i"/> 0163 <arg direction="out" type="(so)"/> 0164 <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QSpiObjectReference"/> 0165 </method> 0166 0<method name="GetURI"> 0167 <arg direction="in" name="i" type="i"/> 0168 <arg direction="out" type="s"/> 0169 </method> 0170 <method name="IsValid"> 0171 <arg direction="out" type="b"/> 0172 </method> 0173 */ 0174 } 0175 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::HypertextInterface)) { 0176 QStandardItem *item = append(i18n("Hypertext")); 0177 setFontBold(item); 0178 Q_UNUSED(item); 0179 /* 0180 <method name="GetNLinks"> 0181 <arg direction="out" type="i"/> 0182 </method> 0183 <method name="GetLink"> 0184 <arg direction="in" name="linkIndex" type="i"/> 0185 <arg direction="out" type="(so)"/> 0186 <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QSpiObjectReference"/> 0187 </method> 0188 <method name="GetLinkIndex"> 0189 <arg direction="in" name="characterIndex" type="i"/> 0190 <arg direction="out" type="i"/> 0191 </method> 0192 */ 0193 } 0194 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::ImageInterface)) { 0195 QStandardItem *item = append(i18n("Image")); 0196 setFontBold(item); 0197 append(i18n("Description"), acc.imageDescription(), item); 0198 append(i18n("Locale"), acc.imageLocale(), item); 0199 append(i18n("Rect"), acc.imageRect(), item); 0200 } 0201 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::SelectionInterface)) { 0202 QStandardItem *item = append(i18n("Selection")); 0203 setFontBold(item); 0204 for (const QAccessibleClient::AccessibleObject &s : acc.selection()) { 0205 append(s.name(), s.role(), item); 0206 } 0207 } 0208 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::TableInterface)) { 0209 QStandardItem *item = append(i18n("Table")); 0210 setFontBold(item); 0211 Q_UNUSED(item); 0212 /* 0213 <property name="NRows" type="i" access="read"/> 0214 <property name="NColumns" type="i" access="read"/> 0215 <property name="Caption" type="(so)" access="read"> 0216 <annotation name="com.trolltech.QtDBus.QtTypeName" value="QSpiObjectReference"/> 0217 </property> 0218 <property name="Summary" type="(so)" access="read"> 0219 <annotation name="com.trolltech.QtDBus.QtTypeName" value="QSpiObjectReference"/> 0220 </property> 0221 <property name="NSelectedRows" type="i" access="read"/> 0222 <property name="NSelectedColumns" type="i" access="read"/> 0223 <method name="GetRowDescription"> 0224 <arg direction="in" name="row" type="i"/> 0225 <arg direction="out" type="s"/> 0226 </method> 0227 <method name="GetColumnDescription"> 0228 <arg direction="in" name="column" type="i"/> 0229 <arg direction="out" type="s"/> 0230 </method> 0231 <method name="GetSelectedRows"> 0232 <arg direction="out" type="ai"/> 0233 <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QSpiIntList"/> 0234 </method> 0235 <method name="GetSelectedColumns"> 0236 <arg direction="out" type="ai"/> 0237 <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QSpiIntList"/> 0238 </method> 0239 */ 0240 } 0241 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::TextInterface)) { 0242 QStandardItem *item = append(i18n("Text")); 0243 setFontBold(item); 0244 int offset = acc.caretOffset(); 0245 append(i18n("Caret Offset"), offset, item); 0246 append(i18n("Character Count"), acc.characterCount(), item); 0247 append(i18n("Character Rect"), acc.characterRect(offset), item); 0248 0249 QString text = acc.text(); 0250 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::EditableTextInterface)) { 0251 append(i18n("Text"), text, item, &mTextItem); 0252 } else { 0253 append(i18n("Text"), text, item); 0254 } 0255 0256 QList<QPair<int, int>> selections = acc.textSelections(); 0257 QStandardItem *selectionsItem = append(i18n("Selections"), selections.count(), item); 0258 for (int i = 0; i < selections.count(); ++i) { 0259 QPair<int, int> sel = selections[i]; 0260 int startOffset = sel.first; 0261 int endOffset = sel.second; 0262 Q_ASSERT(startOffset <= endOffset); 0263 append(QStringLiteral("%1:%2").arg(startOffset).arg(endOffset), text.mid(startOffset, endOffset - startOffset), selectionsItem); 0264 } 0265 } 0266 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::ValueInterface)) { 0267 QStandardItem *item = append(i18n("Value")); 0268 setFontBold(item); 0269 append(i18n("Current"), acc.currentValue(), item, &mValueItem); 0270 append(i18n("Minimum"), acc.minimumValue(), item); 0271 append(i18n("Maximum"), acc.maximumValue(), item); 0272 append(i18n("Increment"), acc.minimumValueIncrement(), item); 0273 } 0274 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::SocketInterface)) { 0275 QStandardItem *item = append(i18n("Socket")); 0276 setFontBold(item); 0277 Q_UNUSED(item); 0278 } 0279 0280 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::EventKeyboardInterface)) { 0281 QStandardItem *item = append(i18n("Event Keyboard")); 0282 setFontBold(item); 0283 Q_UNUSED(item); 0284 } 0285 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::EventMouseInterface)) { 0286 QStandardItem *item = append(i18n("Event Mouse")); 0287 setFontBold(item); 0288 Q_UNUSED(item); 0289 } 0290 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::EventObjectInterface)) { 0291 QStandardItem *item = append(i18n("Event Object")); 0292 setFontBold(item); 0293 Q_UNUSED(item); 0294 } 0295 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::EventWindowInterface)) { 0296 QStandardItem *item = append(i18n("Event Window")); 0297 setFontBold(item); 0298 Q_UNUSED(item); 0299 } 0300 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::EventFocusInterface)) { 0301 QStandardItem *item = append(i18n("Event Focus")); 0302 setFontBold(item); 0303 Q_UNUSED(item); 0304 } 0305 0306 if (interfaces.testFlag(QAccessibleClient::AccessibleObject::ActionInterface)) { 0307 if (!acc.actions().isEmpty()) { 0308 QStandardItem *item = append(i18n("Action")); 0309 setFontBold(item); 0310 for (const QSharedPointer<QAction> &a : acc.actions()) { 0311 const QString shortCut = a->shortcut().toString(); 0312 QString text = a->text(); 0313 qDebug() << " a->shortcut() " << a->shortcut() << " text " << text; 0314 if (!shortCut.isEmpty()) { 0315 text += QStringLiteral(" (%1)").arg(shortCut); 0316 } 0317 auto nameItem = new QStandardItem(text); 0318 auto valueItem = new QStandardItem(a->whatsThis()); 0319 nameItem->setEditable(false); 0320 valueItem->setEditable(false); 0321 item->appendRow(QList<QStandardItem *>() << nameItem << valueItem); 0322 } 0323 } 0324 } 0325 0326 endResetModel(); 0327 } 0328 0329 AccessibleObject ObjectPropertiesModel::currentObject() const 0330 { 0331 return mAccessibleObject; 0332 } 0333 0334 void ObjectPropertiesModel::doubleClicked(const QModelIndex &index) 0335 { 0336 if (!index.isValid() || !index.parent().isValid() || index.parent().data().toString() != i18n("Action")) // FIXME i18n ??? 0337 return; 0338 0339 const auto actions{mAccessibleObject.actions()}; 0340 for (const QSharedPointer<QAction> &action : actions) { 0341 if (action->text() == data(index).toString()) { 0342 action->trigger(); 0343 return; 0344 } 0345 } 0346 } 0347 0348 QStandardItem *ObjectPropertiesModel::append(const QString &name, const QVariant &value, QStandardItem *parentItem, QStandardItem **changeHandler) 0349 { 0350 if (!parentItem) 0351 parentItem = invisibleRootItem(); 0352 auto nameItem = new QStandardItem(name); 0353 QString text; 0354 switch (value.metaType().id()) { 0355 case QMetaType::QPoint: { 0356 const QPoint p = value.toPoint(); 0357 text = QStringLiteral("%1:%2").arg(p.x()).arg(p.y()); 0358 break; 0359 } 0360 case QMetaType::QPointF: { 0361 const QPointF p = value.toPointF(); 0362 text = QStringLiteral("%1:%2").arg(p.x()).arg(p.y()); 0363 break; 0364 } 0365 case QMetaType::QRect: { 0366 const QRect r = value.toRect(); 0367 text = QStringLiteral("%1:%2 %3x%4").arg(r.left()).arg(r.top()).arg(r.width()).arg(r.height()); 0368 break; 0369 } 0370 case QMetaType::QRectF: { 0371 const QRectF r = value.toRectF(); 0372 text = QStringLiteral("%1:%2 %3x%4").arg(r.left()).arg(r.top()).arg(r.width()).arg(r.height()); 0373 break; 0374 } 0375 default: 0376 text = value.toString(); 0377 break; 0378 } 0379 auto valueItem = new QStandardItem(text); 0380 parentItem->appendRow(QList<QStandardItem *>() << nameItem << valueItem); 0381 nameItem->setEditable(false); 0382 0383 if (changeHandler) { 0384 *changeHandler = valueItem; 0385 valueItem->setEditable(true); 0386 } else { 0387 valueItem->setEditable(false); 0388 } 0389 0390 return nameItem; 0391 } 0392 0393 #include "moc_accessiblepropertiesmodel.cpp"