1 /*
2     Copyright 2012 Frederik Gladhorn <gladhorn@kde.org>
3 
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Lesser General Public
6     License as published by the Free Software Foundation; either
7     version 2.1 of the License, or (at your option) version 3, or any
8     later version accepted by the membership of KDE e.V. (or its
9     successor approved by the membership of KDE e.V.), which shall
10     act as a proxy defined in Section 6 of version 3 of the license.
11 
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Lesser General Public License for more details.
16 
17     You should have received a copy of the GNU Lesser General Public
18     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "mainwindow.h"
22 
23 #include <qdialog.h>
24 #include <qdockwidget.h>
25 #include <qmenubar.h>
26 #include <qpointer.h>
27 #include <qsettings.h>
28 #include <qurl.h>
29 #include <QClipboard>
30 
31 #include "qaccessibilityclient/registry.h"
32 #include "qaccessibilityclient/registrycache_p.h"
33 #include "qaccessibilityclient/accessibleobject.h"
34 
35 #include "accessibleproperties.h"
36 #include "accessibletree.h"
37 #include "eventview.h"
38 #include "uiview.h"
39 
40 using namespace QAccessibleClient;
41 
MainWindow(QWidget * parent)42 MainWindow::MainWindow(QWidget *parent)
43     : QMainWindow(parent)
44 {
45     setWindowTitle(QLatin1String("Randamizer"));
46     m_registry = new QAccessibleClient::Registry(this);
47 
48     initUi();
49     initActions();
50     initMenu();
51 
52     QSettings settings("kde.org", "kdea11yapp");
53     QAccessibleClient::RegistryPrivateCacheApi cache(m_registry);
54     cache.setCacheType(QAccessibleClient::RegistryPrivateCacheApi::CacheType(settings.value("cacheStrategy", cache.cacheType()).toInt()));
55     restoreGeometry(settings.value("geometry").toByteArray());
56     restoreState(settings.value("windowState").toByteArray());
57 
58     m_eventsWidget->loadSettings(settings);
59 
60     connect(m_registry, SIGNAL(added(QAccessibleClient::AccessibleObject)), this, SLOT(added(QAccessibleClient::AccessibleObject)));
61     connect(m_registry, SIGNAL(removed(QAccessibleClient::AccessibleObject)), this, SLOT(removed(QAccessibleClient::AccessibleObject)));
62     connect(m_registry, SIGNAL(defunct(QAccessibleClient::AccessibleObject)), this, SLOT(defunct(QAccessibleClient::AccessibleObject)));
63 
64     connect(m_registry, SIGNAL(windowCreated(QAccessibleClient::AccessibleObject)), this, SLOT(windowCreated(QAccessibleClient::AccessibleObject)));
65     connect(m_registry, SIGNAL(windowDestroyed(QAccessibleClient::AccessibleObject)), this, SLOT(windowDestroyed(QAccessibleClient::AccessibleObject)));
66     connect(m_registry, SIGNAL(windowClosed(QAccessibleClient::AccessibleObject)), this, SLOT(windowClosed(QAccessibleClient::AccessibleObject)));
67     connect(m_registry, SIGNAL(windowReparented(QAccessibleClient::AccessibleObject)), this, SLOT(windowReparented(QAccessibleClient::AccessibleObject)));
68     connect(m_registry, SIGNAL(windowMinimized(QAccessibleClient::AccessibleObject)), this, SLOT(windowMinimized(QAccessibleClient::AccessibleObject)));
69     connect(m_registry, SIGNAL(windowMaximized(QAccessibleClient::AccessibleObject)), this, SLOT(windowMaximized(QAccessibleClient::AccessibleObject)));
70     connect(m_registry, SIGNAL(windowRestored(QAccessibleClient::AccessibleObject)), this, SLOT(windowRestored(QAccessibleClient::AccessibleObject)));
71     connect(m_registry, SIGNAL(windowActivated(QAccessibleClient::AccessibleObject)), this, SLOT(windowActivated(QAccessibleClient::AccessibleObject)));
72     connect(m_registry, SIGNAL(windowDeactivated(QAccessibleClient::AccessibleObject)), this, SLOT(windowDeactivated(QAccessibleClient::AccessibleObject)));
73     connect(m_registry, SIGNAL(windowDesktopCreated(QAccessibleClient::AccessibleObject)), this, SLOT(windowDesktopCreated(QAccessibleClient::AccessibleObject)));
74     connect(m_registry, SIGNAL(windowDesktopDestroyed(QAccessibleClient::AccessibleObject)), this, SLOT(windowDesktopDestroyed(QAccessibleClient::AccessibleObject)));
75     connect(m_registry, SIGNAL(windowRaised(QAccessibleClient::AccessibleObject)), this, SLOT(windowRaised(QAccessibleClient::AccessibleObject)));
76     connect(m_registry, SIGNAL(windowLowered(QAccessibleClient::AccessibleObject)), this, SLOT(windowLowered(QAccessibleClient::AccessibleObject)));
77     connect(m_registry, SIGNAL(windowMoved(QAccessibleClient::AccessibleObject)), this, SLOT(windowMoved(QAccessibleClient::AccessibleObject)));
78     connect(m_registry, SIGNAL(windowResized(QAccessibleClient::AccessibleObject)), this, SLOT(windowResized(QAccessibleClient::AccessibleObject)));
79     connect(m_registry, SIGNAL(windowShaded(QAccessibleClient::AccessibleObject)), this, SLOT(windowShaded(QAccessibleClient::AccessibleObject)));
80     connect(m_registry, SIGNAL(windowUnshaded(QAccessibleClient::AccessibleObject)), this, SLOT(windowUnshaded(QAccessibleClient::AccessibleObject)));
81 
82     connect(m_registry, SIGNAL(stateChanged(QAccessibleClient::AccessibleObject,QString,bool)), this, SLOT(stateChanged(QAccessibleClient::AccessibleObject,QString,bool)));
83     connect(m_registry, SIGNAL(childAdded(QAccessibleClient::AccessibleObject,int)), this, SLOT(childAdded(QAccessibleClient::AccessibleObject,int)));
84     connect(m_registry, SIGNAL(childRemoved(QAccessibleClient::AccessibleObject,int)), this, SLOT(childRemoved(QAccessibleClient::AccessibleObject,int)));
85     connect(m_registry, SIGNAL(visibleDataChanged(QAccessibleClient::AccessibleObject)), this, SLOT(visibleDataChanged(QAccessibleClient::AccessibleObject)));
86     connect(m_registry, SIGNAL(selectionChanged(QAccessibleClient::AccessibleObject)), this, SLOT(selectionChanged(QAccessibleClient::AccessibleObject)));
87     connect(m_registry, SIGNAL(modelChanged(QAccessibleClient::AccessibleObject)), this, SLOT(modelChanged(QAccessibleClient::AccessibleObject)));
88 
89     connect(m_registry, SIGNAL(focusChanged(QAccessibleClient::AccessibleObject)), this, SLOT(focusChanged(QAccessibleClient::AccessibleObject)));
90     connect(m_registry, SIGNAL(textCaretMoved(QAccessibleClient::AccessibleObject,int)), this, SLOT(textCaretMoved(QAccessibleClient::AccessibleObject,int)));
91     connect(m_registry, SIGNAL(textSelectionChanged(QAccessibleClient::AccessibleObject)), this, SLOT(textSelectionChanged(QAccessibleClient::AccessibleObject)));
92 
93     connect(m_registry, SIGNAL(textInserted(QAccessibleClient::AccessibleObject,QString,int,int)), this, SLOT(textInserted(QAccessibleClient::AccessibleObject,QString,int,int)));
94     connect(m_registry, SIGNAL(textRemoved(QAccessibleClient::AccessibleObject,QString,int,int)), this, SLOT(textRemoved(QAccessibleClient::AccessibleObject,QString,int,int)));
95     connect(m_registry, SIGNAL(textChanged(QAccessibleClient::AccessibleObject,QString,int,int)), this, SLOT(textChanged(QAccessibleClient::AccessibleObject,QString,int,int)));
96 
97     connect(m_registry, SIGNAL(accessibleNameChanged(QAccessibleClient::AccessibleObject)), this, SLOT(accessibleNameChanged(QAccessibleClient::AccessibleObject)));
98     connect(m_registry, SIGNAL(accessibleDescriptionChanged(QAccessibleClient::AccessibleObject)), this, SLOT(accessibleDescriptionChanged(QAccessibleClient::AccessibleObject)));
99 
100     m_registry->subscribeEventListeners(QAccessibleClient::Registry::AllEventListeners);
101 }
102 
~MainWindow()103 MainWindow::~MainWindow()
104 {
105     delete m_registry;
106 }
107 
closeEvent(QCloseEvent * event)108 void MainWindow::MainWindow::closeEvent(QCloseEvent *event)
109 {
110     QSettings settings("kde.org", "kdea11yapp");
111     settings.setValue("cacheStrategy", int(QAccessibleClient::RegistryPrivateCacheApi(m_registry).cacheType()));
112     settings.setValue("geometry", saveGeometry());
113     settings.setValue("windowState", saveState());
114 
115     m_eventsWidget->saveSettings(settings);
116 
117     settings.sync();
118 
119     QMainWindow::closeEvent(event);
120 }
121 
initActions()122 void MainWindow::MainWindow::initActions()
123 {
124     m_resetTreeAction = new QAction(this);
125     m_resetTreeAction->setText(QString("Reset Tree"));
126     m_resetTreeAction->setShortcut(QKeySequence(QKeySequence::Refresh));
127     connect(m_resetTreeAction, SIGNAL(triggered()), m_accessibleObjectTreeModel, SLOT(resetModel()));
128 
129     m_followFocusAction = new QAction(this);
130     m_followFocusAction->setText(QString("Follow Focus"));
131     m_followFocusAction->setCheckable(true);
132     m_followFocusAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_F));
133 
134     m_showClientCacheAction = new QAction(this);
135     m_showClientCacheAction->setText(QString("Cache..."));
136     connect(m_showClientCacheAction, SIGNAL(triggered()), this, SLOT(showClientCache()));
137 
138     m_enableA11yAction = new QAction(this);
139     m_enableA11yAction->setText(QString("Enable Accessibility"));
140     m_enableA11yAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E));
141     m_enableA11yAction->setCheckable(true);
142     m_enableA11yAction->setChecked(m_registry->isEnabled());
143     connect(m_registry, SIGNAL(enabledChanged(bool)), m_enableA11yAction, SLOT(setChecked(bool)));
144     connect(m_enableA11yAction, SIGNAL(toggled(bool)), m_registry, SLOT(setEnabled(bool)));
145 
146     m_enableScreenReaderAction = new QAction(this);
147     m_enableScreenReaderAction->setText(QString("Enable Screen Reader"));
148     m_enableScreenReaderAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
149     m_enableScreenReaderAction->setCheckable(true);
150     m_enableScreenReaderAction->setChecked(m_registry->isScreenReaderEnabled());
151     connect(m_registry, SIGNAL(screenReaderEnabledChanged(bool)), m_enableScreenReaderAction, SLOT(setChecked(bool)));
152     connect(m_enableScreenReaderAction, SIGNAL(toggled(bool)), m_registry, SLOT(setScreenReaderEnabled(bool)));
153 
154     m_quitAction = new QAction(tr("&Quit"), this);
155     m_quitAction->setShortcuts(QKeySequence::Quit);
156     connect(m_quitAction, SIGNAL(triggered()), this, SLOT(close()));
157 
158     m_copyValueAction = new QAction(tr("&Copy property value"), this);
159     m_copyValueAction->setShortcuts(QKeySequence::Copy);
160     connect(m_copyValueAction, SIGNAL(triggered()), this, SLOT(copyValue()));
161 }
162 
copyValue()163 void MainWindow::copyValue()
164 {
165     QModelIndex selected = m_propertyView->currentIndex();
166 
167     if (!selected.isValid())
168         return;
169 
170     if (selected.column() == 0) {
171         selected = m_propertyView->model()->index(selected.row(), 1, selected.parent());
172         if (!selected.isValid())
173             return;
174     }
175 
176     QGuiApplication::clipboard()->setText(selected.data(Qt::DisplayRole).toString());
177 }
178 
initMenu()179 void MainWindow::MainWindow::initMenu()
180 {
181     QMenu *fileMenu = menuBar()->addMenu(QString("&Tree"));
182     fileMenu->addAction(m_resetTreeAction);
183     fileMenu->addAction(m_followFocusAction);
184     fileMenu->addSeparator();
185     fileMenu->addAction(m_quitAction);
186 
187     QMenu *editMenu = menuBar()->addMenu(QString("&Edit"));
188     editMenu->addAction(m_copyValueAction);
189 
190     QMenu *settingsMenu = menuBar()->addMenu(QString("&Settings"));
191     QMenu *dockerMenu = settingsMenu->addMenu(QString("Docker"));
192     Q_FOREACH(const QDockWidget *docker, findChildren<QDockWidget*>()) {
193         dockerMenu->addAction(docker->toggleViewAction());
194     }
195     settingsMenu->addAction(m_showClientCacheAction);
196     settingsMenu->addSeparator();
197     settingsMenu->addAction(m_enableA11yAction);
198     settingsMenu->addAction(m_enableScreenReaderAction);
199 }
200 
initUi()201 void MainWindow::MainWindow::initUi()
202 {
203     setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks);
204     //setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
205 
206     QDockWidget *treeDocker = new QDockWidget(QString("Tree"), this);
207     treeDocker->setObjectName("tree");
208     treeDocker->setFeatures(QDockWidget::AllDockWidgetFeatures);
209     m_accessibleObjectTreeView = new QTreeView(treeDocker);
210     m_accessibleObjectTreeView->setAccessibleName(QString("Tree of accessibles"));
211     m_accessibleObjectTreeView->setAccessibleDescription(QString("Displays a hierachical tree of accessible objects"));
212     m_accessibleObjectTreeView->setSelectionBehavior(QAbstractItemView::SelectRows);
213     m_accessibleObjectTreeView->setEditTriggers(QAbstractItemView::NoEditTriggers);
214     m_accessibleObjectTreeView->setAlternatingRowColors(true);
215     treeDocker->setWidget(m_accessibleObjectTreeView);
216 
217     m_accessibleObjectTreeModel = new AccessibleTree(this);
218     m_accessibleObjectTreeModel->setRegistry(m_registry);
219     m_accessibleObjectTreeView->setModel(m_accessibleObjectTreeModel);
220     m_accessibleObjectTreeView->setColumnWidth(0, 240);
221     m_accessibleObjectTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
222     connect(m_accessibleObjectTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(selectionChanged(QModelIndex,QModelIndex)));
223     connect(m_accessibleObjectTreeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(treeCustomContextMenuRequested(QPoint)));
224 
225     QDockWidget *propertyDocker = new QDockWidget(QString("&Properties"), this);
226     propertyDocker->setObjectName("properties");
227     propertyDocker->setFeatures(QDockWidget::AllDockWidgetFeatures);
228     m_propertyView = new QTreeView(propertyDocker);
229     propertyDocker->setWidget(m_propertyView);
230     m_propertyView->setAccessibleName(QString("List of properties"));
231     m_propertyView->setAccessibleDescription(QString("Displays a the properties of the selected accessible object"));
232     m_propertyView->setRootIsDecorated(false);
233     m_propertyView->setItemsExpandable(true);
234     m_propertyView->setExpandsOnDoubleClick(false);
235     m_propertyView->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::AnyKeyPressed | QAbstractItemView::EditKeyPressed);
236     m_propertyModel = new ObjectProperties(this);
237     m_propertyView->setModel(m_propertyModel);
238     m_propertyView->setAlternatingRowColors(true);
239     connect(m_propertyView, SIGNAL(doubleClicked(QModelIndex)), m_propertyModel, SLOT(doubleClicked(QModelIndex)));
240 
241     QDockWidget *uiDocker = new QDockWidget(QString("&Boundaries"), this);
242     uiDocker->setObjectName("boundaries");
243     uiDocker->setFeatures(QDockWidget::AllDockWidgetFeatures);
244     m_uiview = new UiView(uiDocker);
245     m_uiview->setAccessibleName(QLatin1String("Boundaries"));
246     m_uiview->setAccessibleDescription(QString("Visualize the component boundaries"));
247     uiDocker->setWidget(m_uiview);
248 
249     QDockWidget *eventsDocker = new QDockWidget(QString("E&vents"), this);
250     eventsDocker->setObjectName("events");
251     eventsDocker->setFeatures(QDockWidget::AllDockWidgetFeatures);
252     m_eventsWidget = new EventsWidget(m_registry, eventsDocker);
253     connect(m_eventsWidget, SIGNAL(anchorClicked(QUrl)), this, SLOT(anchorClicked(QUrl)));
254     eventsDocker->setWidget(m_eventsWidget);
255 
256     addDockWidget(Qt::LeftDockWidgetArea, treeDocker);
257     addDockWidget(Qt::RightDockWidgetArea, propertyDocker);
258     addDockWidget(Qt::RightDockWidgetArea, uiDocker);
259     addDockWidget(Qt::RightDockWidgetArea, eventsDocker);
260     tabifyDockWidget(uiDocker, eventsDocker);
261     tabifyDockWidget(uiDocker, propertyDocker);
262 
263     resize(minimumSize().expandedTo(QSize(760,520)));
264 }
265 
anchorClicked(const QUrl & url)266 void MainWindow::anchorClicked(const QUrl &url)
267 {
268     AccessibleObject object = m_registry->accessibleFromUrl(url);
269     setCurrentObject(object);
270 }
271 
showClientCache()272 void MainWindow::showClientCache()
273 {
274     QPointer<ClientCacheDialog> dlg(new ClientCacheDialog(m_registry, this));
275     dlg->setWindowTitle(m_showClientCacheAction->text());
276     if (dlg->exec() == QDialog::Accepted && dlg) {
277     }
278     if (dlg)
279         dlg->deleteLater();
280 }
281 
setCurrentObject(const QAccessibleClient::AccessibleObject & object)282 void MainWindow::setCurrentObject(const QAccessibleClient::AccessibleObject &object)
283 {
284     QModelIndex index = m_accessibleObjectTreeModel->indexForAccessible(object);
285     if (index.isValid()) {
286         QModelIndex other = m_accessibleObjectTreeModel->index(index.row(), index.column()+1, index.parent());
287         Q_ASSERT(other.isValid());
288         m_accessibleObjectTreeView->selectionModel()->select(QItemSelection(index, other), QItemSelectionModel::SelectCurrent);
289         m_accessibleObjectTreeView->scrollTo(index);
290 
291         // Unlike calling setCurrentIndex the select call aboves doe not emit the selectionChanged signal. So, do explicit.
292         selectionChanged(index, QModelIndex());
293     } else {
294         qWarning() << "No such indexForAccessible=" << object;
295     }
296 }
297 
updateDetails(const AccessibleObject & object,bool force)298 void MainWindow::updateDetails(const AccessibleObject &object, bool force)
299 {
300     if (!force && object != m_propertyModel->currentObject())
301         return;
302 
303     m_propertyModel->setAccessibleObject(object);
304     for(int r = m_propertyModel->rowCount() - 1; r >= 0; --r)
305         m_propertyView->setExpanded(m_propertyModel->indexFromItem(m_propertyModel->item(r, 0)), true);
306     m_propertyView->resizeColumnToContents(0);
307 }
308 
stateChanged(const QAccessibleClient::AccessibleObject & object,const QString & state,bool active)309 void MainWindow::stateChanged(const QAccessibleClient::AccessibleObject &object, const QString &state, bool active)
310 {
311     if (state == QLatin1String("focused")) {
312         m_eventsWidget->addLog(object, EventsWidget::Focus, (active ? QString("true") : QString("false")));
313     } else {
314         QString s = state + QString(": ") + (active ? QString("true") : QString("false"));
315         m_eventsWidget->addLog(object, EventsWidget::StateChanged, s);
316     }
317     updateDetails(object);
318 }
319 
childAdded(const QAccessibleClient::AccessibleObject & object,int childIndex)320 void MainWindow::childAdded(const QAccessibleClient::AccessibleObject &object, int childIndex)
321 {
322     updateDetails(object);
323     m_eventsWidget->addLog(object, EventsWidget::Object, QLatin1String("ChildAdded ") + QString::number(childIndex));
324 }
325 
childRemoved(const QAccessibleClient::AccessibleObject & object,int childIndex)326 void MainWindow::childRemoved(const QAccessibleClient::AccessibleObject &object, int childIndex)
327 {
328     updateDetails(object);
329     m_eventsWidget->addLog(object, EventsWidget::Object, QLatin1String("ChildRemoved ") + QString::number(childIndex));
330 }
331 
visibleDataChanged(const QAccessibleClient::AccessibleObject & object)332 void MainWindow::visibleDataChanged(const QAccessibleClient::AccessibleObject &object)
333 {
334     updateDetails(object);
335     m_eventsWidget->addLog(object, EventsWidget::Object, "VisibleDataChanged");
336 }
337 
selectionChanged(const QAccessibleClient::AccessibleObject & object)338 void MainWindow::selectionChanged(const QAccessibleClient::AccessibleObject &object)
339 {
340     updateDetails(object);
341     m_eventsWidget->addLog(object, EventsWidget::Table, "SelectionChanged");
342 }
343 
modelChanged(const QAccessibleClient::AccessibleObject & object)344 void MainWindow::modelChanged(const QAccessibleClient::AccessibleObject &object)
345 {
346     updateDetails(object);
347     m_eventsWidget->addLog(object, EventsWidget::Table, "ModelChanged");
348 }
349 
selectionChanged(const QModelIndex & current,const QModelIndex &)350 void MainWindow::selectionChanged(const QModelIndex& current, const QModelIndex&)
351 {
352     QAccessibleClient::AccessibleObject acc;
353     if (current.isValid() && current.internalPointer()) {
354         acc = static_cast<AccessibleWrapper*>(current.internalPointer())->acc;
355     }
356     m_uiview->setAccessibleObject(acc);
357     updateDetails(acc, true);
358 }
359 
treeCustomContextMenuRequested(const QPoint & pos)360 void MainWindow::treeCustomContextMenuRequested(const QPoint &pos)
361 {
362     QModelIndex current = m_accessibleObjectTreeView->currentIndex();
363     if (!current.isValid())
364         return;
365     QAccessibleClient::AccessibleObject acc = static_cast<AccessibleWrapper*>(current.internalPointer())->acc;
366     QMenu *menu = new QMenu(this);
367     connect(menu, SIGNAL(aboutToHide()), menu, SLOT(deleteLater()));
368     Q_FOREACH(const QSharedPointer<QAction> &a, acc.actions()) {
369         menu->addAction(a.data());
370     }
371     menu->popup(m_accessibleObjectTreeView->mapToGlobal(pos));
372 }
373 
added(const QAccessibleClient::AccessibleObject & object)374 void MainWindow::added(const QAccessibleClient::AccessibleObject &object)
375 {
376     m_eventsWidget->addLog(object, EventsWidget::Object, QString("Add Object"));
377     m_accessibleObjectTreeModel->addAccessible(object);
378 }
379 
removed(const QAccessibleClient::AccessibleObject & object)380 void MainWindow::removed(const QAccessibleClient::AccessibleObject &object)
381 {
382     m_eventsWidget->addLog(object, EventsWidget::Object, "RemoveObject");
383     m_accessibleObjectTreeModel->removeAccessible(object);
384 }
385 
defunct(const QAccessibleClient::AccessibleObject & object)386 void MainWindow::defunct(const QAccessibleClient::AccessibleObject &object)
387 {
388     removed(object);
389 }
390 
windowCreated(const QAccessibleClient::AccessibleObject & object)391 void MainWindow::windowCreated(const QAccessibleClient::AccessibleObject &object)
392 {
393     m_eventsWidget->addLog(object, EventsWidget::Window, "Create");
394     m_accessibleObjectTreeModel->addAccessible(object);
395 }
396 
windowDestroyed(const QAccessibleClient::AccessibleObject & object)397 void MainWindow::windowDestroyed(const QAccessibleClient::AccessibleObject &object)
398 {
399     m_eventsWidget->addLog(object, EventsWidget::Window, QString("Destroy"));
400     if (!m_accessibleObjectTreeModel->removeAccessible(object)) {
401         // assume the app has gone
402         m_accessibleObjectTreeModel->updateTopLevelApps();
403     }
404 }
405 
windowClosed(const QAccessibleClient::AccessibleObject & object)406 void MainWindow::windowClosed(const QAccessibleClient::AccessibleObject &object)
407 {
408     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowClose"));
409 }
410 
windowReparented(const QAccessibleClient::AccessibleObject & object)411 void MainWindow::windowReparented(const QAccessibleClient::AccessibleObject &object)
412 {
413     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowReparent"));
414 }
415 
windowMinimized(const QAccessibleClient::AccessibleObject & object)416 void MainWindow::windowMinimized(const QAccessibleClient::AccessibleObject &object)
417 {
418     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowMinimize"));
419 }
420 
windowMaximized(const QAccessibleClient::AccessibleObject & object)421 void MainWindow::windowMaximized(const QAccessibleClient::AccessibleObject &object)
422 {
423     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowMaximize"));
424 }
425 
windowRestored(const QAccessibleClient::AccessibleObject & object)426 void MainWindow::windowRestored(const QAccessibleClient::AccessibleObject &object)
427 {
428     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowRestore"));
429 }
430 
windowActivated(const QAccessibleClient::AccessibleObject & object)431 void MainWindow::windowActivated(const QAccessibleClient::AccessibleObject &object)
432 {
433     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowActivate"));
434 }
435 
windowDeactivated(const QAccessibleClient::AccessibleObject & object)436 void MainWindow::windowDeactivated(const QAccessibleClient::AccessibleObject &object)
437 {
438     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowDeactivate"));
439 }
440 
windowDesktopCreated(const QAccessibleClient::AccessibleObject & object)441 void MainWindow::windowDesktopCreated(const QAccessibleClient::AccessibleObject &object)
442 {
443     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowDesktopCreate"));
444 }
445 
windowDesktopDestroyed(const QAccessibleClient::AccessibleObject & object)446 void MainWindow::windowDesktopDestroyed(const QAccessibleClient::AccessibleObject &object)
447 {
448     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowDesktopDestroy"));
449 }
450 
windowRaised(const QAccessibleClient::AccessibleObject & object)451 void MainWindow::windowRaised(const QAccessibleClient::AccessibleObject &object)
452 {
453     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowRaise"));
454 }
455 
windowLowered(const QAccessibleClient::AccessibleObject & object)456 void MainWindow::windowLowered(const QAccessibleClient::AccessibleObject &object)
457 {
458     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowLower"));
459 }
460 
windowMoved(const QAccessibleClient::AccessibleObject & object)461 void MainWindow::windowMoved(const QAccessibleClient::AccessibleObject &object)
462 {
463     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowMove"));
464 }
465 
windowResized(const QAccessibleClient::AccessibleObject & object)466 void MainWindow::windowResized(const QAccessibleClient::AccessibleObject &object)
467 {
468     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowResize"));
469 }
470 
windowShaded(const QAccessibleClient::AccessibleObject & object)471 void MainWindow::windowShaded(const QAccessibleClient::AccessibleObject &object)
472 {
473     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowShade"));
474 }
475 
windowUnshaded(const QAccessibleClient::AccessibleObject & object)476 void MainWindow::windowUnshaded(const QAccessibleClient::AccessibleObject &object)
477 {
478     m_eventsWidget->addLog(object, EventsWidget::Window, QString("WindowUnshade"));
479 }
480 
focusChanged(const QAccessibleClient::AccessibleObject & object)481 void MainWindow::focusChanged(const QAccessibleClient::AccessibleObject &object)
482 {
483     if (m_followFocusAction->isChecked()) {
484         // We need to block the focus for the treeView while setting the current item
485         // to prevent that setting that item would change focus to the treeView.
486         Qt::FocusPolicy prevFocusPolicy = m_accessibleObjectTreeView->focusPolicy();
487         m_accessibleObjectTreeView->setFocusPolicy(Qt::NoFocus);
488 
489         setCurrentObject(object);
490 
491         m_accessibleObjectTreeView->setFocusPolicy(prevFocusPolicy);
492     } else {
493         updateDetails(object);
494     }
495 }
496 
textCaretMoved(const QAccessibleClient::AccessibleObject & object,int pos)497 void MainWindow::MainWindow::textCaretMoved(const QAccessibleClient::AccessibleObject &object, int pos)
498 {
499     updateDetails(object);
500     m_eventsWidget->addLog(object, EventsWidget::Text, QString("Text caret moved (%1)").arg(pos));
501 }
502 
textSelectionChanged(const QAccessibleClient::AccessibleObject & object)503 void MainWindow::MainWindow::textSelectionChanged(const QAccessibleClient::AccessibleObject &object)
504 {
505     updateDetails(object);
506     m_eventsWidget->addLog(object, EventsWidget::Text, QString("TextSelectionChanged"));
507 }
508 
descriptionForText(const QString & type,const QString & text,int startOffset,int endOffset)509 QString descriptionForText(const QString& type, const QString& text, int startOffset, int endOffset)
510 {
511     QString shortText = text;
512     if (shortText.length() > 50) {
513         shortText.truncate(50);
514         shortText.append(QLatin1String("..."));
515     }
516     QString desc = QString("Text %1 (%2, %3): \"%4\"").arg(type).arg(QString::number(startOffset)).arg(QString::number(endOffset)).arg(shortText);
517     return desc;
518 }
519 
textChanged(const QAccessibleClient::AccessibleObject & object,const QString & text,int startOffset,int endOffset)520 void MainWindow::textChanged(const QAccessibleClient::AccessibleObject &object, const QString& text, int startOffset, int endOffset)
521 {
522     updateDetails(object);
523     m_eventsWidget->addLog(object, EventsWidget::Text, descriptionForText(QLatin1String("changed"), text, startOffset, endOffset));
524 }
525 
textInserted(const QAccessibleClient::AccessibleObject & object,const QString & text,int startOffset,int endOffset)526 void MainWindow::textInserted(const QAccessibleClient::AccessibleObject &object, const QString& text, int startOffset, int endOffset)
527 {
528     updateDetails(object);
529     m_eventsWidget->addLog(object, EventsWidget::Text, descriptionForText(QLatin1String("inserted"), text, startOffset, endOffset));
530 }
531 
textRemoved(const QAccessibleClient::AccessibleObject & object,const QString & text,int startOffset,int endOffset)532 void MainWindow::textRemoved(const QAccessibleClient::AccessibleObject &object, const QString& text, int startOffset, int endOffset)
533 {
534     updateDetails(object);
535     m_eventsWidget->addLog(object, EventsWidget::Text, descriptionForText(QLatin1String("removed"), text, startOffset, endOffset));
536 }
537 
accessibleNameChanged(const QAccessibleClient::AccessibleObject & object)538 void MainWindow::accessibleNameChanged(const QAccessibleClient::AccessibleObject &object)
539 {
540     updateDetails(object);
541     m_eventsWidget->addLog(object, EventsWidget::NameChanged);
542     m_accessibleObjectTreeModel->updateAccessible(object);
543 }
544 
accessibleDescriptionChanged(const QAccessibleClient::AccessibleObject & object)545 void MainWindow::accessibleDescriptionChanged(const QAccessibleClient::AccessibleObject &object)
546 {
547     updateDetails(object);
548     m_eventsWidget->addLog(object, EventsWidget::DescriptionChanged);
549     m_accessibleObjectTreeModel->updateAccessible(object);
550 }
551 
552