diff --git a/src/libs/ui/docsetsdialog.cpp b/src/libs/ui/docsetsdialog.cpp index 56fcb8050..d868dd67e 100644 --- a/src/libs/ui/docsetsdialog.cpp +++ b/src/libs/ui/docsetsdialog.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,7 @@ using namespace Zeal; using namespace Zeal::WidgetUi; +using namespace Zeal::Util; #ifdef Q_OS_WIN32 extern Q_CORE_EXPORT int qt_ntfs_permission_lookup; @@ -311,8 +313,7 @@ void DocsetsDialog::downloadCompleted() if (file->open(QIODevice::WriteOnly)) file->write(data); - ui->lastUpdatedLabel->setText(QFileInfo(file->fileName()) - .lastModified().toString(Qt::SystemLocaleShortDate)); + ui->lastUpdatedLabel->setText(ReadableInterval::toReadableString(QFileInfo(file->fileName()).lastModified())); QJsonParseError jsonError; const QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); @@ -518,8 +519,7 @@ void DocsetsDialog::loadDocsetList() return; } - // TODO: Show more user friendly labels, like "5 hours ago" - ui->lastUpdatedLabel->setText(fi.lastModified().toString(Qt::SystemLocaleShortDate)); + ui->lastUpdatedLabel->setText(ReadableInterval::toReadableString(fi.lastModified())); processDocsetList(jsonDoc.array()); } diff --git a/src/libs/util/CMakeLists.txt b/src/libs/util/CMakeLists.txt index d4ab871b3..a7ef562f6 100644 --- a/src/libs/util/CMakeLists.txt +++ b/src/libs/util/CMakeLists.txt @@ -4,6 +4,7 @@ set(CMAKE_AUTOMOC OFF) add_library(Util plist.cpp sqlitedatabase.cpp + readableinterval.cpp version.cpp ) diff --git a/src/libs/util/readableinterval.cpp b/src/libs/util/readableinterval.cpp new file mode 100644 index 000000000..378f56204 --- /dev/null +++ b/src/libs/util/readableinterval.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2015-2018 Oleg Shparber +** Copyright (C) 2013-2014 Jerzy Kozera +** Contact: https://go.zealdocs.org/l/contact +** +** This file is part of Zeal. +** +** Zeal is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** Zeal is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Zeal. If not, see . +** +****************************************************************************/ + +#include "readableinterval.h" + +#include +#include + +#include + +using namespace Zeal::Util; +using namespace std::chrono; + +const char* ReadableInterval::describeTimeUnit(TIME_UNITS unit) +{ + switch (unit) { + case YEAR: return QT_TR_NOOP("%n year(s)"); + case DAY: return QT_TR_NOOP("%n day(s)"); + case HOUR: return QT_TR_NOOP("%n hour(s)"); + case MIN: return QT_TR_NOOP("%n min(s)"); + case SEC: return QT_TR_NOOP("%n sec(s)"); + } + return QT_TR_NOOP("%n unit(s)"); +} + +QString ReadableInterval::pluralForm(TIME_UNITS unit, qint64 quantity) +{ + return tr(describeTimeUnit(unit), "", static_cast(quantity)); +} + +QString ReadableInterval::toReadableString(const QDateTime& timestamp, const QDateTime& reference) +{ + qint64 delta = reference.toMSecsSinceEpoch() - timestamp.toMSecsSinceEpoch(); + bool isPast = delta > 0; + milliseconds ms(abs(delta)); + + if (ms < seconds(1)) { + return tr("now"); + } + + auto year = duration_cast(ms); + ms -= year; + + auto day = duration_cast(ms); + ms -= day; + + auto hour = duration_cast(ms); + ms -= hour; + + auto min = duration_cast(ms); + ms -= min; + + auto sec = duration_cast(ms); + ms -= sec; + + QStringList list; + QList fields({year.count(), day.count(), hour.count(), min.count(), sec.count()}); + QList units({YEAR, DAY, HOUR, MIN, SEC}); + + for (int i = 0, j = 0; i < fields.length() && j < MAX_FIELDS_DISPLAYED; ++i) { + if (fields[i] && ++j) { + list.append(pluralForm(static_cast(units[i]), fields[i])); + } + } + + return QStringLiteral("%1 %2").arg(list.join(tr(", ")), + isPast ? tr("ago") : tr("from now")); +} diff --git a/src/libs/util/readableinterval.h b/src/libs/util/readableinterval.h new file mode 100644 index 000000000..5b5d2354a --- /dev/null +++ b/src/libs/util/readableinterval.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2015-2018 Oleg Shparber +** Contact: https://go.zealdocs.org/l/contact +** +** This file is part of Zeal. +** +** Zeal is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** Zeal is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Zeal. If not, see . +** +****************************************************************************/ + +#ifndef ZEAL_UTIL_READABLEINTERVAL_H +#define ZEAL_UTIL_READABLEINTERVAL_H + +#include +#include + +#include + +namespace { +// TODO : remove with c++20 +using days = std::chrono::duration>; +using years = std::chrono::duration>; + +enum TIME_UNITS { + YEAR, + DAY, + HOUR, + MIN, + SEC +}; + +const qint8 MAX_FIELDS_DISPLAYED = 3; + +} // namespace + +namespace Zeal { +namespace Util { + +class ReadableInterval +{ + Q_DECLARE_TR_FUNCTIONS(ReadableInterval) +public: + static QString toReadableString(const QDateTime& timestamp, const QDateTime& reference = QDateTime::currentDateTime()); +private: + static const char* describeTimeUnit(TIME_UNITS unit); + static QString pluralForm(TIME_UNITS unit, qint64 quantity); +}; + +} // namespace Util +} // namespace Zeal + +#endif // ZEAL_UTIL_READABLEINTERVAL_H