/**************************************************************************** ** ** 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, 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) { qWarning("QWindow::accessibleRoot returned 0"); return; } populateAccessibilityTreeScene(rootInterface); } void AccessibilitySceneManager::handleUpdate(QObject *object, QAccessible::Event reason) { QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(object); if (!interface) return; QString name = interface->text(QAccessible::Name); if (reason == QAccessible::ObjectCreated) { // qDebug() << "ObjectCreated" << object << name; populateAccessibilityScene(interface, 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(); 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(); 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() & QAccessible::Offscreen) { shouldShow = false; } } if (m_optionsWidget->hidePaneItems()) { if (interface->role() & 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, QGraphicsScene *scene) { // Process this interface QGraphicsRectItem * item = new QGraphicsRectItem(); scene->addItem(item); if (!m_rootItem) m_rootItem = item; QString name = interface->text(QAccessibleInterface::Name); QString description; // = interface->text(QAccessibleInterface::Description, child); QString role = translateRole(interface->role()); 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, QGraphicsScene *scene) { if (!interface) return; QGraphicsRectItem *item = processInterface(interface, scene); QObject *object = interface->object(); if (object) { m_graphicsItems.insert(object, item); } for (int i = 0; i < interface->childCount(); ++i) { QAccessibleInterface *child = interface->child(i); updateItems(child->object()); populateAccessibilityScene(child, 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); currentLevel.description += interface->text(QAccessible::DebugDescription); currentLevel.role = translateRole(interface->role()); currentLevel.rect = interface->rect(); currentLevel.state = interface->state(); currentLevel.object = interface->object(); return currentLevel; } void AccessibilitySceneManager::populateAccessibilityTreeScene(QAccessibleInterface * interface) { 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() & QAccessible::Invisible) { return true; } QAccessibleInterface *parent = current->parent(); if (current != interface) delete current; current = parent; } return false; }