Merge remote-tracking branch 'origin/master' into doxygenify

Conflicts:
	src/gui/quotainfo.h
This commit is contained in:
Daniel Molkentin 2015-06-29 18:45:55 +02:00
commit eff4daa00b
17 changed files with 221 additions and 159 deletions

View File

@ -491,6 +491,7 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
if (excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE
|| excluded == CSYNC_FILE_SILENTLY_EXCLUDED) {
SAFE_FREE(st);
continue;
}

View File

@ -62,7 +62,8 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) :
QWidget(parent),
ui(new Ui::AccountSettings),
_wasDisabledBefore(false),
_accountState(accountState)
_accountState(accountState),
_quotaInfo(accountState)
{
ui->setupUi(this);
@ -123,10 +124,8 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) :
connect(_accountState, SIGNAL(stateChanged(int)), SLOT(slotAccountStateChanged(int)));
slotAccountStateChanged(_accountState->state());
QuotaInfo *quotaInfo = _accountState->quotaInfo();
connect( quotaInfo, SIGNAL(quotaUpdated(qint64,qint64)),
connect( &_quotaInfo, SIGNAL(quotaUpdated(qint64,qint64)),
this, SLOT(slotUpdateQuota(qint64,qint64)));
slotUpdateQuota(quotaInfo->lastQuotaTotalBytes(), quotaInfo->lastQuotaUsedBytes());
connect(ui->deleteButton, SIGNAL(clicked()) , this, SLOT(slotDeleteAccount()));
@ -514,5 +513,12 @@ void AccountSettings::slotDeleteAccount()
manager->save();
}
bool AccountSettings::event(QEvent* e)
{
if (e->type() == QEvent::Hide || e->type() == QEvent::Show) {
_quotaInfo.setActive(isVisible());
}
return QWidget::event(e);
}
} // namespace OCC

View File

@ -21,6 +21,7 @@
#include <QTimer>
#include "folder.h"
#include "quotainfo.h"
#include "progressdispatcher.h"
class QModelIndex;
@ -80,9 +81,11 @@ protected slots:
void slotDeleteAccount();
void refreshSelectiveSyncStatus();
void slotForceRemoteDiscoveryOnFolders();
void slotCustomContextMenuRequested(const QPoint&);
private:
void showConnectionLabel( const QString& message, const QString& tooltip = QString() );
bool event(QEvent*) Q_DECL_OVERRIDE;
Ui::AccountSettings *ui;
@ -92,8 +95,7 @@ private:
bool _wasDisabledBefore;
AccountState *_accountState;
QLabel *_quotaLabel;
private slots:
void slotCustomContextMenuRequested(const QPoint&);
QuotaInfo _quotaInfo;
};
} // namespace OCC

View File

