[KLF Backend][KLF Tools][KLF Home]
KLatexFormula Project
klfuserscript.cpp
1/***************************************************************************
2 * file klfuserscript.cpp
3 * This file is part of the KLatexFormula Project.
4 * Copyright (C) 2012 by Philippe Faist
5 * philippe.faist at bluewin.ch
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
22/* $Id$ */
23
24#include <QFileInfo>
25#include <QDir>
26#include <QDateTime>
27#include <QByteArray>
28
29#include <klfdefs.h>
30#include <klfdebug.h>
31#include <klfpobj.h>
32#include <klfdatautil.h>
33
34#include "klfbackend.h"
35#include "klfbackend_p.h"
36#include "klfuserscript.h"
37
38
49/*
50static int read_spec_section(const QString& str, int fromindex, const QRegExp& seprx, QString * extractedPart)
51{
52 int i = fromindex;
53 bool in_quote = false;
54
55 QString s;
56
57 while (i < str.length() && (in_quote || seprx.indexIn(str, i) != i)) {
58 if (str[i] == '\\') {
59 s.append(str[i]);
60 if (i+1 < str.length())
61 s.append(str[i+1]);
62 i += 2; // skip next char, too. The actual escaping will be done with klfEscapedToData()
63 continue;
64 }
65 if (str[i] == '"') {
66 in_quote = !in_quote;
67 ++i;
68 continue;
69 }
70 s.append(str[i]);
71 ++i;
72 }
73
74 *extractedPart = QString::fromLocal8Bit(klfEscapedToData(s.toLocal8Bit()));
75
76 return i; // the position of the last char separator
77}
78
79*/
80
81
82
83
84
85struct KLFUserScriptInfo::Private : public KLFPropertizedObject
86{
87 Private()
88 : KLFPropertizedObject("KLFUserScriptInfo")
89 {
90 refcount = 0;
91 scriptInfoError = KLFERR_NOERROR;
92
93 registerBuiltInProperty(ExeScript, QLatin1String("ExeScript"));
94 registerBuiltInProperty(Category, QLatin1String("Category"));
96 registerBuiltInProperty(Author, QLatin1String("Author"));
97 registerBuiltInProperty(Version, QLatin1String("Version"));
98 registerBuiltInProperty(License, QLatin1String("License"));
99 registerBuiltInProperty(KLFMinVersion, QLatin1String("KLFMinVersion"));
100 registerBuiltInProperty(KLFMaxVersion, QLatin1String("KLFMaxVersion"));
101 registerBuiltInProperty(SettingsFormUI, QLatin1String("SettingsFormUI"));
102 registerBuiltInProperty(CanProvideDefaultSettings, QLatin1String("CanProvideDefaultSettings"));
104 }
105
106 void clear()
107 {
108 // clear all properties
110 for (int k = 0; k < idlist.size(); ++k) {
112 }
113 }
114
115 int refcount;
116 inline int ref() { return ++refcount; }
117 inline int deref() { return --refcount; }
118
119 QString uspath;
120 QString normalizedfname;
121 QString sname;
122 QString basename;
123 int scriptInfoError;
124 QString scriptInfoErrorString;
125
126 QStringList notices;
127 QStringList warnings;
128 QStringList errors;
129
130
131 void _set_xml_read_error(const QString& fullerrmsg)
132 {
133 scriptInfoError = 999;
134 scriptInfoErrorString = fullerrmsg;
135 }
136 void _set_xml_parsing_error(const QString& xmlfname, const QString& errmsg)
137 {
138 scriptInfoError = 999;
139 scriptInfoErrorString = QString("Error parsing scriptinfo XML contents: %1: %2")
141 }
142
143 void read_script_info()
144 {
145 scriptInfoError = KLFERR_NOERROR;
146 scriptInfoErrorString = QString();
147
148 QString xmlfname = QDir::toNativeSeparators(uspath + "/scriptinfo.xml");
150 if ( ! fxml.open(QIODevice::ReadOnly) ) {
151 _set_xml_read_error(QString("Can't open XML file %1: %2").arg(xmlfname).arg(fxml.errorString()));
152 return;
153 }
154
155 QDomDocument doc("klfuserscript-info");
157 bool r = doc.setContent(&fxml, false, &errMsg, &errLine, &errCol);
158 if (!r) {
159 _set_xml_read_error(QString("XML parse error: %1 (file %2 line %3 col %4)")
160 .arg(errMsg).arg(xmlfname).arg(errLine).arg(errCol));
161 return;
162 }
163 fxml.close();
164
165 QDomElement root = doc.documentElement();
166 if (root.nodeName() != "klfuserscript-info") {
167 _set_xml_parsing_error(xmlfname, QString("expected <klfuserscript-info> as root document element"));
168 return;
169 }
170
171 // clear all properties
172 clear();
173
174 setProperty(CanProvideDefaultSettings, false);
175
176 // read XML contents
177 QDomNode n;
178 for (n = root.firstChild(); !n.isNull(); n = n.nextSibling()) {
179 // try to convert the node to an element; ignore non-elements
180 if ( n.nodeType() != QDomNode::ElementNode ) {
181 continue;
182 }
183 QDomElement e = n.toElement();
184 if ( e.isNull() ) {
185 continue;
186 }
187 // parse the elements.
188 QString val = e.text();
189 if (val.isEmpty()) {
190 val = QString(); // empty value is null string
191 }
192 if (e.nodeName() == "exe-script") {
193 if (!property(ExeScript).toString().isEmpty()) {
194 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <exe-script> element"));
195 return;
196 }
197 setProperty(ExeScript, val);
198 } else if (e.nodeName() == "name") {
199 if (!property(Name).toString().isEmpty()) {
200 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <name> element"));
201 return;
202 }
203 setProperty(Name, val);
204 } else if (e.nodeName() == "author") {
205 setProperty(Author, property(Author).toStringList() + (QStringList()<<val));
206 } else if (e.nodeName() == "version") {
207 if (!property(Version).toString().isEmpty()) {
208 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <version> element"));
209 return;
210 }
211 setProperty(Version, val);
212 } else if (e.nodeName() == "license") {
213 if (!property(License).toString().isEmpty()) {
214 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <license> element"));
215 return;
216 }
217 setProperty(License, val);
218 } else if (e.nodeName() == "klf-min-version") {
219 if (!property(KLFMinVersion).toString().isEmpty()) {
220 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <klf-min-version> element"));
221 return;
222 }
223 setProperty(KLFMinVersion, val);
224 } else if (e.nodeName() == "klf-max-version") {
225 if (!property(KLFMaxVersion).toString().isEmpty()) {
226 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <klf-max-version> element"));
227 return;
228 }
229 setProperty(KLFMaxVersion, val);
230 } else if (e.nodeName() == "category") {
231 if (!property(Category).toString().isEmpty()) {
232 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <category> element"));
233 return;
234 }
235 setProperty(Category, val);
236 } else if (e.nodeName() == "settings-form-ui") {
237 if (!property(SettingsFormUI).toString().isEmpty()) {
238 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <settings-form-ui> element"));
239 return;
240 }
241 setProperty(SettingsFormUI, val);
242 } else if (e.nodeName() == "can-provide-default-settings") {
243 setProperty(CanProvideDefaultSettings, klfLoadVariantFromText(val.toUtf8(), "bool").toBool());
244 } else {
245 const QString category = property(Category).toString();
246 if (e.nodeName() == category) {
247 if (!property(CategorySpecificXmlConfig).toByteArray().isEmpty()) {
248 _set_xml_parsing_error(xmlfname, QString::fromLatin1("duplicate <%1> element")
249 .arg(category));
250 return;
251 }
252 // element node matching the category -- keep category-specific config as XML
255 e.save(tstream, 2); }
256 klfDbg("Read category-specific XML: " << xmlrepr);
258 } else {
259 _set_xml_parsing_error(xmlfname, QString::fromLatin1("Unexpected element: %1").arg(e.nodeName()));
260 return;
261 }
262 }
263 } // for all elements
264
265 klfDbg("All properties read: \n" << qPrintable(toString()));
266 } // read_script_info()
267
268
269 static QMap<QString,KLFRefPtr<Private> > userScriptInfoCache;
270
271private:
272 /* no copy constructor */
273 Private(const Private& /*other*/) : KLFPropertizedObject("KLFUserScriptInfo") { }
274};
275
276
277// static
278QMap<QString,KLFRefPtr<KLFUserScriptInfo::Private> > KLFUserScriptInfo::Private::userScriptInfoCache;
279
280static QString normalizedFn(const QString& userScriptFileName)
281{
283}
284
285// static
286KLFUserScriptInfo KLFUserScriptInfo::forceReloadScriptInfo(const QString& userScriptFileName)
287{
289
291 Private::userScriptInfoCache.remove(normalizedfn);
292
294 if (usinfo.scriptInfoError() != KLFERR_NOERROR) {
295 klfWarning(qPrintable(usinfo.scriptInfoErrorString()));
296 }
297
298 return usinfo;
299}
300// static
301void KLFUserScriptInfo::clearCacheAll()
302{
303 // will decrease the refcounts if needed automatically (KLFRefPtr)
304 Private::userScriptInfoCache.clear();
305}
306
307
308// static
309bool KLFUserScriptInfo::hasScriptInfoInCache(const QString& userScriptFileName)
310{
312 klfDbg("userScriptFileName = " << userScriptFileName << "; normalizedfn = " << normalizedfn) ;
313 klfDbg("cache: " << Private::userScriptInfoCache) ;
314 return Private::userScriptInfoCache.contains(normalizedfn);
315}
316
318{
320
322 QString normalizedfn = fi.canonicalFilePath();
323 if (Private::userScriptInfoCache.contains(normalizedfn)) {
324 d = Private::userScriptInfoCache[normalizedfn];
325 } else {
326 d = new KLFUserScriptInfo::Private;
327
328 d()->uspath = normalizedfn;//userScriptFileName;
329 d()->normalizedfname = normalizedfn;
330 d()->sname = fi.fileName();
331 d()->basename = fi.baseName();
332
333 d()->read_script_info();
334
335 if (d()->scriptInfoError == KLFERR_NOERROR) {
336 Private::userScriptInfoCache[normalizedfn] = d();
337 }
338 }
339}
340
343{
344 // will increase the refcount (thanks to KLFRefPtr)
345 d = copy.d;
346}
347
348KLFUserScriptInfo::~KLFUserScriptInfo()
349{
350 d.setNull(); // will delete the data if refcount reaches zero (see KLFRefPtr)
351}
352
354{
355 return d()->uspath;
356}
358{
359 return d()->sname;
360}
362{
363 return d()->basename;
364}
365
366int KLFUserScriptInfo::scriptInfoError() const
367{
368 return d()->scriptInfoError;
369}
370QString KLFUserScriptInfo::scriptInfoErrorString() const
371{
372 return d()->scriptInfoErrorString;
373}
374
375//protected
376void KLFUserScriptInfo::setScriptInfoError(int code, const QString & msg)
377{
378 d()->scriptInfoError = code;
379 d()->scriptInfoErrorString = msg;
380}
381
382QString KLFUserScriptInfo::relativeFile(const QString& fname) const
383{
385}
386
387QString KLFUserScriptInfo::exeScript() const { return scriptInfo(ExeScript).toString(); }
388QString KLFUserScriptInfo::exeScriptFullPath() const
389{
390 return relativeFile(exeScript());
391}
392
393QString KLFUserScriptInfo::category() const { return scriptInfo(Category).toString(); }
394QString KLFUserScriptInfo::name() const { return scriptInfo(Name).toString(); }
395QString KLFUserScriptInfo::author() const { return scriptInfo(Author).toStringList().join("; "); }
396QStringList KLFUserScriptInfo::authorList() const { return scriptInfo(Author).toStringList(); }
397QString KLFUserScriptInfo::version() const { return scriptInfo(Version).toString(); }
398QString KLFUserScriptInfo::license() const { return scriptInfo(License).toString(); }
399QString KLFUserScriptInfo::klfMinVersion() const { return scriptInfo(KLFMinVersion).toString(); }
400QString KLFUserScriptInfo::klfMaxVersion() const { return scriptInfo(KLFMaxVersion).toString(); }
401QString KLFUserScriptInfo::settingsFormUI() const { return scriptInfo(SettingsFormUI).toString(); }
402
403bool KLFUserScriptInfo::canProvideDefaultSettings() const { return scriptInfo(CanProvideDefaultSettings).toBool(); }
404
405QMap<QString,QVariant> KLFUserScriptInfo::queryDefaultSettings(const KLFBackend::klfSettings * settings) const
406{
408
410
411 // since this may be called on start-up, processing app events may lead to process
412 // hanging on mac os x (why???)
413 proc.setProcessAppEvents(false);
414
415 proc.addArgv(QStringList() << QLatin1String("--query-default-settings"));
416
417 // buffers to collect output
420 proc.collectStdoutTo(&stdoutdata);
421 proc.collectStderrTo(&stderrdata);
422
423 bool ok = proc.run();
424 if (!ok) {
425 klfWarning("Error querying default config for user script "<<userScriptBaseName()<<": "
426 << qPrintable(proc.resultErrorString())) ;
427 return QMap<QString,QVariant>();
428 }
429
430 klfDbg("stdoutdata = " << stdoutdata) ;
431 klfDbg("stderrdata = " << stderrdata) ;
432
433 klfDbg("Ran script "<<userScriptPath()<<": stdout="<<stdoutdata<<"\n\tstderr="<<stderrdata) ;
434
435
436 // the output may be one of two formats:
437 // - XML compatible with klf{Save|Load}VariantMap{To|From}XML()
438 // - simple key=value pairs on separate lines
439 // If the output starts with <?xml then we go for XML, otherwise we try to parse
440 // key=value pairs.
441
443 if (trimmedstdoutdata.startsWith("<?xml")) {
444 QDomDocument doc("klfuserscript-default-settings");
446 bool r = doc.setContent(trimmedstdoutdata, false, &errMsg, &errLine, &errCol);
447 if (!r) {
448 klfWarning("XML parse error: "<<qPrintable(errMsg)
449 <<" ("<<qPrintable(userScriptBaseName())<<" default-settings, line "
450 <<errLine<<" col "<<errCol<<")") ;
451 return QVariantMap();
452 }
453
454 QDomElement root = doc.documentElement();
455 if (root.nodeName() != "klfuserscript-default-settings") {
456 klfWarning("expected <klfuserscript-default-settings> as root document element");
457 return QVariantMap();
458 }
459
461 return config;
462 }
463
464 // otherwise, parse key=value pairs
465
466 // get variables
468 foreach (QByteArray line, trimmedstdoutdata.split('\n')) {
469 if (!line.size()) {
470 continue;
471 }
472 int idxeq = line.indexOf('=');
473 if (idxeq == -1) {
474 klfWarning("Invalid line in reported userscript default config: " << line) ;
475 continue;
476 }
477 config[QString::fromUtf8(line.left(idxeq)).trimmed()] = line.mid(idxeq+1).trimmed();
478 }
479
480 return config;
481}
482
483
484
489
490
491bool KLFUserScriptInfo::hasNotices() const
492{
493 return d->notices.size();
494}
495bool KLFUserScriptInfo::hasWarnings() const
496{
497 return d->warnings.size();
498}
499bool KLFUserScriptInfo::hasErrors() const
500{
501 return d->errors.size();
502}
503
504KLF_DEFINE_PROPERTY_GET(KLFUserScriptInfo, QStringList, notices) ;
505
506KLF_DEFINE_PROPERTY_GET(KLFUserScriptInfo, QStringList, warnings) ;
507
508KLF_DEFINE_PROPERTY_GET(KLFUserScriptInfo, QStringList, errors) ;
509
510
511
512QVariant KLFUserScriptInfo::scriptInfo(int propId) const
513{
514 return d()->property(propId);
515}
516
517QVariant KLFUserScriptInfo::scriptInfo(const QString& field) const
518{
520 QString x = field;
521
522 if (x == QLatin1String("Authors")) {
523 x = QLatin1String("Author");
524 }
525
526 klfDbg("x="<<x) ;
527 int id = d()->propertyIdForName(x);
528 if (id < 0) {
529 klfDbg("KLFUserScriptInfo for "<<userScriptName()<<" does not have any information about "
530 <<field<<" ("<<x<<")") ;
531 return QVariant();
532 }
533 return scriptInfo(id);
534}
535
537{
538 return d()->propertyNameList();
539}
540
541QString KLFUserScriptInfo::objectKind() const { return d()->objectKind(); }
542
543
544// protected. Used by eg. KLFExportTypeUserScriptInfo to normalize list property values.
545void KLFUserScriptInfo::internalSetProperty(const QString& key, const QVariant &val)
546{
547 d()->setProperty(key, val);
548}
549
550const KLFPropertizedObject * KLFUserScriptInfo::pobj()
551{
552 return d();
553}
554
555
556static QString escapeListIntoTags(const QStringList& list, const QString& starttag, const QString& endtag)
557{
558 QString html;
559 foreach (QString s, list) {
560 html += starttag + s.toHtmlEscaped() + endtag;
561 }
562 return html;
563}
564
566{
567 QString txt =
568 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
569 "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
570 "p, li { white-space: pre-wrap; }\n"
571 "p.msgnotice { color: blue; font-weight: bold; margin: 2px 0px; }\n"
572 "p.msgwarning { color: #a06000; font-weight: bold; margin: 2px 0px; }\n"
573 "p.msgerror { color: #a00000; font-weight: bold; margin: 2px 0px; }\n"
574 ".scriptinfokey { }\n"
575 ".scriptinfovalue { font-weight: bold; }\n"
576 + extra_css + "\n"
577 "</style></head>\n"
578 "<body>\n";
579
580 // any notices/warnings/errors go first
581 if (hasNotices()) {
582 txt += escapeListIntoTags(notices(), "<p class=\"msgnotice\">", "</p>\n");
583 }
584 if (hasWarnings()) {
585 txt += escapeListIntoTags(warnings(), "<p class=\"msgwarning\">", "</p>\n");
586 }
587 if (hasErrors()) {
588 txt += escapeListIntoTags(errors(), "<p class=\"msgerror\">", "</p>\n");
589 }
590
591 // the user script name (incl ".klfuserscript")
592 txt +=
593 "<p style=\"-qt-block-indent: 0; text-indent: 0px; margin-top: 8px; margin-bottom: 0px\">\n"
594 "<span class=\"scriptinfokey\">" + QObject::tr("Script Name:", "[[user script info text]]")
595 + "</span>&nbsp;&nbsp;"
596 "<span class=\"scriptinfovalue\">" + userScriptName().toHtmlEscaped() + "</span><br />\n";
597
598 // the category
599 txt += "<span class=\"scriptinfokey\">" + QObject::tr("Category:", "[[user script info text]]")
600 + "</span>&nbsp;&nbsp;"
601 "<span class=\"scriptinfovalue\">" + category().toHtmlEscaped() + "</span><br />\n";
602
603 if (!version().isEmpty()) {
604 // the version
605 txt += "<span class=\"scriptinfokey\">" + QObject::tr("Version:", "[[user script info text]]")
606 + "</span>&nbsp;&nbsp;"
607 "<span class=\"scriptinfovalue\">" + version().toHtmlEscaped() + "</span><br />\n";
608 }
609 if (!author().isEmpty()) {
610 // the author
611 txt += "<span class=\"scriptinfokey\">" + QObject::tr("Author:", "[[user script info text]]")
612 + "</span>&nbsp;&nbsp;"
613 "<span class=\"scriptinfovalue\">" + author().toHtmlEscaped() + "</span><br />\n";
614 }
615
616 if (!license().isEmpty()) {
617 // the license
618 txt += "<span class=\"scriptinfokey\">" + QObject::tr("License:", "[[user script info text]]")
619 + "</span>&nbsp;&nbsp;"
620 "<span class=\"scriptinfovalue\">" + license().toHtmlEscaped() + "</span><br />\n";
621 }
622
623 return txt;
624}
625
626
627
628// static
629QMap<QString,QString> KLFUserScriptInfo::usConfigToStrMap(const QVariantMap& usconfig)
630{
633 mdata[QLatin1String("KLF_USCONFIG_") + it.key()] = klfSaveVariantToText(it.value(), true);
634 return mdata;
635}
636
637// static
638QStringList KLFUserScriptInfo::usConfigToEnvList(const QVariantMap& usconfig)
639{
640 return klfMapToEnvironmentList(KLFUserScriptInfo::usConfigToStrMap(usconfig));
641}
642
643
644inline QStringList space_sep_values(const QString& val)
645{
646 return val.split(QRegExp("\\s+"), QString::SkipEmptyParts);
647}
648
649
650
651
652struct KLFBackendEngineUserScriptInfoPrivate : public KLFPropertizedObject
653{
654 KLF_PRIVATE_INHERIT_HEAD(KLFBackendEngineUserScriptInfo,
655 : KLFPropertizedObject("KLFBackendEngineUserScriptInfo"))
656 {
657 registerBuiltInProperty(KLFBackendEngineUserScriptInfo::SpitsOut, QLatin1String("SpitsOut"));
658 registerBuiltInProperty(KLFBackendEngineUserScriptInfo::SkipFormats, QLatin1String("SkipFormats"));
659 registerBuiltInProperty(KLFBackendEngineUserScriptInfo::DisableInputs, QLatin1String("DisableInputs"));
660 registerBuiltInProperty(KLFBackendEngineUserScriptInfo::InputFormUI, QLatin1String("InputFormUI"));
661 }
662 void clear()
663 {
664 // clear all properties
666 for (int k = 0; k < idlist.size(); ++k) {
668 }
669 }
670
671 void _set_xml_parsing_error(const QString& errmsg)
672 {
673 K->setScriptInfoError(1001, QString("Error parsing klf-backend-engine XML config: %1: %2")
674 .arg(K->userScriptBaseName()).arg(errmsg));
675 }
676 void parse_category_config(const QByteArray & ba)
677 {
678 QDomDocument doc("klf-backend-engine");
680 bool r = doc.setContent(ba, false, &errMsg, &errLine, &errCol);
681 if (!r) {
682 K->setScriptInfoError(
683 1001,
684 QString("XML parse error: %1 (klf-backend-engine in %2, relative line %3 col %4)")
685 .arg(errMsg).arg(K->userScriptBaseName()).arg(errLine).arg(errCol));
686 return;
687 }
688
689 QDomElement root = doc.documentElement();
690 if (root.nodeName() != "klf-backend-engine") {
691 _set_xml_parsing_error(QString("expected <klf-backend-engine> element"));
692 return;
693 }
694
695 // clear all properties
696 clear();
697
698 // read XML contents
699 QDomNode n;
700 for (n = root.firstChild(); !n.isNull(); n = n.nextSibling()) {
701 // try to convert the node to an element; ignore non-elements
702 if ( n.nodeType() != QDomNode::ElementNode ) {
703 continue;
704 }
705 QDomElement e = n.toElement();
706 if ( e.isNull() ) {
707 continue;
708 }
709 // parse the elements.
710 QString val = e.text();
711 if (val.isEmpty()) {
712 val = QString(); // empty value is null string
713 }
714 if (e.nodeName() == "spits-out") {
715 if (!property(KLFBackendEngineUserScriptInfo::SpitsOut).toStringList().isEmpty()) {
716 _set_xml_parsing_error(QString("duplicate <spits-out> element"));
717 return;
718 }
719 setProperty(KLFBackendEngineUserScriptInfo::SpitsOut, space_sep_values(val));
720 } else if (e.nodeName() == "skip-formats") {
721 if (!property(KLFBackendEngineUserScriptInfo::SkipFormats).toString().isEmpty()) {
722 _set_xml_parsing_error(QString("duplicate <skip-formats> element"));
723 return;
724 }
726 if (e.hasAttribute("selector")) {
727 // all-except -> ALL_EXCEPT
728 QString s = e.attribute("selector").toUpper();
729 lst << space_sep_values(s.replace('-', '_'));
730 }
731 lst << space_sep_values(val);
732 setProperty(KLFBackendEngineUserScriptInfo::SkipFormats, lst);
733 } else if (e.nodeName() == "disable-inputs") {
734 if (!property(KLFBackendEngineUserScriptInfo::DisableInputs).toStringList().isEmpty()) {
735 _set_xml_parsing_error(QString("duplicate <disable-inputs> element"));
736 return;
737 }
739 if (e.hasAttribute("selector")) {
740 // all-except -> ALL_EXCEPT
741 QString s = e.attribute("selector").toUpper();
742 lst << space_sep_values(s.replace('-', '_'));
743 }
744 lst << space_sep_values(val);
745 setProperty(KLFBackendEngineUserScriptInfo::DisableInputs, lst);
746 } else if (e.nodeName() == "input-form-ui") {
747 if (!property(KLFBackendEngineUserScriptInfo::InputFormUI).toStringList().isEmpty()) {
748 _set_xml_parsing_error(QString("duplicate <input-form-ui> element"));
749 return;
750 }
751 setProperty(KLFBackendEngineUserScriptInfo::InputFormUI, val);
752 } else {
753 _set_xml_parsing_error(QString("Found unexpected element: %1").arg(e.nodeName()));
754 return;
755 }
756 }
757
758 klfDbg("Read all klfbackend-engine properties:\n" << qPrintable(toString()));
759 }
760};
761
762
763
764KLFBackendEngineUserScriptInfo::KLFBackendEngineUserScriptInfo(const QString& uspath)
765 : KLFUserScriptInfo(uspath)
766{
768
769 if (category() != "klf-backend-engine") {
770 klfWarning("KLFBackendEngineUserScriptInfo instantiated for user script "
771 << uspath << ", which is of category " << category()) ;
772 } else {
773 d->parse_category_config(categorySpecificXmlConfig());
774 }
775}
776
777KLFBackendEngineUserScriptInfo::~KLFBackendEngineUserScriptInfo()
778{
780}
781
782
783
785{
786 return klfBackendEngineInfo(SpitsOut).toStringList();
787}
789{
790 return klfBackendEngineInfo(SkipFormats).toStringList();
791}
793{
794 return klfBackendEngineInfo(DisableInputs).toStringList();
795}
797{
798 return klfBackendEngineInfo(InputFormUI).toString();
799}
800
801
802QVariant KLFBackendEngineUserScriptInfo::klfBackendEngineInfo(int propId) const
803{
804 return d->property(propId);
805}
806
807QVariant KLFBackendEngineUserScriptInfo::klfBackendEngineInfo(const QString& field) const
808{
810 QString x = field;
811
812 klfDbg("x="<<x) ;
813 int id = d->propertyIdForName(x);
814 if (id < 0) {
815 klfDbg("KLFBackendEngineUserScriptInfo for "<<userScriptName()<<" does not have any information about "
816 <<field<<" ("<<x<<")") ;
817 return QVariant();
818 }
819 return scriptInfo(id);
820}
821
822QStringList KLFBackendEngineUserScriptInfo::klfBackendEngineInfosList() const
823{
824 return d->propertyNameList();
825}
826
827
828
829
830
831
832
833
834
835
836// ----------------------------------------
837
838struct KLFUserScriptFilterProcessPrivate
839{
840 KLF_PRIVATE_HEAD(KLFUserScriptFilterProcess)
841 {
842 usinfo = NULL;
843 }
844
845 KLFUserScriptInfo * usinfo;
846
847 // log of user script output
848 static QStringList log;
849};
850
851// static
852QStringList KLFUserScriptFilterProcessPrivate::log = QStringList();
853
854
856 const KLFBackend::klfSettings * settings)
857 : KLFFilterProcess("User Script " + userScriptFileName, settings, QString(), true)
858{
860 klfDbg("userScriptFileName= "<<userScriptFileName) ;
861
863
864 d->usinfo = new KLFUserScriptInfo(userScriptFileName);
865
866 QString exescript = d->usinfo->exeScriptFullPath();
867 klfDbg("exescript = " << exescript) ;
868 setArgv(QStringList() << exescript);
869}
870
871
872KLFUserScriptFilterProcess::~KLFUserScriptFilterProcess()
873{
874 delete d->usinfo;
876}
877
878void KLFUserScriptFilterProcess::addUserScriptConfig(const QVariantMap& usconfig)
879{
880 QStringList envlist = KLFUserScriptInfo::usConfigToEnvList(usconfig);
881 addExecEnviron(envlist);
882}
883
884
886{
888
889 // for user script debugging
890 QString thislog = QString::fromLatin1("<h1 class=\"userscript-run\">")
891 + QObject::tr("Output from %1", "KLFUserScriptFilterProcess").arg(QLatin1String("<span class=\"userscriptname\">")
892 +d->usinfo->userScriptBaseName().toHtmlEscaped()
893 +QLatin1String("</span>")) +
894 QLatin1String("</h1>\n") +
895 QLatin1String("<p class=\"userscript-run-datetime\">") +
896 QDateTime::currentDateTime().toString(Qt::DefaultLocaleLongDate).toHtmlEscaped()
897 + QLatin1String("</p>") ;
898
899 // error message, if any
901 if (errstr.size()) {
902 thislog += QString::fromLatin1("<div class=\"userscript-error\">%1</div>").arg(errstr); // errstr is already HTML
903 }
904
905 QString templ = QString::fromLatin1("<p><span class=\"output-type\">%1</span>\n"
906 "<pre class=\"output\">%2</pre></p>\n") ;
907
909 if (bstdout.size()) {
910 thislog += templ.arg("STDOUT").arg(QString::fromLocal8Bit(bstdout).toHtmlEscaped());
911 }
913 if (bstderr.size()) {
914 thislog += templ.arg("STDERR").arg(QString::fromLocal8Bit(bstderr).toHtmlEscaped());
915 }
916
917 // start discarding old logs after 255 entries
918 if (KLFUserScriptFilterProcessPrivate::log.size() > 255) {
919 KLFUserScriptFilterProcessPrivate::log.erase(KLFUserScriptFilterProcessPrivate::log.begin());
920 }
921
922 KLFUserScriptFilterProcessPrivate::log << thislog;
923
924 return ret;
925}
926
927
929{
931 QStringList::const_iterator it = KLFUserScriptFilterProcessPrivate::log.cend();
932 while (it != KLFUserScriptFilterProcessPrivate::log.cbegin()) {
933 --it;
934 loghtml += *it;
935 }
936 if (!include_head) {
937 return loghtml;
938 }
939 return QLatin1String("<html><head>"
940 "<meta charset=\"utf-8\">"
941 "<title>User Script Log</title>"
942 "<style type=\"text/css\">"
943 ".userscript-run { font-weight: bold; font-size: 2em; } "
944 ".userscriptname { font: monospace; } "
945 ".output-type { font-weight: bold; } "
946 "</style>"
947 "</head>"
948 "<body>") + loghtml + QLatin1String("</body></html>") ;
949}
QStringList spitsOut() const
List of formats that this script will generate.
QString inputFormUI() const
A UI input form file (Qt designer file) for additional input.
QStringList skipFormats() const
List of formats that klfbackend should not attempt to generate.
QStringList disableInputs() const
List of user input fields that should be disabled.
virtual bool do_run(const QByteArray &indata, const QMap< QString, QByteArray * > outdatalist)
Actually run the process.
QByteArray collectedStdout() const
The collected stdout data of the process that just ran.
QByteArray collectedStderr() const
The collected stderr data of the process that just ran.
virtual QString resultErrorString() const
virtual QVariant property(const QString &propName) const
virtual bool setProperty(const QString &propname, const QVariant &value)
void registerBuiltInProperty(int propId, const QString &propName) const
QList< int > registeredPropertyIdList() const
virtual QString toString(uint toStringFlags=0) const
void setNull()
static QString getUserScriptLogHtml(bool include_head=true)
Return the user script log, formatted in human-readable HTML.
virtual bool do_run(const QByteArray &indata, const QMap< QString, QByteArray * > outdatalist)
KLFUserScriptFilterProcess(const QString &scriptFileName, const KLFBackend::klfSettings *settings=NULL)
Summary of the info returned by a user script.
QString userScriptPath() const
e.g. "/path/to/klffeynmf.klfuserscript"
@ CategorySpecificXmlConfig
XML representation of the category-specific configuration (QByteArray)
QString settingsFormUI() const
A UI widget form file (Qt designer file) to display for setting up the user script.
QString userScriptName() const
e.g. "klffeynmf.klfuserscript"
QStringList scriptInfosList() const
A list of Keys (eg. "Name", "Author", ... including custom infos) found in the scriptinfo.
QString htmlInfo(const QString &extra_css=QString()) const
Formats most (all?) properties in HTML, suitable for human-readable text display.
QString userScriptBaseName() const
e.g. "klffeynmf"
KLFUserScriptInfo(const QString &userScriptPath)
QByteArray categorySpecificXmlConfig() const
The XML for the category-specific config.
Definition of class KLFBackend.
#define KLFERR_NOERROR
No Error.
Definition klfbackend.h:46
KLF_EXPORT QVariant klfLoadVariantFromText(const QByteArray &stringdata, const char *dataTypeName, const char *listOrMapDataTypeName)
KLF_EXPORT QByteArray klfSaveVariantToText(const QVariant &value, bool saveListAndMapsAsXML, QByteArray *savedType, QByteArray *savedListOrMapType)
KLF_EXPORT QVariantMap klfLoadVariantMapFromXML(const QDomElement &xmlNode)
#define klfWarning(streamableItems)
#define KLF_DEBUG_BLOCK(msg)
#define klfDbg(streamableItems)
#define KLF_DELETE_PRIVATE
#define KLF_INIT_PRIVATE(ClassName)
QStringList klfMapToEnvironmentList(const QMap< QString, QString > &map)
QDateTime currentDateTime()
QString toString(Qt::DateFormat format) const
QString toNativeSeparators(const QString &pathName)
QDomNode firstChild() const
QString nodeName() const
QString canonicalFilePath() const
iterator begin()
const_iterator cend() const
void clear()
iterator end()
iterator erase(iterator pos)
bool isEmpty() const
const Key key(const T &value, const Key &defaultKey) const
int size() const
const T value(const Key &key, const T &defaultValue) const
QString tr(const char *sourceText, const char *disambiguation, int n)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const
QString fromLatin1(const char *str, int size)
QString fromLocal8Bit(const char *str, int size)
QString fromUtf8(const char *str, int size)
QString & replace(int position, int n, QChar after)
QString toHtmlEscaped() const
QString trimmed() const
QString join(const QString &separator) const
bool toBool() const
QByteArray toByteArray() const
QString toString() const
QStringList toStringList() const
General settings for KLFBackend::getLatexFormula()
Definition klfbackend.h:219

Generated by doxygen 1.10.0