categoryaggregator.cpp 5.23 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
    Copyright (C) 2017 Volker Krause <vkrause@kde.org>

    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    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 Library 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 <http://www.gnu.org/licenses/>.
*/

#include "categoryaggregator.h"
19
#include "chartutil.h"
20
21

#include <model/categoryaggregationmodel.h>
22
#include <model/extrarowsproxymodel.h>
23
24
#include <model/rolemappingproxymodel.h>
#include <model/timeaggregationmodel.h>
25

26
27
28
#include <QtCharts/QAreaSeries>
#include <QtCharts/QChart>
#include <QtCharts/QDateTimeAxis>
29
#include <QtCharts/QHPieModelMapper>
30
#include <QtCharts/QLineSeries>
31
#include <QtCharts/QPieSeries>
32
33
34
#include <QtCharts/QValueAxis>
#include <QtCharts/QVXYModelMapper>

35
36
#include <QDebug>

37
using namespace UserFeedback::Analyzer;
38
using namespace QtCharts;
39
40
41
42
43
44
45
46

CategoryAggregator::CategoryAggregator() = default;
CategoryAggregator::~CategoryAggregator() = default;

Aggregator::ChartModes CategoryAggregator::chartModes() const
{
    Aggregator::ChartModes modes = None;
    if (aggregation().elements().size() == 1)
47
        modes |= Timeline | Singular;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    return modes;
}

QString CategoryAggregator::displayName() const
{
    const auto e = aggregation().elements().at(0);
    return e.schemaEntry().name();
}

QAbstractItemModel* CategoryAggregator::timeAggregationModel()
{
    if (!m_model && !aggregation().elements().isEmpty()) {
        m_model.reset(new CategoryAggregationModel);
        m_model->setSourceModel(sourceModel());
        const auto e = aggregation().elements().at(0);
        m_model->setAggregationValue(e.schemaEntry().name() + QLatin1Char('.') + e.schemaEntryElement().name());
64
        QObject::connect(m_model.get(), &QAbstractItemModel::modelReset, [this]() {
65
66
            updateSingularChart();
            updateTimelineChart();
67
        });
68
69
70
71
72
73
    }
    return m_model.get();
}

QtCharts::QChart* CategoryAggregator::timelineChart()
{
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
    if (!m_timelineChart) {
        m_timelineChart.reset(new QChart);
        ChartUtil::applyTheme(m_timelineChart.get());
        auto xAxis = new QDateTimeAxis(m_timelineChart.get());
        xAxis->setFormat(QStringLiteral("yyyy-MM-dd")); // TODO, follow aggregation mode
        auto yAxis = new QValueAxis(m_timelineChart.get());
        xAxis->setTickCount(std::min(timeAggregationModel()->rowCount(), 12));
        yAxis->setMinorTickCount(4);

        m_timelineChart->addAxis(xAxis, Qt::AlignBottom);
        m_timelineChart->addAxis(yAxis, Qt::AlignLeft);
        updateTimelineChart();
    }

    return m_timelineChart.get();
}
90

91
92
93
94
95
void CategoryAggregator::updateTimelineChart()
{
    if (!m_timelineChart)
        return;
    m_timelineChart->removeAllSeries();
96
97

    QLineSeries *prevSeries = nullptr;
98
99
100
    auto model = new RoleMappingProxyModel(m_timelineChart.get());
    model->setSourceModel(timeAggregationModel());
    model->addRoleMapping(Qt::DisplayRole, TimeAggregationModel::AccumulatedDisplayRole);
101
102
103
104
    for (int i = 1; i < timeAggregationModel()->columnCount(); ++i) {
        auto series = new QLineSeries;

        auto mapper = new QVXYModelMapper(series);
105
        mapper->setModel(model);
106
107
108
109
110
111
112
113
114
115
        mapper->setXColumn(0);
        mapper->setYColumn(i);
        mapper->setFirstRow(0);
        mapper->setSeries(series);

        auto areaSeries = new QAreaSeries(series, prevSeries);
        series->setParent(areaSeries); // otherwise series isn't deleted by removeAllSeries!
        areaSeries->setName(timeAggregationModel()->headerData(i, Qt::Horizontal).toString().toHtmlEscaped());
        m_timelineChart->addSeries(areaSeries);

116
117
        areaSeries->attachAxis(m_timelineChart->axisX());
        areaSeries->attachAxis(m_timelineChart->axisY());
118
119
120
121

        prevSeries = series;
    }

122
123
124
    const auto max = timeAggregationModel()->index(0, 0).data(TimeAggregationModel::MaximumValueRole).toInt();
    m_timelineChart->axisY()->setRange(0, max);
    qobject_cast<QValueAxis*>(m_timelineChart->axisY())->applyNiceNumbers();
125
}
126
127
128

QtCharts::QChart* CategoryAggregator::singlularChart()
{
Volker Krause's avatar
Volker Krause committed
129
130
131
    if (!m_singularChart) {
        m_singularChart.reset(new QChart);
        ChartUtil::applyTheme(m_singularChart.get());
132
133
        updateSingularChart();
    }
134

Volker Krause's avatar
Volker Krause committed
135
    return m_singularChart.get();
136
137
138
139
}

void CategoryAggregator::updateSingularChart()
{
Volker Krause's avatar
Volker Krause committed
140
    if (!m_singularChart)
141
        return;
Volker Krause's avatar
Volker Krause committed
142
    m_singularChart->removeAllSeries();
143
144
145

    if (sourceModel()->rowCount() <= 0)
        return;
146

Volker Krause's avatar
Volker Krause committed
147
148
    auto series = new QPieSeries(m_singularChart.get());
    auto mapper = new QHPieModelMapper(m_singularChart.get());
149
150
151
    auto modelWithLabels = new ExtraRowsProxyModel(mapper);
    modelWithLabels->setSourceModel(singularAggregationModel());
    mapper->setModel(modelWithLabels);
152
153
    mapper->setFirstColumn(1);
    mapper->setValuesRow(0);
154
    mapper->setLabelsRow(1);
155
    mapper->setSeries(series);
156

Volker Krause's avatar
Volker Krause committed
157
    m_singularChart->addSeries(series);
158
}