diff options
author | Arno <am@disconnect.de> | 2011-02-12 14:59:36 +0100 |
---|---|---|
committer | Arno <am@disconnect.de> | 2011-02-12 14:59:36 +0100 |
commit | a2e6438b97a8b9055bee400ccc40a062f0a0e9db (patch) | |
tree | 9ad9d23a390fa8749fcad3e09d32e3cacd76e1f7 | |
parent | 1cba003449f2c875b3be81a9f7c5835b183e78c8 (diff) | |
download | SheMov-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 :)
-rw-r--r-- | shemov.pro | 1 | ||||
-rw-r--r-- | shemov.qrc | 1 | ||||
-rw-r--r-- | statistics.html | 67 | ||||
-rw-r--r-- | statisticsdialog.cpp | 256 | ||||
-rw-r--r-- | statisticsdialog.h | 35 |
5 files changed, 217 insertions, 143 deletions
@@ -5,7 +5,6 @@ CONFIG += warn_on \ debug CONFIG -= release QT += sql -QT += webkit SOURCES = main.cpp \ filesystemdirproxy.cpp \ filesystemwidget.cpp \ @@ -6,7 +6,6 @@ <file>shemov.png</file> <file>archive.svg</file> <file>shemov_splash.png</file> - <file>statistics.html</file> <file>back_dick.png</file> <file>up_dick.png</file> <file>chastity_belt.png</file> diff --git a/statistics.html b/statistics.html deleted file mode 100644 index d4432c2..0000000 --- a/statistics.html +++ /dev/null @@ -1,67 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" -"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> -<title>{title}</title> -<style type="text/css"> -body, html { - margin: 10px; - padding: 10px; - background: #0015F2; - color: #d9ed1b; -} -body { - min-width: 100%; -} -h1 { - text-align:center; - margin-top: 0; - padding-top: 0; -} -.overview { - border: 1px solid; - margin-left: auto; - margin-right: auto; -} -td.desc { - width: 15%; -} -td.total { - width: 15%; - text-align: right; -} -.bar { - width: 60%; - background-color: #0FE6FD; - text-align: right; - border-left: solid 1px; - padding-right: 0.5em; -} -.bar div { - border-top: 2px solid #066FF7; - border-bottom: 2px solid #066FF7; - background-color: #d9ed1b; - text-align: right; - float: left; - padding-top: 0; - height: 1em; -} -</style> -</head> -<body> -<h1>{title}</h1> -<table class="overview"> -<thead> -<tr> -<th>{desc}</th> -<th>Graph</th> -<th>Number</th> -</tr> -</thead> -<tbody> -{table} -</tbody> -</table> -</body> -</html> 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); + } + } +} diff --git a/statisticsdialog.h b/statisticsdialog.h index 70f2e55..4e7107a 100644 --- a/statisticsdialog.h +++ b/statisticsdialog.h @@ -11,6 +11,11 @@ #include <QDialog> #include <QList> #include <QVariant> +#include <QSize> +#include <QFont> +#include <QTextDocument> + +class QPaintEvent; class StatisticsDialog : public QDialog { Q_OBJECT @@ -19,11 +24,37 @@ class StatisticsDialog : public QDialog { ~StatisticsDialog() {} private: - QString table(const QList<QList<QVariant> > &data, int max) const; QList<QList<QVariant> > queryData(const QString &query) const; - int max(const QList<QList<QVariant> > &data) const; QString generalStatistics() const; }; +class GraphWidget : public QWidget { + Q_OBJECT + public: + GraphWidget(const QList<QList<QVariant> > data, const QString header, QWidget *parent = 0); + GraphWidget(const QString &text, const QString header, QWidget *parent = 0); + virtual ~GraphWidget() {} + virtual QSize sizeHint() const; + + protected: + virtual void paintEvent(QPaintEvent *event); + + private: + QList<QList<QVariant> > mData; + int mDescWidth; + const int mBarHeight; + const int mMargin; + const QString mHeader; + QSize mHeaderSize; + QFont mHeaderFont; + QFont mDataFont; + int mMaxValue; + int mPercentageWidth; + int mTotal; + const QString mText; + bool mIsText; + QTextDocument mDoc; +}; + #endif |