2017-04-27 18:26:05 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2017-11-22 23:59:26 +00:00
|
|
|
#include <QFileDevice>
|
2019-06-06 05:41:29 +00:00
|
|
|
#include <QRegularExpression>
|
2019-04-26 16:03:23 +00:00
|
|
|
#include <list>
|
2015-04-21 15:23:13 +00:00
|
|
|
|
|
|
|
#include "templatelayout.h"
|
2020-05-01 11:43:52 +00:00
|
|
|
#include "core/divelist.h"
|
2019-11-24 14:02:34 +00:00
|
|
|
#include "core/selection.h"
|
2015-04-21 15:23:13 +00:00
|
|
|
|
2015-08-21 16:01:27 +00:00
|
|
|
QList<QString> grantlee_templates, grantlee_statistics_templates;
|
2015-07-24 07:26:25 +00:00
|
|
|
|
2020-12-12 12:28:36 +00:00
|
|
|
int getTotalWork(const print_options &printOptions)
|
2015-05-30 13:32:15 +00:00
|
|
|
{
|
2020-12-12 12:28:36 +00:00
|
|
|
if (printOptions.print_selected) {
|
2015-06-21 04:13:22 +00:00
|
|
|
// return the correct number depending on all/selected dives
|
|
|
|
// but don't return 0 as we might divide by this number
|
2017-09-18 14:10:47 +00:00
|
|
|
return amount_selected && !in_planner() ? amount_selected : 1;
|
2015-06-21 04:13:22 +00:00
|
|
|
}
|
2016-01-08 17:32:42 +00:00
|
|
|
return dive_table.nr;
|
2015-05-30 13:32:15 +00:00
|
|
|
}
|
2015-04-21 15:23:13 +00:00
|
|
|
|
2015-07-24 07:26:25 +00:00
|
|
|
void find_all_templates()
|
|
|
|
{
|
2019-04-01 20:15:19 +00:00
|
|
|
const QLatin1String ext(".html");
|
2015-07-26 13:58:00 +00:00
|
|
|
grantlee_templates.clear();
|
2015-08-21 16:01:27 +00:00
|
|
|
grantlee_statistics_templates.clear();
|
2015-10-18 21:25:14 +00:00
|
|
|
QDir dir(getPrintingTemplatePathUser());
|
2019-04-01 20:15:19 +00:00
|
|
|
const QStringList list = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
|
|
|
|
for (const QString &filename: list) {
|
2017-11-24 18:55:16 +00:00
|
|
|
if (filename.at(filename.size() - 1) != '~' && filename.endsWith(ext))
|
2016-01-08 17:42:27 +00:00
|
|
|
grantlee_templates.append(filename);
|
2015-07-24 07:26:25 +00:00
|
|
|
}
|
2016-01-08 17:42:27 +00:00
|
|
|
|
2015-08-21 16:01:27 +00:00
|
|
|
// find statistics templates
|
2015-10-18 21:25:14 +00:00
|
|
|
dir.setPath(getPrintingTemplatePathUser() + QDir::separator() + "statistics");
|
2019-04-01 20:15:19 +00:00
|
|
|
const QStringList stat = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
|
|
|
|
for (const QString &filename: stat) {
|
2017-11-24 18:55:16 +00:00
|
|
|
if (filename.at(filename.size() - 1) != '~' && filename.endsWith(ext))
|
2016-01-08 17:42:27 +00:00
|
|
|
grantlee_statistics_templates.append(filename);
|
2015-08-21 16:01:27 +00:00
|
|
|
}
|
2015-07-24 07:26:25 +00:00
|
|
|
}
|
|
|
|
|
2017-11-22 23:59:26 +00:00
|
|
|
/* find templates which are part of the bundle in the user path
|
|
|
|
* and set them as read only.
|
|
|
|
*/
|
|
|
|
void set_bundled_templates_as_read_only()
|
|
|
|
{
|
|
|
|
QDir dir;
|
|
|
|
const QString stats("statistics");
|
|
|
|
QStringList list, listStats;
|
|
|
|
QString pathBundle = getPrintingTemplatePathBundle();
|
|
|
|
QString pathUser = getPrintingTemplatePathUser();
|
|
|
|
|
|
|
|
dir.setPath(pathBundle);
|
|
|
|
list = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
|
|
|
|
dir.setPath(pathBundle + QDir::separator() + stats);
|
|
|
|
listStats = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
|
|
|
|
for (int i = 0; i < listStats.length(); i++)
|
|
|
|
listStats[i] = stats + QDir::separator() + listStats.at(i);
|
|
|
|
list += listStats;
|
|
|
|
|
|
|
|
foreach (const QString& f, list)
|
|
|
|
QFile::setPermissions(pathUser + QDir::separator() + f, QFileDevice::ReadOwner | QFileDevice::ReadUser);
|
|
|
|
}
|
|
|
|
|
2017-11-24 20:54:54 +00:00
|
|
|
void copy_bundled_templates(QString src, QString dst, QStringList *templateBackupList)
|
|
|
|
{
|
|
|
|
QDir dir(src);
|
|
|
|
if (!dir.exists())
|
|
|
|
return;
|
2019-04-01 20:15:19 +00:00
|
|
|
const auto dirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
|
|
|
for (const QString &d: dirs) {
|
2017-11-24 20:54:54 +00:00
|
|
|
QString dst_path = dst + QDir::separator() + d;
|
|
|
|
dir.mkpath(dst_path);
|
|
|
|
copy_bundled_templates(src + QDir::separator() + d, dst_path, templateBackupList);
|
|
|
|
}
|
2019-04-01 20:15:19 +00:00
|
|
|
const auto files = dir.entryList(QDir::Files);
|
|
|
|
for (const QString &f: files) {
|
2017-11-24 20:54:54 +00:00
|
|
|
QFile fileSrc(src + QDir::separator() + f);
|
|
|
|
QFile fileDest(dst + QDir::separator() + f);
|
|
|
|
if (fileDest.exists()) {
|
|
|
|
// if open() fails the file is either locked or r/o. try to remove it and then overwrite
|
|
|
|
if (!fileDest.open(QFile::ReadWrite | QFile::Text)) {
|
|
|
|
fileDest.setPermissions(QFileDevice::WriteOwner | QFileDevice::WriteUser);
|
|
|
|
fileDest.remove();
|
|
|
|
} else { // if the file is not read-only create a backup
|
|
|
|
fileDest.close();
|
|
|
|
const QString targetFile = fileDest.fileName().replace(".html", "-User.html");
|
|
|
|
fileDest.copy(targetFile);
|
|
|
|
*templateBackupList << targetFile;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fileSrc.copy(fileDest.fileName()); // in all cases copy the file
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-12 12:28:36 +00:00
|
|
|
TemplateLayout::TemplateLayout(const print_options &printOptions, const template_options &templateOptions) :
|
|
|
|
printOptions(printOptions), templateOptions(templateOptions)
|
2015-06-10 11:39:15 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-04-21 15:23:13 +00:00
|
|
|
QString TemplateLayout::generate()
|
|
|
|
{
|
2015-05-30 13:32:15 +00:00
|
|
|
int progress = 0;
|
2019-04-26 15:51:25 +00:00
|
|
|
int totalWork = getTotalWork(printOptions);
|
2015-05-30 13:32:15 +00:00
|
|
|
|
2015-04-21 15:23:13 +00:00
|
|
|
QString htmlContent;
|
|
|
|
|
2020-12-12 14:08:56 +00:00
|
|
|
State state;
|
2015-04-21 15:23:13 +00:00
|
|
|
|
|
|
|
struct dive *dive;
|
2017-09-18 14:10:47 +00:00
|
|
|
if (in_planner()) {
|
2020-12-12 14:08:56 +00:00
|
|
|
state.dives.append(DiveObjectHelperGrantlee(&displayed_dive));
|
2017-09-18 14:10:47 +00:00
|
|
|
emit progressUpdated(100.0);
|
|
|
|
} else {
|
|
|
|
int i;
|
|
|
|
for_each_dive (i, dive) {
|
|
|
|
//TODO check for exporting selected dives only
|
2020-12-12 12:28:36 +00:00
|
|
|
if (!dive->selected && printOptions.print_selected)
|
2017-09-18 14:10:47 +00:00
|
|
|
continue;
|
2020-12-12 14:08:56 +00:00
|
|
|
state.dives.append(DiveObjectHelperGrantlee(dive));
|
2017-09-18 14:10:47 +00:00
|
|
|
progress++;
|
|
|
|
emit progressUpdated(lrint(progress * 100.0 / totalWork));
|
|
|
|
}
|
2015-04-21 15:23:13 +00:00
|
|
|
}
|
|
|
|
|
2020-12-12 12:28:36 +00:00
|
|
|
QString templateContents = readTemplate(printOptions.p_template);
|
2020-08-21 11:24:10 +00:00
|
|
|
|
|
|
|
QList<token> tokens = lexer(templateContents);
|
|
|
|
QString buffer;
|
|
|
|
QTextStream out(&buffer);
|
2020-12-12 16:20:00 +00:00
|
|
|
parser(tokens, 0, tokens.size(), out, state);
|
2020-08-21 11:24:10 +00:00
|
|
|
htmlContent = out.readAll();
|
|
|
|
return htmlContent;
|
2015-04-21 15:23:13 +00:00
|
|
|
}
|
|
|
|
|
2015-08-21 17:03:42 +00:00
|
|
|
QString TemplateLayout::generateStatistics()
|
|
|
|
{
|
|
|
|
QString htmlContent;
|
2020-12-12 14:08:56 +00:00
|
|
|
|
|
|
|
State state;
|
2015-08-21 17:03:42 +00:00
|
|
|
|
|
|
|
int i = 0;
|
2018-10-06 08:58:12 +00:00
|
|
|
stats_summary_auto_free stats;
|
2018-10-06 14:50:46 +00:00
|
|
|
calculate_stats_summary(&stats, false);
|
2018-10-06 08:58:12 +00:00
|
|
|
while (stats.stats_yearly != NULL && stats.stats_yearly[i].period) {
|
2020-12-13 12:05:30 +00:00
|
|
|
state.years.append(&stats.stats_yearly[i]);
|
2015-08-21 17:03:42 +00:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2020-12-12 12:28:36 +00:00
|
|
|
QString templateFile = QString("statistics") + QDir::separator() + printOptions.p_template;
|
2020-08-21 11:24:10 +00:00
|
|
|
QString templateContents = readTemplate(templateFile);
|
|
|
|
|
|
|
|
QList<token> tokens = lexer(templateContents);
|
|
|
|
QString buffer;
|
|
|
|
QTextStream out(&buffer);
|
2020-12-12 16:20:00 +00:00
|
|
|
parser(tokens, 0, tokens.size(), out, state);
|
2020-08-21 11:24:10 +00:00
|
|
|
htmlContent = out.readAll();
|
|
|
|
return htmlContent;
|
2015-08-21 17:03:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-05 04:21:39 +00:00
|
|
|
QString TemplateLayout::readTemplate(QString template_name)
|
|
|
|
{
|
2015-10-18 21:25:14 +00:00
|
|
|
QFile qfile(getPrintingTemplatePathUser() + QDir::separator() + template_name);
|
2015-07-05 04:21:39 +00:00
|
|
|
if (qfile.open(QFile::ReadOnly | QFile::Text)) {
|
|
|
|
QTextStream in(&qfile);
|
|
|
|
return in.readAll();
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
void TemplateLayout::writeTemplate(QString template_name, QString grantlee_template)
|
|
|
|
{
|
2015-10-18 21:25:14 +00:00
|
|
|
QFile qfile(getPrintingTemplatePathUser() + QDir::separator() + template_name);
|
2015-07-05 04:21:39 +00:00
|
|
|
if (qfile.open(QFile::ReadWrite | QFile::Text)) {
|
2018-02-25 12:51:41 +00:00
|
|
|
qfile.write(qPrintable(grantlee_template));
|
2015-07-07 01:12:36 +00:00
|
|
|
qfile.resize(qfile.pos());
|
2015-07-05 04:21:39 +00:00
|
|
|
qfile.close();
|
|
|
|
}
|
|
|
|
}
|
2020-08-21 11:24:10 +00:00
|
|
|
|
|
|
|
struct token stringToken(QString s)
|
|
|
|
{
|
|
|
|
struct token newtoken;
|
|
|
|
newtoken.type = LITERAL;
|
|
|
|
newtoken.contents = s;
|
|
|
|
return newtoken;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QRegularExpression keywordFor(R"(\bfor\b)");
|
|
|
|
static QRegularExpression keywordEndfor(R"(\bendfor\b)");
|
|
|
|
static QRegularExpression keywordBlock(R"(\bblock\b)");
|
|
|
|
static QRegularExpression keywordEndblock(R"(\bendblock\b)");
|
|
|
|
static QRegularExpression keywordIf(R"(\bif\b)");
|
|
|
|
static QRegularExpression keywordEndif(R"(\bendif\b)");
|
|
|
|
|
|
|
|
struct token operatorToken(QString s)
|
|
|
|
{
|
|
|
|
struct token newtoken;
|
|
|
|
|
|
|
|
QRegularExpressionMatch match = keywordFor.match(s);
|
|
|
|
if (match.hasMatch()) {
|
|
|
|
newtoken.type = FORSTART;
|
|
|
|
newtoken.contents = s.mid(match.capturedEnd());
|
|
|
|
return newtoken;
|
|
|
|
}
|
|
|
|
match = keywordEndfor.match(s);
|
|
|
|
if (match.hasMatch()) {
|
|
|
|
newtoken.type = FORSTOP;
|
|
|
|
newtoken.contents = "";
|
|
|
|
return newtoken;
|
|
|
|
}
|
|
|
|
match = keywordBlock.match(s);
|
|
|
|
if (match.hasMatch()) {
|
|
|
|
newtoken.type = BLOCKSTART;
|
|
|
|
newtoken.contents = s.mid(match.capturedEnd());
|
|
|
|
return newtoken;
|
|
|
|
}
|
|
|
|
match = keywordEndblock.match(s);
|
|
|
|
if (match.hasMatch()) {
|
|
|
|
newtoken.type = BLOCKSTOP;
|
|
|
|
newtoken.contents = "";
|
|
|
|
return newtoken;
|
|
|
|
}
|
|
|
|
match = keywordIf.match(s);
|
|
|
|
if (match.hasMatch()) {
|
|
|
|
newtoken.type = IFSTART;
|
|
|
|
newtoken.contents = s.mid(match.capturedEnd());
|
|
|
|
return newtoken;
|
|
|
|
}
|
|
|
|
match = keywordEndif.match(s);
|
|
|
|
if (match.hasMatch()) {
|
|
|
|
newtoken.type = IFSTOP;
|
|
|
|
newtoken.contents = "";
|
|
|
|
return newtoken;
|
|
|
|
}
|
|
|
|
|
|
|
|
newtoken.type = PARSERERROR;
|
|
|
|
newtoken.contents = "";
|
|
|
|
return newtoken;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QRegularExpression op(R"(\{%([\w\s\.\|\:]+)%\})"); // Look for {% stuff %}
|
|
|
|
|
|
|
|
QList<token> TemplateLayout::lexer(QString input)
|
|
|
|
{
|
|
|
|
QList<token> tokenList;
|
|
|
|
|
|
|
|
int last = 0;
|
|
|
|
QRegularExpressionMatch match = op.match(input);
|
|
|
|
while (match.hasMatch()) {
|
|
|
|
tokenList << stringToken(input.mid(last, match.capturedStart() - last));
|
|
|
|
tokenList << operatorToken(match.captured(1));
|
|
|
|
last = match.capturedEnd();
|
|
|
|
match = op.match(input, last);
|
|
|
|
}
|
|
|
|
tokenList << stringToken(input.mid(last));
|
|
|
|
return tokenList;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QRegularExpression var(R"(\{\{\s*(\w+)\.(\w+)\s*(\|\s*(\w+))?\s*\}\})"); // Look for {{ stuff.stuff|stuff }}
|
|
|
|
|
2020-12-12 14:08:56 +00:00
|
|
|
QString TemplateLayout::translate(QString s, State &state)
|
2020-08-21 11:24:10 +00:00
|
|
|
{
|
|
|
|
QString out;
|
|
|
|
int last = 0;
|
|
|
|
QRegularExpressionMatch match = var.match(s);
|
|
|
|
while (match.hasMatch()) {
|
|
|
|
QString obname = match.captured(1);
|
|
|
|
QString memname = match.captured(2);
|
|
|
|
out += s.mid(last, match.capturedStart() - last);
|
2020-12-12 14:08:56 +00:00
|
|
|
QString listname = state.types.value(obname, obname);
|
|
|
|
QVariant value = getValue(listname, memname, state);
|
2020-08-21 11:24:10 +00:00
|
|
|
out += value.toString();
|
|
|
|
last = match.capturedEnd();
|
|
|
|
match = var.match(s, last);
|
|
|
|
}
|
|
|
|
out += s.mid(last);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QRegularExpression forloop(R"(\s*(\w+)\s+in\s+(\w+))"); // Look for "VAR in LISTNAME"
|
|
|
|
static QRegularExpression ifstatement(R"(forloop\.counter\|\s*divisibleby\:\s*(\d+))"); // Look for forloop.counter|divisibleby: NUMBER
|
|
|
|
|
2020-12-12 14:08:56 +00:00
|
|
|
template<typename V, typename T>
|
2020-12-12 16:20:00 +00:00
|
|
|
void TemplateLayout::parser_for(QList<token> tokenList, int from, int to, QTextStream &out, State &state,
|
2020-12-12 14:08:56 +00:00
|
|
|
const V &data, const T *&act)
|
|
|
|
{
|
|
|
|
const T *old = act;
|
|
|
|
int i = 1; // Loop iterators start at one
|
|
|
|
int olditerator = state.forloopiterator;
|
|
|
|
for (const T &item: data) {
|
|
|
|
act = &item;
|
2020-12-12 16:20:00 +00:00
|
|
|
state.forloopiterator = i++;
|
|
|
|
parser(tokenList, from, to, out, state);
|
2020-12-12 14:08:56 +00:00
|
|
|
}
|
|
|
|
act = old;
|
|
|
|
state.forloopiterator = olditerator;
|
|
|
|
}
|
|
|
|
|
2020-12-12 16:20:00 +00:00
|
|
|
// Find end of for or if block. Keeps track of nested blocks.
|
|
|
|
// Pos should point one past the starting tag.
|
|
|
|
// Returns -1 if no matching end tag found.
|
|
|
|
static int findEnd(const QList<token> &tokenList, int from, int to, token_t start, token_t end)
|
2020-08-21 11:24:10 +00:00
|
|
|
{
|
2020-12-12 16:20:00 +00:00
|
|
|
int depth = 1;
|
|
|
|
for (int pos = from; pos < to; ++pos) {
|
|
|
|
if (tokenList[pos].type == start) {
|
|
|
|
++depth;
|
|
|
|
} else if (tokenList[pos].type == end) {
|
|
|
|
if (--depth <= 0)
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TemplateLayout::parser(QList<token> tokenList, int from, int to, QTextStream &out, State &state)
|
|
|
|
{
|
|
|
|
for (int pos = from; pos < to; ++pos) {
|
2020-08-21 11:24:10 +00:00
|
|
|
switch (tokenList[pos].type) {
|
|
|
|
case LITERAL:
|
2020-12-12 14:08:56 +00:00
|
|
|
out << translate(tokenList[pos].contents, state);
|
2020-08-21 11:24:10 +00:00
|
|
|
break;
|
|
|
|
case BLOCKSTART:
|
|
|
|
case BLOCKSTOP:
|
|
|
|
break;
|
|
|
|
case FORSTART:
|
|
|
|
{
|
|
|
|
QString argument = tokenList[pos].contents;
|
|
|
|
++pos;
|
|
|
|
QRegularExpressionMatch match = forloop.match(argument);
|
|
|
|
if (match.hasMatch()) {
|
|
|
|
QString itemname = match.captured(1);
|
|
|
|
QString listname = match.captured(2);
|
2020-12-12 14:08:56 +00:00
|
|
|
state.types[itemname] = listname;
|
2020-08-21 11:24:10 +00:00
|
|
|
QString buffer;
|
|
|
|
QTextStream capture(&buffer);
|
2020-12-12 16:20:00 +00:00
|
|
|
int loop_end = findEnd(tokenList, pos, to, FORSTART, FORSTOP);
|
|
|
|
if (loop_end < 0) {
|
|
|
|
out << "UNMATCHED FOR: '" << argument << "'";
|
|
|
|
break;
|
|
|
|
}
|
2020-12-12 14:08:56 +00:00
|
|
|
if (listname == "years") {
|
2020-12-12 16:20:00 +00:00
|
|
|
parser_for(tokenList, pos, loop_end, capture, state, state.years, state.currentYear);
|
2020-12-12 14:08:56 +00:00
|
|
|
} else if (listname == "dives") {
|
2020-12-12 16:20:00 +00:00
|
|
|
parser_for(tokenList, pos, loop_end, capture, state, state.dives, state.currentDive);
|
2020-12-12 14:08:56 +00:00
|
|
|
} else if (listname == "cylinders") {
|
|
|
|
if (state.currentDive)
|
2020-12-12 16:20:00 +00:00
|
|
|
parser_for(tokenList, pos, loop_end, capture, state, state.currentDive->cylinders, state.currentCylinder);
|
2020-12-12 14:08:56 +00:00
|
|
|
else
|
|
|
|
qWarning("cylinders loop outside of dive");
|
|
|
|
} else if (listname == "cylinderObjects") {
|
|
|
|
if (state.currentDive)
|
2020-12-12 16:20:00 +00:00
|
|
|
parser_for(tokenList, pos, loop_end, capture, state, state.currentDive->cylinderObjects, state.currentCylinderObject);
|
2020-12-12 14:08:56 +00:00
|
|
|
else
|
|
|
|
qWarning("cylinderObjects loop outside of dive");
|
2020-12-12 16:20:00 +00:00
|
|
|
} else {
|
|
|
|
qWarning("unknown loop: %s", qPrintable(listname));
|
2020-08-21 11:24:10 +00:00
|
|
|
}
|
2020-12-12 14:08:56 +00:00
|
|
|
state.types.remove(itemname);
|
2020-08-21 11:24:10 +00:00
|
|
|
out << capture.readAll();
|
2020-12-12 16:20:00 +00:00
|
|
|
pos = loop_end;
|
2020-08-21 11:24:10 +00:00
|
|
|
} else {
|
|
|
|
out << "PARSING ERROR: '" << argument << "'";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IFSTART:
|
|
|
|
{
|
|
|
|
QString argument = tokenList[pos].contents;
|
|
|
|
++pos;
|
|
|
|
QRegularExpressionMatch match = ifstatement.match(argument);
|
|
|
|
if (match.hasMatch()) {
|
2020-12-12 16:20:00 +00:00
|
|
|
int if_end = findEnd(tokenList, pos, to, IFSTART, IFSTOP);
|
|
|
|
if (if_end < 0) {
|
|
|
|
out << "UNMATCHED IF: '" << argument << "'";
|
|
|
|
break;
|
|
|
|
}
|
2020-08-21 11:24:10 +00:00
|
|
|
int divisor = match.captured(1).toInt();
|
2020-12-12 14:08:56 +00:00
|
|
|
int counter = std::max(0, state.forloopiterator);
|
2020-12-12 16:20:00 +00:00
|
|
|
if (!(counter % divisor)) {
|
|
|
|
QString buffer;
|
|
|
|
QTextStream capture(&buffer);
|
|
|
|
parser(tokenList, pos, if_end, capture, state);
|
2020-08-21 11:24:10 +00:00
|
|
|
out << capture.readAll();
|
2020-12-12 16:20:00 +00:00
|
|
|
}
|
|
|
|
pos = if_end;
|
2020-08-21 11:24:10 +00:00
|
|
|
} else {
|
|
|
|
out << "PARSING ERROR: '" << argument << "'";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FORSTOP:
|
|
|
|
case IFSTOP:
|
2020-12-12 16:20:00 +00:00
|
|
|
out << "UNEXPECTED END: " << tokenList[pos].contents;
|
2020-08-21 11:24:10 +00:00
|
|
|
return;
|
|
|
|
case PARSERERROR:
|
|
|
|
out << "PARSING ERROR";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-12 14:08:56 +00:00
|
|
|
QVariant TemplateLayout::getValue(QString list, QString property, const State &state)
|
2020-08-21 11:24:10 +00:00
|
|
|
{
|
|
|
|
if (list == "template_options") {
|
|
|
|
if (property == "font") {
|
2020-12-12 14:08:56 +00:00
|
|
|
switch (templateOptions.font_index) {
|
2020-08-21 11:24:10 +00:00
|
|
|
case 0:
|
|
|
|
return "Arial, Helvetica, sans-serif";
|
|
|
|
case 1:
|
|
|
|
return "Impact, Charcoal, sans-serif";
|
|
|
|
case 2:
|
|
|
|
return "Georgia, serif";
|
|
|
|
case 3:
|
|
|
|
return "Courier, monospace";
|
|
|
|
case 4:
|
|
|
|
return "Verdana, Geneva, sans-serif";
|
|
|
|
}
|
|
|
|
} else if (property == "borderwidth") {
|
2020-12-12 14:08:56 +00:00
|
|
|
return templateOptions.border_width;
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "font_size") {
|
2020-12-12 14:08:56 +00:00
|
|
|
return templateOptions.font_size / 9.0;
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "line_spacing") {
|
2020-12-12 14:08:56 +00:00
|
|
|
return templateOptions.line_spacing;
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "color1") {
|
2020-12-12 14:08:56 +00:00
|
|
|
return templateOptions.color_palette.color1.name();
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "color2") {
|
2020-12-12 14:08:56 +00:00
|
|
|
return templateOptions.color_palette.color2.name();
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "color3") {
|
2020-12-12 14:08:56 +00:00
|
|
|
return templateOptions.color_palette.color3.name();
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "color4") {
|
2020-12-12 14:08:56 +00:00
|
|
|
return templateOptions.color_palette.color4.name();
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "color5") {
|
2020-12-12 14:08:56 +00:00
|
|
|
return templateOptions.color_palette.color5.name();
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "color6") {
|
2020-12-12 14:08:56 +00:00
|
|
|
return templateOptions.color_palette.color6.name();
|
2020-08-21 11:24:10 +00:00
|
|
|
}
|
|
|
|
} else if (list == "print_options") {
|
|
|
|
if (property == "grayscale") {
|
2020-12-12 14:08:56 +00:00
|
|
|
if (printOptions.color_selected) {
|
2020-08-21 11:24:10 +00:00
|
|
|
return "";
|
|
|
|
} else {
|
|
|
|
return "-webkit-filter: grayscale(100%)";
|
|
|
|
}
|
|
|
|
}
|
2020-12-12 14:08:56 +00:00
|
|
|
} else if (list =="years") {
|
|
|
|
if (!state.currentYear)
|
|
|
|
return QVariant();
|
2020-12-13 12:05:30 +00:00
|
|
|
const stats_t *object = *state.currentYear;
|
2020-08-21 11:24:10 +00:00
|
|
|
if (property == "year") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return object->period;
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "dives") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return object->selection_size;
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "min_temp") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return object->min_temp.mkelvin == 0 ? "0" : get_temperature_string(object->min_temp, true);
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "max_temp") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return object->max_temp.mkelvin == 0 ? "0" : get_temperature_string(object->max_temp, true);
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "total_time") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return get_dive_duration_string(object->total_time.seconds, gettextFromC::tr("h"),
|
2020-08-21 11:24:10 +00:00
|
|
|
gettextFromC::tr("min"), gettextFromC::tr("sec"), " ");
|
|
|
|
} else if (property == "avg_time") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return get_minutes(object->total_time.seconds / object->selection_size);
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "shortest_time") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return get_minutes(object->shortest_time.seconds);
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "longest_time") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return get_minutes(object->longest_time.seconds);
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "avg_depth") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return get_depth_string(object->avg_depth);
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "min_depth") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return get_depth_string(object->min_depth);
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "max_depth") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return get_depth_string(object->max_depth);
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "avg_sac") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return get_volume_string(object->avg_sac);
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "min_sac") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return get_volume_string(object->min_sac);
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "max_sac") {
|
2020-12-13 12:05:30 +00:00
|
|
|
return get_volume_string(object->max_sac);
|
2020-08-21 11:24:10 +00:00
|
|
|
}
|
2020-12-08 22:44:44 +00:00
|
|
|
} else if (list == "cylinders") {
|
2020-12-12 14:08:56 +00:00
|
|
|
if (state.currentCylinder && property == "description") {
|
|
|
|
return *state.currentCylinder;
|
2020-12-08 22:44:44 +00:00
|
|
|
}
|
|
|
|
} else if (list == "cylinderObjects") {
|
2020-12-12 14:08:56 +00:00
|
|
|
if (!state.currentCylinderObject)
|
|
|
|
return QVariant();
|
|
|
|
const CylinderObjectHelper &object = *state.currentCylinderObject;
|
2020-08-21 11:24:10 +00:00
|
|
|
if (property == "description") {
|
|
|
|
return object.description;
|
|
|
|
} else if (property == "size") {
|
|
|
|
return object.size;
|
|
|
|
} else if (property == "workingPressure") {
|
|
|
|
return object.workingPressure;
|
|
|
|
} else if (property == "startPressure") {
|
|
|
|
return object.startPressure;
|
|
|
|
} else if (property == "endPressure") {
|
|
|
|
return object.endPressure;
|
|
|
|
} else if (property == "gasMix") {
|
|
|
|
return object.gasMix;
|
|
|
|
}
|
2020-12-08 22:44:44 +00:00
|
|
|
} else if (list == "dives") {
|
2020-12-12 14:08:56 +00:00
|
|
|
if (!state.currentDive)
|
|
|
|
return QVariant();
|
|
|
|
const DiveObjectHelperGrantlee &object = *state.currentDive;
|
2020-08-21 11:24:10 +00:00
|
|
|
if (property == "number") {
|
|
|
|
return object.number;
|
|
|
|
} else if (property == "id") {
|
|
|
|
return object.id;
|
|
|
|
} else if (property == "rating") {
|
|
|
|
return object.rating;
|
|
|
|
} else if (property == "visibility") {
|
|
|
|
return object.visibility;
|
2020-12-11 16:31:04 +00:00
|
|
|
} else if (property == "wavesize") {
|
|
|
|
return object.wavesize;
|
|
|
|
} else if (property == "current") {
|
|
|
|
return object.current;
|
|
|
|
} else if (property == "surge") {
|
|
|
|
return object.surge;
|
|
|
|
} else if (property == "chill") {
|
|
|
|
return object.chill;
|
2020-08-21 11:24:10 +00:00
|
|
|
} else if (property == "date") {
|
|
|
|
return object.date();
|
|
|
|
} else if (property == "time") {
|
|
|
|
return object.time();
|
|
|
|
} else if (property == "timestamp") {
|
|
|
|
return QVariant::fromValue(object.timestamp);
|
|
|
|
} else if (property == "location") {
|
|
|
|
return object.location;
|
|
|
|
} else if (property == "gps") {
|
|
|
|
return object.gps;
|
|
|
|
} else if (property == "gps_decimal") {
|
|
|
|
return object.gps_decimal;
|
|
|
|
} else if (property == "dive_site") {
|
|
|
|
return object.dive_site;
|
|
|
|
} else if (property == "duration") {
|
|
|
|
return object.duration;
|
|
|
|
} else if (property == "noDive") {
|
|
|
|
return object.noDive;
|
|
|
|
} else if (property == "depth") {
|
|
|
|
return object.depth;
|
|
|
|
} else if (property == "divemaster") {
|
|
|
|
return object.divemaster;
|
|
|
|
} else if (property == "buddy") {
|
|
|
|
return object.buddy;
|
|
|
|
} else if (property == "airTemp") {
|
|
|
|
return object.airTemp;
|
|
|
|
} else if (property == "waterTemp") {
|
|
|
|
return object.waterTemp;
|
|
|
|
} else if (property == "notes") {
|
|
|
|
return object.notes;
|
|
|
|
} else if (property == "tags") {
|
|
|
|
return object.tags;
|
|
|
|
} else if (property == "gas") {
|
|
|
|
return object.gas;
|
|
|
|
} else if (property == "sac") {
|
|
|
|
return object.sac;
|
|
|
|
} else if (property == "weightList") {
|
|
|
|
return object.weightList;
|
|
|
|
} else if (property == "weights") {
|
|
|
|
return object.weights;
|
|
|
|
} else if (property == "singleWeight") {
|
|
|
|
return object.singleWeight;
|
|
|
|
} else if (property == "suit") {
|
|
|
|
return object.suit;
|
|
|
|
} else if (property == "cylinderList") {
|
|
|
|
return object.cylinderList();
|
|
|
|
} else if (property == "cylinders") {
|
|
|
|
return object.cylinders;
|
|
|
|
} else if (property == "cylinderObjects") {
|
|
|
|
return QVariant::fromValue(object.cylinderObjects);
|
|
|
|
} else if (property == "maxcns") {
|
|
|
|
return object.maxcns;
|
|
|
|
} else if (property == "otu") {
|
|
|
|
return object.otu;
|
|
|
|
} else if (property == "sumWeight") {
|
|
|
|
return object.sumWeight;
|
|
|
|
} else if (property == "getCylinder") {
|
|
|
|
return object.getCylinder;
|
|
|
|
} else if (property == "startPressure") {
|
|
|
|
return object.startPressure;
|
|
|
|
} else if (property == "endPressure") {
|
|
|
|
return object.endPressure;
|
|
|
|
} else if (property == "firstGas") {
|
|
|
|
return object.firstGas;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return QVariant();
|
|
|
|
}
|