File indexing completed on 2024-04-28 16:30:32

0001 /***************************************************************************
0002  * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr
0003  * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  ***************************************************************************/
0006 /** @file
0007  * A report class for document
0008  *
0009  * @author Stephane MANKOWSKI
0010  */
0011 #include "skgreport.h"
0012 
0013 #include <grantlee/engine.h>
0014 #include <grantlee/metatype.h>
0015 #include <grantlee/qtlocalizer.h>
0016 #include <grantlee/templateloader.h>
0017 
0018 #include <kaboutdata.h>
0019 #include <kcolorscheme.h>
0020 
0021 #include <qdir.h>
0022 #include <qfile.h>
0023 #include <qfont.h>
0024 #include <qfontdatabase.h>
0025 #include <qstandardpaths.h>
0026 #include <qurl.h>
0027 #include "qregularexpression.h"
0028 #include <QRandomGenerator>
0029 
0030 #include "skgdocument.h"
0031 #include "skgobjectbase.h"
0032 #include "skgtraces.h"
0033 
0034 GRANTLEE_BEGIN_LOOKUP(SKGObjectBase)
0035 Q_UNUSED(object)
0036 Q_UNUSED(property)
0037 GRANTLEE_END_LOOKUP
0038 
0039 SKGReport::SKGReport(SKGDocument* iDocument)
0040     :  m_document(iDocument), m_previous(nullptr), m_pointSize(10)
0041 {
0042     SKGTRACEINFUNC(1)
0043 
0044     // Grantlee initialization
0045     Grantlee::registerMetaType<SKGObjectBase>();
0046 }
0047 
0048 SKGReport::~SKGReport()
0049 {
0050     SKGTRACEINFUNC(1)
0051     if (m_previous != nullptr) {
0052         delete m_previous;
0053         m_previous = nullptr;
0054     }
0055 }
0056 
0057 SKGDocument* SKGReport::getDocument() const
0058 {
0059     return m_document;
0060 }
0061 
0062 void SKGReport::setPeriod(const QString& iPeriod)
0063 {
0064     if (iPeriod != m_cache[QStringLiteral("period")]) {
0065         cleanCache(false);
0066         if (m_previous != nullptr) {
0067             delete m_previous;
0068             m_previous = nullptr;
0069         }
0070         m_cache[QStringLiteral("period")] = iPeriod;
0071         emit changed();
0072     }
0073 }
0074 
0075 QString SKGReport::getPeriod()
0076 {
0077     QString month = m_cache.value(QStringLiteral("period")).toString();
0078     if (month.isEmpty()) {
0079         month = QDate::currentDate().toString(QStringLiteral("yyyy-MM"));
0080         m_cache[QStringLiteral("period")] = month;
0081     }
0082     return month;
0083 }
0084 
0085 void SKGReport::setSqlFilter(const QString& iFilter)
0086 {
0087     if (iFilter != m_cache[QStringLiteral("filter")]) {
0088         cleanCache(false);
0089         m_cache[QStringLiteral("filter")] = iFilter;
0090         emit changed();
0091     }
0092 }
0093 
0094 QString SKGReport::getSqlFilter()
0095 {
0096     return m_cache.value(QStringLiteral("filter")).toString();;
0097 }
0098 
0099 QString SKGReport::getPreviousPeriod()
0100 {
0101     QString previousmonth = m_cache.value(QStringLiteral("previousperiod")).toString();
0102     if (previousmonth.isEmpty()) {
0103         QString period = getPeriod();
0104         if (!period.isEmpty()) {
0105             previousmonth = SKGServices::getNeighboringPeriod(period);
0106         }
0107         m_cache[QStringLiteral("previousperiod")] = previousmonth;
0108     }
0109     return previousmonth;
0110 }
0111 
0112 SKGReport* SKGReport::getPrevious()
0113 {
0114     if (m_previous == nullptr) {
0115         m_previous = m_document->getReport();
0116         m_previous->setPeriod(getPreviousPeriod());
0117     }
0118     return m_previous;
0119 }
0120 
0121 void SKGReport::setTipsOfDay(const QStringList& iTipsOfDays)
0122 {
0123     m_tipsOfTheDay = iTipsOfDays;
0124 
0125     emit changed();
0126 }
0127 
0128 QString SKGReport::getTipOfDay() const
0129 {
0130     auto tips = getTipsOfDay();
0131     auto tip = tips.count() > 0 ? SKGServices::htmlToString(tips.at(QRandomGenerator::global()->bounded(tips.size()))) : QString();
0132     return tip;
0133 }
0134 
0135 QStringList SKGReport::getTipsOfDay() const
0136 {
0137     return m_tipsOfTheDay;
0138 }
0139 
0140 QVariantHash SKGReport::getContextProperty()
0141 {
0142     QVariantHash mapping;
0143     addItemsInMapping(mapping);
0144 
0145     if (m_document != nullptr) {
0146         mapping.insert(QStringLiteral("document"), QVariant::fromValue<QObject*>(m_document));
0147     }
0148     return mapping;
0149 }
0150 
0151 void SKGReport::addItemsInMapping(QVariantHash& iMapping)
0152 {
0153     iMapping.insert(QStringLiteral("report"), QVariant::fromValue<QObject*>(this));
0154     iMapping.insert(QStringLiteral("current_date"), QDate::currentDate());
0155     KColorScheme scheme(QPalette::Normal, KColorScheme::Window);
0156     iMapping.insert(QStringLiteral("color_negativetext"), scheme.foreground(KColorScheme::NegativeText).color().name().right(6));
0157     iMapping.insert(QStringLiteral("color_positivetext"), scheme.foreground(KColorScheme::PositiveText).color().name().right(6));
0158     iMapping.insert(QStringLiteral("color_neutraltext"), scheme.foreground(KColorScheme::NeutralText).color().name().right(6));
0159     iMapping.insert(QStringLiteral("color_normaltext"), scheme.foreground(KColorScheme::NormalText).color().name().right(6));
0160     iMapping.insert(QStringLiteral("color_inactivetext"), scheme.foreground(KColorScheme::InactiveText).color().name().right(6));
0161     iMapping.insert(QStringLiteral("color_activetext"), scheme.foreground(KColorScheme::ActiveText).color().name().right(6));
0162     iMapping.insert(QStringLiteral("color_linktext"), scheme.foreground(KColorScheme::LinkText).color().name().right(6));
0163     iMapping.insert(QStringLiteral("color_visitedtext"), scheme.foreground(KColorScheme::VisitedText).color().name().right(6));
0164     iMapping.insert(QStringLiteral("color_normalbackground"), scheme.background(KColorScheme::NormalBackground).color().name().right(6));
0165     iMapping.insert(QStringLiteral("color_activebackground"), scheme.background(KColorScheme::ActiveBackground).color().name().right(6));
0166 
0167     QFont generalFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont);
0168     iMapping.insert(QStringLiteral("font_family"), generalFont.family());
0169 
0170     QString dir = "file://" % QFileInfo(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/infopage/kde_infopage.css"))).dir().absolutePath() % '/';
0171     {
0172         QFile file(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/infopage/kde_infopage.css")));
0173         if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
0174             iMapping.insert(QStringLiteral("kde_infopage_css"), QString(file.readAll()).replace(QStringLiteral("url("), "url(" % dir));
0175         }
0176     }
0177 
0178     KAboutData about = KAboutData::applicationData();
0179     iMapping.insert(QStringLiteral("about_welcome"), i18nc("Welcome message", "Welcome to %1", about.displayName()));
0180     iMapping.insert(QStringLiteral("about_programname"), about.displayName());
0181     iMapping.insert(QStringLiteral("about_version"), about.version());
0182     iMapping.insert(QStringLiteral("about_bugaddress"), about.bugAddress());
0183     iMapping.insert(QStringLiteral("about_copyrightstatement"), about.copyrightStatement());
0184     iMapping.insert(QStringLiteral("about_homepage"), about.homepage());
0185     iMapping.insert(QStringLiteral("about_shortdescription"), about.shortDescription());
0186     iMapping.insert(QStringLiteral("about_othertext"), about.otherText());
0187     iMapping.insert(QStringLiteral("about_did_you_know"), i18nc("Title for tips of the day", "Did you know …?"));
0188 }
0189 
0190 SKGError SKGReport::getReportFromTemplate(SKGReport* iReport, const QString& iFile, QString& oHtml)
0191 {
0192     SKGError err;
0193     SKGTRACEINFUNCRC(10, err)
0194 
0195     // Prepare grantlee engine
0196     Grantlee::Engine gEngine;
0197     gEngine.addDefaultLibrary(QStringLiteral("grantlee_skgfilters"));
0198 
0199     QSharedPointer<Grantlee::FileSystemTemplateLoader> gLoader = QSharedPointer<Grantlee::FileSystemTemplateLoader>(new Grantlee::FileSystemTemplateLoader());
0200     gLoader->setTemplateDirs(QStringList(QFileInfo(iFile).dir().absolutePath()));
0201     gEngine.addTemplateLoader(gLoader);
0202 
0203     Grantlee::Template gTemplate = gEngine.loadByName(QFileInfo(iFile).fileName());
0204     if (gTemplate->error() != 0u) {
0205         err = SKGError(gTemplate->error(), gTemplate->errorString());
0206     } else {
0207         QVariantHash mapping;
0208         if (iReport != nullptr) {
0209             mapping = iReport->getContextProperty();
0210         }
0211         Grantlee::Context gContext(mapping);
0212 
0213         // Generation
0214         {
0215             SKGTRACEINFUNCRC(10, err)
0216             oHtml = gTemplate->render(&gContext);
0217             QRegularExpression rx(QStringLiteral("\\n\\s*\\n"));
0218             oHtml = oHtml.replace(rx, QStringLiteral("\n"));
0219             if (gTemplate->error() != 0u) {
0220                 err = SKGError(gTemplate->error(), gTemplate->errorString());
0221             }
0222         }
0223     }
0224     return err;
0225 }
0226 
0227 void SKGReport::cleanCache(bool iEmitSignal)
0228 {
0229     QString month = m_cache.value(QStringLiteral("period")).toString();
0230     QString filter = m_cache.value(QStringLiteral("filter")).toString();
0231     m_cache.clear();
0232     if (!month.isEmpty()) {
0233         m_cache[QStringLiteral("period")] = month;
0234     }
0235     if (!filter.isEmpty()) {
0236         m_cache[QStringLiteral("filter")] = filter;
0237     }
0238     if (iEmitSignal) {
0239         emit changed();
0240     }
0241 }
0242 
0243 void SKGReport::addParameter(const QString& iName, const QVariant& ivalue)
0244 {
0245     m_parameters[iName] = ivalue;
0246 }
0247 
0248 void SKGReport::setPointSize(int iPointSize)
0249 {
0250     m_pointSize = iPointSize;
0251     emit changed();
0252 }
0253 
0254 int SKGReport::getPointSize() const
0255 {
0256     return m_pointSize;
0257 }