35#include "klfbackend_p.h"
36#include "klfuserscript.h"
110 for (
int k = 0; k < idlist.
size(); ++k) {
116 inline int ref() {
return ++refcount; }
117 inline int deref() {
return --refcount; }
120 QString normalizedfname;
124 QString scriptInfoErrorString;
127 QStringList warnings;
131 void _set_xml_read_error(
const QString& fullerrmsg)
133 scriptInfoError = 999;
134 scriptInfoErrorString = fullerrmsg;
136 void _set_xml_parsing_error(
const QString& xmlfname,
const QString& errmsg)
138 scriptInfoError = 999;
139 scriptInfoErrorString = QString(
"Error parsing scriptinfo XML contents: %1: %2")
140 .
arg(xmlfname).
arg(errmsg);
143 void read_script_info()
146 scriptInfoErrorString = QString();
149 QFile fxml(xmlfname);
150 if ( ! fxml.open(QIODevice::ReadOnly) ) {
151 _set_xml_read_error(QString(
"Can't open XML file %1: %2").arg(xmlfname).arg(fxml.errorString()));
155 QDomDocument doc(
"klfuserscript-info");
156 QString errMsg;
int errLine, errCol;
157 bool r = doc.setContent(&fxml,
false, &errMsg, &errLine, &errCol);
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));
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"));
180 if ( n.
nodeType() != QDomNode::ElementNode ) {
188 QString val = e.
text();
198 }
else if (e.
nodeName() ==
"name") {
204 }
else if (e.
nodeName() ==
"author") {
206 }
else if (e.
nodeName() ==
"version") {
212 }
else if (e.
nodeName() ==
"license") {
218 }
else if (e.
nodeName() ==
"klf-min-version") {
220 _set_xml_parsing_error(xmlfname,
QString::fromLatin1(
"duplicate <klf-min-version> element"));
224 }
else if (e.
nodeName() ==
"klf-max-version") {
226 _set_xml_parsing_error(xmlfname,
QString::fromLatin1(
"duplicate <klf-max-version> element"));
230 }
else if (e.
nodeName() ==
"category") {
236 }
else if (e.
nodeName() ==
"settings-form-ui") {
238 _set_xml_parsing_error(xmlfname,
QString::fromLatin1(
"duplicate <settings-form-ui> element"));
242 }
else if (e.
nodeName() ==
"can-provide-default-settings") {
254 { QTextStream tstream(&xmlrepr);
255 e.
save(tstream, 2); }
256 klfDbg(
"Read category-specific XML: " << xmlrepr);
269 static QMap<QString,KLFRefPtr<Private> > userScriptInfoCache;
290 QString normalizedfn = normalizedFn(userScriptFileName);
291 Private::userScriptInfoCache.remove(normalizedfn);
295 klfWarning(qPrintable(usinfo.scriptInfoErrorString()));
301void KLFUserScriptInfo::clearCacheAll()
304 Private::userScriptInfoCache.clear();
309bool KLFUserScriptInfo::hasScriptInfoInCache(
const QString& userScriptFileName)
311 QString normalizedfn = normalizedFn(userScriptFileName);
312 klfDbg(
"userScriptFileName = " << userScriptFileName <<
"; normalizedfn = " << normalizedfn) ;
313 klfDbg(
"cache: " << Private::userScriptInfoCache) ;
314 return Private::userScriptInfoCache.contains(normalizedfn);
323 if (Private::userScriptInfoCache.contains(normalizedfn)) {
324 d = Private::userScriptInfoCache[normalizedfn];
326 d =
new KLFUserScriptInfo::Private;
328 d()->uspath = normalizedfn;
329 d()->normalizedfname = normalizedfn;
333 d()->read_script_info();
336 Private::userScriptInfoCache[normalizedfn] = d();
348KLFUserScriptInfo::~KLFUserScriptInfo()
363 return d()->basename;
366int KLFUserScriptInfo::scriptInfoError()
const
368 return d()->scriptInfoError;
370QString KLFUserScriptInfo::scriptInfoErrorString()
const
372 return d()->scriptInfoErrorString;
376void KLFUserScriptInfo::setScriptInfoError(
int code,
const QString & msg)
378 d()->scriptInfoError = code;
379 d()->scriptInfoErrorString = msg;
382QString KLFUserScriptInfo::relativeFile(
const QString& fname)
const
387QString KLFUserScriptInfo::exeScript()
const {
return scriptInfo(ExeScript).toString(); }
388QString KLFUserScriptInfo::exeScriptFullPath()
const
390 return relativeFile(exeScript());
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(); }
403bool KLFUserScriptInfo::canProvideDefaultSettings()
const {
return scriptInfo(CanProvideDefaultSettings).
toBool(); }
413 proc.setProcessAppEvents(
false);
415 proc.addArgv(QStringList() << QLatin1String(
"--query-default-settings"));
418 QByteArray stdoutdata;
419 QByteArray stderrdata;
420 proc.collectStdoutTo(&stdoutdata);
421 proc.collectStderrTo(&stderrdata);
423 bool ok = proc.run();
426 << qPrintable(proc.resultErrorString())) ;
427 return QMap<QString,QVariant>();
430 klfDbg(
"stdoutdata = " << stdoutdata) ;
431 klfDbg(
"stderrdata = " << stderrdata) ;
442 QByteArray trimmedstdoutdata = stdoutdata.
trimmed();
444 QDomDocument doc(
"klfuserscript-default-settings");
445 QString errMsg;
int errLine, errCol;
446 bool r = doc.setContent(trimmedstdoutdata,
false, &errMsg, &errLine, &errCol);
448 klfWarning(
"XML parse error: "<<qPrintable(errMsg)
450 <<errLine<<
" col "<<errCol<<
")") ;
451 return QVariantMap();
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();
467 QMap<QString,QVariant> config;
468 foreach (QByteArray line, trimmedstdoutdata.
split(
'\n')) {
474 klfWarning(
"Invalid line in reported userscript default config: " << line) ;
491bool KLFUserScriptInfo::hasNotices()
const
493 return d->notices.size();
495bool KLFUserScriptInfo::hasWarnings()
const
497 return d->warnings.size();
499bool KLFUserScriptInfo::hasErrors()
const
501 return d->errors.size();
514 return d()->property(propId);
527 int id = d()->propertyIdForName(x);
530 <<field<<
" ("<<x<<
")") ;
533 return scriptInfo(
id);
538 return d()->propertyNameList();
547 d()->setProperty(key, val);
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"
582 txt += escapeListIntoTags(notices(),
"<p class=\"msgnotice\">",
"</p>\n");
585 txt += escapeListIntoTags(warnings(),
"<p class=\"msgwarning\">",
"</p>\n");
588 txt += escapeListIntoTags(errors(),
"<p class=\"msgerror\">",
"</p>\n");
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> "
599 txt +=
"<span class=\"scriptinfokey\">" +
QObject::tr(
"Category:",
"[[user script info text]]")
600 +
"</span> "
601 "<span class=\"scriptinfovalue\">" + category().
toHtmlEscaped() +
"</span><br />\n";
603 if (!version().isEmpty()) {
605 txt +=
"<span class=\"scriptinfokey\">" +
QObject::tr(
"Version:",
"[[user script info text]]")
606 +
"</span> "
607 "<span class=\"scriptinfovalue\">" + version().
toHtmlEscaped() +
"</span><br />\n";
609 if (!author().isEmpty()) {
611 txt +=
"<span class=\"scriptinfokey\">" +
QObject::tr(
"Author:",
"[[user script info text]]")
612 +
"</span> "
613 "<span class=\"scriptinfovalue\">" + author().
toHtmlEscaped() +
"</span><br />\n";
616 if (!license().isEmpty()) {
618 txt +=
"<span class=\"scriptinfokey\">" +
QObject::tr(
"License:",
"[[user script info text]]")
619 +
"</span> "
620 "<span class=\"scriptinfovalue\">" + license().
toHtmlEscaped() +
"</span><br />\n";
632 for (QVariantMap::const_iterator it = usconfig.begin(); it != usconfig.end(); ++it)
638QStringList KLFUserScriptInfo::usConfigToEnvList(
const QVariantMap& usconfig)
646 return val.
split(
QRegExp(
"\\s+"), QString::SkipEmptyParts);
654 KLF_PRIVATE_INHERIT_HEAD(KLFBackendEngineUserScriptInfo,
666 for (
int k = 0; k < idlist.
size(); ++k) {
671 void _set_xml_parsing_error(
const QString& errmsg)
673 K->setScriptInfoError(1001, QString(
"Error parsing klf-backend-engine XML config: %1: %2")
674 .arg(K->userScriptBaseName()).arg(errmsg));
676 void parse_category_config(
const QByteArray & ba)
678 QDomDocument doc(
"klf-backend-engine");
679 QString errMsg;
int errLine, errCol;
680 bool r = doc.setContent(ba,
false, &errMsg, &errLine, &errCol);
682 K->setScriptInfoError(
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));
689 QDomElement root = doc.documentElement();
690 if (root.
nodeName() !=
"klf-backend-engine") {
691 _set_xml_parsing_error(QString(
"expected <klf-backend-engine> element"));
702 if ( n.
nodeType() != QDomNode::ElementNode ) {
710 QString val = e.
text();
715 if (!
property(KLFBackendEngineUserScriptInfo::SpitsOut).toStringList().isEmpty()) {
716 _set_xml_parsing_error(QString(
"duplicate <spits-out> element"));
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"));
729 lst << space_sep_values(s.
replace(
'-',
'_'));
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"));
742 lst << space_sep_values(s.
replace(
'-',
'_'));
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"));
751 setProperty(KLFBackendEngineUserScriptInfo::InputFormUI, val);
753 _set_xml_parsing_error(QString(
"Found unexpected element: %1").arg(e.
nodeName()));
758 klfDbg(
"Read all klfbackend-engine properties:\n" << qPrintable(
toString()));
764KLFBackendEngineUserScriptInfo::KLFBackendEngineUserScriptInfo(
const QString& uspath)
769 if (category() !=
"klf-backend-engine") {
770 klfWarning(
"KLFBackendEngineUserScriptInfo instantiated for user script "
771 << uspath <<
", which is of category " << category()) ;
777KLFBackendEngineUserScriptInfo::~KLFBackendEngineUserScriptInfo()
786 return klfBackendEngineInfo(SpitsOut).toStringList();
790 return klfBackendEngineInfo(SkipFormats).toStringList();
794 return klfBackendEngineInfo(DisableInputs).toStringList();
798 return klfBackendEngineInfo(InputFormUI).toString();
802QVariant KLFBackendEngineUserScriptInfo::klfBackendEngineInfo(
int propId)
const
804 return d->property(
propId);
807QVariant KLFBackendEngineUserScriptInfo::klfBackendEngineInfo(
const QString& field)
const
813 int id = d->propertyIdForName(x);
815 klfDbg(
"KLFBackendEngineUserScriptInfo for "<<
userScriptName()<<
" does not have any information about "
816 <<field<<
" ("<<x<<
")") ;
819 return scriptInfo(
id);
822QStringList KLFBackendEngineUserScriptInfo::klfBackendEngineInfosList()
const
824 return d->propertyNameList();
838struct KLFUserScriptFilterProcessPrivate
840 KLF_PRIVATE_HEAD(KLFUserScriptFilterProcess)
845 KLFUserScriptInfo * usinfo;
848 static QStringList log;
857 : KLFFilterProcess(
"User Script " + userScriptFileName, settings,
QString(), true)
860 klfDbg(
"userScriptFileName= "<<userScriptFileName) ;
866 QString exescript = d->usinfo->exeScriptFullPath();
867 klfDbg(
"exescript = " << exescript) ;
872KLFUserScriptFilterProcess::~KLFUserScriptFilterProcess()
878void KLFUserScriptFilterProcess::addUserScriptConfig(
const QVariantMap& usconfig)
880 QStringList envlist = KLFUserScriptInfo::usConfigToEnvList(usconfig);
881 addExecEnviron(envlist);
892 +d->usinfo->userScriptBaseName().toHtmlEscaped()
906 "<pre class=\"output\">%2</pre></p>\n") ;
909 if (bstdout.
size()) {
913 if (bstderr.
size()) {
918 if (KLFUserScriptFilterProcessPrivate::log.size() > 255) {
919 KLFUserScriptFilterProcessPrivate::log.erase(KLFUserScriptFilterProcessPrivate::log.begin());
922 KLFUserScriptFilterProcessPrivate::log << thislog;
932 while (it != KLFUserScriptFilterProcessPrivate::log.cbegin()) {
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; } "
virtual QString objectKind() const=0
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
KLFPropertizedObject(const QString &propertyNameSpace)
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
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.
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)
int indexOf(char ch, int from) const
QByteArray left(int len) const
QByteArray mid(int pos, int len) const
QList< QByteArray > split(char sep) const
bool startsWith(const QByteArray &ba) const
QByteArray trimmed() const
QDateTime currentDateTime()
QString toString(Qt::DateFormat format) const
QString toNativeSeparators(const QString &pathName)
QString attribute(const QString &name, const QString &defValue) const
bool hasAttribute(const QString &name) const
QDomNode firstChild() const
QDomNode nextSibling() const
NodeType nodeType() const
void save(QTextStream &stream, int indent, EncodingPolicy encodingPolicy) const
QDomElement toElement() const
QString canonicalFilePath() 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)
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QString toHtmlEscaped() const
QByteArray toUtf8() const
General settings for KLFBackend::getLatexFormula()