/*
* Copyright (C) 2013 Canonical, Ltd.
*
* This program 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; version 3.
*
* This program 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 this program. If not, see .
*
* Author: Pete Woods
*/
#include "UserMetrics.h"
#include
#include
#include
#include
#include
using namespace UserMetricsOutput;
namespace UserMetricsOutput
{
class UserMetricsDataPrivate;
class UserMetricsPrivate;
class Q_DECL_EXPORT UserMetricsData: public QObject
{
public:
explicit UserMetricsData(QObject *parent);
UserMetricsData(const QString &label,
const ColorTheme &firstColor,
const QVariantList &firstMonth,
const ColorTheme &secondColor,
const QVariantList &secondMonth, QObject* parent);
~UserMetricsData();
protected:
UserMetricsDataPrivate * const d_ptr;
public:
const QString & label() const;
const ColorTheme & firstColor() const;
const QVariantList & firstMonth() const;
const ColorTheme & secondColor() const;
const QVariantList & secondMonth() const;
int length() const;
private:
Q_DECLARE_PRIVATE(UserMetricsData)
};
class UserMetricsPrivate: QObject
{
public:
explicit UserMetricsPrivate(UserMetrics *parent);
~UserMetricsPrivate();
public:
typedef QSharedPointer UserMetricsDataPtr;
typedef QMultiMap FakeDataMap;
UserMetrics * const q_ptr;
QString m_label;
ColorTheme m_firstColor;
QVariantListModel m_firstMonth;
ColorTheme m_secondColor;
QVariantListModel m_secondMonth;
int m_currentDay;
QString m_username;
FakeDataMap::const_iterator m_dataIndex;
UserMetricsDataPtr m_newData;
FakeDataMap m_fakeData;
void setUsername(const QString &username);
protected:
void nextFakeData();
void generateFakeData();
void loadFakeData();
void finishSetFakeData();
private:
Q_DECLARE_PUBLIC(UserMetrics)
};
class UserMetricsDataPrivate: QObject
{
public:
explicit UserMetricsDataPrivate(UserMetricsData *parent);
UserMetricsDataPrivate(const QString &label,
const ColorTheme &firstColor,
const QVariantList &firstMonth,
const ColorTheme &secondColor,
const QVariantList &secondMonth, UserMetricsData *parent);
~UserMetricsDataPrivate();
UserMetricsData * const q_ptr;
QString m_label;
ColorTheme m_firstColor;
QVariantList m_firstMonth;
ColorTheme m_secondColor;
QVariantList m_secondMonth;
int m_length;
protected:
int calculateLength();
private:
Q_DECLARE_PUBLIC(UserMetricsData)
};
}
UserMetricsDataPrivate::UserMetricsDataPrivate(UserMetricsData *parent) :
q_ptr(parent), m_firstColor(this), m_secondColor(this)
{
m_length = calculateLength();
}
UserMetricsDataPrivate::UserMetricsDataPrivate(const QString &label,
const ColorTheme &firstColor, const QVariantList &firstMonth,
const ColorTheme &secondColor,
const QVariantList &secondMonth, UserMetricsData *parent) :
q_ptr(parent), m_label(label), m_firstColor(this), m_firstMonth(
firstMonth), m_secondColor(this), m_secondMonth(secondMonth)
{
m_length = calculateLength();
m_firstColor = firstColor;
m_secondColor = secondColor;
}
UserMetricsDataPrivate::~UserMetricsDataPrivate()
{
}
int UserMetricsDataPrivate::calculateLength()
{
int day(m_firstMonth.size());
auto it = m_firstMonth.end(), end = m_firstMonth.begin();
while (it != end)
{
--it;
--day;
if (!it->isNull())
{
return day;
}
}
return -1;
}
UserMetricsData::UserMetricsData(QObject *parent) :
QObject(parent), d_ptr(new UserMetricsDataPrivate(this))
{
}
UserMetricsData::UserMetricsData(const QString &label,
const ColorTheme &firstColor, const QVariantList &firstMonth,
const ColorTheme &secondColor,
const QVariantList &secondMonth, QObject* parent) :
QObject(parent), d_ptr(
new UserMetricsDataPrivate(label, firstColor, firstMonth,
secondColor, secondMonth, this))
{
}
UserMetricsData::~UserMetricsData()
{
delete d_ptr;
}
const QString & UserMetricsData::label() const
{
return d_ptr->m_label;
}
const ColorTheme & UserMetricsData::firstColor() const
{
return d_ptr->m_firstColor;
}
const QVariantList & UserMetricsData::firstMonth() const
{
return d_ptr->m_firstMonth;
}
const ColorTheme & UserMetricsData::secondColor() const
{
return d_ptr->m_secondColor;
}
const QVariantList & UserMetricsData::secondMonth() const
{
return d_ptr->m_secondMonth;
}
int UserMetricsData::length() const
{
return d_ptr->m_length;
}
UserMetricsPrivate::UserMetricsPrivate(UserMetrics *parent) :
q_ptr(parent), m_firstColor(this), m_secondColor(this)
{
m_fakeData.insert("", UserMetricsDataPtr(new UserMetricsData(this)));
}
UserMetricsPrivate::~UserMetricsPrivate()
{
}
void UserMetricsPrivate::setUsername(const QString &username)
{
if (m_username == username && m_newData) {
return;
}
m_username = username;
m_dataIndex = m_fakeData.constFind(m_username);
if (m_dataIndex == m_fakeData.end())
{
m_dataIndex = m_fakeData.constFind("");
}
loadFakeData();
q_ptr->usernameChanged(m_username);
}
void UserMetricsPrivate::generateFakeData()
{
std::default_random_engine generator;
std::normal_distribution distribution(0.5, 0.2);
auto rand = std::bind(distribution, generator);
QVector colours;
colours.push_back(QColor::fromRgbF(0.3, 0.27, 0.32));
colours.push_back(QColor::fromRgbF(0.83, 0.49, 0.58));
colours.push_back(QColor::fromRgbF(0.63, 0.51, 0.59));
colours.push_back(QColor::fromRgbF(0.28, 0.26, 0.4));
colours.push_back(QColor::fromRgbF(0.47, 0.38, 0.56));
colours.push_back(QColor::fromRgbF(0.69, 0.65, 0.78));
colours.push_back(QColor::fromRgbF(0.32, 0.21, 0.16));
colours.push_back(QColor::fromRgbF(0.55, 0.45, 0.32));
colours.push_back(QColor::fromRgbF(0.85, 0.74, 0.53));
colours.push_back(QColor::fromRgbF(0.25, 0.31, 0.19));
colours.push_back(QColor::fromRgbF(0.63, 0.53, 0.3));
colours.push_back(QColor::fromRgbF(0.89, 0.56, 0.31));
ColorTheme first(colours[0], colours[1], colours[2]);
ColorTheme second(colours[3], colours[4], colours[5]);
ColorTheme eighth(colours[6], colours[7], colours[8]);
ColorTheme ninth(colours[9], colours[10], colours[11]);
{
QVariantList firstMonth;
while (firstMonth.size() < 17)
firstMonth.push_back(QVariant(rand()));
while (firstMonth.size() < 31)
firstMonth.push_back(QVariant());
QVariantList secondMonth;
while (secondMonth.size() < 31)
secondMonth.push_back(QVariant(rand()));
QSharedPointer data(
new UserMetricsData("52km travelled", first, firstMonth,
ninth, secondMonth, this));
m_fakeData.insert("single", data);
}
{
QVariantList firstMonth;
while (firstMonth.size() < 17)
firstMonth.push_back(QVariant(rand()));
while (firstMonth.size() < 31)
firstMonth.push_back(QVariant());
QVariantList secondMonth;
while (secondMonth.size() < 31)
secondMonth.push_back(QVariant(rand()));
QSharedPointer data(
new UserMetricsData("33 messages today", second,
firstMonth, eighth, secondMonth, this));
m_fakeData.insert("single", data);
}
{
QVariantList firstMonth;
while (firstMonth.size() < 17)
firstMonth.push_back(QVariant(rand()));
while (firstMonth.size() < 31)
firstMonth.push_back(QVariant());
QVariantList secondMonth;
while (secondMonth.size() < 31)
secondMonth.push_back(QVariant(rand()));
QSharedPointer data(
new UserMetricsData("19 minutes talk time", eighth,
firstMonth, second, secondMonth, this));
m_fakeData.insert("single", data);
// Also use same data for some tablet users
m_fakeData.insert("has-password", data);
m_fakeData.insert("no-password", data);
m_fakeData.insert("empty-name", data);
}
}
void UserMetricsPrivate::loadFakeData()
{
m_newData = *m_dataIndex;
bool oldLabelEmpty = m_label.isEmpty();
bool newLabelEmpty = m_newData->label().isEmpty();
if (oldLabelEmpty && !newLabelEmpty)
{
q_ptr->dataAboutToAppear();
finishSetFakeData();
} else if (!oldLabelEmpty && newLabelEmpty)
{
q_ptr->dataAboutToDisappear();
} else if (!oldLabelEmpty && !newLabelEmpty)
{
q_ptr->dataAboutToChange();
}
// we emit no signal if the data has stayed empty
}
void UserMetricsPrivate::finishSetFakeData()
{
bool oldLabelEmpty = m_label.isEmpty();
bool newLabelEmpty = m_newData->label().isEmpty();
m_label = m_newData->label();
m_firstColor = m_newData->firstColor();
m_firstMonth.setVariantList(m_newData->firstMonth());
m_secondColor = m_newData->secondColor();
m_secondMonth.setVariantList(m_newData->secondMonth());
bool currentDayChanged = m_currentDay != m_newData->length();
m_currentDay = m_newData->length();
q_ptr->labelChanged(m_label);
if (currentDayChanged)
{
q_ptr->currentDayChanged(m_currentDay);
}
if (oldLabelEmpty && !newLabelEmpty)
{
q_ptr->dataAppeared();
} else if (!oldLabelEmpty && newLabelEmpty)
{
q_ptr->dataDisappeared();
} else if (!oldLabelEmpty && !newLabelEmpty)
{
q_ptr->dataChanged();
}
// we emit no signal if the data has stayed empty
}
void UserMetricsPrivate::nextFakeData()
{
++m_dataIndex;
if (m_dataIndex == m_fakeData.end() || m_dataIndex.key() != m_username)
{
m_dataIndex = m_fakeData.constFind(m_username);
}
loadFakeData();
}
UserMetrics::UserMetrics(QObject *parent) :
QObject(parent), d_ptr(new UserMetricsPrivate(this))
{
d_ptr->generateFakeData();
setUsername("");
connect(this, SIGNAL(nextDataSource()), this, SLOT(nextDataSourceSlot()),
Qt::QueuedConnection);
connect(this, SIGNAL(readyForDataChange()), this,
SLOT(readyForDataChangeSlot()), Qt::QueuedConnection);
}
UserMetrics::~UserMetrics()
{
delete d_ptr;
}
QString UserMetrics::label() const
{
if (d_ptr->m_label.isEmpty()) {
return "No data";
} else {
return d_ptr->m_label;
}
}
QString UserMetrics::username() const
{
return d_ptr->m_username;
}
void UserMetrics::setUsername(const QString &username)
{
d_ptr->setUsername(username);
}
ColorTheme *UserMetrics::firstColor() const
{
return &d_ptr->m_firstColor;
}
ColorTheme *UserMetrics::secondColor() const
{
return &d_ptr->m_secondColor;
}
QAbstractItemModel *UserMetrics::firstMonth() const
{
return &d_ptr->m_firstMonth;
}
QAbstractItemModel *UserMetrics::secondMonth() const
{
return &d_ptr->m_secondMonth;
}
int UserMetrics::currentDay() const
{
return d_ptr->m_currentDay;
}
void UserMetrics::nextDataSourceSlot()
{
d_ptr->nextFakeData();
}
void UserMetrics::readyForDataChangeSlot()
{
d_ptr->finishSetFakeData();
}
/**
* Factory methods
*/
UserMetrics * UserMetrics::getInstance()
{
return new UserMetrics();
}