summaryrefslogtreecommitdiffstats
path: root/util/accessibilityinspector/accessibilityscenemanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'util/accessibilityinspector/accessibilityscenemanager.cpp')
-rw-r--r--util/accessibilityinspector/accessibilityscenemanager.cpp487
1 files changed, 487 insertions, 0 deletions
diff --git a/util/accessibilityinspector/accessibilityscenemanager.cpp b/util/accessibilityinspector/accessibilityscenemanager.cpp
new file mode 100644
index 0000000000..aa0b93d29e
--- /dev/null
+++ b/util/accessibilityinspector/accessibilityscenemanager.cpp
@@ -0,0 +1,487 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ ** All rights reserved.
+ ** Contact: Nokia Corporation (qt-info@nokia.com)
+ **
+ ** This file is part of the tools applications of the Qt Toolkit.
+ **
+ ** $QT_BEGIN_LICENSE:LGPL$
+ ** GNU Lesser General Public License Usage
+ ** This file may be used under the terms of the GNU Lesser General Public
+ ** License version 2.1 as published by the Free Software Foundation and
+ ** appearing in the file LICENSE.LGPL included in the packaging of this
+ ** file. Please review the following information to ensure the GNU Lesser
+ ** General Public License version 2.1 requirements will be met:
+ ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ **
+ ** In addition, as a special exception, Nokia gives you certain additional
+ ** rights. These rights are described in the Nokia Qt LGPL Exception
+ ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+ **
+ ** GNU General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU General
+ ** Public License version 3.0 as published by the Free Software Foundation
+ ** and appearing in the file LICENSE.GPL included in the packaging of this
+ ** file. Please review the following information to ensure the GNU General
+ ** Public License version 3.0 requirements will be met:
+ ** http://www.gnu.org/copyleft/gpl.html.
+ **
+ ** Other Usage
+ ** Alternatively, this file may be used in accordance with the terms and
+ ** conditions contained in a signed written agreement between you and Nokia.
+ **
+ **
+ **
+ **
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+#include "accessibilityscenemanager.h"
+
+AccessibilitySceneManager::AccessibilitySceneManager()
+{
+ m_window = 0;
+ m_view = 0;
+ m_scene = 0;
+ m_rootItem = 0;
+ m_optionsWidget = 0;
+ m_selectedObject = 0;
+}
+
+void AccessibilitySceneManager::populateAccessibilityScene()
+{
+ m_scene->clear();
+ m_graphicsItems.clear();
+
+ QAccessibleInterface * rootInterface = m_window->accessibleRoot();
+ if (!rootInterface)
+ return;
+
+ populateAccessibilityScene(rootInterface, 0, m_scene);
+}
+
+void AccessibilitySceneManager::updateAccessibilitySceneItemFlags()
+{
+ qDebug() << "update";
+ foreach (QObject *object, m_graphicsItems.keys()) {
+ if (!object)
+ continue;
+ QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(object);
+ if (!interface)
+ continue;
+ updateItemFlags(m_graphicsItems.value(object), interface);
+ delete interface;
+ }
+}
+
+void AccessibilitySceneManager::populateAccessibilityTreeScene()
+{
+ m_treeScene->clear();
+ QAccessibleInterface * rootInterface = m_window->accessibleRoot();
+ if (!rootInterface)
+ return;
+
+ populateAccessibilityTreeScene(rootInterface, 0);
+}
+
+void AccessibilitySceneManager::handleUpdate(QObject *object, QAccessible::Event reason)
+{
+ QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(object);
+ if (!interface)
+ return;
+
+ QString name = interface->text(QAccessible::Name, 0);
+
+ if (reason == QAccessible::ObjectCreated) {
+ // qDebug() << "ObjectCreated" << object << name;
+ populateAccessibilityScene(interface, 0, m_scene);
+ }
+
+ QGraphicsRectItem *item = m_graphicsItems.value(object);
+
+ if (!item) {
+// qDebug() << "populateAccessibilityScene failed for" << object;
+ return;
+ }
+
+ if (reason == QAccessible::LocationChanged) {
+
+ //if (name.startsWith("List"))
+ qDebug() << "locationChange" << object << name << interface->rect(0);
+
+ updateItem(item, interface);
+ for (int i = 0; i < interface->childCount(); ++i) {
+ QAccessibleInterface *child = 0;
+ int ret = interface->navigate(QAccessible::Child, i + 1, &child);
+ if (ret == 0 && child) {
+ updateItem(m_graphicsItems.value(child->object()), child);
+ delete child;
+ }
+ }
+
+ delete interface;
+ } else if (reason == QAccessible::ObjectDestroyed) {
+// qDebug() << "ObjectDestroyed" << object << name;
+ delete m_graphicsItems.value(object);
+ m_graphicsItems.remove(object);
+ m_animatedObjects.remove(object);
+ if (object == m_selectedObject) {
+ m_selectedObject = 0;
+ }
+ } else if (reason == QAccessible::ObjectHide) {
+// qDebug() << "ObjectCreated Hide" << object;
+ updateItemFlags(item, interface);
+ } else if (reason == QAccessible::ObjectShow) {
+// qDebug() << "ObjectCreated Show" << object;
+ updateItemFlags(item, interface);
+ } else if (reason == QAccessible::ScrollingStart) {
+ qDebug() << "ObjectCreated ScrollingStart" << object;
+ QAccessibleInterface *child = 0;
+ for (int i = 0; i < interface->childCount(); ++i) {
+ int ret = interface->navigate(QAccessible::Child, i + 1, &child);
+ if (ret == 0 && child) {
+ m_animatedObjects.insert(child->object());
+ delete child;
+ }
+ }
+ } else if (reason == QAccessible::ScrollingEnd) {
+ // qDebug() << "ObjectCreated ScrollingEnd" << object;
+ foreach (QObject *object, m_animatedObjects) {
+ updateItem(m_graphicsItems.value(object), interface);
+ }
+ delete interface;
+ m_animatedObjects.clear();
+
+ } else {
+ qDebug() << "other update" << object;
+ }
+}
+
+void AccessibilitySceneManager::setSelected(QObject *object)
+{
+ m_scene->update(); // scedule update
+
+ // clear existing selection
+ if (m_selectedObject) {
+ QObject *previousSelectedObject = m_selectedObject;
+ m_selectedObject = 0;
+ updateItem(previousSelectedObject);
+ }
+
+ m_selectedObject = object;
+ updateItem(object);
+
+ populateAccessibilityTreeScene();
+}
+
+void AccessibilitySceneManager::changeScale(int)
+{
+ // No QGraphicsView::setScale :(
+
+ //m_view->scale(scale / 10.0, scale / 10.0);
+ //if (m_rootItem)
+ // m_view->ensureVisible(m_rootItem);
+}
+
+void AccessibilitySceneManager::updateItems(QObject *root)
+{
+ QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(root);
+ if (!interface)
+ return;
+ updateItem(m_graphicsItems.value(root), interface);
+
+ for (int i = 0; i < interface->childCount(); ++i) {
+ QAccessibleInterface *child = interface->child(i);
+ updateItems(child->object());
+ delete child;
+ }
+
+ delete interface;
+}
+
+void AccessibilitySceneManager::updateItem(QObject *object)
+{
+ if (!object)
+ return;
+
+ QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(object);
+ if (!interface)
+ return;
+
+ updateItem(m_graphicsItems.value(object), interface);
+
+ delete interface;
+}
+
+void AccessibilitySceneManager::updateItem(QGraphicsRectItem *item, QAccessibleInterface *interface)
+{
+ if (!item)
+ return;
+
+ QRect rect = interface->rect(0);
+ item->setPos(rect.topLeft());
+ item->setRect(QRect(QPoint(0,0), rect.size()));
+
+ updateItemFlags(item, interface);
+}
+
+void AccessibilitySceneManager::updateItemFlags(QGraphicsRectItem *item, QAccessibleInterface *interface)
+{
+ // qDebug() << "udpateItemFlags" << interface << interface->object();
+
+ bool shouldShow = true;
+
+ if (m_optionsWidget->hideInvisibleItems()) {
+ if (isHidden(interface)) {
+ shouldShow = false;
+ }
+ }
+
+ if (m_optionsWidget->hideOffscreenItems()) {
+ if (interface->state(0) & QAccessible::Offscreen) {
+ shouldShow = false;
+ }
+ }
+
+ if (m_optionsWidget->hidePaneItems()) {
+ if (interface->role(0) & QAccessible::Pane) {
+ shouldShow = false;
+ }
+ }
+
+ item->setVisible(shouldShow);
+
+ if (interface->object() == m_selectedObject)
+ item->setBrush(QColor(Qt::yellow));
+ else
+ item->setBrush(QColor(Qt::white));
+
+ m_view->update();
+}
+
+QGraphicsRectItem * AccessibilitySceneManager::processInterface(QAccessibleInterface * interface, int child, QGraphicsScene *scene)
+{
+ // Process this interface
+
+ QGraphicsRectItem * item = new QGraphicsRectItem();
+ scene->addItem(item);
+ if (!m_rootItem)
+ m_rootItem = item;
+
+ QString name = interface->text(QAccessibleInterface::Name, child);
+ QString description; // = interface->text(QAccessibleInterface::Description, child);
+ QString role = translateRole(interface->role(child));
+ int childCount = interface->childCount();
+
+ /* qDebug() << "name:" << name << "local pos" <<
+ interface->rect(0) << "description" << description << "childCount" << childCount;
+*/
+
+ updateItem(item, interface);
+
+ QGraphicsSimpleTextItem * textItem = new QGraphicsSimpleTextItem();
+ textItem->setParentItem(item);
+ textItem->setPos(QPoint(5, 5));
+
+ QString text;
+ text.append("Name: " + name + " ");
+ if (!description.isEmpty())
+ text.append("Description: " + description + " ");
+ text.append("Role: " + role + " ");
+ if (childCount > 0)
+ text.append("ChildCount: " + QString::number(childCount) + " ");
+ textItem->setText(text);
+
+ QFont font;
+ font.setPointSize(10);
+ // font.setPointSize(14);
+ textItem->setFont(font);
+
+ return item;
+}
+
+void AccessibilitySceneManager::populateAccessibilityScene(QAccessibleInterface * interface, int child, QGraphicsScene *scene)
+{
+ if (!interface)
+ return;
+
+ QGraphicsRectItem *item = processInterface(interface, child, scene);
+
+ QObject *object = interface->object();
+ if (object) {
+ m_graphicsItems.insert(object, item);
+ }
+
+ // Possibly process children
+ if (child != 0)
+ return;
+
+ for (int i = 0; i < interface->childCount(); ++i) {
+ QAccessibleInterface *child = interface->child(i);
+ updateItems(child->object());
+ populateAccessibilityScene(child, 0, scene);
+ delete child;
+ }
+}
+
+AccessibilitySceneManager::TreeItem AccessibilitySceneManager::computeLevels(QAccessibleInterface * interface, int level)
+{
+ if (interface == 0)
+ return TreeItem();
+
+ TreeItem currentLevel;
+
+ int usedChildren = 0;
+ for (int i = 0; i < interface->childCount(); ++i) {
+ QAccessibleInterface *child = interface->child(i);
+ if (child != 0) {
+ ++usedChildren;
+ TreeItem childLevel = computeLevels(child, level + 1);
+ currentLevel.children.append(childLevel);
+ currentLevel.width += childLevel.width + m_treeItemHorizontalPadding;
+ delete child;
+ }
+ }
+
+ // leaf node case
+ if (usedChildren == 0) {
+ currentLevel.width = m_treeItemWidth + m_treeItemHorizontalPadding;
+ }
+
+ // capture information:
+ currentLevel.name = interface->text(QAccessible::Name, 0);
+ //currentLevel.description += interface->text(QAccessible::DebugDescription, 0);
+ currentLevel.role = translateRole(interface->role(0));
+ currentLevel.rect = interface->rect(0);
+ currentLevel.state = interface->state(0);
+ currentLevel.object = interface->object();
+
+ return currentLevel;
+}
+
+void AccessibilitySceneManager::populateAccessibilityTreeScene(QAccessibleInterface * interface, int child)
+{
+ if (!interface)
+ return;
+
+ // set some layout metrics:
+ m_treeItemWidth = 90;
+ m_treeItemHorizontalPadding = 10;
+ m_treeItemHeight = 60;
+ m_treeItemVerticalPadding = 30;
+
+ // We want to draw the accessibility hiearchy as a vertical
+ // tree, growing from the root node at the top.
+
+ // First, figure out the number of levels and the width of each level:
+ m_rootTreeItem = computeLevels(interface, 0);
+
+ // create graphics items for each tree item
+ addGraphicsItems(m_rootTreeItem, 0, 0);
+}
+
+void AccessibilitySceneManager::addGraphicsItems(AccessibilitySceneManager::TreeItem item, int row, int xPos)
+{
+ //qDebug() << "add graphics item" << row << item.name << item.role << xPos << item.width << item.children.count();
+
+ int yPos = row * (m_treeItemHeight + m_treeItemVerticalPadding);
+
+ // Process this interface
+ QGraphicsRectItem * graphicsItem = new QGraphicsRectItem();
+ graphicsItem->setPos(xPos, yPos);
+ graphicsItem->setRect(0, 0, m_treeItemWidth, m_treeItemHeight);
+ graphicsItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
+
+ if (item.object == m_selectedObject)
+ graphicsItem->setBrush(QColor(Qt::yellow));
+ else
+ graphicsItem->setBrush(QColor(Qt::white));
+
+ if (item.state & QAccessible::Invisible) {
+ QPen linePen;
+ linePen.setStyle(Qt::DashLine);
+ graphicsItem->setPen(linePen);
+ }
+
+ m_treeScene->addItem(graphicsItem);
+
+ QGraphicsTextItem * textItem = new QGraphicsTextItem();
+ textItem->setParentItem(graphicsItem);
+ textItem->setPos(QPoint(0, 0));
+
+ QFont font;
+ font.setPointSize(8);
+ textItem->setFont(font);
+
+ QString text;
+ text += item.name + "\n";
+ text += item.role + "\n";
+ text += item.description.split(" ", QString::SkipEmptyParts).join("\n") + "\n";
+ text += "P:" + QString::number(item.rect.x()) + " " + QString::number(item.rect.y()) + " ";
+ text += "S:" + QString::number(item.rect.width()) + " " + QString::number(item.rect.height()) + "\n";
+
+ textItem->setPlainText(text);
+
+ // recurse to children
+ int childIndex = 0;
+ int childCount = item.children.count();
+ int segmentSize = item.width / qMax(1, childCount);
+ int segmentCenterOffset = segmentSize / 2;
+ int segmentsStart = xPos - (item.width / 2);
+ foreach (TreeItem child, item.children) {
+ // spread the children out, covering the width, centered on xPos
+ int segmentPosition = segmentsStart + (segmentSize * childIndex) + segmentCenterOffset;
+ addGraphicsItems(child, row + 1, segmentPosition);
+ ++childIndex;
+ }
+
+ // add lines from parents to kids
+ int boxBottom = yPos + m_treeItemHeight;
+ int boxMiddleX = xPos + m_treeItemWidth / 2;
+ int yBottomMiddle = boxBottom + m_treeItemVerticalPadding / 2;
+ int boxTop = yPos;
+ int yTopMiddle = boxTop - m_treeItemVerticalPadding / 2;
+
+ if (row > 0) {
+ QGraphicsLineItem *childVerticalStem = new QGraphicsLineItem();
+ childVerticalStem->setLine(boxMiddleX, yTopMiddle, boxMiddleX, boxTop);
+ m_treeScene->addItem(childVerticalStem);
+ }
+
+ if (childCount > 0) {
+ QGraphicsLineItem *parentVerticalStem = new QGraphicsLineItem();
+ parentVerticalStem->setLine(boxMiddleX, boxBottom, boxMiddleX, yBottomMiddle);
+ m_treeScene->addItem(parentVerticalStem);
+ }
+
+ if (childCount > 1) {
+ QGraphicsLineItem *horizontalStem = new QGraphicsLineItem();
+ // match the end points with the horizontal lines
+ int lineStartX = segmentsStart + segmentCenterOffset + m_treeItemWidth / 2;
+ int lineStopX = segmentsStart + segmentSize * (childCount -1) + segmentCenterOffset + m_treeItemWidth / 2;
+ horizontalStem->setLine(lineStartX, yBottomMiddle, lineStopX , yBottomMiddle);
+ m_treeScene->addItem(horizontalStem);
+ }
+}
+
+bool AccessibilitySceneManager::isHidden(QAccessibleInterface *interface)
+{
+ QAccessibleInterface *current = interface;
+ while (current) {
+
+ if (current->state(0) & QAccessible::Invisible) {
+ return true;
+ }
+
+ QAccessibleInterface *parent = current->parent();
+
+ if (current != interface)
+ delete current;
+ current = parent;
+ }
+
+ return false;
+}