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 /statisticsdialog.cpp | |
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 :)
Diffstat (limited to 'statisticsdialog.cpp')
-rw-r--r-- | statisticsdialog.cpp | 256 |
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); + } + } +} |