File indexing completed on 2025-01-26 03:28:31

0001 /*
0002     SPDX-FileCopyrightText: 2023 Montel Laurent <montel@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 "mainwidget.h"
0008 #include "accessibletreewidget.h"
0009 #include "accessiblewrapper.h"
0010 #include "eventview.h"
0011 #include "model/accessibleobjecttreemodel.h"
0012 #include "propertytreewidget.h"
0013 #include "uiview.h"
0014 
0015 #include <KLocalizedString>
0016 
0017 #include <QHBoxLayout>
0018 #include <QSplitter>
0019 #include <QTabWidget>
0020 
0021 MainWidget::MainWidget(QAccessibleClient::Registry *registry, QWidget *parent)
0022     : QWidget{parent}
0023     , mSplitter(new QSplitter(this))
0024     , mTabWidget(new QTabWidget(this))
0025     , mAccessibleTreeWidget(new AccessibleTreeWidget(registry, this))
0026     , mPropertyTreeWidget(new PropertyTreeWidget(this))
0027     , mEventsWidget(new EventsWidget(this))
0028     , mUiview(new UiView(this))
0029     , mRegistry(registry)
0030 {
0031     auto mainLayout = new QHBoxLayout(this);
0032     mainLayout->setContentsMargins({});
0033     mainLayout->setObjectName(QLatin1StringView("mainLayout"));
0034 
0035     mSplitter->setObjectName(QLatin1StringView("mSplitter"));
0036     mainLayout->addWidget(mSplitter);
0037 
0038     mAccessibleTreeWidget->setObjectName(QLatin1StringView("mAccessibleTreeWidget"));
0039     mTabWidget->setObjectName(QLatin1StringView("mTabWidget"));
0040     mTabWidget->setMovable(true);
0041     mTabWidget->setDocumentMode(true);
0042 
0043     mSplitter->addWidget(mAccessibleTreeWidget);
0044     mSplitter->addWidget(mTabWidget);
0045 
0046     mPropertyTreeWidget->setObjectName(QLatin1StringView("mPropertyTreeWidget"));
0047     mEventsWidget->setObjectName(QLatin1StringView("mEventsWidget"));
0048     mUiview->setObjectName(QLatin1StringView("mUiview"));
0049 
0050     mTabWidget->addTab(mPropertyTreeWidget, i18nc("@title:window", "Properties"));
0051     mTabWidget->addTab(mEventsWidget, i18nc("@title:window", "Events"));
0052     mTabWidget->addTab(mUiview, i18nc("@title:window", "Boundaries"));
0053 
0054     connect(mEventsWidget, &EventsWidget::anchorClicked, this, &MainWidget::anchorClicked);
0055     connect(mAccessibleTreeWidget, &AccessibleTreeWidget::accessibleTreeviewSelectionChanged, this, &MainWidget::selectionChanged);
0056     connect(mRegistry, &QAccessibleClient::Registry::added, this, &MainWidget::added);
0057     connect(mRegistry, &QAccessibleClient::Registry::removed, this, &MainWidget::removed);
0058     connect(mRegistry, &QAccessibleClient::Registry::defunct, this, &MainWidget::defunct);
0059 
0060     connect(mRegistry, &QAccessibleClient::Registry::windowCreated, this, &MainWidget::windowCreated);
0061     connect(mRegistry, &QAccessibleClient::Registry::windowDestroyed, this, &MainWidget::windowDestroyed);
0062     connect(mRegistry, &QAccessibleClient::Registry::windowClosed, this, &MainWidget::windowClosed);
0063     connect(mRegistry, &QAccessibleClient::Registry::windowReparented, this, &MainWidget::windowReparented);
0064     connect(mRegistry, &QAccessibleClient::Registry::windowMinimized, this, &MainWidget::windowMinimized);
0065     connect(mRegistry, &QAccessibleClient::Registry::windowMaximized, this, &MainWidget::windowMaximized);
0066     connect(mRegistry, &QAccessibleClient::Registry::windowRestored, this, &MainWidget::windowRestored);
0067     connect(mRegistry, &QAccessibleClient::Registry::windowActivated, this, &MainWidget::windowActivated);
0068     connect(mRegistry, &QAccessibleClient::Registry::windowDeactivated, this, &MainWidget::windowDeactivated);
0069     connect(mRegistry, &QAccessibleClient::Registry::windowDesktopCreated, this, &MainWidget::windowDesktopCreated);
0070     connect(mRegistry, &QAccessibleClient::Registry::windowDesktopDestroyed, this, &MainWidget::windowDesktopDestroyed);
0071     connect(mRegistry, &QAccessibleClient::Registry::windowRaised, this, &MainWidget::windowRaised);
0072     connect(mRegistry, &QAccessibleClient::Registry::windowLowered, this, &MainWidget::windowLowered);
0073     connect(mRegistry, &QAccessibleClient::Registry::windowMoved, this, &MainWidget::windowMoved);
0074     connect(mRegistry, &QAccessibleClient::Registry::windowResized, this, &MainWidget::windowResized);
0075     connect(mRegistry, &QAccessibleClient::Registry::windowShaded, this, &MainWidget::windowShaded);
0076     connect(mRegistry, &QAccessibleClient::Registry::windowUnshaded, this, &MainWidget::windowUnshaded);
0077 
0078     connect(mRegistry, &QAccessibleClient::Registry::stateChanged, this, &MainWidget::stateChanged);
0079     connect(mRegistry, &QAccessibleClient::Registry::childAdded, this, &MainWidget::childAdded);
0080     connect(mRegistry, &QAccessibleClient::Registry::childRemoved, this, &MainWidget::childRemoved);
0081     connect(mRegistry, &QAccessibleClient::Registry::visibleDataChanged, this, &MainWidget::visibleDataChanged);
0082     connect(mRegistry, &QAccessibleClient::Registry::selectionChanged, this, &MainWidget::selectionChanged2);
0083     connect(mRegistry, &QAccessibleClient::Registry::modelChanged, this, &MainWidget::modelChanged);
0084 
0085     connect(mRegistry, &QAccessibleClient::Registry::focusChanged, this, &MainWidget::focusChanged);
0086     connect(mRegistry, &QAccessibleClient::Registry::textCaretMoved, this, &MainWidget::textCaretMoved);
0087     connect(mRegistry, &QAccessibleClient::Registry::textSelectionChanged, this, &MainWidget::textSelectionChanged);
0088 
0089     connect(mRegistry, &QAccessibleClient::Registry::textInserted, this, &MainWidget::textInserted);
0090     connect(mRegistry, &QAccessibleClient::Registry::textRemoved, this, &MainWidget::textRemoved);
0091     connect(mRegistry, &QAccessibleClient::Registry::textChanged, this, &MainWidget::textChanged);
0092 
0093     connect(mRegistry, &QAccessibleClient::Registry::accessibleNameChanged, this, &MainWidget::accessibleNameChanged);
0094     connect(mRegistry, &QAccessibleClient::Registry::accessibleDescriptionChanged, this, &MainWidget::accessibleDescriptionChanged);
0095 }
0096 
0097 MainWidget::~MainWidget() = default;
0098 
0099 void MainWidget::saveSettings(QSettings &settings)
0100 {
0101     mEventsWidget->saveSettings(settings);
0102     mAccessibleTreeWidget->saveSettings(settings);
0103     mPropertyTreeWidget->saveSettings(settings);
0104 }
0105 
0106 void MainWidget::loadSettings(QSettings &settings)
0107 {
0108     mEventsWidget->loadSettings(settings);
0109     mAccessibleTreeWidget->loadSettings(settings);
0110     mPropertyTreeWidget->loadSettings(settings);
0111 }
0112 
0113 void MainWidget::copyValue()
0114 {
0115     mPropertyTreeWidget->copyValue();
0116 }
0117 
0118 void MainWidget::resetModel()
0119 {
0120     mAccessibleTreeWidget->accessibleObjectTreeModel()->resetModel();
0121 }
0122 
0123 void MainWidget::updateDetails(const QAccessibleClient::AccessibleObject &object, bool force)
0124 {
0125     mPropertyTreeWidget->updateDetails(object, force);
0126 }
0127 
0128 void MainWidget::anchorClicked(const QUrl &url)
0129 {
0130     const QAccessibleClient::AccessibleObject object = mRegistry->accessibleFromUrl(url);
0131     mAccessibleTreeWidget->setCurrentObject(object);
0132 }
0133 
0134 bool MainWidget::followFocus() const
0135 {
0136     return mFollowFocus;
0137 }
0138 
0139 void MainWidget::setFollowFocus(bool newFollowFocus)
0140 {
0141     mFollowFocus = newFollowFocus;
0142 }
0143 
0144 void MainWidget::stateChanged(const QAccessibleClient::AccessibleObject &object, const QString &state, bool active)
0145 {
0146     if (state == QLatin1String("focused")) {
0147         mEventsWidget->addLog(object, EventsWidget::Focus, (active ? i18n("true") : i18n("false")));
0148     } else {
0149         const QString s = state + QStringLiteral(": ") + (active ? i18n("true") : i18n("false"));
0150         mEventsWidget->addLog(object, EventsWidget::StateChanged, s);
0151     }
0152     updateDetails(object);
0153 }
0154 
0155 void MainWidget::childAdded(const QAccessibleClient::AccessibleObject &object, int childIndex)
0156 {
0157     updateDetails(object);
0158     mEventsWidget->addLog(object, EventsWidget::Object, i18n("Child Added %1", QString::number(childIndex)));
0159 }
0160 
0161 void MainWidget::childRemoved(const QAccessibleClient::AccessibleObject &object, int childIndex)
0162 {
0163     updateDetails(object);
0164     mEventsWidget->addLog(object, EventsWidget::Object, i18n("Child Removed %1", QString::number(childIndex)));
0165 }
0166 
0167 void MainWidget::visibleDataChanged(const QAccessibleClient::AccessibleObject &object)
0168 {
0169     updateDetails(object);
0170     mEventsWidget->addLog(object, EventsWidget::Object, i18n("Visible Data Changed"));
0171 }
0172 
0173 void MainWidget::selectionChanged2(const QAccessibleClient::AccessibleObject &object)
0174 {
0175     updateDetails(object);
0176     mEventsWidget->addLog(object, EventsWidget::Table, i18n("Selection Changed"));
0177 }
0178 
0179 void MainWidget::modelChanged(const QAccessibleClient::AccessibleObject &object)
0180 {
0181     updateDetails(object);
0182     mEventsWidget->addLog(object, EventsWidget::Table, i18n("Model Changed"));
0183 }
0184 
0185 void MainWidget::selectionChanged(const QModelIndex &current)
0186 {
0187     QAccessibleClient::AccessibleObject acc;
0188     if (current.isValid() && current.internalPointer()) {
0189         acc = static_cast<AccessibleWrapper *>(current.internalPointer())->acc;
0190     }
0191     mUiview->setAccessibleObject(acc);
0192     updateDetails(acc, true);
0193 }
0194 
0195 void MainWidget::added(const QAccessibleClient::AccessibleObject &object)
0196 {
0197     mEventsWidget->addLog(object, EventsWidget::Object, i18n("Add Object"));
0198     mAccessibleTreeWidget->accessibleObjectTreeModel()->addAccessible(object);
0199 }
0200 
0201 void MainWidget::removed(const QAccessibleClient::AccessibleObject &object)
0202 {
0203     mEventsWidget->addLog(object, EventsWidget::Object, i18n("Remove Object"));
0204     mAccessibleTreeWidget->accessibleObjectTreeModel()->removeAccessible(object);
0205 }
0206 
0207 void MainWidget::defunct(const QAccessibleClient::AccessibleObject &object)
0208 {
0209     removed(object);
0210 }
0211 
0212 void MainWidget::windowCreated(const QAccessibleClient::AccessibleObject &object)
0213 {
0214     mEventsWidget->addLog(object, EventsWidget::Window, i18n("Create"));
0215     mAccessibleTreeWidget->accessibleObjectTreeModel()->addAccessible(object);
0216 }
0217 
0218 void MainWidget::windowDestroyed(const QAccessibleClient::AccessibleObject &object)
0219 {
0220     mEventsWidget->addLog(object, EventsWidget::Window, i18n("Destroy"));
0221     if (!mAccessibleTreeWidget->accessibleObjectTreeModel()->removeAccessible(object)) {
0222         // assume the app has gone
0223         mAccessibleTreeWidget->accessibleObjectTreeModel()->updateTopLevelApps();
0224     }
0225 }
0226 
0227 void MainWidget::windowClosed(const QAccessibleClient::AccessibleObject &object)
0228 {
0229     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowClose"));
0230 }
0231 
0232 void MainWidget::windowReparented(const QAccessibleClient::AccessibleObject &object)
0233 {
0234     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowReparent"));
0235 }
0236 
0237 void MainWidget::windowMinimized(const QAccessibleClient::AccessibleObject &object)
0238 {
0239     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowMinimize"));
0240 }
0241 
0242 void MainWidget::windowMaximized(const QAccessibleClient::AccessibleObject &object)
0243 {
0244     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowMaximize"));
0245 }
0246 
0247 void MainWidget::windowRestored(const QAccessibleClient::AccessibleObject &object)
0248 {
0249     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowRestore"));
0250 }
0251 
0252 void MainWidget::windowActivated(const QAccessibleClient::AccessibleObject &object)
0253 {
0254     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowActivate"));
0255 }
0256 
0257 void MainWidget::windowDeactivated(const QAccessibleClient::AccessibleObject &object)
0258 {
0259     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowDeactivate"));
0260 }
0261 
0262 void MainWidget::windowDesktopCreated(const QAccessibleClient::AccessibleObject &object)
0263 {
0264     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowDesktopCreate"));
0265 }
0266 
0267 void MainWidget::windowDesktopDestroyed(const QAccessibleClient::AccessibleObject &object)
0268 {
0269     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowDesktopDestroy"));
0270 }
0271 
0272 void MainWidget::windowRaised(const QAccessibleClient::AccessibleObject &object)
0273 {
0274     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowRaise"));
0275 }
0276 
0277 void MainWidget::windowLowered(const QAccessibleClient::AccessibleObject &object)
0278 {
0279     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowLower"));
0280 }
0281 
0282 void MainWidget::windowMoved(const QAccessibleClient::AccessibleObject &object)
0283 {
0284     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowMove"));
0285 }
0286 
0287 void MainWidget::windowResized(const QAccessibleClient::AccessibleObject &object)
0288 {
0289     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowResize"));
0290 }
0291 
0292 void MainWidget::windowShaded(const QAccessibleClient::AccessibleObject &object)
0293 {
0294     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowShade"));
0295 }
0296 
0297 void MainWidget::windowUnshaded(const QAccessibleClient::AccessibleObject &object)
0298 {
0299     mEventsWidget->addLog(object, EventsWidget::Window, QStringLiteral("WindowUnshade"));
0300 }
0301 
0302 void MainWidget::focusChanged(const QAccessibleClient::AccessibleObject &object)
0303 {
0304     if (mFollowFocus) {
0305         // We need to block the focus for the treeView while setting the current item
0306         // to prevent that setting that item would change focus to the treeView.
0307         Qt::FocusPolicy prevFocusPolicy = mAccessibleTreeWidget->focusPolicy();
0308         mAccessibleTreeWidget->setFocusPolicy(Qt::NoFocus);
0309 
0310         mAccessibleTreeWidget->setCurrentObject(object);
0311 
0312         mAccessibleTreeWidget->setFocusPolicy(prevFocusPolicy);
0313     } else {
0314         updateDetails(object);
0315     }
0316 }
0317 
0318 void MainWidget::textCaretMoved(const QAccessibleClient::AccessibleObject &object, int pos)
0319 {
0320     updateDetails(object);
0321     mEventsWidget->addLog(object, EventsWidget::Text, i18n("Text caret moved (%1)", pos));
0322 }
0323 
0324 void MainWidget::textSelectionChanged(const QAccessibleClient::AccessibleObject &object)
0325 {
0326     updateDetails(object);
0327     mEventsWidget->addLog(object, EventsWidget::Text, QStringLiteral("TextSelectionChanged"));
0328 }
0329 
0330 QString descriptionForText(const QString &type, const QString &text, int startOffset, int endOffset)
0331 {
0332     QString shortText = text;
0333     if (shortText.length() > 50) {
0334         shortText.truncate(50);
0335         shortText.append(QLatin1String("..."));
0336     }
0337     const QString desc = QStringLiteral("Text %1 (%2, %3): \"%4\"").arg(type).arg(QString::number(startOffset)).arg(QString::number(endOffset)).arg(shortText);
0338     return desc;
0339 }
0340 
0341 void MainWidget::textChanged(const QAccessibleClient::AccessibleObject &object, const QString &text, int startOffset, int endOffset)
0342 {
0343     updateDetails(object);
0344     mEventsWidget->addLog(object, EventsWidget::Text, descriptionForText(QLatin1String("changed"), text, startOffset, endOffset));
0345 }
0346 
0347 void MainWidget::textInserted(const QAccessibleClient::AccessibleObject &object, const QString &text, int startOffset, int endOffset)
0348 {
0349     updateDetails(object);
0350     mEventsWidget->addLog(object, EventsWidget::Text, descriptionForText(QLatin1String("inserted"), text, startOffset, endOffset));
0351 }
0352 
0353 void MainWidget::textRemoved(const QAccessibleClient::AccessibleObject &object, const QString &text, int startOffset, int endOffset)
0354 {
0355     updateDetails(object);
0356     mEventsWidget->addLog(object, EventsWidget::Text, descriptionForText(QLatin1String("removed"), text, startOffset, endOffset));
0357 }
0358 
0359 void MainWidget::accessibleNameChanged(const QAccessibleClient::AccessibleObject &object)
0360 {
0361     updateDetails(object);
0362     mEventsWidget->addLog(object, EventsWidget::NameChanged);
0363     mAccessibleTreeWidget->accessibleObjectTreeModel()->updateAccessible(object);
0364 }
0365 
0366 void MainWidget::accessibleDescriptionChanged(const QAccessibleClient::AccessibleObject &object)
0367 {
0368     updateDetails(object);
0369     mEventsWidget->addLog(object, EventsWidget::DescriptionChanged);
0370     mAccessibleTreeWidget->accessibleObjectTreeModel()->updateAccessible(object);
0371 }
0372 
0373 #include "moc_mainwidget.cpp"