summaryrefslogtreecommitdiffstats
path: root/old/plugins/qtuitest_widgets/qtwidgets/testdatetimeedit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'old/plugins/qtuitest_widgets/qtwidgets/testdatetimeedit.cpp')
-rw-r--r--old/plugins/qtuitest_widgets/qtwidgets/testdatetimeedit.cpp477
1 files changed, 477 insertions, 0 deletions
diff --git a/old/plugins/qtuitest_widgets/qtwidgets/testdatetimeedit.cpp b/old/plugins/qtuitest_widgets/qtwidgets/testdatetimeedit.cpp
new file mode 100644
index 0000000..4ce47dc
--- /dev/null
+++ b/old/plugins/qtuitest_widgets/qtwidgets/testdatetimeedit.cpp
@@ -0,0 +1,477 @@
+/****************************************************************************
+**
+** 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 "testdatetimeedit.h"
+#include "testwidgetslog.h"
+
+#include <QLayout>
+#include <QLineEdit>
+#include <QStyleOptionSpinBox>
+
+namespace QtUiTest {
+
+TestDateTimeEdit::TestDateTimeEdit(QObject* _q)
+ : TestGenericTextWidget(_q), q(qobject_cast<QDateTimeEdit*>(_q))
+{
+ TestWidgetsLog();
+ connect(q, SIGNAL(dateTimeChanged(QDateTime)),
+ this, SLOT(onDateTimeChanged(QDateTime)));
+}
+
+void TestDateTimeEdit::onDateTimeChanged(const QDateTime& dt)
+{ emit entered(dt); }
+
+QString TestDateTimeEdit::text() const
+{
+ TestWidgetsLog();
+ return q->dateTime().toString();
+}
+
+QVariant TestDateTimeEdit::value() const
+{
+ return q->dateTime();
+}
+
+QRegExp dateFormatToRegExp(const QString& format)
+{
+ QString re;
+ QString fmt = format;
+
+#define REPLACE_TOK(A,B) \
+ if (fmt.startsWith(A)) { \
+ re += B; \
+ fmt.remove(0, qstrlen(A)); \
+ continue; \
+ }
+ while (!fmt.isEmpty()) {
+ REPLACE_TOK("yyyy", "(\\d{4})");
+ REPLACE_TOK("yy", "(\\d{2})");
+
+ REPLACE_TOK("MMMM", "(\\w+)");
+ REPLACE_TOK("MMM", "(\\w+)");
+ REPLACE_TOK("MM", "([01]\\d)");
+ REPLACE_TOK("M", "(\\d\\d?)");
+
+ REPLACE_TOK("dddd", "(\\w+)");
+ REPLACE_TOK("ddd", "(\\w+)");
+ REPLACE_TOK("dd", "([0123]\\d)");
+ REPLACE_TOK("d", "(\\d{1,2})");
+
+ REPLACE_TOK("hh", "([012]\\d)");
+ REPLACE_TOK("h", "(\\d{1,2})");
+
+ REPLACE_TOK("HH", "([012]\\d)");
+ REPLACE_TOK("H", "(\\d{1,2})");
+
+ REPLACE_TOK("mm", "([0-5]\\d)");
+ REPLACE_TOK("m", "(\\d{1,2})");
+
+ REPLACE_TOK("ss", "([0-5]\\d)");
+ REPLACE_TOK("s", "(\\d{1,2})");
+
+ REPLACE_TOK("zzz", "(\\d{3})");
+ REPLACE_TOK("z", "(\\d{0,3})");
+
+ REPLACE_TOK("AP", "(AM|PM)");
+ REPLACE_TOK("ap", "(am|pm)");
+ REPLACE_TOK("A", "(AM|PM)");
+ REPLACE_TOK("a", "(am|pm)");
+
+ re += QString("\\x%1").arg(fmt.at(0).unicode(), 4, 16, QChar('0'));
+ fmt.remove(0,1);
+ }
+#undef REPLACE_TOK
+
+ TestWidgetsLog() << format << "resulted in" << re;
+
+ return QRegExp(re);
+}
+
+bool TestDateTimeEdit::canEnter(const QVariant& item) const
+{
+ QString text;
+ if (item.canConvert<QDateTime>()) {
+ text = item.value<QDateTime>().toString( q->displayFormat() );
+ } else if (item.canConvert<QDate>()) {
+ text = item.value<QDate>().toString( q->displayFormat() );
+ } else if (item.canConvert<QTime>()) {
+ text = item.value<QTime>().toString( q->displayFormat() );
+ } else {
+ text = item.toString();
+ }
+ int dont_care = 0;
+ TestWidgetsLog() << text << "format:" << q->displayFormat();
+ bool ret = (QValidator::Acceptable ==
+ static_cast<QAbstractSpinBox*>(q)->validate(text, dont_care));
+ if (ret) {
+ TestWidgetsLog() << "Can enter" << item;
+ } else {
+ TestWidgetsLog() << "Can't enter" << item;
+ }
+ return ret;
+}
+
+QPoint TestDateTimeEdit::nextClick( const QStringList& cap,
+ QMap<QDateTimeEdit::Section,int> const& capMap,
+ bool *final, bool *ok)
+{
+ if (ok) *ok = false;
+ if (final) *final = false;
+
+ QPoint ret;
+
+ int activeSection = -1;
+ int moveUpDown = 0;
+ int sectionsNeedingChanges = 0;
+ bool ampm = q->displayedSections() & QDateTimeEdit::AmPmSection;
+
+ /* Sections, from most to least significant.
+ * It is necessary to edit most significant first because that can affect
+ * the allowed values from less significant fields (e.g., can't select
+ * '30' in days if '02' is selected for month).
+ */
+ static const QDateTimeEdit::Section sections[] = {
+ QDateTimeEdit::YearSection,
+ QDateTimeEdit::MonthSection,
+ QDateTimeEdit::DaySection,
+ QDateTimeEdit::HourSection,
+ QDateTimeEdit::MinuteSection,
+ QDateTimeEdit::SecondSection,
+ QDateTimeEdit::MSecSection,
+ QDateTimeEdit::AmPmSection,
+ (QDateTimeEdit::Section)0
+ };
+
+ {
+ int i = 0;
+ for (QDateTimeEdit::Section section = sections[i];
+ section;
+ section = sections[++i]) {
+ if (!(q->displayedSections() & section)) continue;
+ QString text = q->sectionText(section);
+ int cap_i = capMap.value(section);
+ TestWidgetsLog() << "i" << i << "text" << text << "cap_i" << cap_i
+ << "cap" << cap.at(cap_i);
+ if (text != cap.at(cap_i)) {
+ ++sectionsNeedingChanges;
+ if (-1 == activeSection) {
+ bool is_int = false;
+ int src = text.toInt(&is_int);
+ int dest = cap.at(cap_i).toInt(&is_int);
+ if (!is_int && section == QDateTimeEdit::MonthSection) {
+ if (q->displayFormat().contains("MMMM")) {
+ moveUpDown = QDate::fromString(cap.at(cap_i), "MMMM").month() - QDate::fromString(text, "MMMM").month();
+ } else if (q->displayFormat().contains("MMM")) {
+ moveUpDown = QDate::fromString(cap.at(cap_i), "MMM").month() - QDate::fromString(text, "MMM").month();
+ }
+ } else if (section == QDateTimeEdit::AmPmSection) {
+ if (text.toUpper() == "PM")
+ moveUpDown = -1;
+ else
+ moveUpDown = 1;
+ } else if (section == QDateTimeEdit::HourSection && ampm && (dest == 12 || src == 12)) {
+ moveUpDown = (src - dest);
+ } else {
+ moveUpDown = (dest - src);
+ }
+ activeSection = cap_i;
+ }
+ }
+ }
+ }
+
+ /* If there is only one section that requires a change,
+ * AND that section is off the desired value by one,
+ * AND that section already has focus,
+ * then this should be the last necessary click. */
+ if (final && (1 == sectionsNeedingChanges) && (1 == qAbs(moveUpDown)) && q->currentSectionIndex() == activeSection)
+ *final = true;
+
+ TestWidgetsLog() << "activeSection" << activeSection << "currentSectionIndex" << q->currentSectionIndex();
+
+ if (-1 == activeSection) {
+ /* No clicking required; already at target value */
+ if (final) *final = true;
+ } else if (q->currentSectionIndex() != activeSection) {
+ /* Clicking required; need to move cursor to correct section */
+ int begin = -1, end = -1;
+ {
+ QString text = q->text();
+ for (int i = 0; i < activeSection; ++i) {
+ QString sec = q->sectionText(q->sectionAt(i));
+ text.replace(text.indexOf(sec), sec.length(), QString(sec.length(), '_'));
+ }
+ QString sec = q->sectionText(q->sectionAt(activeSection));
+ begin = text.indexOf(sec);
+ end = begin + sec.length();
+ TestWidgetsLog() << "sec" << sec << "lies from" << begin << "to" << end << "in" << text;
+ }
+ QPoint pos(0, q->height()/2);
+ QLineEdit* le = q->findChild<QLineEdit*>();
+ QPoint clickPos;
+ while (le->rect().contains(pos) && clickPos.isNull()) {
+ int cursor = le->cursorPositionAt(pos);
+ if (cursor >= begin && cursor < end) {
+ clickPos = q->mapFromGlobal(le->mapToGlobal(pos));
+ }
+ pos.setX(pos.x() + 2);
+ }
+ ret = clickPos;
+ if (ret.isNull()) {
+ if (ok) *ok = false;
+ QtUiTest::setErrorString(QString("Could not determine where to click in "
+ "date edit to move cursor between position %1 and %2").arg(begin).arg(end));
+ return ret;
+ }
+ } else if (moveUpDown != 0) {
+ /* Clicking required; need to move up */
+ QStyle const* style = q->style();
+ QStyleOptionSpinBox opt;
+ opt.initFrom(q);
+ QRect rect = style->subControlRect(QStyle::CC_SpinBox, &opt,
+ (moveUpDown > 0) ? QStyle::SC_SpinBoxUp : QStyle::SC_SpinBoxDown,
+ q);
+ TestWidgetsLog() << "move " << ((moveUpDown > 0) ? "up" : "down") << rect;
+ ret = rect.center();
+ }
+
+ if (ok) *ok = true;
+ return ret;
+}
+
+bool TestDateTimeEdit::enterByMouse(const QString& format, const QDateTime& dt)
+{
+ bool final = false;
+ bool ok = true;
+
+ QRegExp re( dateFormatToRegExp(format) );
+ if (-1 == re.indexIn( dt.toString(format) )) {
+ TestWidgetsLog() << "regex didn't match, re:" << re << "date:" << dt.toString(format);
+ return false;
+ }
+
+ QStringList cap = re.capturedTexts();
+ cap.removeFirst();
+
+ TestWidgetsLog() << "cap" << cap << "text" << q->text();
+
+ /* Mapping from section to index in cap.
+ * Wouldn't be necessary if QDateTimeEdit had the inverse of sectionAt().
+ */
+ QMap<QDateTimeEdit::Section,int> capMap;
+ for (int i = 0; i < q->sectionCount(); ++i) {
+ capMap.insert( q->sectionAt(i), i );
+ }
+
+ do {
+ QPoint nc = nextClick(cap, capMap, &final, &ok);
+ if (ok) {
+ if (!ensureVisiblePoint(nc)) return false;
+ QtUiTest::mouseClick(q->mapToGlobal(nc));
+// On some platforms, this takes too long
+#ifndef Q_OS_MAC
+ QtUiTest::waitForSignal(q, SIGNAL(dateTimeChanged(QDateTime)));
+#endif
+ }
+ } while (!final && ok);
+
+ return ok;
+}
+
+bool TestDateTimeEdit::enterByKeys(const QString& format, const QDateTime& dt, bool noCommit)
+{
+ if (!hasEditFocus() && !setEditFocus(true)) return false;
+ TestWidgetsLog() << "got focus";
+
+ for (int i = 0, m = q->sectionCount(); i < m; ++i) {
+ if (!enterSectionByKeys(q->sectionAt(i), format, dt))
+ return false;
+ }
+
+ if (noCommit) return true;
+
+ return setEditFocus(false);
+}
+
+bool TestDateTimeEdit::enter(const QVariant& item, bool noCommit)
+{
+ QString text;
+ QDateTime dt;
+ QString format = q->displayFormat();
+ TestWidgetsLog() << "Format: " << format;
+ if (item.canConvert<QDateTime>()) {
+ dt = item.value<QDateTime>();
+ text = dt.toString( format );
+ TestWidgetsLog() << "QDateTime";
+ } else if (item.canConvert<QDate>()) {
+ dt = QDateTime(item.value<QDate>(), QTime());
+ text = dt.toString( format );
+ TestWidgetsLog() << "QDate";
+ } else if (item.canConvert<QTime>()) {
+ dt = QDateTime(QDate(1970,1,1), item.value<QTime>());
+ text = dt.toString( format );
+ TestWidgetsLog() << "QTime";
+ } else {
+ text = item.toString();
+ dt = QDateTime::fromString(text, format);
+ TestWidgetsLog() << "String";
+ }
+ int dont_care = 0;
+ if (QValidator::Acceptable !=
+ static_cast<QAbstractSpinBox*>(q)->validate(text, dont_care)) {
+ TestWidgetsLog() << "Can't enter" << item << "(text:" << text << ")";
+ return false;
+ }
+
+ if (text == q->text()) return true;
+
+ if (QtUiTest::mousePreferred()) {
+ return enterByMouse(format, dt);
+ } else {
+ return enterByKeys(format, dt, noCommit);
+ }
+
+ return false;
+}
+
+bool TestDateTimeEdit::enterSectionByKeys(QDateTimeEdit::Section section,
+ const QString& fmt, const QDateTime& dt)
+{
+ using namespace QtUiTest;
+
+ if (fmt.isEmpty() || !dt.isValid()) return false;
+
+#define TRY(str) if (fmt.contains(str)) { \
+ text = dt.toString(str); \
+}
+
+ QString text;
+ switch (section) {
+ case QDateTimeEdit::YearSection:
+ TRY("yyyy")
+ else TRY("yy");
+ break;
+ case QDateTimeEdit::MonthSection:
+ TRY("MMMM")
+ else TRY("MMM")
+ else TRY("MM")
+ else TRY("M");
+ break;
+ case QDateTimeEdit::DaySection:
+ TRY("dddd")
+ else TRY("ddd")
+ else TRY("dd")
+ else TRY("d");
+ break;
+ case QDateTimeEdit::HourSection:
+ TRY("hh")
+ else TRY("h")
+ else TRY("HH")
+ else TRY("H");
+ if (fmt.contains("AP") || fmt.contains("ap")) {
+ // Need to use 12 hour format
+ if (fmt.contains("hh")) {
+ text = dt.toString("hh ap");
+ text = text.left(text.indexOf(' '));
+ }
+ else if (fmt.contains("h")) {
+ text = dt.toString("h ap");
+ text = text.left(text.indexOf(' '));
+ }
+ }
+ break;
+ case QDateTimeEdit::MinuteSection:
+ TRY("mm")
+ else TRY("m");
+ break;
+ case QDateTimeEdit::SecondSection:
+ TRY("ss")
+ else TRY("s");
+ break;
+ case QDateTimeEdit::MSecSection:
+ TRY("zzz")
+ else TRY("z");
+ break;
+ case QDateTimeEdit::AmPmSection:
+ TRY("AP")
+ else TRY("ap");
+ break;
+ default:
+ return false;
+ }
+#undef TRY
+
+ if (text.isEmpty()) return false;
+
+ QMap<int,int> sectionMap;
+ for (int i = 0; i < q->sectionCount(); ++i) {
+ sectionMap.insert(q->sectionAt(i), i);
+ }
+
+ int i = 0;
+ while (q->currentSection() != section && ++i < 100) {
+ Qt::KeyboardModifiers mod = (q->currentSectionIndex() < sectionMap[section]) ? Qt::KeyboardModifiers(0) : Qt::ShiftModifier;
+ TestWidgetsLog() << "Entering extra key click (before " + text + ") to move to prev/next section";
+ if (!keyClick(q, Qt::Key_Tab)) {
+ setErrorString("Key click did not go to the expected widget.");
+ return false;
+ }
+ }
+ if (q->currentSection() != section) {
+ setErrorString("Could not move focus to desired section.");
+ return false;
+ }
+
+ TestWidgetsLog() << "Going to enter" << text << "in section" << section;
+
+ foreach (const QChar& c, text) {
+ if (!keyClick(q, asciiToKey(c.toLatin1()))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool TestDateTimeEdit::canWrap(QObject *o)
+{ return qobject_cast<QDateTimeEdit*>(o); }
+
+}