diff options
Diffstat (limited to 'src/objectBrowser/qtestbrowserdlg.cpp')
-rw-r--r-- | src/objectBrowser/qtestbrowserdlg.cpp | 1139 |
1 files changed, 1139 insertions, 0 deletions
diff --git a/src/objectBrowser/qtestbrowserdlg.cpp b/src/objectBrowser/qtestbrowserdlg.cpp new file mode 100644 index 0000000..b0531ec --- /dev/null +++ b/src/objectBrowser/qtestbrowserdlg.cpp @@ -0,0 +1,1139 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of QtSystemTest. +** +** $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 "qtestbrowserdlg_p.h" +#include <QtSystemTest/QstConnection> + +#include <QAction> +#include <QMenu> +#include <QPushButton> +#include <QDesktopWidget> +#include <QLineEdit> +#include <QComboBox> +#include <QSpinBox> +#include <QTreeWidget> +#include <QTableWidget> +#include <QHeaderView> +#include <QSplitter> +#include <QLayout> +#include <QPixmap> +#include <QMouseEvent> +#include <QPaintEvent> +#include <QPainter> +#include <QVariantMap> +#include <QMetaMethod> +#include <QApplication> +#include <QClipboard> +#include <QMessageBox> +#include <QCheckBox> +#include <QScrollArea> + +QString signature(const QVariantMap &map) +{ + return map[QstConnection::signatureProperty].toString(); +} + +TestImageViewer::TestImageViewer(QWidget *parent, Qt::WindowFlags f) + : QLabel(parent, f) +{ +} + +TestImageViewer::~TestImageViewer() +{ +} + +void TestImageViewer::setSelectedArea(const QRect& rect) +{ + m_selectedArea = rect; + update(); +} + +void TestImageViewer::mouseReleaseEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + emit clicked(event->pos()); + } +} + +void TestImageViewer::paintEvent(QPaintEvent *event) +{ + QLabel::paintEvent(event); + if (m_selectedArea.isNull()) { + return; + } + + QPainter painter(this); + painter.setPen(Qt::red); + painter.drawRect(m_selectedArea); +} + +QTestBrowserDlg::QTestBrowserDlg( QstConnection* test, const QVariantMap &item, const QVariantMap &imgItem ) + : QDialog(0, Qt::Window) + , m_test(0) + , m_image(0) + , m_appContext(0) + , m_tree(0) + , m_queryTab(0) + , m_propertyTab(0) + , m_itemPropertyTable(0) + , m_queryTable(0) + , m_resultsTable(0) + , m_contextTableItem(0) + , m_flagInvisible(0) + , m_flagDisabled(0) + , m_flagIgnoreScan(0) + , m_refreshAction(0) + , m_expandAction(0) + , m_collapseAction(0) + , m_methodsAction(0) + , m_propertyRefreshAction(0) + , m_propertyMethodsAction(0) + , m_propertyPropertiesAction(0) + , m_propertyQueryAction(0) + , m_propertyCopyAction(0) + , m_propertyCopyTableAction(0) + , m_queryClearAction(0) + , m_queryCopyAction(0) +{ + setSystemTest(test); + createActions(); + createWidgets(); + updateAppContext(); + setBaseItems(item, imgItem); +} + +QTestBrowserDlg::~QTestBrowserDlg() +{ +} + +void QTestBrowserDlg::createActions() +{ + m_refreshAction = new QAction(tr("Refresh"), this); + m_refreshAction->setShortcut(QKeySequence::Refresh); + connect(m_refreshAction, SIGNAL(triggered()), this, SLOT(refresh())); + addAction(m_refreshAction); + + m_expandAction = new QAction(tr("Expand Tree"), this); + m_expandAction->setShortcut(QKeySequence(tr("Alt+E"))); + connect(m_expandAction, SIGNAL(triggered()), this, SLOT(expandAll())); + addAction(m_expandAction); + + m_collapseAction = new QAction(tr("Collapse Tree"), this); + m_collapseAction->setShortcut(QKeySequence(tr("Alt+C"))); + connect(m_collapseAction, SIGNAL(triggered()), this, SLOT(collapseAll())); + addAction(m_collapseAction); + + m_methodsAction = new QAction(tr("View Methods"), this); + m_methodsAction->setShortcut(QKeySequence(tr("Alt+M"))); + connect(m_methodsAction, SIGNAL(triggered()), this, SLOT(viewMethods())); + addAction(m_methodsAction); + + m_propertyRefreshAction = new QAction(tr("Refresh Properties"), this); + connect(m_propertyRefreshAction, SIGNAL(triggered()), this, SLOT(refreshProperties())); + + m_propertyMethodsAction = new QAction(this); + connect(m_propertyMethodsAction, SIGNAL(triggered()), this, SLOT(viewPropertyMethods())); + + m_propertyPropertiesAction = new QAction(this); + connect(m_propertyPropertiesAction, SIGNAL(triggered()), this, SLOT(viewPropertyProperties())); + + m_propertyQueryAction = new QAction(tr("Add as Query Condition"), this); + connect(m_propertyQueryAction, SIGNAL(triggered()), this, SLOT(addPropertyAsQueryCondition())); + + m_propertyCopyAction = new QAction(tr("Copy"), this); + connect(m_propertyCopyAction, SIGNAL(triggered()), this, SLOT(copyTableItemValue())); + + m_propertyCopyTableAction = new QAction(tr("Copy Table"), this); + connect(m_propertyCopyTableAction, SIGNAL(triggered()), this, SLOT(copyTable())); + + m_queryClearAction = new QAction(tr("Clear Query"), this); + connect(m_queryClearAction, SIGNAL(triggered()), this, SLOT(clearQuery())); + + m_queryCopyAction = new QAction(tr("Copy Query"), this); + connect(m_queryCopyAction, SIGNAL(triggered()), this, SLOT(copyQuery())); + +} + +void QTestBrowserDlg::createWidgets() +{ + QHBoxLayout *mainLayout = new QHBoxLayout( this ); + QSplitter *mainSplitter = new QSplitter(Qt::Horizontal, this); + QSplitter *leftSplitter = new QSplitter(Qt::Vertical, this); + QSplitter *rightSplitter = new QSplitter(Qt::Vertical, this); + + mainLayout->addWidget(mainSplitter); + mainSplitter->addWidget(leftSplitter); + mainSplitter->addWidget(rightSplitter); + mainSplitter->setStretchFactor(0, 0); + mainSplitter->setStretchFactor(1, 1); + + m_image = new TestImageViewer(); + m_image->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + connect(m_image, SIGNAL(clicked(QPoint)), this, SLOT(onImageClicked(QPoint))); + + m_image->setAlignment( Qt::AlignCenter ); + m_image->setFrameShape( QLabel::NoFrame ); + m_image->setScaledContents( false ); + + QScrollArea *scrollArea = new QScrollArea; + scrollArea->setWidget(m_image); + leftSplitter->addWidget(scrollArea); + leftSplitter->setStretchFactor(0, 2); + + m_appContext = new QComboBox(this); + m_appContext->installEventFilter(this); + leftSplitter->addWidget(m_appContext); + + m_queryTab = createQueryTab(); + leftSplitter->addWidget(m_queryTab); + + m_tree = new QTreeWidget( this ); + connect(m_tree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(onItemChanged(QTreeWidgetItem*,QTreeWidgetItem*))); + m_tree->setColumnCount(6); + m_tree->setHeaderLabels(QStringList() << QLatin1String("Type") << QLatin1String("Signature") << QLatin1String("QML id") << QLatin1String("objectName") << QLatin1String("Geometry") << QLatin1String("text")); + + rightSplitter->addWidget(m_tree); + rightSplitter->setStretchFactor(0, 2); + m_propertyTab = new QTabWidget(this); + m_itemPropertyTable = new QTableWidget(this); + initPropertyTable(m_itemPropertyTable); + + m_propertyTab->addTab(m_itemPropertyTable, QLatin1String("Item Properties")); + m_propertyTab->setTabEnabled(0, false); + m_propertyTab->setTabPosition(QTabWidget::South); + m_propertyTab->setTabsClosable(true); + connect(m_propertyTab, SIGNAL(tabCloseRequested(int)), this, SLOT(onTabCloseRequested(int))); + + rightSplitter->addWidget(m_propertyTab); + + setWindowTitle( "Object Browser" ); + m_tabItemSignatures.append(""); +} + +QTabWidget * QTestBrowserDlg::createQueryTab() +{ + QTabWidget *tabWidget = new QTabWidget(this); + QFrame *queryFrame = new QFrame(this); + QFrame *flagsFrame = new QFrame(this); + QVBoxLayout *queryLayout = new QVBoxLayout(queryFrame); + QVBoxLayout *flagsLayout = new QVBoxLayout(flagsFrame); + + m_queryTable = new QTableWidget(this); + static QStringList labels(QStringList() << QString() << QLatin1String("Property") << QLatin1String("Value")); + m_queryTable->setColumnCount(labels.count()); + m_queryTable->verticalHeader()->hide(); + m_queryTable->horizontalHeader()->setStretchLastSection(true); + m_queryTable->setHorizontalHeaderLabels(labels); + m_queryTable->setContextMenuPolicy(Qt::CustomContextMenu); + m_queryTable->setEditTriggers(QAbstractItemView::AllEditTriggers); + m_queryTable->setRowCount(1); + addQueryRow(); + m_queryTable->resizeColumnsToContents(); + m_queryTable->setSpan(1, 0, 1, labels.count()); + QPushButton *addButton = new QPushButton(tr("Add New Condition")); + m_queryTable->setCellWidget(1, 0, addButton); + connect(addButton, SIGNAL(clicked()), this, SLOT(addQueryRow()) ); + connect(m_queryTable, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(onQueryItemChanged(QTableWidgetItem*))); + connect(m_queryTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onQueryContextMenu(QPoint))); + QPushButton *queryButton = new QPushButton("Query"); + connect( queryButton, SIGNAL(clicked()), this, SLOT(doQuery()) ); + queryLayout->addWidget(m_queryTable); + queryLayout->addWidget(queryButton); + + m_flagInvisible = new QCheckBox(QLatin1String("Scan Invisible Items"), this); + m_flagDisabled = new QCheckBox(QLatin1String("Scan Disabled Items"), this); + m_flagIgnoreScan = new QCheckBox(QLatin1String("Ignore Scanned"), this); + QLabel *flagsInfo = new QLabel(QLatin1String("Query Flags are used to control how the search is performed. Please refer to the QtUiTest documentation for details.")); + flagsInfo->setWordWrap(true); + flagsLayout->addWidget(m_flagInvisible); + flagsLayout->addWidget(m_flagDisabled); + flagsLayout->addWidget(m_flagIgnoreScan); + flagsLayout->addWidget(flagsInfo); + + m_resultsTable = new QTableWidget(this); + static QStringList resultLabels(QStringList() << QLatin1String("Signature") << QLatin1String("QML id")); + m_resultsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_resultsTable->setColumnCount(resultLabels.count()); + m_resultsTable->setSelectionBehavior(QAbstractItemView::SelectRows); + m_resultsTable->setSelectionMode(QAbstractItemView::SingleSelection); + m_resultsTable->verticalHeader()->hide(); + m_resultsTable->horizontalHeader()->setStretchLastSection(true); + m_resultsTable->setHorizontalHeaderLabels(resultLabels); + connect(m_resultsTable, SIGNAL(itemSelectionChanged()), this, SLOT(onResultsItemSelected())); + + tabWidget->addTab(queryFrame, tr("Query")); + tabWidget->addTab(flagsFrame, tr("Query Flags")); + tabWidget->addTab(m_resultsTable, tr("Results")); + + return tabWidget; +} + +void QTestBrowserDlg::updateAppContext() +{ + disconnect(m_appContext, SIGNAL(currentIndexChanged(QString)), this, SLOT(onAppContextChanged(QString))); + m_appContext->clear(); + m_appContext->setCurrentIndex(-1); + QStringList appIds = m_test->getAppIds(); + int appIndex = appIds.indexOf(m_test->currentAppId()); + foreach (const QString &id, appIds) { + QString appName; + QVariantMap appData = m_test->applicationData(id); + appName = appData["appName"].toString(); + appName.append(QString("(%1)").arg(id)); + m_appContext->addItem(appName, id); + } + m_appContext->setCurrentIndex(appIndex); + connect(m_appContext, SIGNAL(currentIndexChanged(QString)), this, SLOT(onAppContextChanged(QString))); +} + +QSize QTestBrowserDlg::sizeHint() const +{ + return QSize(960, 960); +} + +void QTestBrowserDlg::contextMenuEvent(QContextMenuEvent *e) +{ + m_methodsAction->setText(QString("View Methods for %1").arg(currentTabSignature())); + + QMenu menu(this); + menu.addAction(m_refreshAction); + menu.addSeparator(); + menu.addAction(m_expandAction); + menu.addAction(m_collapseAction); + menu.addSeparator(); + menu.addAction(m_methodsAction); + menu.addSeparator(); + + QMenu *subMenu = menu.addMenu(tr("Add Query Condition")); + subMenu->addAction(QLatin1String("CHILD_OF")); + subMenu->addAction(QLatin1String("DESCENDANT_OF")); + subMenu->addAction(QLatin1String("PARENT_OF")); + subMenu->addAction(QLatin1String("ANCESTOR_OF")); + connect(subMenu, SIGNAL(triggered(QAction*)), this, SLOT(onMenuQueryCondition(QAction*))); + menu.exec(e->globalPos()); +} + +void QTestBrowserDlg::setSystemTest ( QstConnection *test ) +{ + m_test = test; + connect(m_test, SIGNAL(appFinished(QString)), this, SLOT(onAppFinished(QString))); + connect(m_test, SIGNAL(appStarted(QString)), this, SLOT(onAppStarted(QString))); +} + +void QTestBrowserDlg::setImage( const QPixmap &img ) +{ + if (!img.isNull()) { + m_image->setPixmap(img); + } else { + m_image->setText("No image available"); + } + + m_image->adjustSize(); + updateGeometry(); +} + +void QTestBrowserDlg::setBaseItems( const QVariantMap &item, const QVariantMap &imgItem ) +{ + if (item.isEmpty()) { + m_appId = m_test->currentAppId(); + qDebug() << "current app id" << m_appId; + m_appId = m_appContext->itemData(m_appContext->currentIndex()).toString(); + m_test->setAppId(m_appId); + QVariantMap appData = m_test->applicationData(m_appId); + m_baseItem = appData["appObject"].toMap(); + m_imgItem = m_baseItem; + } else { + m_baseItem = item; + m_imgItem = imgItem; + m_appId = item[QstConnection::appIdProperty].toString(); + } + refresh(); +} + +void QTestBrowserDlg::setObjectMap ( const QVariantMap &map ) +{ + m_tree->setCursor(Qt::WaitCursor); + m_map = map; + m_geometry = m_map["geometry"].toMap(); + m_children = m_map["children"].toMap(); + m_window = m_map["window"].toMap(); + QString sig = signature(m_baseItem); + + m_tree->clear(); + m_treeMap.clear(); + + addItemToTree(sig); + m_tree->expandAll(); + m_tree->resizeColumnToContents(0); + m_tree->setCursor(Qt::ArrowCursor); +} + +void QTestBrowserDlg::closeWindow() +{ + QDialog::accept(); + deleteLater(); +} + +void QTestBrowserDlg::onImageClicked( const QPoint& point ) +{ + QPoint p = point + m_origin; + QString selectedItem; + int selectedArea=-1; + + foreach (const QString &item, m_window.keys()) { + if (m_window[item] == m_currentWindowSignature) { + QRect rect = m_geometry[item].toRect(); + if (rect.contains(p) && m_map["visible"].toMap()[item].toBool()) { + if (selectedArea == -1 || selectedArea > abs(rect.width() * rect.height())) { + selectedItem = item; + selectedArea = abs(rect.width() * rect.height()); + } + } + } + } + selectItem(selectedItem); +} + +void QTestBrowserDlg::selectItem( const QString &item ) +{ + QTreeWidgetItem *treeItem = m_treeMap[item]; + if (treeItem && treeItem != m_tree->currentItem() && !treeItem->isDisabled()) { + m_tree->collapseAll(); + m_tree->setCurrentItem(treeItem); + } +} + +void QTestBrowserDlg::onItemChanged(QTreeWidgetItem *item, QTreeWidgetItem *prev) +{ + Q_UNUSED(prev); + if (!item || !m_test) { + return; + } + + QString itemSignature = item->text(1); + QString windowSignature = m_window[itemSignature].toString(); + if (windowSignature != m_currentWindowSignature) { + m_currentWindowSignature = windowSignature; + m_imgItem = widgetSpec(windowSignature); + refreshImage(); + } + + QRect rect; + rect = m_geometry[item->text(1)].toRect(); + rect.moveTopLeft(rect.topLeft() - m_origin); + m_image->setSelectedArea(rect); + + QVariantMap propertyMap = + m_test->getProperties(widgetSpec(itemSignature)); + + updatePropertyTable(m_itemPropertyTable, propertyMap); + m_tabItemSignatures.replace(0, itemSignature); + m_propertyTab->setCurrentIndex(0); + m_propertyTab->setTabEnabled(0, true); + m_propertyTab->setTabToolTip(0, QString("Properties: %1").arg(itemSignature)); +} + +void QTestBrowserDlg::onAppContextChanged(const QString &context) +{ + Q_UNUSED(context); + setBaseItems(); +} + +void QTestBrowserDlg::initTable(QTableWidget *table, const QStringList &labels) +{ + table->setColumnCount(labels.count()); + table->verticalHeader()->hide(); + table->horizontalHeader()->setStretchLastSection(true); + table->setHorizontalHeaderLabels(labels); + table->setContextMenuPolicy(Qt::CustomContextMenu); +} + +void QTestBrowserDlg::initPropertyTable(QTableWidget *table) +{ + static QStringList propertyHeaders(QStringList() + << QLatin1String("Property") + << QLatin1String("Value") + ); + + initTable(table, propertyHeaders); + connect(table, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(onPropertyDoubleClicked(QTableWidgetItem*))); + connect(table, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onPropertyContextMenu(QPoint))); +} + +void QTestBrowserDlg::initMethodsTable(QTableWidget *table) +{ + static QStringList methodsHeaders(QStringList() + << QLatin1String("Method Type") + << QLatin1String("Return Type") + << QLatin1String("Method Signature") + ); + + initTable(table, methodsHeaders); + connect(table, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onMethodsContextMenu(QPoint))); +} + +void QTestBrowserDlg::updatePropertyTable(QTableWidget *table, const QVariantMap &propertyMap) +{ + QVariantMap previousValues = table->property("_qttPrevMap").toMap(); + + table->clearContents(); + table->setRowCount(propertyMap.size()); + table->clearSpans(); + + int row = 0; + foreach (const QString &propertyName, propertyMap.keys()) { + QTableWidgetItem *nameItem = new QTableWidgetItem(propertyName); + nameItem->setFlags(Qt::ItemIsEnabled); + table->setItem(row, 0, nameItem); + QVariant value = propertyMap[propertyName]; + + if (value.type() == QVariant::List) { + QVariantList list = value.toList(); + if (list.size() > 0) { + if (list.size() > 1) { + table->setRowCount(table->rowCount() + list.size() -1); + table->setSpan(row, 0, list.size(), 1); + } + foreach (const QVariant &item, list) { + QTableWidgetItem *valueItem = valueToTableItem(item); + valueItem->setFlags(Qt::ItemIsEnabled); + table->setItem(row++, 1, valueItem); + } + continue; + } + } + + QTableWidgetItem *valueItem = valueToTableItem(value, previousValues.value(propertyName)); + valueItem->setFlags(Qt::ItemIsEnabled); + table->setItem(row, 1, valueItem); + row++; + } + + table->resizeRowsToContents(); + int size = table->horizontalHeader()->sectionSize(0); + table->resizeColumnToContents(0); + if (size > table->horizontalHeader()->sectionSize(0)) { + table->horizontalHeader()->resizeSection(0, size); + } + table->setProperty("_qttPrevMap", propertyMap); +} + +void QTestBrowserDlg::updateMethodsTable(QTableWidget *table, const QVariantList &methods) +{ + table->clearContents(); + table->setRowCount(methods.size()); + table->clearSpans(); + + int row = 0; + foreach (const QVariant &method, methods) { + QVariantMap map = method.toMap(); + int methodType = map["methodType"].toInt(); + QString methodTypeName; + switch (methodType) { + case QMetaMethod::Method: + methodTypeName = QLatin1String("Method"); + break; + case QMetaMethod::Signal: + methodTypeName = QLatin1String("Signal"); + break; + case QMetaMethod::Slot: + methodTypeName = QLatin1String("Slot"); + break; + case QMetaMethod::Constructor: + methodTypeName = QLatin1String("Constructor"); + break; + } + QString returnType = map["returnType"].toString(); + QString signature = map["signature"].toString(); + + QTableWidgetItem *typeItem = new QTableWidgetItem(methodTypeName); + typeItem->setFlags(Qt::ItemIsEnabled); + table->setItem(row, 0, typeItem); + + QTableWidgetItem *retItem = new QTableWidgetItem(returnType); + retItem->setFlags(Qt::ItemIsEnabled); + table->setItem(row, 1, retItem); + + QTableWidgetItem *sigItem = new QTableWidgetItem(signature); + sigItem->setFlags(Qt::ItemIsEnabled); + table->setItem(row, 2, sigItem); + + row++; + } + + table->resizeRowsToContents(); + table->resizeColumnsToContents(); + table->sortItems(1); +} + +QTableWidgetItem *QTestBrowserDlg::valueToTableItem(const QVariant &value, const QVariant &previous) +{ + QString valueString = valueToString(value); + QTableWidgetItem *valueItem = new QTableWidgetItem(valueString); + if (previous.isValid() && valueToString(previous) != valueString) { + valueItem->setBackground(QBrush("#ffff80")); + } + if (value.type() == QVariant::Map) { + QString sig = signature(value.toMap()); + if (m_treeMap.contains(sig)) { + valueItem->setForeground(QBrush(Qt::blue)); + } else if (!sig.isEmpty()) { + valueItem->setForeground(QBrush(Qt::darkGreen)); + } + } else if (valueString.startsWith(QChar('<')) + && valueString.endsWith(QChar('>'))) { + valueItem->setForeground(QBrush(Qt::gray)); + return valueItem; + } + valueItem->setData(Qt::UserRole, value); + return valueItem; +} + +QString QTestBrowserDlg::valueToString(const QVariant &value) +{ + QString valueString; + if (value.canConvert(QVariant::String)) { + valueString = value.toString(); + } else if (value.type() == QVariant::List) { + QVariantList list = value.toList(); + if (list.length() == 0) { + valueString = QLatin1String("<Empty List>"); + } else { + QStringList itemStrings; + foreach (const QVariant& item, list) { + itemStrings << valueToString(item); + } + valueString = itemStrings.join(QLatin1String(", ")); + } + } else if (value.type() == QVariant::Map) { + QVariantMap map = value.toMap(); + valueString = signature(map); + if (valueString.isEmpty()) { + if (map.contains(QstConnection::enumProperty)) { + valueString = QString("%1 (%2)").arg(map[QstConnection::valueProperty].toInt()).arg(map[QstConnection::enumProperty].toString()); + } else { + valueString = QLatin1String("<QVariantMap>"); + } + } + } else if (value.type() == QVariant::PointF) { + QRectF rectf = value.toRectF(); + valueString = QString("QPointF (%1,%2)").arg(rectf.x()).arg(rectf.y()); + } else if (value.type() == QVariant::RectF) { + QRectF rectf = value.toRectF(); + valueString = QString("QRectF (%1,%2 %3x%4)").arg(rectf.x()).arg(rectf.y()).arg(rectf.width()).arg(rectf.height()); + } else if (value.type() == QVariant::Size) { + QSize size = value.toSize(); + valueString = QString("QSize (%1x%2)").arg(size.width()).arg(size.height()); + } else if (value.type() == QVariant::SizeF) { + QSizeF size = value.toSizeF(); + valueString = QString("QSizeF (%1x%2)").arg(size.width()).arg(size.height()); + } else { + valueString = QString("<%1>").arg(value.typeName()); + } + return valueString; +} + +void QTestBrowserDlg::addItemToTree(const QString &item, QTreeWidgetItem *parent) +{ + QString geoString; + if (m_geometry.contains(item)) { + QRect rect = m_geometry[item].toRect(); + geoString = QString("%1,%2 %3x%4").arg(rect.x()).arg(rect.y()).arg(rect.width()).arg(rect.height()); + } + QTreeWidgetItem *treeItem = new QTreeWidgetItem(parent, QStringList() << + m_map["type"].toMap()[item].toString() << + item << + m_map["qmlid"].toMap()[item].toString() << + m_map["objectName"].toMap()[item].toString() << + geoString << + m_map["text"].toMap()[item].toString() + ); + if (!m_map["visible"].toMap()[item].toBool()) { + treeItem->setForeground(0, QBrush(Qt::gray)); + } + m_tree->addTopLevelItem(treeItem); + m_treeMap[item] = treeItem; + + foreach (const QString &child, m_children[item].toStringList()) { + addItemToTree(child, treeItem); + } +} + +void QTestBrowserDlg::addQueryRow(const QString &property, const QVariant &value) +{ + static QStringList relationshipProperties(QStringList() + << QLatin1String("ANCESTOR_OF") << QLatin1String("CHILD_OF") << QLatin1String("DESCENDANT_OF") << QLatin1String("PARENT_OF")); + + static QStringList qmlProperties(QStringList() + << QLatin1String("QMLID") << QLatin1String("QMLINHERITS") << QLatin1String("QMLTYPE")); + + static QStringList defaultProperties(QStringList() + << QLatin1String("CLASSNAME") << QLatin1String("INHERITS") << QLatin1String("LABEL") << QLatin1String("PROPERTY")); + + int row = m_queryTable->rowCount()-1; + m_queryTable->insertRow(row); + + QTableWidgetItem *checkItem = new QTableWidgetItem(QString()); + checkItem->setCheckState(Qt::Checked); + m_queryTable->setItem(row, 0, checkItem); + + QComboBox *propertyCombo = new QComboBox(); + propertyCombo->addItems(defaultProperties); + propertyCombo->insertSeparator(99); + propertyCombo->addItems(relationshipProperties); + propertyCombo->insertSeparator(99); + propertyCombo->addItems(qmlProperties); + propertyCombo->setEditable(true); + propertyCombo->lineEdit()->setText(property); + propertyCombo->setMaxVisibleItems(propertyCombo->count()+1); + m_queryTable->setCellWidget(row, 1, propertyCombo); + + QTableWidgetItem *valueItem = new QTableWidgetItem(); + if (value.canConvert(QVariant::String)) { + valueItem->setText(value.toString()); + valueItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable); + } else { + valueItem->setText(valueToString(value)); + valueItem->setData(Qt::UserRole, value); + valueItem->setFlags(Qt::NoItemFlags); + } + + m_queryTable->setItem(row, 2, valueItem); + m_queryTable->resizeRowsToContents(); + m_queryTable->scrollToItem(checkItem, QAbstractItemView::PositionAtTop); +} + +QVariantMap QTestBrowserDlg::queryMap() const +{ + QVariantMap map; + for (int i=0; i<m_queryTable->rowCount()-1;) { + QComboBox *propertyCombo = qobject_cast<QComboBox*>(m_queryTable->cellWidget(i, 1)); + QString property; + if (propertyCombo) { + property = propertyCombo->currentText(); + } + QTableWidgetItem *valueItem = m_queryTable->item(i, 2); + QVariant value = valueItem->data(Qt::UserRole); + if (!value.isValid()) { + value = valueItem->text(); + } + if (property.isEmpty() && value.isNull()) { + m_queryTable->removeRow(i); + continue; + } + + if (property.isEmpty()) { + QMessageBox::warning(const_cast<QTestBrowserDlg*>(this), tr("Invalid Query"), QLatin1String("An empty property is not permitted")); + return QVariantMap(); + } + + if (map.contains(property)) { + QMessageBox::warning(const_cast<QTestBrowserDlg*>(this), tr("Invalid Query"), QString("There are duplicate instances of property '%1'").arg(property)); + return QVariantMap(); + } + + map[property] = value; + i++; + } + + if (map.isEmpty()) { + QMessageBox::warning(const_cast<QTestBrowserDlg*>(this), tr("Invalid Query"), QLatin1String("No properties were specified !")); + } + + return map; +} + +void QTestBrowserDlg::doQuery() +{ + m_resultsTable->clearContents(); + m_resultsTable->setRowCount(0); + + QVariantMap map = queryMap(); + if (map.isEmpty()) { + return; + } + + int flags=0; + if (m_flagInvisible->isChecked()) flags |= QstConnection::ScanInvisible; + if (m_flagDisabled->isChecked()) flags |= QstConnection::ScanDisabledItems; + if (m_flagIgnoreScan->isChecked()) flags |= QstConnection::IgnoreScanned; + + QString currentAppId = m_test->currentAppId(); + if (currentAppId != m_appId) { + m_test->setAppId(m_appId); + } + m_matches = m_test->findByProperties(map, flags); + if (currentAppId != m_appId) { + m_test->setAppId(currentAppId); + } + + m_resultsTable->setRowCount(m_matches.count()); + int row=0; + QVariantMap idMap = m_map["qmlid"].toMap(); + foreach (const QString &match, m_matches) { + QTableWidgetItem *item = new QTableWidgetItem(match); + m_resultsTable->setItem(row, 0, item); + QTableWidgetItem *idItem = new QTableWidgetItem(idMap[match].toString()); + m_resultsTable->setItem(row, 1, idItem); + row++; + } + m_resultsTable->resizeRowsToContents(); + m_resultsTable->resizeColumnsToContents(); + m_queryTab->setTabText(2, QString("Results (%1)").arg(m_matches.count())); + m_queryTab->setCurrentIndex(2); +} + +void QTestBrowserDlg::clearQuery() +{ + for (int i=0; i<m_queryTable->rowCount()-1;) { + m_queryTable->removeRow(i); + } +} + +void QTestBrowserDlg::copyQuery() +{ + QVariantMap map = queryMap(); + if (map.isEmpty()) { + return; + } +// QApplication::clipboard()->setText(m_test->objectToString(map)); +} + +void QTestBrowserDlg::expandAll() +{ + m_tree->expandAll(); + m_tree->scrollToItem(m_tree->currentItem()); +} + +void QTestBrowserDlg::collapseAll() +{ + + m_tree->collapseAll(); + m_tree->scrollToItem(m_tree->currentItem()); +} + +void QTestBrowserDlg::refresh() +{ + setObjectMap(m_test->getObjects(m_baseItem)); + refreshImage(); +} + +void QTestBrowserDlg::refreshImage() +{ + m_tree->setEnabled(false); + QImage img(m_test->grabImage(m_imgItem)); + m_origin = m_geometry[m_imgItem["_signature_"].toString()].toRect().topLeft(); + setImage(QPixmap::fromImage(img)); + m_tree->setEnabled(true); +} + +void QTestBrowserDlg::showMatch(int index) +{ + selectItem(m_matches[index]); +} + +void QTestBrowserDlg::viewMethods() +{ + QString currentItem = currentTabSignature(); + QVariantList methods = + m_test->getMethods(widgetSpec(currentItem)); + + QTableWidget *methodsTable = new QTableWidget(); + initMethodsTable(methodsTable); + updateMethodsTable(methodsTable, methods); + int newTabIndex = m_propertyTab->addTab(methodsTable, QString("Methods: %1").arg(currentItem)); + m_tabItemSignatures.append(currentItem); + m_propertyTab->setCurrentIndex(newTabIndex); +} + +void QTestBrowserDlg::onPropertyDoubleClicked(QTableWidgetItem *item) +{ + QString itemText = item->text(); + if (m_treeMap.contains(itemText)) { + selectItem(itemText); + } else { + QVariant value = item->data(Qt::UserRole); + if (value.type() == QVariant::Map) { + QVariantMap map = value.toMap(); + if (map.contains(QstConnection::signatureProperty)) { + openPropertyTab(map[QstConnection::signatureProperty].toString()); + } + } + } +} + +void QTestBrowserDlg::openPropertyTab(const QString &signature) +{ + QVariantMap propertyMap = + m_test->getProperties(widgetSpec(signature)); + + QTableWidget *propertyTable = new QTableWidget(); + initPropertyTable(propertyTable); + updatePropertyTable(propertyTable, propertyMap); + int newTabIndex = m_propertyTab->addTab(propertyTable, QString("Properties: %1").arg(signature)); + m_tabItemSignatures.append(signature); + m_propertyTab->setCurrentIndex(newTabIndex); + +} + +void QTestBrowserDlg::onTabCloseRequested(int tabIndex) +{ + if (tabIndex > 0) { + QWidget *w = m_propertyTab->widget(tabIndex); + m_propertyTab->removeTab(tabIndex); + delete w; + m_tabItemSignatures.removeAt(tabIndex); + } +} + +QString QTestBrowserDlg::currentTabSignature() const +{ + return m_tabItemSignatures.at(m_propertyTab->currentIndex()); +} + +void QTestBrowserDlg::onPropertyContextMenu(const QPoint &pos) +{ + QTableWidget *propertyTable = qobject_cast<QTableWidget*>(m_propertyTab->currentWidget()); + if (propertyTable) { + m_contextTableItem = propertyTable->itemAt(pos); + QMenu menu(this); + + m_methodsAction->setText(QString("View Methods for %1").arg(currentTabSignature())); + menu.addAction(m_propertyRefreshAction); + menu.addSeparator(); + menu.addAction(m_methodsAction); + + if (tableItemIsWidgetIdentifier(m_contextTableItem)) { + m_propertyMethodsAction->setText(QString("View Methods for %1").arg(m_contextTableItem->text())); + m_propertyPropertiesAction->setText(QString("View Properties for %1").arg(m_contextTableItem->text())); + menu.addSeparator(); + menu.addAction(m_propertyMethodsAction); + menu.addAction(m_propertyPropertiesAction); + } + + // Add as Query Condition, only if item is not part of a list + // and the value is valid + if (m_contextTableItem + && propertyTable->rowSpan(m_contextTableItem->row(), 0) == 1 + && propertyTable->item(m_contextTableItem->row(), 1)->data(Qt::UserRole).isValid()) { + menu.addSeparator(); + menu.addAction(m_propertyQueryAction); + } + menu.addSeparator(); + menu.addAction(m_propertyCopyAction); + menu.addAction(m_propertyCopyTableAction); + menu.exec(propertyTable->mapToGlobal(pos)); + m_contextTableItem = 0; + } +} + +void QTestBrowserDlg::onMethodsContextMenu(const QPoint &pos) +{ + QTableWidget *propertyTable = qobject_cast<QTableWidget*>(m_propertyTab->currentWidget()); + if (propertyTable) { + m_contextTableItem = propertyTable->itemAt(pos); + QMenu menu(this); + menu.addAction(m_propertyCopyAction); + menu.addAction(m_propertyCopyTableAction); + menu.exec(propertyTable->mapToGlobal(pos)); + m_contextTableItem = 0; + } +} + +void QTestBrowserDlg::refreshProperties() +{ + QTableWidget *propertyTable = qobject_cast<QTableWidget*>(m_propertyTab->currentWidget()); + if (propertyTable) { + propertyTable->setCursor(Qt::WaitCursor); + QVariantMap propertyMap = + m_test->getProperties(widgetSpec(currentTabSignature())); + updatePropertyTable(propertyTable, propertyMap); + propertyTable->setCursor(Qt::ArrowCursor); + } +} + +void QTestBrowserDlg::viewPropertyMethods() +{ + if (m_contextTableItem) { + QString signature = m_contextTableItem->text(); + QVariantList methods = + m_test->getMethods(widgetSpec(signature)); + + QTableWidget *methodsTable = new QTableWidget(); + initMethodsTable(methodsTable); + updateMethodsTable(methodsTable, methods); + int newTabIndex = m_propertyTab->addTab(methodsTable, QString("Methods: %1").arg(signature)); + m_tabItemSignatures.append(signature); + m_propertyTab->setCurrentIndex(newTabIndex); + } +} + +void QTestBrowserDlg::viewPropertyProperties() +{ + if (m_contextTableItem) { + QString signature = m_contextTableItem->text(); + openPropertyTab(signature); + } +} + +void QTestBrowserDlg::addPropertyAsQueryCondition() +{ + if (m_contextTableItem) { + int row = m_contextTableItem->row(); + QTableWidget *table = m_contextTableItem->tableWidget(); + QTableWidgetItem *propertyItem = table->item(row, 0); + QTableWidgetItem *valueItem = table->item(row, 1); + QVariant value = valueItem->data(Qt::UserRole); + if (value.type() == QVariant::Map) { + QVariantMap map = value.toMap(); + if (map.contains("_enum_")) + value = map.value("_enum_"); + else if (map.contains("_signature_")) + value = map.value("_signature_"); + else + return; + } + addQueryRow(propertyItem->text(), value); + } + m_queryTab->setCurrentIndex(0); +} + +void QTestBrowserDlg::copyTableItemValue() +{ + if (m_contextTableItem) { + QApplication::clipboard()->setText(m_contextTableItem->text()); + } +} + +void QTestBrowserDlg::copyTable() +{ + QTableWidget *propertyTable = qobject_cast<QTableWidget*>(m_propertyTab->currentWidget()); + QString text; + for (int row = 0; row < propertyTable->rowCount(); ++row) { + for (int col = 0; col < propertyTable->columnCount(); ++col) { + QString cellText; + QTableWidgetItem *item = propertyTable->item(row, col); + if (item) { + cellText = propertyTable->item(row, col)->text(); + } + text += QString("%1%2").arg(col ? "\t" : "").arg(cellText); + } + text += QLatin1String("\n"); + } + QApplication::clipboard()->setText(text); +} + +bool QTestBrowserDlg::tableItemIsWidgetIdentifier(const QTableWidgetItem *item) +{ + if (!item) return false; + QVariant value = item->data(Qt::UserRole); + return value.type() == QVariant::Map + && value.toMap().contains(QstConnection::signatureProperty); +} + +QVariantMap QTestBrowserDlg::widgetSpec(const QString &signature) +{ + return m_test->widgetFromSignature(signature, m_appId); +} + +void QTestBrowserDlg::onConnectionClosed() +{ + QMessageBox::warning(this, tr("Connection Lost"), tr("Connection to the test system has been lost.")); +} + +void QTestBrowserDlg::onQueryItemChanged(QTableWidgetItem *item) +{ + if (item->column() == 0 && item->checkState() == Qt::Unchecked) { + m_queryTable->removeRow(item->row()); + } +} + +void QTestBrowserDlg::onQueryContextMenu(const QPoint &pos) +{ + QMenu menu(this); + + menu.addAction(m_queryClearAction); + menu.addAction(m_queryCopyAction); + + menu.exec(m_queryTable->mapToGlobal(pos)); +} + +void QTestBrowserDlg::onResultsItemSelected() +{ + selectItem(m_resultsTable->item(m_resultsTable->currentRow(), 0)->text()); +} + +void QTestBrowserDlg::onMenuQueryCondition(QAction *action) +{ + addQueryRow(action->text(), currentTabSignature()); + m_queryTab->setCurrentIndex(0); +} + +void QTestBrowserDlg::onAppFinished(const QString& appId) +{ + updateAppContext(); + if (appId == m_appId) { + QMessageBox::warning(this, tr("Application Closed"), tr("The application was closed.")); + setBaseItems(); + } +} + +void QTestBrowserDlg::onAppStarted(const QString& appId) +{ + Q_UNUSED(appId); + updateAppContext(); +} + +bool QTestBrowserDlg::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == m_appContext && event->type() == QEvent::MouseButtonPress) { + for (int i=0; i<m_appContext->count(); i++) { + if (m_appContext->itemText(i).isEmpty()) { + QVariantMap appData = m_test->applicationData(m_appContext->itemData(i).toString()); + m_appContext->setItemText(i, appData["appId"].toString()); + } + } + return false; + } else { + return QDialog::eventFilter(obj, event); + } +} |