diff options
Diffstat (limited to 'old/libqtslave/qtestwidgets.cpp')
-rw-r--r-- | old/libqtslave/qtestwidgets.cpp | 1000 |
1 files changed, 1000 insertions, 0 deletions
diff --git a/old/libqtslave/qtestwidgets.cpp b/old/libqtslave/qtestwidgets.cpp new file mode 100644 index 0000000..45f3770 --- /dev/null +++ b/old/libqtslave/qtestwidgets.cpp @@ -0,0 +1,1000 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of QtUiTest. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtestwidgets.h> +#include <QtGui> + +#define qLog(A) if (1); else qDebug() << #A + +bool active_test_widget_valid = false; + +uint qHash(QPointer<QObject> o) +{ return qHash((QObject*)o); } + +inline QString dehyphenate(const QString& in) +{ return QString(in).remove(QChar(0x00AD)); } + +/*! + Returns a unique string identifier for \a object. +*/ +QString QTestWidgets::signature( const QObject *object ) +{ + if (!object) return "ERROR_NO_OBJECT"; + return uniqueName(object); +} + +/*! + Returns a name for the object that is unique within the same peer level. +*/ +QString QTestWidgets::uniqueName( const QObject *o ) +{ + if (o && o->metaObject()) { + return QString("%1[%2]").arg(o->metaObject()->className()).arg((long)(void*)o,0,32).replace(' ', '_'); + } + + return "err_uniqueName"; +} + +/* + Returns the best matching buddy widget for the \a label by scanning through \a search_list. + The match is done based on the position information. +*/ +QObject* QTestWidgets::locateBuddy( const QObject *label, const QObjectList &search_list ) +{ + if (label == 0) return false; + QtUiTest::Widget* lw = qtuitest_cast<QtUiTest::Widget*>(label); + + QtUiTest::LabelOrientation orientation = QtUiTest::labelOrientation(); + int start = 0; + int end = 0; + int highNearEdge = 0; + int lowNearEdge = 0; + + if (orientation == QtUiTest::LabelLeft || orientation == QtUiTest::LabelRight) { + start = lw->y(); + end = start + lw->height(); + + if (orientation == QtUiTest::LabelLeft) + lowNearEdge = lw->x() + lw->width(); + else + highNearEdge = lw->x(); + + } else if (orientation == QtUiTest::LabelBelow || orientation == QtUiTest::LabelAbove) { + start = lw->x(); + end = start + lw->width(); + + if (orientation == QtUiTest::LabelBelow) + highNearEdge = lw->y(); + else + lowNearEdge = lw->y() + lw->height(); + } + + QObject *buddy = 0; + int w_start = 0; + int w_end = 0; + int nearest = -1; + + foreach(QObject *w, search_list) { + QtUiTest::Widget* qw = qtuitest_cast<QtUiTest::Widget*>(w); + if ( w && w != label && QTestWidgets::widgetVisible(w)) { + + if (orientation == QtUiTest::LabelLeft || orientation == QtUiTest::LabelRight) { + w_start = qw->y(); + w_end = w_start + qw->height(); + + if (orientation == QtUiTest::LabelLeft) + highNearEdge = qw->x(); + else + lowNearEdge = qw->x() + qw->width(); + } else if (orientation == QtUiTest::LabelBelow || orientation == QtUiTest::LabelAbove) { + w_start = qw->x(); + w_end = w_start + qw->width(); + + if (orientation == QtUiTest::LabelBelow) + lowNearEdge = qw->y() + qw->height(); + else + highNearEdge = qw->y(); + } + + if ((start == w_start || + (start < w_start && end > w_start) || + (start > w_start && start < w_end)) && + (lowNearEdge < highNearEdge) && + (!w->inherits("QGroupBox")) && + (!w->inherits("QToolBox"))) { + int distance = highNearEdge - lowNearEdge; + if (nearest == -1 || nearest > distance) { + nearest = distance; + buddy = w; + } + + } + } + } + + return buddy; +} + +/* + Returns true if the widget is truly visible, i.e. the widget claims it is visible, + all parents are visible and a parent is the activeWindow. +*/ +bool QTestWidgets::widgetVisible( QObject *widget ) +{ + if (widget == 0) return false; + QtUiTest::Widget* w = qtuitest_cast<QtUiTest::Widget*>(widget); + QtUiTest::Widget* aw = qtuitest_cast<QtUiTest::Widget*>(activeWidget()); + bool is_active = (aw == 0); + while (w) { + if (!w->isVisible()) return false; + if (w == aw) is_active = true; + w = qtuitest_cast<QtUiTest::Widget*>(w->parent()); + } + return is_active; +} + +/*! + Returns the testWidget that is associated with the given \a signature. +*/ +QObject *QTestWidgets::testWidget( const QString signature ) +{ + if (signature.isEmpty()) { + return focusWidget(); + } + + return QActiveTestWidget::instance()->testWidget(signature); +} + +QObject *QActiveTestWidget::testWidget( const QString &signature ) +{ + QObject *rec = d->testWidgetsBySignature.value( signature, 0 ); + return rec; +} + +void QActiveTestWidget::registerTestWidget( QObject *ao ) +{ + QString new_signature = QTestWidgets::signature( ao ); + d->testWidgetsBySignature[new_signature] = ao; + connect( ao, SIGNAL(destroyed(QObject*)), this, SLOT(onDestroyed(QObject*)), Qt::DirectConnection ); +} + +void QActiveTestWidget::onDestroyed(QObject *o) +{ + if (o) { + d->removeTestWidget(o); + } +} + +/*! + \internal + + Returns a list of all top-level QObjects in the current application. +*/ +QObjectList QTestWidgets::topLevelObjects() +{ + QWidgetList wl = qApp->topLevelWidgets(); + QObjectList ol = qApp->children(); + foreach(QWidget *w, wl) { + if (!ol.contains(w)) ol << w; + } + return ol; +} + +/*! + Returns the current activeWindow, activePopupWidget or activeModalWidget. +*/ +QObject* QTestWidgets::activeWidget() +{ + QObject *fw = focusWidget(); + + QObject *w = 0; + if (qApp) { + if (w == 0) w = qApp->activeModalWidget(); + if (w == 0) w = qApp->activePopupWidget(); + if (w == 0) w = qApp->activeWindow(); + } + + if (!w) w = fw; + return w; +} + +/* + Returns the widget that has focus. +*/ +QObject* QTestWidgets::focusWidget() +{ + QObject *fw = qApp->focusWidget(); + QtUiTest::Widget *qw = qtuitest_cast<QtUiTest::Widget*>(fw); + + // The widget with focus might not be a QWidget, eg, could + // be an item in a QGraphicsView. Use focusProxy to find + // the actual item with focus. + if (qw) { + QObject *focusProxy = qw->focusProxy(); + while (focusProxy) { + fw = focusProxy; + qw = qtuitest_cast<QtUiTest::Widget*>(fw); + focusProxy = qw ? qw->focusProxy() : 0; + } + } + + return fw; +} + +QStringList QTestWidgets::objectListToSignatures(const QObjectList& ol) +{ + QStringList ret; + foreach (QObject *obj, ol) { + ret << QTestWidgets::signature(obj); + } + return ret; +} + +QString QTestWidgets::labelText(const QString& text) +{ + return text.trimmed().replace(QRegExp("&(.)"), "\\1"); +} + +// ********************************************************************** + +QActiveTestWidgetData::QActiveTestWidgetData() +{ +} + +QActiveTestWidgetData::~QActiveTestWidgetData() +{ +} + +void QActiveTestWidgetData::clear() +{ + resolved_buddy_pairs.clear(); + visible_tw_buddies.clear(); + unresolved_tw_buddies.clear(); + visible_tw_labels.clear(); + unresolved_tw_labels.clear(); + app_windows.clear(); + testWidgetsBySignature.clear(); +} + +void QActiveTestWidgetData::removeTestWidget( QObject *w ) +{ + resolved_buddy_pairs.remove(w); + visible_tw_buddies.removeAll(w); + unresolved_tw_buddies.removeAll(w); + visible_tw_labels.removeAll(w); + unresolved_tw_labels.removeAll(w); + app_windows.removeAll(w); + testWidgetsBySignature.remove( QTestWidgets::signature(w) ); +} + +bool QActiveTestWidgetData::scan( QObject *ao ) +{ + //FIXME: Investigate next line - required? + if (qobject_cast<QAbstractSpinBox*>(ao)) return false; + + QActiveTestWidget::instance()->registerTestWidget(ao); + + QtUiTest::Widget* aw = qtuitest_cast<QtUiTest::Widget*>(ao); + if (aw == 0) return false; + + bool any_appended = false; + foreach(QObject *o, aw->children()) { + QActiveTestWidget::instance()->registerTestWidget(o); + + if (!QTestWidgets::widgetVisible(o)) { + continue; + } + + // Recursively scan child widgets + any_appended |= scan(o); + + QtUiTest::Widget* qw = qtuitest_cast<QtUiTest::Widget*>(o); + + QtUiTest::LabelWidget* lw = qtuitest_cast<QtUiTest::LabelWidget*>(o); + if (lw && lw->labelText() != "") { + visible_tw_labels.append(o); + } + + if (qw->ignoreScan()) { + continue; + } + + if (!visible_tw_buddies.contains(o)) { + any_appended = true; + visible_tw_buddies.append(o); + } + } + + return any_appended; +} + +void QActiveTestWidgetData::scanWindows() +{ + app_windows.clear(); + foreach (QWidget *w, qApp->topLevelWidgets()) { + if (w->isWindow() && !w->windowTitle().isEmpty()) { + app_windows.append(w); + } + } +} + +void QActiveTestWidgetData::resolveLabels() +{ + // resolve relationship between label and buddy fields + unresolved_tw_labels = visible_tw_labels; + unresolved_tw_buddies = visible_tw_buddies; + foreach (QObject *w, visible_tw_labels) { + QObject *buddy = 0; + QtUiTest::LabelWidget* lw = qtuitest_cast<QtUiTest::LabelWidget*>(w); + + if (lw) { + buddy = lw->buddy(); + } + + if (!buddy) + buddy = QTestWidgets::locateBuddy( w, visible_tw_buddies ); + + if (!buddy) continue; + + // If the buddy has a focus proxy, set that as the actual buddy, + // as that's the widget that will always receive focus. + QtUiTest::Widget *qbuddy = qtuitest_cast<QtUiTest::Widget*>(buddy); + QObject *focusProxy = qbuddy->focusProxy(); + while (focusProxy) { + buddy = focusProxy; + qbuddy = qtuitest_cast<QtUiTest::Widget*>(focusProxy); + focusProxy = qbuddy ? qbuddy->focusProxy() : 0; + } + + resolved_buddy_pairs.insert( w, buddy ); + unresolved_tw_buddies.removeAll( buddy ); + unresolved_tw_labels.removeAll( buddy ); + if (buddy != w) visible_tw_labels.removeAll( buddy ); + unresolved_tw_labels.removeAll( w ); + } +} + +void QActiveTestWidgetData::sort() +{ + qStableSort(visible_tw_buddies.begin(), visible_tw_buddies.end(), QTestWidgets::lessThan); + qStableSort(visible_tw_labels.begin(), visible_tw_labels.end(), QTestWidgets::lessThan); +} + +QObject* QActiveTestWidgetData::findWidgetByLabel( const QString &text, QString &error ) +{ + error = ""; + QObjectList possibleMatches; + QObjectList definiteMatches; + QString labelText = QTestWidgets::labelText(text); + + foreach (QObject *o, resolved_buddy_pairs.keys()) { + QtUiTest::LabelWidget* lw = qtuitest_cast<QtUiTest::LabelWidget*>(o); + QtUiTest::TextWidget* tw = qtuitest_cast<QtUiTest::TextWidget*>(o); + if (lw && QTestWidgets::labelText(lw->labelText()) == labelText) { + definiteMatches << resolved_buddy_pairs[o]; + } else if (tw && QTestWidgets::labelText(tw->selectedText()) == labelText) { + possibleMatches << resolved_buddy_pairs[o]; + } + } + if (definiteMatches.count() == 1 || definiteMatches.toSet().count() == 1) { + return definiteMatches[0]; + } + if (definiteMatches.count() > 1 && definiteMatches.toSet().count() > 1) { + error = "ERROR: '" + labelText + "' is ambiguous.\n Available labels: " + allLabels().join(","); + return 0; + } + + // No definite matches. + if (possibleMatches.count() == 1 || possibleMatches.toSet().count() == 1) { + return possibleMatches[0]; + } + if (possibleMatches.count() > 1 && possibleMatches.toSet().count() > 1) { + error = "ERROR: '" + labelText + "' is ambiguous.\n Available labels: " + allLabels().join(","); + return 0; + } + + error = "ERROR: No label with text '" + labelText + "' found.\n Available labels: " + allLabels().join(","); + return 0; +} + +QObjectList QActiveTestWidgetData::findWidgetsByLabel( const QString &text ) +{ + QObjectList matches; + QString labelText = QTestWidgets::labelText(text); + + for (int i=0; i<visible_tw_labels.count(); i++) + { + QObject *o = qobject_cast<QObject*>(visible_tw_labels.at(i)); + if (o) { + QtUiTest::LabelWidget* lw = qtuitest_cast<QtUiTest::LabelWidget*>(o); + QtUiTest::TextWidget* tw = qtuitest_cast<QtUiTest::TextWidget*>(o); + if ((lw && QTestWidgets::labelText(lw->labelText()) == labelText) || + (tw && QTestWidgets::labelText(tw->selectedText()) == labelText)) { + matches << resolved_buddy_pairs[o]; + } + } + } + + return matches; +} + +bool QActiveTestWidgetData::findWidget( const QString &labelOrSignature, QObject *&buddy, QString &error, int offset ) +{ + error = ""; + buddy = 0; + + qLog(QtUitest) << QString("QActiveTestWidgetData::findWidget(%1,%2)").arg(labelOrSignature).arg(offset).toLatin1(); + + if (labelOrSignature.contains("[") && labelOrSignature.contains("]")) { + // it's probably signature + buddy = QTestWidgets::testWidget(labelOrSignature); + } + + if (buddy == 0) { + if (!QActiveTestWidget::instance()->rescan(error)) return false; + buddy = findWidgetByLabel(labelOrSignature, error); + } + + if (buddy != 0 && offset == 0) { + qLog(QtUitest) << QString("QActiveTestWidgetData::findWidget(offset=0) ... found: " + QTestWidgets::signature(buddy)).toLatin1(); + + return true; + } + + int index = 0; + int pos = visible_tw_buddies.indexOf(buddy); + if (pos < 0) { + error = "ERROR: Buddy widget for '" + labelOrSignature + "' not found.\nAvailable labels: " + allLabels().join(","); + return false; + } + index = pos + offset; + + qLog(QtUitest) << QString("QActiveTestWidgetData::findWidget(offset=%1) index=%2 ").arg(offset).arg(index).toLatin1(); + + if ((index >= 0) && (index < visible_tw_buddies.count())) { + buddy = qobject_cast<QObject*>(visible_tw_buddies.at(index)); + if (buddy) + return true; + } + + return false; +} + +QWidget *QActiveTestWidgetData::findWindow( const QString &titleOrSignature ) +{ + QWidget *ret = 0; + foreach (QObject *o, app_windows) { + QWidget *window = qobject_cast<QWidget*>(o); + if (window && + (window->windowTitle() == titleOrSignature || + QTestWidgets::signature(window) == titleOrSignature)) { + return window; + } + } + return ret; +} + +QStringList QActiveTestWidgetData::allLabels() +{ + QStringList ret; + foreach (QObject *label, visible_tw_labels) { + QtUiTest::LabelWidget* lw = qtuitest_cast<QtUiTest::LabelWidget*>(label); + if (label) ret << lw->labelText(); + } + return ret; +} + +QStringList QActiveTestWidgetData::getWindowTitles() +{ + QStringList ret; + foreach (QObject *o, app_windows) { + QWidget *window = qobject_cast<QWidget*>(o); + if (window) ret << window->windowTitle(); + } + return ret; +} + +// **************************************************************** + +#include <QTime> +QActiveTestWidget::QActiveTestWidget() +{ + active_widget = 0; + d = new QActiveTestWidgetData(); + scan_busy = false; + active_test_widget_valid = false; +} + +QActiveTestWidget::~QActiveTestWidget() +{ + delete d; +} + +QActiveTestWidget* QActiveTestWidget::instance() +{ + static QActiveTestWidget qatw; + return &qatw; +} + +void QActiveTestWidget::clear() +{ + if (active_widget) active_widget->removeEventFilter(this); + active_widget = 0; + scan_time = 0; + if (d == 0) { + d = new QActiveTestWidgetData(); + } else + d->clear(); +} + +const QString QActiveTestWidget::NoActiveWidgetError("ERROR: No active widget available"); + +bool QActiveTestWidget::rescan( QString &error, int timeout ) +{ + if (scan_busy) return true; + scan_busy = true; + + if (d == 0) d = new QActiveTestWidgetData(); + + QTime t; + t.start(); + QObject *aw = 0; + while (aw == 0) { + if (!QApplication::startingUp()) { + aw = QTestWidgets::activeWidget(); + if (aw != 0) break; + } + if (t.elapsed() >= timeout) { + error = QString("%1 (timeout %2 ms)").arg(NoActiveWidgetError).arg(t.elapsed()); + scan_busy = false; + return false; + } + QtUiTest::wait(3); + } + + clear(); + if (aw == 0) { + error = "ERROR: No active widget available"; + scan_busy = false; + return false; + } + active_widget = aw; + active_widget->installEventFilter(this); + + d->scan(active_widget); + d->scanWindows(); + + d->resolveLabels(); + d->sort(); + scan_time = t.elapsed(); + + scan_busy = false; + active_test_widget_valid = true; + return true; +} + +//TODO: Should probably rewrite toString() +QString QActiveTestWidget::toString() +{ + QString ret; + if (!d) rescan(ret, 1000); + ret = QString("Application : %1").arg(qApp->applicationName()); + ret += "\nActive Widget: " + (active_widget ? QTestWidgets::signature(active_widget) : "(no active widget)"); + ret += "\nFocus Widget : " + QTestWidgets::signature(QTestWidgets::focusWidget()); + + bool first = true; + QHash< QPointer<QObject>,QPointer<QObject> >::iterator i = d->resolved_buddy_pairs.begin(); + while (i != d->resolved_buddy_pairs.end()) { + QObject *buddy_rec = i.value(); + QObject *lbl = i.key(); // must be label + QtUiTest::LabelWidget* lw = qtuitest_cast<QtUiTest::LabelWidget*>(lbl); + if (buddy_rec && lw) { + QString lbl_txt = lw->labelText(); + QtUiTest::LabelWidget* blw = qtuitest_cast<QtUiTest::LabelWidget*>(buddy_rec); + QString buddy_txt; + if (blw) + buddy_txt = blw->labelText(); + if (buddy_txt.length() > 50) + buddy_txt = buddy_txt.left(50) + " [...]"; + + QObject *buddy(buddy_rec); + Q_ASSERT(buddy); + QtUiTest::Widget *bw = qtuitest_cast<QtUiTest::Widget*>(buddy); + + QLatin1String cn(buddy->metaObject()->className()); + if (first) { + ret += "\nBuddypairs:"; + first = false; + } + ret += QString("\n Label: %1[%2] '%3' -- Buddy: %4[%5] '%6' x:%7 y:%8 h:%9 w:%10"). + arg(lbl->metaObject()->className()). + arg((long)(void*)lbl,0,32). + arg(lbl_txt). + arg(cn). + arg((long)(void*)buddy,0,32). + arg(buddy_txt). + arg(bw->x()). + arg(bw->y()). + arg(bw->height()). + arg(bw->width()); + } + ++i; + } + + first = true; + foreach(QObject* buddy_rec, d->unresolved_tw_buddies) { + if (buddy_rec) { + QtUiTest::Widget *bw = qtuitest_cast<QtUiTest::Widget*>(buddy_rec); + if (bw) { + if (first) { + ret += "\nWidgets without a buddy Label:"; + first = false; + } + ret += QString("\n %1 x:%2 y:%3 h:%4 w:%5").arg(QTestWidgets::signature(buddy_rec)).arg(bw->x()).arg(bw->y()).arg(bw->height()).arg(bw->width()).toLatin1(); + } + } + } + + first = true; + foreach(QObject* buddy_rec, d->unresolved_tw_buddies) { + if (buddy_rec) { + QtUiTest::Widget *bw = qtuitest_cast<QtUiTest::Widget*>(buddy_rec); + if (bw) { + if (first) { + ret += "\nDisabled widgets without a buddy Label:"; + first = false; + } + ret += QString("\n %1 x:%2 y:%3 h:%4 w:%5").arg(QTestWidgets::signature(buddy_rec)).arg(bw->x()).arg(bw->y()).arg(bw->height()).arg(bw->width()).toLatin1(); + } + } + } + + first = true; + foreach(QObject *lbl, d->unresolved_tw_labels) { + if (lbl) { + QtUiTest::Widget *vw = qtuitest_cast<QtUiTest::Widget*>(lbl); + QtUiTest::LabelWidget* lw = qtuitest_cast<QtUiTest::LabelWidget*>(lbl); + if (!vw || !lw) continue; + QString txt = lw->labelText(); + if (first) { + ret += "\nLabels without a buddy widget:"; + first = false; + } + ret += QString("\n %1 Text: %2 x:%3 y:%4 h:%5 w:%6").arg(QTestWidgets::signature(lbl)).arg(txt).arg(vw->x()).arg(vw->y()).arg(vw->height()).arg(vw->width()).toLatin1(); + } + } + + first = true; + foreach(QObject *tw, d->visible_tw_buddies) { + QtUiTest::Widget *bw = qtuitest_cast<QtUiTest::Widget*>(tw); + if (bw) { + if (first) { + ret += "\nBuddy widgets sorted on position:"; + first = false; + } + ret += QString("\n %1 x:%2 y:%3 h:%4 w:%5").arg(QTestWidgets::signature(tw)).arg(bw->x()).arg(bw->y()).arg(bw->height()).arg(bw->width()); + } + } + + return ret; +} + +QStringList QActiveTestWidget::allLabels() +{ + if (d) return d->allLabels(); + return QStringList("ERROR: No labels found"); +} + +QStringList QActiveTestWidget::getWindowTitles() +{ + QString error; + if (!d && !rescan(error)) return QStringList(error); + d->scanWindows(); + return d->getWindowTitles(); +} + +QWidget *QActiveTestWidget::findWindow( const QString &titleOrSignature ) +{ + QString error; + if (!d && !rescan(error)) return 0; + d->scanWindows(); + return d->findWindow(titleOrSignature); +} + +/*! + Returns the friendliest possible, unambiguous name for \a o. +*/ +QString QActiveTestWidget::friendlyName( QObject* o ) +{ + QtUiTest::Widget* w = qtuitest_cast<QtUiTest::Widget*>(o); + + if (!w) + return QTestWidgets::signature(o); + else if (w->inherits(QtUiTest::TabBar)) + return "tabBar()"; + + QString ret; + rescan(ret, 50); + + // Look through all of the buddy/label pairs. + // If this widget is in the list, then return its label as the friendly name. + QObject* label = 0; + QHash< QPointer<QObject>, QPointer<QObject> >::iterator i; + int focusableBuddyCount = 0; + for ( i = d->resolved_buddy_pairs.begin(); i != d->resolved_buddy_pairs.end(); ++i) { + QObject* buddy = i.value(); + if (!buddy) continue; + + // Determine if this widget can ever have focus. + QtUiTest::Widget *widget = qtuitest_cast<QtUiTest::Widget*>(buddy); + if (widget->focusPolicy() != Qt::NoFocus) { + ++focusableBuddyCount; + } + label = i.key(); + if (!label) continue; + + if (widget == w) + break; + + widget = qtuitest_cast<QtUiTest::Widget*>(label); + if (widget == w) + break; + label = 0; + } + + if (!label) { + // If this is the _only_ widget that can have focus, + // an empty string is good enough. + if (!focusableBuddyCount || ((1 == focusableBuddyCount) && w->hasFocus())) + return QString(); + return QTestWidgets::signature(o); + } + + // If we get here, then the widget was in the list of buddy/label pairs, + // so we can return the label text. + QtUiTest::LabelWidget* lw = qtuitest_cast<QtUiTest::LabelWidget*>(label); + if (lw) { + ret = QTestWidgets::labelText(lw->labelText()); + } else { + ret = QTestWidgets::signature(o); + } + return ret; +} + +bool QActiveTestWidget::findWidget( const QString &labelOrSignature, QObject *&buddy, QString &error, int offset ) +{ + bool was_valid = active_test_widget_valid; + bool ok = findWidget_impl(labelOrSignature,buddy,error,offset); + if (!ok && was_valid) { + active_test_widget_valid = false; + if (!rescan(error)) return false; + ok = findWidget_impl(labelOrSignature,buddy,error,offset); + } + if (!ok) error += "\n" + toString(); + return ok; +} + +bool QActiveTestWidget::findWidget_impl( const QString &labelOrSignature, QObject *&buddy, QString &error, int offset ) +{ + if (labelOrSignature.isEmpty()) { + buddy = QTestWidgets::focusWidget(); + if (buddy == 0) { + error = "ERROR: No focus Widget available\n"; + } + return buddy != 0; + } + + return d->findWidget( labelOrSignature, buddy, error, offset ); +} + +QObjectList QActiveTestWidget::findObjectsByProperty( const QString &property, const QVariant &searchValue, const QObjectList &initList ) +{ + QObjectList foundList; + QRegExp searchRegExp = searchValue.toRegExp(); + QString searchString = searchValue.toString(); + + if (!searchRegExp.isEmpty() && !searchRegExp.isValid()) + { + QtUiTest::setErrorString("Invalid regular expression"); + return foundList; + } + + QObjectList searchList(initList); + QString propertyUpper = property.toUpper(); + + if (searchList.isEmpty()) { + searchList << QTestWidgets::activeWidget(); + + foreach (QObject *tw, d->resolved_buddy_pairs.values()) { + if (!searchList.contains(tw)) searchList << tw; + } + + foreach (QObject *tw, d->unresolved_tw_buddies) { + if (!searchList.contains(tw)) searchList << tw; + } + + foreach (QObject *l, d->visible_tw_labels) { + if (!searchList.contains(l)) searchList << l; + } + } + + QObjectList filterList; + if (propertyUpper == "LABEL") { + filterList = d->findWidgetsByLabel(searchValue.toString()); + } else if (propertyUpper == "CHILD_OF") { + QObject *parent; + QString error; + QString labelOrSignature(searchValue.toString()); + if (findWidget_impl(labelOrSignature, parent, error, 0)) { + QtUiTest::Widget *qw = qtuitest_cast<QtUiTest::Widget*>(parent); + if (qw) filterList = qw->children(); + } + } else if (propertyUpper == "DESCENDANT_OF") { + QObject *parent; + QString error; + QString labelOrSignature(searchValue.toString()); + if (findWidget_impl(labelOrSignature, parent, error, 0)) { + QtUiTest::Widget *qw = qtuitest_cast<QtUiTest::Widget*>(parent); + if (qw) qw->descendants(filterList); + } + } else if (propertyUpper == "PARENT_OF") { + QObject *child; + QString error; + QString labelOrSignature(searchValue.toString()); + if (findWidget_impl(labelOrSignature, child, error, 0)) { + QtUiTest::Widget *qw = qtuitest_cast<QtUiTest::Widget*>(child); + filterList << qw->parent(); + } + } + + foreach (QObject *obj, searchList) { + + QtUiTest::Widget *w = qtuitest_cast<QtUiTest::Widget*>(obj); + if (w) { + QVariant value = w->getProperty(property); + if (value.isValid()) { + if (QObject *obj = value.value<QObject*>()) { + value = QTestWidgets::signature(obj); + } + if ((value == searchValue) || + (value.canConvert(QVariant::String) && value.toString() == searchString)) { + foundList << obj; + } else if (!searchRegExp.isEmpty() && searchRegExp.exactMatch(value.toString())) { + foundList << obj; + } + continue; + } + } + + QMetaObject const *mo = obj->metaObject(); + + // Handle className like a property + if (propertyUpper == "CLASSNAME" && mo->className() == searchValue) { + foundList << obj; + continue; + } + + if (propertyUpper == "INHERITS" && obj->inherits(searchValue.toString().toLatin1())) { + foundList << obj; + continue; + } + + if ((propertyUpper == "LABEL" || + propertyUpper == "CHILD_OF" || + propertyUpper == "DESCENDANT_OF" || + propertyUpper == "PARENT_OF") && filterList.contains(obj)) { + foundList << obj; + continue; + } + + if (propertyUpper == "TESTWIDGET") { + if ((searchValue == "ActivateWidget" && qtuitest_cast<QtUiTest::ActivateWidget*>(obj)) || + (searchValue == "LabelWidget" && qtuitest_cast<QtUiTest::LabelWidget*>(obj)) || + (searchValue == "CheckWidget" && qtuitest_cast<QtUiTest::CheckWidget*>(obj)) || + (searchValue == "CheckItemWidget" && qtuitest_cast<QtUiTest::CheckItemWidget*>(obj)) || + (searchValue == "TextWidget" && qtuitest_cast<QtUiTest::TextWidget*>(obj)) || + (searchValue == "ListWidget" && qtuitest_cast<QtUiTest::ListWidget*>(obj)) || + (searchValue == "InputWidget" && qtuitest_cast<QtUiTest::InputWidget*>(obj)) || + (searchValue == "SelectWidget" && qtuitest_cast<QtUiTest::SelectWidget*>(obj)) || + (searchValue == "IndexedWidget" && qtuitest_cast<QtUiTest::IndexedWidget*>(obj))) { + foundList << obj; + continue; + } + } + + // Accessibility properties (preliminary support) +#ifndef QT_NO_ACCESSIBILITY + if (propertyUpper == "ROLE") { + QAccessibleInterface *accIface = QAccessible::queryAccessibleInterface(obj); + if (accIface && accIface->role(0) == searchValue.toInt()) + foundList << obj; + delete accIface; + continue; + } + + if (propertyUpper == "STATE") { + QAccessibleInterface *accIface = QAccessible::queryAccessibleInterface(obj); + if (accIface && accIface->state(0) & searchValue.toInt()) + foundList << obj; + delete accIface; + continue; + } +#endif + + } + + return foundList; +} + +QObjectList QActiveTestWidget::findObjectsByProperty( const QVariantMap &searchValues ) +{ + QObjectList searchList; + + QVariantMap::const_iterator i = searchValues.constBegin(); + while (i != searchValues.constEnd()) { + searchList = findObjectsByProperty(i.key(), i.value(), searchList); + if (searchList.isEmpty()) + break; + ++i; + } + + return searchList; +} + +bool QActiveTestWidget::eventFilter(QObject * /*obj*/, QEvent *event) +{ + if (event->type() == QEvent::Hide || + event->type() == QEvent::Show || + event->type() == QEvent::EnabledChange || +#ifdef Q_WS_QWS + event->type() == QEvent::EnterEditFocus || + event->type() == QEvent::LeaveEditFocus || +#endif + event->type() == QEvent::ParentChange || + event->type() == QEvent::FocusIn || + event->type() == QEvent::FocusOut || + event->type() == QEvent::HideToParent || + event->type() == QEvent::ShowToParent || + event->type() == QEvent::WindowTitleChange || + event->type() == QEvent::ChildAdded || + event->type() == QEvent::ChildRemoved ) active_test_widget_valid = false; + return false; +} |