@ -12,7 +12,6 @@
*/
#include "accountstate.h"
#include "quotainfo.h"
#include "accountmanager.h"
#include "account.h"
#include "creds/abstractcredentials.h"
@ -25,15 +24,12 @@ namespace OCC {
AccountState::AccountState(AccountPtr account)
: QObject()
, _account(account)
, _quotaInfo(0)
, _state(AccountState::Disconnected)
, _connectionStatus(ConnectionValidator::Undefined)
, _waitingForNewCredentials(false)
{
qRegisterMetaType<AccountState*>("AccountState*");
_quotaInfo = new QuotaInfo(this); // Need to be initialized when 'this' is fully initialized
connect(account.data(), SIGNAL(invalidCredentials()),
SLOT(slotInvalidCredentials()));
connect(account.data(), SIGNAL(credentialsFetched(AbstractCredentials*)),
@ -134,11 +130,6 @@ bool AccountState::isConnectedOrTemporarilyUnavailable() const
return isConnected() || _state == ServiceUnavailable;
}
QuotaInfo *AccountState::quotaInfo()
{
return _quotaInfo;
}
void AccountState::checkConnectivity()
{
if (isSignedOut() || _waitingForNewCredentials) {

View File

@ -25,7 +25,6 @@ class QSettings;
namespace OCC {
class QuotaInfo;
class AccountState;
class Account;
class AbstractCredentials;
@ -83,8 +82,6 @@ public:
bool isConnected() const;
bool isConnectedOrTemporarilyUnavailable() const;
QuotaInfo *quotaInfo();
/// Triggers a ping to the server to update state and
/// connection status and errors.
void checkConnectivity();
@ -105,7 +102,6 @@ protected Q_SLOTS:
private:
AccountPtr _account;
QuotaInfo *_quotaInfo;
State _state;
ConnectionStatus _connectionStatus;
QStringList _connectionErrors;

View File

@ -645,7 +645,7 @@ void FolderStatusModel::slotSetProgress(const ProgressInfo &progress)
//: Example text: "uploading foobar.png (1MB of 2MB) time left 2 minutes at a rate of 24Kb/s"
fileProgressString = tr("%1 %2 (%3 of %4) %5 left at a rate of %6/s")
.arg(kindString, itemFileName, s1, s2,
Utility::timeToDescriptiveString(progress.fileProgress(curItem).estimatedEta, 3, " ", true),
Utility::durationToDescriptiveString(progress.fileProgress(curItem).estimatedEta),
Utility::octetsToString(estimatedBw) );
} else {
//: Example text: "uploading foobar.png (2MB of 2MB)"
@ -672,7 +672,7 @@ void FolderStatusModel::slotSetProgress(const ProgressInfo &progress)
overallSyncString = tr("%1 of %2, file %3 of %4\nTotal time left %5")
.arg(s1, s2)
.arg(currentFile).arg(totalFileCount)
.arg( Utility::timeToDescriptiveString(progress.totalProgress().estimatedEta, 3, " ", true) );
.arg( Utility::durationToDescriptiveString(progress.totalProgress().estimatedEta) );
} else if (totalFileCount > 0) {
// Don't attemt to estimate the time left if there is no kb to transfer.
overallSyncString = tr("file %1 of %2") .arg(currentFile).arg(totalFileCount);

View File

@ -63,6 +63,7 @@ NetworkSettings::NetworkSettings(QWidget *parent) :
connect(_ui->autoUploadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
connect(_ui->downloadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
connect(_ui->noDownloadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
connect(_ui->autoDownloadLimitRadioButton, SIGNAL(clicked()), SLOT(saveBWLimitSettings()));
connect(_ui->downloadSpinBox, SIGNAL(valueChanged(int)), SLOT(saveBWLimitSettings()));
connect(_ui->uploadSpinBox, SIGNAL(valueChanged(int)), SLOT(saveBWLimitSettings()));
}
@ -109,16 +110,25 @@ void NetworkSettings::loadProxySettings()
void NetworkSettings::loadBWLimitSettings()
{
ConfigFile cfgFile;
_ui->downloadLimitRadioButton->setChecked(cfgFile.useDownloadLimit());
int uploadLimit = cfgFile.useUploadLimit();
if ( uploadLimit >= 1 ) {
int useDownloadLimit = cfgFile.useDownloadLimit();
if ( useDownloadLimit >= 1 ) {
_ui->downloadLimitRadioButton->setChecked(true);
} else if (useDownloadLimit == 0){
_ui->noDownloadLimitRadioButton->setChecked(true);
} else {
_ui->autoDownloadLimitRadioButton->setChecked(true);
}
_ui->downloadSpinBox->setValue(cfgFile.downloadLimit());
int useUploadLimit = cfgFile.useUploadLimit();
if ( useUploadLimit >= 1 ) {
_ui->uploadLimitRadioButton->setChecked(true);
} else if (uploadLimit == 0){
} else if (useUploadLimit == 0){
_ui->noUploadLimitRadioButton->setChecked(true);
} else {
_ui->autoUploadLimitRadioButton->setChecked(true);
}
_ui->downloadSpinBox->setValue(cfgFile.downloadLimit());
_ui->uploadSpinBox->setValue(cfgFile.uploadLimit());
}
@ -151,7 +161,14 @@ void NetworkSettings::saveProxySettings()
void NetworkSettings::saveBWLimitSettings()
{
ConfigFile cfgFile;
cfgFile.setUseDownloadLimit(_ui->downloadLimitRadioButton->isChecked());
if (_ui->downloadLimitRadioButton->isChecked()) {
cfgFile.setUseDownloadLimit(1);
} else if (_ui->noDownloadLimitRadioButton->isChecked()) {
cfgFile.setUseDownloadLimit(0);
} else if (_ui->autoDownloadLimitRadioButton->isChecked()) {
cfgFile.setUseDownloadLimit(-1);
}
cfgFile.setDownloadLimit(_ui->downloadSpinBox->value());
if (_ui->uploadLimitRadioButton->isChecked()) {
cfgFile.setUseUploadLimit(1);
@ -160,8 +177,6 @@ void NetworkSettings::saveBWLimitSettings()
} else if (_ui->autoUploadLimitRadioButton->isChecked()) {
cfgFile.setUseUploadLimit(-1);
}
cfgFile.setDownloadLimit(_ui->downloadSpinBox->value());
cfgFile.setUploadLimit(_ui->uploadSpinBox->value());
FolderMan::instance()->setDirtyNetworkLimits();

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>518</width>
<height>384</height>
<width>542</width>
<height>391</height>
</rect>
</property>
<property name="windowTitle">
@ -104,7 +104,7 @@
<item>
<widget class="QSpinBox" name="portSpinBox">
<property name="enabled">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@ -141,13 +141,22 @@
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="userLineEdit">
<property name="enabled">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="text">
<string/>
@ -157,7 +166,7 @@
<item>
<widget class="QLineEdit" name="passwordLineEdit">
<property name="enabled">
<bool>true</bool>
<bool>false</bool>
</property>
<property name="text">
<string/>
@ -190,14 +199,37 @@
<string>Download Bandwidth</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<item row="3" column="0">
<widget class="QRadioButton" name="downloadLimitRadioButton">
<property name="text">
<string>Limit to</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="0" column="0" colspan="2">
<widget class="QRadioButton" name="noDownloadLimitRadioButton">
<property name="text">
<string>No limit</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>147</width>
<height>25</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QSpinBox" name="downloadSpinBox">
@ -221,42 +253,13 @@
</item>
</layout>
</item>
<item row="0" column="0" colspan="2">
<widget class="QRadioButton" name="noDownloadLimitRadioButton">
<item row="1" column="0" colspan="2">
<widget class="QRadioButton" name="autoDownloadLimitRadioButton">
<property name="text">
<string>No limit</string>
</property>
<property name="checked">
<bool>true</bool>
<string>Limit automatically</string>
</property>
</widget>
</item>
<item row="2" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0" colspan="2">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>147</width>
<height>25</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
@ -323,19 +326,6 @@
</item>
</layout>
</item>
<item row="2" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
<zorder>autoUploadLimitRadioButton</zorder>
<zorder>uploadLimitRadioButton</zorder>

View File

@ -476,12 +476,11 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo&
quint64 totalFileCount = qMax(progress.totalFiles(), currentFile);
_actionStatus->setText( tr("Syncing %1 of %2 (%3 left)")
.arg( currentFile ).arg( totalFileCount )
.arg( Utility::timeToDescriptiveString(progress.totalProgress().estimatedEta, 2, " ",true) ) );
.arg( Utility::durationToDescriptiveString(progress.totalProgress().estimatedEta) ) );
} else {
QString totalSizeStr = Utility::octetsToString( progress.totalSize() );
_actionStatus->setText( tr("Syncing %1 (%2 left)")
.arg( totalSizeStr )
.arg( Utility::timeToDescriptiveString(progress.totalProgress().estimatedEta, 2, " ",true) ) );
.arg( totalSizeStr, Utility::durationToDescriptiveString(progress.totalProgress().estimatedEta) ) );
}

View File

@ -25,31 +25,39 @@ namespace OCC {
namespace {
static const int defaultIntervalT = 30*1000;
static const int failIntervalT = 5*1000;
static const int initialTimeT = 1*1000;
}
QuotaInfo::QuotaInfo(AccountState *accountState)
: QObject(accountState)
QuotaInfo::QuotaInfo(AccountState *accountState, QObject *parent)
: QObject(parent)
, _accountState(accountState)
, _lastQuotaTotalBytes(0)
, _lastQuotaUsedBytes(0)
, _jobRestartTimer(new QTimer(this))
, _active(false)
{
connect(accountState, SIGNAL(stateChanged(int)),
SLOT(slotAccountStateChanged(int)));
connect(_jobRestartTimer, SIGNAL(timeout()), SLOT(slotCheckQuota()));
_jobRestartTimer->setSingleShot(true);
if (canGetQuota()) {
_jobRestartTimer->start(initialTimeT);
}
SLOT(slotAccountStateChanged()));
connect(&_jobRestartTimer, SIGNAL(timeout()), SLOT(slotCheckQuota()));
_jobRestartTimer.setSingleShot(true);
}
void QuotaInfo::slotAccountStateChanged(int /*state*/)
void QuotaInfo::setActive(bool active)
{
_active = active;
slotAccountStateChanged();
}
void QuotaInfo::slotAccountStateChanged()
{
if (canGetQuota()) {
_jobRestartTimer->start(initialTimeT);
auto elapsed = _lastQuotaRecieved.msecsTo(QDateTime::currentDateTime());
if (_lastQuotaRecieved.isNull() || elapsed >= defaultIntervalT) {
slotCheckQuota();
} else {
_jobRestartTimer.start(defaultIntervalT - elapsed);
}
} else {
_jobRestartTimer->stop();
_jobRestartTimer.stop();
}
}
@ -57,12 +65,12 @@ void QuotaInfo::slotRequestFailed()
{
_lastQuotaTotalBytes = 0;
_lastQuotaUsedBytes = 0;
_jobRestartTimer->start(failIntervalT);
_jobRestartTimer.start(failIntervalT);
}
bool QuotaInfo::canGetQuota() const
{
if (! _accountState) {
if (! _accountState || !_active) {
return false;
}
AccountPtr account = _accountState->account();
@ -77,12 +85,17 @@ void QuotaInfo::slotCheckQuota()
return;
}
if (_job) {
// The previous job was not finished? Then we cancel it!
_job->deleteLater();
}
AccountPtr account = _accountState->account();
PropfindJob *job = new PropfindJob(account, "/", this);
job->setProperties(QList<QByteArray>() << "quota-available-bytes" << "quota-used-bytes");
connect(job, SIGNAL(result(QVariantMap)), SLOT(slotUpdateLastQuota(QVariantMap)));
connect(job, SIGNAL(networkError(QNetworkReply*)), SLOT(slotRequestFailed()));
job->start();
_job = new PropfindJob(account, "/", this);
_job->setProperties(QList<QByteArray>() << "quota-available-bytes" << "quota-used-bytes");
connect(_job, SIGNAL(result(QVariantMap)), SLOT(slotUpdateLastQuota(QVariantMap)));
connect(_job, SIGNAL(networkError(QNetworkReply*)), SLOT(slotRequestFailed()));
_job->start();
}
void QuotaInfo::slotUpdateLastQuota(const QVariantMap &result)
@ -93,7 +106,8 @@ void QuotaInfo::slotUpdateLastQuota(const QVariantMap &result)
_lastQuotaUsedBytes = result["quota-used-bytes"].toDouble();
_lastQuotaTotalBytes = _lastQuotaUsedBytes + avail;
emit quotaUpdated(_lastQuotaTotalBytes, _lastQuotaUsedBytes);
_jobRestartTimer->start(defaultIntervalT);
_jobRestartTimer.start(defaultIntervalT);
_lastQuotaRecieved = QDateTime::currentDateTime();
}
}

View File

@ -17,31 +17,52 @@
#include <QObject>
#include <QPointer>
#include <QVariant>
class QTimer;
#include <QTimer>
#include <QDateTime>
namespace OCC {
class AccountState;
class PropfindJob;
/*!
* \brief The QuotaInfo class
* \brief handles getting the quota to display in the UI
*
* It is typically owned by the AccountSetting page.
*
* The quota is requested if those 3 conditions are met:
* - This object is active via setActive() (typically if the settings page is visible.)
* - The account is connected.
* - Every 30 seconds (defaultIntervalT) or 5 seconds in case of failure (failIntervalT)
*
* We only request the quota when the UI is visible otherwise this might slow down the server with
* too many requests. But we still need to do it every 30 seconds otherwise user complains that the
* quota is not updated fast enough when changed on the server.
*
* If the quota job is not finished within 30 seconds, it is cancelled and another one is started
*
* \ingroup gui
*/
class QuotaInfo : public QObject {
Q_OBJECT
public:
QuotaInfo(AccountState *account);
explicit QuotaInfo(OCC::AccountState* accountState, QObject* parent = 0);
qint64 lastQuotaTotalBytes() const { return _lastQuotaTotalBytes; }
qint64 lastQuotaUsedBytes() const { return _lastQuotaUsedBytes; }
/**
* When the quotainfo is active, it requests the quota at regular interval.
* When setting it to active it will request the quota imediatly if the last time
* the quota was requested was more than the interval
*/
void setActive(bool active);
public Q_SLOTS:
void slotCheckQuota();
private Q_SLOTS:
void slotUpdateLastQuota(const QVariantMap &);
void slotAccountStateChanged(int state);
void slotAccountStateChanged();
void slotRequestFailed();
Q_SIGNALS:
@ -53,7 +74,10 @@ private:
QPointer<AccountState> _accountState;
qint64 _lastQuotaTotalBytes;
qint64 _lastQuotaUsedBytes;
QTimer *_jobRestartTimer;
QTimer _jobRestartTimer;
QDateTime _lastQuotaRecieved; // the time at which de quota was recieved last
bool _active; // if we should check at regular interval (when the UI is visible)
QPointer<PropfindJob> _job; // the currently running job
};

View File

@ -514,9 +514,9 @@ int ConfigFile::useUploadLimit() const
return getValue(useUploadLimitC, QString::null, 0).toInt();
}
bool ConfigFile::useDownloadLimit() const
int ConfigFile::useDownloadLimit() const
{
return getValue(useDownloadLimitC, QString::null, false).toBool();
return getValue(useDownloadLimitC, QString::null, 0).toInt();
}
void ConfigFile::setUseUploadLimit(int val)
@ -524,9 +524,9 @@ void ConfigFile::setUseUploadLimit(int val)
setValue(useUploadLimitC, val);
}
void ConfigFile::setUseDownloadLimit(bool enable)
void ConfigFile::setUseDownloadLimit(int val)
{
setValue(useDownloadLimitC, enable);
setValue(useDownloadLimitC, val);
}
int ConfigFile::uploadLimit() const

View File

@ -91,9 +91,9 @@ public:
/** 0: no limit, 1: manual, >0: automatic */
int useUploadLimit() const;
bool useDownloadLimit() const;
int useDownloadLimit() const;
void setUseUploadLimit(int);
void setUseDownloadLimit(bool);
void setUseDownloadLimit(int);
/** in kbyte/s */
int uploadLimit() const;
int downloadLimit() const;

View File

@ -242,7 +242,7 @@ void GETFileJob::slotReadyRead()
if (_bandwidthLimited) {
toRead = qMin(qint64(bufferSize), _bandwidthQuota);
if (toRead == 0) {
qDebug() << Q_FUNC_INFO << "Out of quota";
//qDebug() << Q_FUNC_INFO << "Out of quota";
break;
}
_bandwidthQuota -= toRead;

View File

@ -304,45 +304,43 @@ static QList<QPair<QString,quint32> > timeMapping = QList<QPair<QString,quint32>
QPair<QString,quint32>("%1h",3600) <<
QPair<QString,quint32>("%1m",60) <<
QPair<QString,quint32>("%1s",1);
QString Utility::timeToDescriptiveString(quint64 msecs, quint8 precision, QString separator, bool specific)
{
return timeToDescriptiveString( timeMapping , msecs, precision, separator, specific);
}
QString Utility::durationToDescriptiveString(quint64 msecs)
{
struct Period { const char *name; quint64 msec; };
Q_DECL_CONSTEXPR const Period periods[] = {
{ QT_TRANSLATE_NOOP("Utility", "%Ln year(s)") , 365*24*3600*1000L },
{ QT_TRANSLATE_NOOP("Utility", "%Ln month(s)") , 30*24*3600*1000L },
{ QT_TRANSLATE_NOOP("Utility", "%Ln day(s)") , 24*3600*1000L },
{ QT_TRANSLATE_NOOP("Utility", "%Ln hour(s)") , 3600*1000L },
{ QT_TRANSLATE_NOOP("Utility", "%Ln minute(s)") , 60*1000L },
{ QT_TRANSLATE_NOOP("Utility", "%Ln second(s)") , 1000L },
{ 0, 0 }
};
QString Utility::timeToDescriptiveString(QList<QPair<QString,quint32> > &timeMapping, quint64 msecs, quint8 precision, QString separator, bool specific)
{
quint64 secs = msecs / 1000;
QString retStr = QString(timeMapping.last().first).arg(0); // default value in case theres no actual time in msecs.
QList<QPair<QString,quint32> > values;
bool timeStartFound = false;
for(QList<QPair<QString,quint32> >::Iterator itr = timeMapping.begin(); itr != timeMapping.end() && precision > 0; itr++) {
quint64 result = secs / itr->second;
if(!timeStartFound) {
if(result == 0 ) {
continue;
}
retStr = "";
timeStartFound= true;
}
secs -= result * itr->second;
values.append(QPair<QString,quint32>(itr->first,result));
precision--;
int p = 0;
while (periods[p].name && msecs < periods[p].msec) {
p++;
}
for(QList<QPair<QString,quint32> >::Iterator itr = values.begin(); itr < values.end(); itr++) {
retStr = retStr.append((specific || itr == values.end()-1) ? itr->first : "%1").arg(itr->second, (itr == values.begin() ? 1 :2 ), 10, QChar('0'));
if(itr < values.end()-1) {
retStr.append(separator);
}
if (!periods[p].name) {
return QCoreApplication::translate("Utility", "0 seconds");
}
return retStr;
auto firstPart = QCoreApplication::translate("Utility", periods[p].name, 0, int(msecs / periods[p].msec));
if (!periods[p+1].name) {
return firstPart;
}
quint64 secondPartNum = qRound( double(msecs % periods[p].msec) / periods[p+1].msec);
if (secondPartNum == 0) {
return firstPart;
}
return QCoreApplication::translate("Utility", "%1 %2").arg(firstPart,
QCoreApplication::translate("Utility", periods[p+1].name, 0, secondPartNum));
}
bool Utility::hasDarkSystray()

View File

@ -64,13 +64,11 @@ namespace Utility
OWNCLOUDSYNC_EXPORT qint64 qDateTimeToTime_t(const QDateTime &t);
/**
* @brief Convert milliseconds to HMS string.
* @brief Convert milliseconds duration to human readable string.
* @param quint64 msecs the milliseconds to convert to string.
* @param uint precision the amount of sub dviving scale to include in the result.
* @return an HMS representation of the milliseconds value.
*/
OWNCLOUDSYNC_EXPORT QString timeToDescriptiveString(QList<QPair<QString,quint32> > &timeMapping, quint64 msecs, quint8 precision, QString separator, bool specific);
OWNCLOUDSYNC_EXPORT QString timeToDescriptiveString(quint64 msecs, quint8 precision, QString separator, bool specific);
OWNCLOUDSYNC_EXPORT QString durationToDescriptiveString(quint64 msecs);
/**
* @brief hasDarkSystray - determines whether the systray is dark or light.

View File

@ -75,6 +75,34 @@ private slots:
QVERIFY(toCSyncScheme("https://example.com/owncloud/") ==
"ownclouds://example.com/owncloud/");
}
void testDurationToDescriptiveString()
{
QLocale::setDefault(QLocale("C"));
//NOTE: in order for the plural to work we would need to load the english translation
quint64 sec = 1000;
quint64 hour = 3600 * sec;
QDateTime current = QDateTime::currentDateTime();
QCOMPARE(durationToDescriptiveString(0), QString("0 seconds") );
QCOMPARE(durationToDescriptiveString(5), QString("0 seconds") );
QCOMPARE(durationToDescriptiveString(1000), QString("1 second(s)") );
QCOMPARE(durationToDescriptiveString(1005), QString("1 second(s)") );
QCOMPARE(durationToDescriptiveString(56123), QString("56 second(s)") );
QCOMPARE(durationToDescriptiveString(90*sec), QString("1 minute(s) 30 second(s)") );
QCOMPARE(durationToDescriptiveString(3*hour), QString("3 hour(s)") );
QCOMPARE(durationToDescriptiveString(3*hour + 20*sec), QString("3 hour(s)") );
QCOMPARE(durationToDescriptiveString(3*hour + 70*sec), QString("3 hour(s) 1 minute(s)") );
QCOMPARE(durationToDescriptiveString(3*hour + 100*sec), QString("3 hour(s) 2 minute(s)") );
QCOMPARE(durationToDescriptiveString(current.msecsTo(current.addYears(4).addMonths(5).addDays(2).addSecs(23*60*60))),
QString("4 year(s) 5 month(s)") );
QCOMPARE(durationToDescriptiveString(current.msecsTo(current.addDays(2).addSecs(23*60*60))),
QString("2 day(s) 23 hour(s)") );
}
};
#endif