File indexing completed on 2024-05-12 05:09:21
0001 /*************************************************************************** 0002 Copyright (C) 2021 Robby Stephenson <robby@periapsis.org> 0003 ***************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or * 0008 * modify it under the terms of the GNU General Public License as * 0009 * published by the Free Software Foundation; either version 2 of * 0010 * the License or (at your option) version 3 or any later version * 0011 * accepted by the membership of KDE e.V. (or its successor approved * 0012 * by the membership of KDE e.V.), which shall act as a proxy * 0013 * defined in Section 14 of version 3 of the license. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0022 * * 0023 ***************************************************************************/ 0024 0025 #include "yeardistributionreport.h" 0026 #include "../document.h" 0027 #include "../tellico_debug.h" 0028 0029 #include <KLocalizedString> 0030 0031 #include <QApplication> 0032 #include <QVBoxLayout> 0033 #include <QChartView> 0034 #include <QBarSet> 0035 #include <QBarSeries> 0036 #include <QValueAxis> 0037 #include <QGraphicsSimpleTextItem> 0038 0039 using namespace QtCharts; 0040 using Tellico::YearDistributionReport; 0041 0042 class YearDistributionReport::View : public QChartView { 0043 Q_OBJECT 0044 public: 0045 View(QChart* chart, QWidget* parent) : QChartView(chart, parent), m_tip(nullptr) {}; 0046 0047 public: 0048 void tooltip(bool status, int index, QBarSet* barSet) { 0049 if(status) { 0050 if(!m_tip) m_tip = new QGraphicsSimpleTextItem(chart()); 0051 m_tip->setText(QString::number(index) + QLatin1String(" : ") + QString::number(barSet->at(index))); 0052 const QPointF p(index, barSet->at(index)); 0053 m_tip->setPos(chart()->mapToPosition(p) + QPointF(5, -20)); 0054 m_tip->setZValue(11); 0055 m_tip->show(); 0056 } else { 0057 m_tip->hide(); 0058 } 0059 } 0060 0061 private: 0062 QGraphicsSimpleTextItem* m_tip; 0063 }; 0064 0065 YearDistributionReport::YearDistributionReport() : ChartReport() { 0066 } 0067 0068 QString YearDistributionReport::title() const { 0069 return i18n("Year Distribution"); 0070 } 0071 0072 QWidget* YearDistributionReport::createWidget() { 0073 // create a new widget every time 0074 Data::CollPtr coll = Data::Document::self()->collection(); 0075 Q_ASSERT(coll); 0076 0077 QString yearField = QStringLiteral("year"); 0078 if(!coll->hasField(yearField)) { 0079 yearField = QStringLiteral("pub_year"); 0080 } 0081 if(!coll->hasField(yearField)) { 0082 myDebug() << "No year field in collection"; 0083 return nullptr; 0084 } 0085 const bool multiple = coll->fieldByName(yearField)->hasFlag(Data::Field::AllowMultiple); 0086 0087 QMap<QString, int> entryYearCount; 0088 foreach(Data::EntryPtr entry, coll->entries()) { 0089 const QString year = entry->field(yearField); 0090 if(year.isEmpty()) { 0091 continue; 0092 } 0093 QStringList years; 0094 if(multiple) { 0095 years = FieldFormat::splitValue(year); 0096 } else { 0097 years << year; 0098 } 0099 foreach(const QString& y, years) { 0100 entryYearCount[y]++; 0101 } 0102 } 0103 0104 if(entryYearCount.isEmpty()) { 0105 return nullptr; 0106 } 0107 0108 bool ok; 0109 const uint minYear = entryYearCount.firstKey().toUInt(&ok); 0110 if(!ok) return nullptr; 0111 const uint maxYear = entryYearCount.lastKey().toUInt(&ok); 0112 if(!ok) return nullptr; 0113 0114 // pad beginning of bar set with zeros in order to use the year as an index number 0115 QList<qreal> zeroes; 0116 zeroes.reserve(minYear); 0117 for(uint i = 0; i < minYear; ++i) zeroes.append(0); 0118 auto barSet = new QBarSet(yearField); 0119 barSet->append(zeroes); 0120 0121 const uint yearDelta = maxYear-minYear; 0122 for(uint yd = 0; yd <= yearDelta; ++yd) { 0123 const QString yearString = QString::number(minYear + yd); 0124 // some years might not be represented in the map, the bar set will have 0 for them 0125 barSet->append(entryYearCount.value(yearString, 0)); 0126 } 0127 0128 auto series = new QBarSeries; 0129 series->append(barSet); 0130 0131 auto chart = new QChart; 0132 chart->addSeries(series); 0133 chart->setTitle(i18n("Year Distribution")); 0134 chart->legend()->setVisible(false); 0135 chart->setAcceptHoverEvents(true); 0136 chart->setTheme(qApp->palette().color(QPalette::Window).lightnessF() < 0.25 ? QChart::ChartThemeDark 0137 : QChart::ChartThemeLight); 0138 QFont f = chart->titleFont(); 0139 int fontSize = f.pointSize(); 0140 if(fontSize > 0) { 0141 f.setPointSize(qRound(fontSize * 1.3)); 0142 } else { 0143 f.setPixelSize(qRound(f.pixelSize() * 1.3)); 0144 } 0145 f.setWeight(QFont::Bold); 0146 chart->setTitleFont(f); 0147 0148 auto axisX = new QValueAxis; 0149 axisX->setLabelFormat(QStringLiteral("%d")); 0150 axisX->setRange(minYear, maxYear); 0151 axisX->setTitleText(coll->fieldTitleByName(yearField)); 0152 chart->addAxis(axisX, Qt::AlignBottom); 0153 series->attachAxis(axisX); 0154 axisX->applyNiceNumbers(); 0155 0156 auto axisY = new QValueAxis; 0157 axisY->setLabelFormat(QStringLiteral("%d")); 0158 axisY->setTitleText(i18nc("Distinct number of items", "Count")); 0159 chart->addAxis(axisY, Qt::AlignLeft); 0160 series->attachAxis(axisY); 0161 if(axisY->max() < 5) axisY->setMax(5); 0162 axisY->applyNiceNumbers(); 0163 axisY->setMinorTickCount(4); 0164 axisY->setMinorGridLineVisible(true); 0165 0166 auto widget = new QWidget; 0167 auto layout = new QVBoxLayout(widget); 0168 layout->setMargin(0); 0169 layout->setSpacing(0); 0170 auto chartView = new View(chart, widget); 0171 chartView->setRenderHint(QPainter::Antialiasing); 0172 // avoid a transparent frame around the chart 0173 chartView->setBackgroundBrush(chart->backgroundBrush()); 0174 QObject::connect(series, &QBarSeries::hovered, chartView, &View::tooltip); 0175 layout->addWidget(chartView); 0176 widget->setLayout(layout); 0177 return widget; 0178 } 0179 0180 #include "yeardistributionreport.moc"