summaryrefslogtreecommitdiffstats
path: root/statisticsdialog.cpp
diff options
context:
space:
mode:
authorArno <am@disconnect.de>2011-02-12 14:59:36 +0100
committerArno <am@disconnect.de>2011-02-12 14:59:36 +0100
commita2e6438b97a8b9055bee400ccc40a062f0a0e9db (patch)
tree9ad9d23a390fa8749fcad3e09d32e3cacd76e1f7 /statisticsdialog.cpp
parent1cba003449f2c875b3be81a9f7c5835b183e78c8 (diff)
downloadSheMov-a2e6438b97a8b9055bee400ccc40a062f0a0e9db.tar.gz
SheMov-a2e6438b97a8b9055bee400ccc40a062f0a0e9db.tar.bz2
SheMov-a2e6438b97a8b9055bee400ccc40a062f0a0e9db.zip
Revamp statisticsdialog
Once again redesign the statisticsdialog. Switch back from WebKit and HTML/CSS graph bars to a QWidget. Never forget about QPainter::translate() again :)
Diffstat (limited to 'statisticsdialog.cpp')
-rw-r--r--statisticsdialog.cpp256
1 files changed, 184 insertions, 72 deletions
diff --git a/statisticsdialog.cpp b/statisticsdialog.cpp
index 30141c2..c25ceee 100644
--- a/statisticsdialog.cpp
+++ b/statisticsdialog.cpp
@@ -13,61 +13,52 @@
#include <QPushButton>
#include <QLocale>
#include <QFile>
-#include <QWebView>
+#include <QFontMetrics>
+#include <QFont>
+#include <QApplication>
+#include <QPainter>
+#include <QBrush>
+#include <QPen>
+#include <QPaintEvent>
+#include <QLinearGradient>
+#include <QColor>
+#include <QPainterPath>
+#include <QTextOption>
+#include <QScrollArea>
+#include <QPalette>
+#include <QLabel>
+
+class GraphWidget;
#include "statisticsdialog.h"
StatisticsDialog::StatisticsDialog(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f){
- //html skeleton
- QFile htmlFile(":/statistics.html");
- htmlFile.open(QIODevice::ReadOnly);
- QString html = htmlFile.readAll();
-
- //genre distribution
- QWebView *genreView = new QWebView;
- QString genreHtml = html;
- genreHtml.replace("{title}", tr("Genre distribution"));
- genreHtml.replace("{desc}", tr("Genres"));
QList<QList<QVariant> > data = queryData("SELECT genres.tgenrename, COUNT(seriesparts_genremap.iseriesparts_id) FROM genres, seriesparts_genremap WHERE genres.igenres_id = seriesparts_genremap.igenres_id GROUP BY genres.tgenrename ORDER BY count DESC;");
- QString tableData = table(data, max(data));
- genreHtml.replace("{table}", tableData);
- genreView->setHtml(genreHtml);
-
- //quality distribution
- QWebView *qualityView = new QWebView;
- QString qualityHtml = html;
- qualityHtml.replace("{title}", tr("Quality distribution"));
- qualityHtml.replace("{desc}", tr("Quality"));
+ GraphWidget *genreWidget = new GraphWidget(data, tr("Genre Distribution"));
data = queryData("SELECT files.siquality, COUNT(seriesparts.iseriesparts_id) FROM files, seriesparts WHERE files.iseriespart_id = seriesparts.iseriesparts_id AND files.siquality IS NOT NULL GROUP BY files.siquality ORDER by siquality desc;");
- tableData = table(data, max(data));
- qualityHtml.replace("{table}", tableData);
- qualityView->setHtml(qualityHtml);
-
- //top 20 actors
- QWebView *topActorView = new QWebView;
- QString topActorHtml = html;
- topActorHtml.replace("{title}", tr("Top 20 actors"));
- topActorHtml.replace("{desc}", tr("Actor"));
+ GraphWidget *qualityWidget = new GraphWidget(data, tr("Quality Distribution"));
data = queryData("SELECT actors.tactorname, COUNT(seriesparts_actormap.iseriesparts_id) FROM actors, seriesparts_actormap WHERE actors.iactors_id = seriesparts_actormap.iactors_id GROUP BY actors.tactorname ORDER BY count desc LIMIT 20");
- tableData = table(data, max(data));
- topActorHtml.replace("{table}", tableData);
- topActorView->setHtml(topActorHtml);
-
- //general statistics
- QWebView *generalView = new QWebView;
- QString generalHtml = html;
- generalHtml.remove(QRegExp("<thead>.*</thead>"));
- tableData = generalStatistics();
- generalHtml.replace("{title}", tr("General statistics"));
- generalHtml.replace("{table}", tableData);
- generalView->setHtml(generalHtml);
+ GraphWidget *actorWidget = new GraphWidget(data, tr("Top 20 Actors"));
+ GraphWidget *generalWidget = new GraphWidget(generalStatistics(), tr("General Statistics"));
//tab
+ QScrollArea *genreScroll = new QScrollArea;
+ genreScroll->setWidgetResizable(true);
+ genreScroll->setWidget(genreWidget);
+ QScrollArea *qualityScroll = new QScrollArea;
+ qualityScroll->setWidgetResizable(true);
+ qualityScroll->setWidget(qualityWidget);
+ QScrollArea *actorScroll = new QScrollArea;
+ actorScroll->setWidgetResizable(true);
+ actorScroll->setWidget(actorWidget);
+ QScrollArea *generalScroll = new QScrollArea;
+ generalScroll->setWidgetResizable(true);
+ generalScroll->setWidget(generalWidget);
QTabWidget *tab = new QTabWidget;
- tab->addTab(genreView, tr("Genres"));
- tab->addTab(qualityView, tr("Quality"));
- tab->addTab(topActorView, tr("Top 20 actors"));
- tab->addTab(generalView, tr("General statistics"));
+ tab->addTab(genreScroll, tr("Genres"));
+ tab->addTab(qualityScroll, tr("Quality"));
+ tab->addTab(actorScroll, tr("Top 20 actors"));
+ tab->addTab(generalScroll, tr("General Statistics"));
//close button
QPushButton *close = new QPushButton(tr("Close"));
@@ -84,21 +75,6 @@ StatisticsDialog::StatisticsDialog(QWidget *parent, Qt::WindowFlags f) : QDialog
setWindowTitle(tr("SheMov - Statistics"));
}
-QString StatisticsDialog::table(const QList<QList<QVariant> > &data, int max) const {
- QString table;
- QLocale loc;
- foreach(QList<QVariant> l, data){
- table.append("<tr>");
- int percent = l.at(1).toInt() * 100 / max - 1;
- percent = percent < 1 ? 1 : percent;
- table.append(QString("<td class=\"descr\">%1</td>").arg(l.at(0).toString()));
- table.append(QString("<td class=\"bar\"><div style=\"width: %1%\" class=\"bar\"></div></td>").arg(percent));
- table.append(QString("<td class=\"total\">%1</td>").arg(loc.toString(l.at(1).toInt())));
- table.append("</tr>");
- }
- return table;
-}
-
QList<QList<QVariant> > StatisticsDialog::queryData(const QString &query) const {
QSqlDatabase db = QSqlDatabase::database("treedb");
QSqlQuery q(query, db);
@@ -111,17 +87,6 @@ QList<QList<QVariant> > StatisticsDialog::queryData(const QString &query) const
return retval;
}
-int StatisticsDialog::max(const QList<QList<QVariant> > &data) const{
- int retval = 0;
- foreach(QList<QVariant> l, data){
- int value = l.at(1).toInt();
- if(value > retval){
- retval = value;
- }
- }
- return retval;
-}
-
QString StatisticsDialog::generalStatistics() const{
//get database
QSqlDatabase db = QSqlDatabase::database("treedb");
@@ -177,7 +142,7 @@ QString StatisticsDialog::generalStatistics() const{
int genreCount = q10.value(0).toInt();
//build the tabel
- QString retval;
+ QString retval("<table>");
QLocale loc;
retval.append(QString("<tr><td>Number of series</td><td style=\"padding-left: 30px\">%1</td></tr>").arg(numSeries));
retval.append(QString("<tr><td>Number of movies</td><td style=\"padding-left: 30px\">%1</td></tr>").arg(numMovies));
@@ -189,5 +154,152 @@ QString StatisticsDialog::generalStatistics() const{
retval.append(QString("<tr><td>Archived files size</td><td style=\"padding-left: 30px\">%1 GB</td></tr>").arg(loc.toString(archivedFileSize)));
retval.append(QString("<tr><td>Number of actors</td><td style=\"padding-left: 30px\">%1</td></tr>").arg(actorCount));
retval.append(QString("<tr><td>Number of genres</td><td style=\"padding-left: 30px\">%1</td></tr>").arg(genreCount));
+ retval.append("</table>");
return retval;
}
+
+GraphWidget::GraphWidget(const QList<QList<QVariant> > data, const QString header, QWidget *parent) : QWidget(parent), mData(data), mDescWidth(-1), mBarHeight(20), mMargin(10), mHeader(header), mMaxValue(-1), mPercentageWidth(-1), mTotal(0), mIsText(false){
+ //setup fonts
+ mHeaderFont = QFont("Arial", 20, QFont::Bold, true);
+ mDataFont = QFont("Arial", 12);
+
+ //calc max width of data, maxData and total
+ QFontMetrics fmd = QFontMetrics(mDataFont);
+ foreach(QList<QVariant> d, mData){
+ int width = fmd.size(Qt::TextSingleLine, d.at(0).toString()).width();
+ if(width > mDescWidth){
+ mDescWidth = width;
+ }
+ int v = d.at(1).toInt();
+ if(v > mMaxValue){
+ mMaxValue = v;
+ }
+ mTotal += d.at(1).toInt();
+ }
+
+ //set percentage width
+ foreach(QList<QVariant> d, mData){
+ qreal percentage = d.at(1).toFloat() * 100.0 / static_cast<float>(mTotal);
+ QString pString = QString("%1 (%2%)").arg(QString::number(d.at(1).toInt())).arg(QString::number(percentage, 'f', 2));
+ int width = fmd.size(Qt::TextSingleLine, pString).width();
+ if(width > mPercentageWidth){
+ mPercentageWidth = width;
+ }
+ }
+
+ //calc heading size
+ QFontMetrics fmh = QFontMetrics(mHeaderFont);
+ mHeaderSize = fmh.size(Qt::TextSingleLine, mHeader);
+
+ //set minimum size
+ setMinimumWidth(300);
+ setMinimumHeight(sizeHint().height());
+}
+
+GraphWidget::GraphWidget(const QString &text, const QString header, QWidget *parent): QWidget(parent), mBarHeight(-1), mMargin(20), mHeader(header), mText(text), mIsText(true){
+ //setup fonts
+ mHeaderFont = QFont("Arial", 20, QFont::Bold, true);
+ mDataFont = QFont("Arial", 12);
+
+ //calc heading size
+ QFontMetrics fmh = QFontMetrics(mHeaderFont);
+ mHeaderSize = fmh.size(Qt::TextSingleLine, mHeader);
+
+ //setup textDocument
+ mDoc.setDefaultFont(mDataFont);
+ mDoc.setDefaultStyleSheet("table { color: #004646 }");
+ mDoc.setHtml(mText);
+
+ //set minimum size
+ setMinimumWidth(300);
+ setMinimumHeight(sizeHint().height());
+}
+
+QSize GraphWidget::sizeHint() const {
+ if(mIsText){
+ return QSize(mDoc.size().width(), mDoc.size().height() + mHeaderSize.height() + mMargin);
+ }else{
+ int height = mData.size() * mBarHeight;
+ height += (mData.size() - 1) * mMargin; //margins between bars
+ height += 2 * mMargin; //top and bottom margin
+ return QSize(width(), height);
+ }
+}
+
+void GraphWidget::paintEvent(QPaintEvent *event){
+ Q_UNUSED(event);
+ QPainter p(this);
+
+ //draw background
+ QColor gColor1(186, 115, 101);
+ QColor gColor2(236, 210, 196);
+ QLinearGradient bgGradient(width() / 2, 0, width() / 2, height());
+ bgGradient.setColorAt(0, gColor1);
+ bgGradient.setColorAt(1, gColor2);
+ p.fillRect(rect(), bgGradient);
+
+ //draw heading
+ QColor headerColor(0, 70, 70);
+ const int topHeading = 5;
+ QRect headerRect(QPoint(mMargin * 4, topHeading), mHeaderSize);
+ QPen headerPen(headerColor);
+ headerPen.setWidth(3);
+ p.setPen(headerPen);
+ p.setFont(mHeaderFont);
+ p.drawText(headerRect, mHeader);
+
+ //draw line left to heading
+ QFontMetrics hfm(mHeaderFont);
+ int starty = topHeading + hfm.height() / 2;
+ int lstopx = mMargin * 4 - 10;
+ p.drawLine(mMargin, starty, lstopx, starty);
+
+ //draw line right to heading
+ int rstartx = mMargin * 4 + mHeaderSize.width() + 10;
+ int rstopx = width() - mMargin;
+ p.drawLine(rstartx, starty, rstopx, starty);
+
+ //draw data
+ p.setFont(mDataFont);
+ QPen dataPen(headerPen);
+ dataPen.setWidth(1);
+ p.setPen(dataPen);
+ if(mIsText){
+ int startx = (width() - mDoc.size().width()) / 2;
+ int starty = mHeaderSize.height() + mMargin;
+ p.translate(startx, starty);
+ mDoc.drawContents(&p);
+ }else{
+ int startTranslation = mHeaderSize.height() + mMargin;
+ p.translate(mMargin, startTranslation);
+ int curWidth = width() - 4 * mMargin - mDescWidth - mPercentageWidth; //1x margin in translation
+ QTextOption opt;
+ opt.setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ QTextOption optLeft;
+ opt.setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+ foreach(QList<QVariant> l, mData){
+ //draw lead
+ QRect textRect(0, 0, mDescWidth, mBarHeight);
+ p.drawText(textRect, l.at(0).toString(), opt);
+ //draw data rect
+ int dstartx = mDescWidth + mMargin;
+ qreal dwidth = l.at(1).toFloat() * curWidth / mMaxValue;
+ QRectF dataRect(dstartx, 0, dwidth, mBarHeight);
+ QLinearGradient dataGradient(dataRect.x(), dataRect.y() + dataRect.height() / 2.0, curWidth, dataRect.y() + dataRect.height() / 2.0);
+ QColor dgc1(0, 70, 70);
+ QColor dgc2(0, 255, 255);
+ dataGradient.setColorAt(0, dgc1);
+ dataGradient.setColorAt(1, dgc2);
+ p.fillRect(dataRect, dataGradient);
+ p.drawRect(dataRect);
+ //draw absolute and percentage
+ int pstartx = dataRect.width() + 2 * mMargin + mDescWidth;
+ QRect percentageRect(pstartx, 0, mPercentageWidth, 20);
+ qreal percent = l.at(1).toInt() * 100.0 / static_cast<float>(mTotal);
+ QString pString = QString("%1 (%2%)").arg(QString::number(l.at(1).toInt())).arg(QString::number(percent, 'f', 2));
+ p.drawText(percentageRect, pString, optLeft);
+ //translate
+ p.translate(0, mMargin + mBarHeight);
+ }
+ }
+}