/* * 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(); }