1 /***************************************************************************
2 * SPDX-FileCopyrightText: 2021 S. MANKOWSKI stephane@mankowski.fr
3 * SPDX-FileCopyrightText: 2021 G. DE BURE support@mankowski.fr
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 ***************************************************************************/
6 /** @file
7 * A report class for document
8 *
9 * @author Stephane MANKOWSKI
10 */
11 #include "skgreport.h"
12
13 #include <grantlee/engine.h>
14 #include <grantlee/metatype.h>
15 #include <grantlee/qtlocalizer.h>
16 #include <grantlee/templateloader.h>
17
18 #include <kaboutdata.h>
19 #include <kcolorscheme.h>
20
21 #include <qdir.h>
22 #include <qfile.h>
23 #include <qfont.h>
24 #include <qfontdatabase.h>
25 #include <qstandardpaths.h>
26 #include <qurl.h>
27 #include "qregularexpression.h"
28 #include <QRandomGenerator>
29
30 #include "skgdocument.h"
31 #include "skgobjectbase.h"
32 #include "skgtraces.h"
33
34 GRANTLEE_BEGIN_LOOKUP(SKGObjectBase)
Q_UNUSED(object)35 Q_UNUSED(object)
36 Q_UNUSED(property)
37 GRANTLEE_END_LOOKUP
38
39 SKGReport::SKGReport(SKGDocument* iDocument)
40 : m_document(iDocument), m_previous(nullptr), m_pointSize(10)
41 {
42 SKGTRACEINFUNC(1)
43
44 // Grantlee initialization
45 Grantlee::registerMetaType<SKGObjectBase>();
46 }
47
~SKGReport()48 SKGReport::~SKGReport()
49 {
50 SKGTRACEINFUNC(1)
51 if (m_previous != nullptr) {
52 delete m_previous;
53 m_previous = nullptr;
54 }
55 }
56
getDocument() const57 SKGDocument* SKGReport::getDocument() const
58 {
59 return m_document;
60 }
61
setPeriod(const QString & iPeriod)62 void SKGReport::setPeriod(const QString& iPeriod)
63 {
64 if (iPeriod != m_cache[QStringLiteral("period")]) {
65 cleanCache(false);
66 if (m_previous != nullptr) {
67 delete m_previous;
68 m_previous = nullptr;
69 }
70 m_cache[QStringLiteral("period")] = iPeriod;
71 emit changed();
72 }
73 }
74
getPeriod()75 QString SKGReport::getPeriod()
76 {
77 QString month = m_cache.value(QStringLiteral("period")).toString();
78 if (month.isEmpty()) {
79 month = QDate::currentDate().toString(QStringLiteral("yyyy-MM"));
80 m_cache[QStringLiteral("period")] = month;
81 }
82 return month;
83 }
84
setSqlFilter(const QString & iFilter)85 void SKGReport::setSqlFilter(const QString& iFilter)
86 {
87 if (iFilter != m_cache[QStringLiteral("filter")]) {
88 cleanCache(false);
89 m_cache[QStringLiteral("filter")] = iFilter;
90 emit changed();
91 }
92 }
93
getSqlFilter()94 QString SKGReport::getSqlFilter()
95 {
96 return m_cache.value(QStringLiteral("filter")).toString();;
97 }
98
getPreviousPeriod()99 QString SKGReport::getPreviousPeriod()
100 {
101 QString previousmonth = m_cache.value(QStringLiteral("previousperiod")).toString();
102 if (previousmonth.isEmpty()) {
103 QString period = getPeriod();
104 if (!period.isEmpty()) {
105 previousmonth = SKGServices::getNeighboringPeriod(period);
106 }
107 m_cache[QStringLiteral("previousperiod")] = previousmonth;
108 }
109 return previousmonth;
110 }
111
getPrevious()112 SKGReport* SKGReport::getPrevious()
113 {
114 if (m_previous == nullptr) {
115 m_previous = m_document->getReport();
116 m_previous->setPeriod(getPreviousPeriod());
117 }
118 return m_previous;
119 }
120
setTipsOfDay(const QStringList & iTipsOfDays)121 void SKGReport::setTipsOfDay(const QStringList& iTipsOfDays)
122 {
123 m_tipsOfTheDay = iTipsOfDays;
124
125 emit changed();
126 }
127
getTipOfDay() const128 QString SKGReport::getTipOfDay() const
129 {
130 auto tips = getTipsOfDay();
131 auto tip = tips.count() > 0 ? SKGServices::htmlToString(tips.at(QRandomGenerator::global()->bounded(tips.size()))) : QString();
132 return tip;
133 }
134
getTipsOfDay() const135 QStringList SKGReport::getTipsOfDay() const
136 {
137 return m_tipsOfTheDay;
138 }
139
getContextProperty()140 QVariantHash SKGReport::getContextProperty()
141 {
142 QVariantHash mapping;
143 addItemsInMapping(mapping);
144
145 if (m_document != nullptr) {
146 mapping.insert(QStringLiteral("document"), QVariant::fromValue<QObject*>(m_document));
147 }
148 return mapping;
149 }
150
addItemsInMapping(QVariantHash & iMapping)151 void SKGReport::addItemsInMapping(QVariantHash& iMapping)
152 {
153 iMapping.insert(QStringLiteral("report"), QVariant::fromValue<QObject*>(this));
154 iMapping.insert(QStringLiteral("current_date"), QDate::currentDate());
155 KColorScheme scheme(QPalette::Normal, KColorScheme::Window);
156 iMapping.insert(QStringLiteral("color_negativetext"), scheme.foreground(KColorScheme::NegativeText).color().name().right(6));
157 iMapping.insert(QStringLiteral("color_positivetext"), scheme.foreground(KColorScheme::PositiveText).color().name().right(6));
158 iMapping.insert(QStringLiteral("color_neutraltext"), scheme.foreground(KColorScheme::NeutralText).color().name().right(6));
159 iMapping.insert(QStringLiteral("color_normaltext"), scheme.foreground(KColorScheme::NormalText).color().name().right(6));
160 iMapping.insert(QStringLiteral("color_inactivetext"), scheme.foreground(KColorScheme::InactiveText).color().name().right(6));
161 iMapping.insert(QStringLiteral("color_activetext"), scheme.foreground(KColorScheme::ActiveText).color().name().right(6));
162 iMapping.insert(QStringLiteral("color_linktext"), scheme.foreground(KColorScheme::LinkText).color().name().right(6));
163 iMapping.insert(QStringLiteral("color_visitedtext"), scheme.foreground(KColorScheme::VisitedText).color().name().right(6));
164 iMapping.insert(QStringLiteral("color_normalbackground"), scheme.background(KColorScheme::NormalBackground).color().name().right(6));
165 iMapping.insert(QStringLiteral("color_activebackground"), scheme.background(KColorScheme::ActiveBackground).color().name().right(6));
166
167 QFont generalFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont);
168 iMapping.insert(QStringLiteral("font_family"), generalFont.family());
169
170 QString dir = "file://" % QFileInfo(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/infopage/kde_infopage.css"))).dir().absolutePath() % '/';
171 {
172 QFile file(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/infopage/kde_infopage.css")));
173 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
174 iMapping.insert(QStringLiteral("kde_infopage_css"), QString(file.readAll()).replace(QStringLiteral("url("), "url(" % dir));
175 }
176 }
177
178 KAboutData about = KAboutData::applicationData();
179 iMapping.insert(QStringLiteral("about_welcome"), i18nc("Welcome message", "Welcome to %1", about.displayName()));
180 iMapping.insert(QStringLiteral("about_programname"), about.displayName());
181 iMapping.insert(QStringLiteral("about_version"), about.version());
182 iMapping.insert(QStringLiteral("about_bugaddress"), about.bugAddress());
183 iMapping.insert(QStringLiteral("about_copyrightstatement"), about.copyrightStatement());
184 iMapping.insert(QStringLiteral("about_homepage"), about.homepage());
185 iMapping.insert(QStringLiteral("about_shortdescription"), about.shortDescription());
186 iMapping.insert(QStringLiteral("about_othertext"), about.otherText());
187 iMapping.insert(QStringLiteral("about_did_you_know"), i18nc("Title for tips of the day", "Did you know ...?"));
188 }
189
getReportFromTemplate(SKGReport * iReport,const QString & iFile,QString & oHtml)190 SKGError SKGReport::getReportFromTemplate(SKGReport* iReport, const QString& iFile, QString& oHtml)
191 {
192 SKGError err;
193 SKGTRACEINFUNCRC(10, err)
194
195 // Prepare grantlee engine
196 Grantlee::Engine gEngine;
197 gEngine.addDefaultLibrary(QStringLiteral("grantlee_skgfilters"));
198
199 QSharedPointer<Grantlee::FileSystemTemplateLoader> gLoader = QSharedPointer<Grantlee::FileSystemTemplateLoader>(new Grantlee::FileSystemTemplateLoader());
200 gLoader->setTemplateDirs(QStringList(QFileInfo(iFile).dir().absolutePath()));
201 gEngine.addTemplateLoader(gLoader);
202
203 Grantlee::Template gTemplate = gEngine.loadByName(QFileInfo(iFile).fileName());
204 if (gTemplate->error() != 0u) {
205 err = SKGError(gTemplate->error(), gTemplate->errorString());
206 } else {
207 QVariantHash mapping;
208 if (iReport != nullptr) {
209 mapping = iReport->getContextProperty();
210 }
211 Grantlee::Context gContext(mapping);
212
213 // Generation
214 {
215 SKGTRACEINFUNCRC(10, err)
216 oHtml = gTemplate->render(&gContext);
217 QRegularExpression rx(QStringLiteral("\\n\\s*\\n"));
218 oHtml = oHtml.replace(rx, QStringLiteral("\n"));
219 if (gTemplate->error() != 0u) {
220 err = SKGError(gTemplate->error(), gTemplate->errorString());
221 }
222 }
223 }
224 return err;
225 }
226
cleanCache(bool iEmitSignal)227 void SKGReport::cleanCache(bool iEmitSignal)
228 {
229 QString month = m_cache.value(QStringLiteral("period")).toString();
230 QString filter = m_cache.value(QStringLiteral("filter")).toString();
231 m_cache.clear();
232 if (!month.isEmpty()) {
233 m_cache[QStringLiteral("period")] = month;
234 }
235 if (!filter.isEmpty()) {
236 m_cache[QStringLiteral("filter")] = filter;
237 }
238 if (iEmitSignal) {
239 emit changed();
240 }
241 }
242
addParameter(const QString & iName,const QVariant & ivalue)243 void SKGReport::addParameter(const QString& iName, const QVariant& ivalue)
244 {
245 m_parameters[iName] = ivalue;
246 }
247
setPointSize(int iPointSize)248 void SKGReport::setPointSize(int iPointSize)
249 {
250 m_pointSize = iPointSize;
251 emit changed();
252 }
253
getPointSize() const254 int SKGReport::getPointSize() const
255 {
256 return m_pointSize;
257 }
258