From 695d85363e537b51b5d0ae6ab08a9a1e7d9e8354 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Mon, 6 Apr 2015 13:47:16 +0300 Subject: Item delegates: show localized detailed tooltips and "What's this?" texts Extract the common part from QItemDelegate and QStyledItemDelegate which uses QLocale to convert a value for Qt::DisplayRole to a string. Use this code to get the text for tooltips and "What's this?". [ChangeLog][QtWidgets][QAbstractItemDelegate] Show localized detailed tooltips and "What's this?" texts. Task-number: QTBUG-16469 Change-Id: I8618763d45b8cfddafc2f263d658ba256be60a15 Reviewed-by: Giuseppe D'Angelo --- src/widgets/itemviews/qabstractitemdelegate.cpp | 55 ++++++++++++++++--- src/widgets/itemviews/qabstractitemdelegate_p.h | 3 +- src/widgets/itemviews/qitemdelegate.cpp | 42 +++------------ src/widgets/itemviews/qstyleditemdelegate.cpp | 36 +------------ .../itemviews/qitemdelegate/qitemdelegate.pro | 2 +- .../itemviews/qitemdelegate/tst_qitemdelegate.cpp | 62 ++++++++++++++++++++++ 6 files changed, 121 insertions(+), 79 deletions(-) diff --git a/src/widgets/itemviews/qabstractitemdelegate.cpp b/src/widgets/itemviews/qabstractitemdelegate.cpp index c2dd1ec8fd..00f2b87f93 100644 --- a/src/widgets/itemviews/qabstractitemdelegate.cpp +++ b/src/widgets/itemviews/qabstractitemdelegate.cpp @@ -370,6 +370,7 @@ bool QAbstractItemDelegate::helpEvent(QHelpEvent *event, const QStyleOptionViewItem &option, const QModelIndex &index) { + Q_D(QAbstractItemDelegate); Q_UNUSED(option); if (!event || !view) @@ -378,9 +379,10 @@ bool QAbstractItemDelegate::helpEvent(QHelpEvent *event, #ifndef QT_NO_TOOLTIP case QEvent::ToolTip: { QHelpEvent *he = static_cast(event); - QVariant tooltip = index.data(Qt::ToolTipRole); - if (tooltip.canConvert()) { - QToolTip::showText(he->globalPos(), tooltip.toString(), view); + const int precision = inherits("QItemDelegate") ? 10 : 6; // keep in sync with DBL_DIG in qitemdelegate.cpp + const QString tooltip = d->textForRole(Qt::ToolTipRole, index.data(Qt::ToolTipRole), option.locale, precision); + if (!tooltip.isEmpty()) { + QToolTip::showText(he->globalPos(), tooltip, view); return true; } break;} @@ -392,9 +394,10 @@ bool QAbstractItemDelegate::helpEvent(QHelpEvent *event, break; } case QEvent::WhatsThis: { QHelpEvent *he = static_cast(event); - QVariant whatsthis = index.data(Qt::WhatsThisRole); - if (whatsthis.canConvert()) { - QWhatsThis::showText(he->globalPos(), whatsthis.toString(), view); + const int precision = inherits("QItemDelegate") ? 10 : 6; // keep in sync with DBL_DIG in qitemdelegate.cpp + const QString whatsthis = d->textForRole(Qt::WhatsThisRole, index.data(Qt::WhatsThisRole), option.locale, precision); + if (!whatsthis.isEmpty()) { + QWhatsThis::showText(he->globalPos(), whatsthis, view); return true; } break ; } @@ -537,6 +540,46 @@ bool QAbstractItemDelegatePrivate::tryFixup(QWidget *editor) return true; } +QString QAbstractItemDelegatePrivate::textForRole(Qt::ItemDataRole role, const QVariant &value, const QLocale &locale, int precision) const +{ + const QLocale::FormatType formatType = (role == Qt::DisplayRole) ? QLocale::ShortFormat : QLocale::LongFormat; + QString text; + switch (value.userType()) { + case QMetaType::Float: + text = locale.toString(value.toFloat()); + break; + case QVariant::Double: + text = locale.toString(value.toDouble(), 'g', precision); + break; + case QVariant::Int: + case QVariant::LongLong: + text = locale.toString(value.toLongLong()); + break; + case QVariant::UInt: + case QVariant::ULongLong: + text = locale.toString(value.toULongLong()); + break; + case QVariant::Date: + text = locale.toString(value.toDate(), formatType); + break; + case QVariant::Time: + text = locale.toString(value.toTime(), formatType); + break; + case QVariant::DateTime: { + const QDateTime dateTime = value.toDateTime(); + text = locale.toString(dateTime.date(), formatType) + + QLatin1Char(' ') + + locale.toString(dateTime.time(), formatType); + break; } + default: + text = value.toString(); + if (role == Qt::DisplayRole) + text.replace(QLatin1Char('\n'), QChar::LineSeparator); + break; + } + return text; +} + void QAbstractItemDelegatePrivate::_q_commitDataAndCloseEditor(QWidget *editor) { Q_Q(QAbstractItemDelegate); diff --git a/src/widgets/itemviews/qabstractitemdelegate_p.h b/src/widgets/itemviews/qabstractitemdelegate_p.h index 05f1bd138c..1796290ba9 100644 --- a/src/widgets/itemviews/qabstractitemdelegate_p.h +++ b/src/widgets/itemviews/qabstractitemdelegate_p.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE -class QAbstractItemDelegatePrivate : public QObjectPrivate +class Q_AUTOTEST_EXPORT QAbstractItemDelegatePrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QAbstractItemDelegate) public: @@ -60,6 +60,7 @@ public: bool editorEventFilter(QObject *object, QEvent *event); bool tryFixup(QWidget *editor); + QString textForRole(Qt::ItemDataRole role, const QVariant &value, const QLocale &locale, int precision = 6) const; void _q_commitDataAndCloseEditor(QWidget *editor); }; diff --git a/src/widgets/itemviews/qitemdelegate.cpp b/src/widgets/itemviews/qitemdelegate.cpp index cd952737dd..2b6e1210ca 100644 --- a/src/widgets/itemviews/qitemdelegate.cpp +++ b/src/widgets/itemviews/qitemdelegate.cpp @@ -61,6 +61,7 @@ #include +// keep in sync with QAbstractItemDelegate::helpEvent() #ifndef DBL_DIG # define DBL_DIG 10 #endif @@ -96,7 +97,7 @@ public: return text; } - static QString valueToText(const QVariant &value, const QStyleOptionViewItem &option); + QString valueToText(const QVariant &value, const QStyleOptionViewItem &option) const; QItemEditorFactory *f; bool clipPainting; @@ -326,40 +327,9 @@ void QItemDelegate::setClipping(bool clip) d->clipPainting = clip; } -QString QItemDelegatePrivate::valueToText(const QVariant &value, const QStyleOptionViewItem &option) +QString QItemDelegatePrivate::valueToText(const QVariant &value, const QStyleOptionViewItem &option) const { - QString text; - switch (value.userType()) { - case QMetaType::Float: - text = option.locale.toString(value.toFloat(), 'g'); - break; - case QVariant::Double: - text = option.locale.toString(value.toDouble(), 'g', DBL_DIG); - break; - case QVariant::Int: - case QVariant::LongLong: - text = option.locale.toString(value.toLongLong()); - break; - case QVariant::UInt: - case QVariant::ULongLong: - text = option.locale.toString(value.toULongLong()); - break; - case QVariant::Date: - text = option.locale.toString(value.toDate(), QLocale::ShortFormat); - break; - case QVariant::Time: - text = option.locale.toString(value.toTime(), QLocale::ShortFormat); - break; - case QVariant::DateTime: - text = option.locale.toString(value.toDateTime().date(), QLocale::ShortFormat); - text += QLatin1Char(' '); - text += option.locale.toString(value.toDateTime().time(), QLocale::ShortFormat); - break; - default: - text = replaceNewLine(value.toString()); - break; - } - return text; + return textForRole(Qt::DisplayRole, value, option.locale, DBL_DIG); } /*! @@ -428,7 +398,7 @@ void QItemDelegate::paint(QPainter *painter, QRect displayRect; value = index.data(Qt::DisplayRole); if (value.isValid() && !value.isNull()) { - text = QItemDelegatePrivate::valueToText(value, opt); + text = d->valueToText(value, opt); displayRect = textRectangle(painter, d->textLayoutBounds(opt), opt.font, text); } @@ -1055,7 +1025,7 @@ QRect QItemDelegate::rect(const QStyleOptionViewItem &option, return QRect(QPoint(0, 0), option.decorationSize); case QVariant::String: default: { - QString text = QItemDelegatePrivate::valueToText(value, option); + const QString text = d->valueToText(value, option); value = index.data(Qt::FontRole); QFont fnt = qvariant_cast(value).resolve(option.font); return textRectangle(0, d->textLayoutBounds(option), fnt, text); } diff --git a/src/widgets/itemviews/qstyleditemdelegate.cpp b/src/widgets/itemviews/qstyleditemdelegate.cpp index f02f98cb31..483cfbdc36 100644 --- a/src/widgets/itemviews/qstyleditemdelegate.cpp +++ b/src/widgets/itemviews/qstyleditemdelegate.cpp @@ -255,41 +255,7 @@ QStyledItemDelegate::~QStyledItemDelegate() */ QString QStyledItemDelegate::displayText(const QVariant &value, const QLocale& locale) const { - QString text; - switch (value.userType()) { - case QMetaType::Float: - case QVariant::Double: - text = locale.toString(value.toReal()); - break; - case QVariant::Int: - case QVariant::LongLong: - text = locale.toString(value.toLongLong()); - break; - case QVariant::UInt: - case QVariant::ULongLong: - text = locale.toString(value.toULongLong()); - break; - case QVariant::Date: - text = locale.toString(value.toDate(), QLocale::ShortFormat); - break; - case QVariant::Time: - text = locale.toString(value.toTime(), QLocale::ShortFormat); - break; - case QVariant::DateTime: - text = locale.toString(value.toDateTime().date(), QLocale::ShortFormat); - text += QLatin1Char(' '); - text += locale.toString(value.toDateTime().time(), QLocale::ShortFormat); - break; - default: - // convert new lines into line separators - text = value.toString(); - for (int i = 0; i < text.count(); ++i) { - if (text.at(i) == QLatin1Char('\n')) - text[i] = QChar::LineSeparator; - } - break; - } - return text; + return d_func()->textForRole(Qt::DisplayRole, value, locale); } /*! diff --git a/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro b/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro index f7fb41e60c..02a71f8101 100644 --- a/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro +++ b/tests/auto/widgets/itemviews/qitemdelegate/qitemdelegate.pro @@ -1,6 +1,6 @@ CONFIG += testcase TARGET = tst_qitemdelegate -QT += widgets testlib +QT += widgets widgets-private testlib SOURCES += tst_qitemdelegate.cpp win32:!wince:!winrt: LIBS += -luser32 diff --git a/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp index 25f27cb0c7..45bac13c92 100644 --- a/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp +++ b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp @@ -56,6 +56,8 @@ #include #include +#include + Q_DECLARE_METATYPE(QAbstractItemDelegate::EndEditHint) #if defined (Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) @@ -229,6 +231,8 @@ private slots: void task257859_finalizeEdit(); void QTBUG4435_keepSelectionOnCheck(); + + void QTBUG16469_textForRole(); }; @@ -1558,6 +1562,64 @@ void tst_QItemDelegate::testLineEditValidation() QCOMPARE(item->data(Qt::DisplayRole).toString(), QStringLiteral("abc,def")); } +void tst_QItemDelegate::QTBUG16469_textForRole() +{ +#ifndef QT_BUILD_INTERNAL + QSKIP("This test requires a developer build"); +#else + struct TestDelegate : public QItemDelegate + { + QString textForRole(Qt::ItemDataRole role, const QVariant &value, const QLocale &locale) + { + QAbstractItemDelegatePrivate *d = reinterpret_cast(qGetPtrHelper(d_ptr)); + return d->textForRole(role, value, locale); + } + } delegate; + QLocale locale; + + const float f = 123.456f; + QCOMPARE(delegate.textForRole(Qt::DisplayRole, f, locale), locale.toString(f)); + QCOMPARE(delegate.textForRole(Qt::ToolTipRole, f, locale), locale.toString(f)); + const double d = 123.456; + QCOMPARE(delegate.textForRole(Qt::DisplayRole, d, locale), locale.toString(d, 'g', 6)); + QCOMPARE(delegate.textForRole(Qt::ToolTipRole, d, locale), locale.toString(d, 'g', 6)); + const int i = 1234567; + QCOMPARE(delegate.textForRole(Qt::DisplayRole, i, locale), locale.toString(i)); + QCOMPARE(delegate.textForRole(Qt::ToolTipRole, i, locale), locale.toString(i)); + const qlonglong ll = 1234567; + QCOMPARE(delegate.textForRole(Qt::DisplayRole, ll, locale), locale.toString(ll)); + QCOMPARE(delegate.textForRole(Qt::ToolTipRole, ll, locale), locale.toString(ll)); + const uint ui = 1234567; + QCOMPARE(delegate.textForRole(Qt::DisplayRole, ui, locale), locale.toString(ui)); + QCOMPARE(delegate.textForRole(Qt::ToolTipRole, ui, locale), locale.toString(ui)); + const qulonglong ull = 1234567; + QCOMPARE(delegate.textForRole(Qt::DisplayRole, ull, locale), locale.toString(ull)); + QCOMPARE(delegate.textForRole(Qt::ToolTipRole, ull, locale), locale.toString(ull)); + + const QDateTime dateTime = QDateTime::currentDateTime(); + const QDate date = dateTime.date(); + const QTime time = dateTime.time(); + const QString shortDate = locale.toString(date, QLocale::ShortFormat); + const QString longDate = locale.toString(date, QLocale::LongFormat); + const QString shortTime = locale.toString(time, QLocale::ShortFormat); + const QString longTime = locale.toString(time, QLocale::LongFormat); + QCOMPARE(delegate.textForRole(Qt::DisplayRole, date, locale), shortDate); + QCOMPARE(delegate.textForRole(Qt::ToolTipRole, date, locale), longDate); + QCOMPARE(delegate.textForRole(Qt::DisplayRole, time, locale), shortTime); + QCOMPARE(delegate.textForRole(Qt::ToolTipRole, time, locale), longTime); + QCOMPARE(delegate.textForRole(Qt::DisplayRole, dateTime, locale), shortDate + QLatin1Char(' ') + shortTime); + QCOMPARE(delegate.textForRole(Qt::ToolTipRole, dateTime, locale), longDate + QLatin1Char(' ') + longTime); + + const QString text("text"); + QCOMPARE(delegate.textForRole(Qt::DisplayRole, text, locale), text); + QCOMPARE(delegate.textForRole(Qt::ToolTipRole, text, locale), text); + const QString multipleLines("multiple\nlines"); + QString multipleLines2 = multipleLines; + multipleLines2.replace(QLatin1Char('\n'), QChar::LineSeparator); + QCOMPARE(delegate.textForRole(Qt::DisplayRole, multipleLines, locale), multipleLines2); + QCOMPARE(delegate.textForRole(Qt::ToolTipRole, multipleLines, locale), multipleLines); +#endif +} // ### _not_ covered: -- cgit v1.2.3