LimeReport/limereport/lrscriptenginemanager.h

502 lines
19 KiB
C
Raw Normal View History

2016-02-17 10:11:00 +03:00
/***************************************************************************
* This file is part of the Lime Report project *
* Copyright (C) 2015 by Alexander Arin *
* arin_a@bk.ru *
* *
** GNU General Public License Usage **
* *
* This library is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
* *
** GNU Lesser General Public License **
* *
* This library is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library. *
* If not, see <http://www.gnu.org/licenses/>. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
****************************************************************************/
#ifndef LRSCRIPTENGINEMANAGER_H
#define LRSCRIPTENGINEMANAGER_H
#include <QtScript/QScriptEngine>
2016-02-17 10:11:00 +03:00
#include <QVector>
#include <QIcon>
#include <QAbstractItemModel>
#include <QDebug>
#include <QtGlobal>
#include <QScriptable>
#include <QFont>
#include <QComboBox>
2016-11-01 20:42:45 +03:00
//#include <QJSEngine>
2016-06-10 18:05:18 +03:00
#ifdef HAVE_UI_LOADER
#include <QDialog>
#endif
2016-02-17 10:11:00 +03:00
#include "base/lrsingleton.h"
2016-11-01 20:42:45 +03:00
#include "lrglobal.h"
2016-02-17 10:11:00 +03:00
#include "lrscriptenginemanagerintf.h"
2017-08-18 22:55:29 +03:00
#include "lrcallbackdatasourceintf.h"
2016-06-10 18:05:18 +03:00
#include "lrcollection.h"
2016-02-17 10:11:00 +03:00
namespace LimeReport{
2016-02-17 10:28:27 +03:00
class DataSourceManager;
class BaseDesignIntf;
2017-08-25 18:01:59 +03:00
class PageItemDesignIntf;
class BandDesignIntf;
2016-02-17 10:28:27 +03:00
2017-08-18 22:55:29 +03:00
struct ContentItem {
QString content;
int indent;
int pageNumber;
2017-08-31 02:53:34 +03:00
QString uniqKey;
2017-08-18 22:55:29 +03:00
};
class TableOfContens : public QObject{
Q_OBJECT
public:
2017-08-25 18:01:59 +03:00
TableOfContens(QObject* parent = 0):QObject(parent){}
2017-08-18 22:55:29 +03:00
~TableOfContens();
void setItem(const QString& uniqKey, const QString& content, int pageNumber, int indent = 0);
2017-08-18 22:55:29 +03:00
void clear();
2017-08-25 18:01:59 +03:00
bool isEmpty(){ return m_tableOfContens.isEmpty();}
2017-08-18 22:55:29 +03:00
private slots:
void slotOneSlotDS(LimeReport::CallbackInfo info, QVariant &data);
private:
QVector<ContentItem*> m_tableOfContens;
QHash<QString, ContentItem* > m_hash;
};
2016-02-17 10:11:00 +03:00
struct ScriptFunctionDesc{
enum FuncType {Native,Script};
2016-11-01 20:42:45 +03:00
ScriptValueType scriptValue;
2016-02-17 10:11:00 +03:00
QString name;
QString description;
QString category;
FuncType type;
};
class ScriptEngineNode {
public:
2016-06-10 18:05:18 +03:00
enum NodeType{Root,Category,Function,Dialog,DialogElement};
2016-02-17 10:18:19 +03:00
ScriptEngineNode(const QString& name="", const QString& description ="", NodeType type=Root, ScriptEngineNode* parent=0, const QIcon& icon=QIcon())
:m_name(name), m_description(description), m_icon(icon), m_type(type), m_parent(parent){}
2016-02-17 10:11:00 +03:00
virtual ~ScriptEngineNode();
int childCount(){return m_childs.count();}
ScriptEngineNode* child(int index){return m_childs[index];}
ScriptEngineNode* parent(){return m_parent;}
2016-02-17 10:18:19 +03:00
ScriptEngineNode* addChild(const QString& name="", const QString &description="", NodeType type=Root, const QIcon& icon=QIcon());
2016-02-17 10:11:00 +03:00
int row();
QString name(){return m_name;}
2016-02-17 10:18:19 +03:00
QString description(){return m_description;}
2016-02-17 10:11:00 +03:00
QIcon icon(){return m_icon;}
void clear();
NodeType type(){return m_type;}
private:
QString m_name;
2016-02-17 10:18:19 +03:00
QString m_description;
2016-02-17 10:11:00 +03:00
QIcon m_icon;
NodeType m_type;
ScriptEngineNode* m_parent;
QVector<ScriptEngineNode*> m_childs;
};
class ScriptEngineManager;
class ScriptEngineModel : public QAbstractItemModel{
Q_OBJECT
public:
friend class ScriptEngineManager;
explicit ScriptEngineModel():m_scriptManager(0), m_rootNode(new ScriptEngineNode()){}
2016-02-17 10:11:00 +03:00
explicit ScriptEngineModel(ScriptEngineManager* scriptManager);
~ScriptEngineModel();
2016-02-17 10:11:00 +03:00
QModelIndex parent(const QModelIndex &child) const;
QModelIndex index(int row, int column, const QModelIndex &parent) const;
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
void setScriptEngineManager(ScriptEngineManager* scriptManager);
2016-06-10 18:05:18 +03:00
inline ScriptEngineManager* scriptEngineManager(){return m_scriptManager;}
2016-02-17 10:11:00 +03:00
private slots:
void slotScriptEngineChanged();
private:
ScriptEngineNode* nodeFromIndex(const QModelIndex &index) const;
void updateModel();
private:
ScriptEngineManager* m_scriptManager;
ScriptEngineNode* m_rootNode;
};
2016-06-10 18:05:18 +03:00
class DialogDescriber : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QByteArray description READ description WRITE setDescription)
public:
typedef QSharedPointer<DialogDescriber> Ptr;
static Ptr create(const QString& name, const QByteArray &desc);
static Ptr create(){return Ptr(new DialogDescriber);}
QString name() const;
void setName(const QString& name);
QByteArray description() const;
void setDescription(const QByteArray& description);
private :
QString m_name;
QByteArray m_description;
};
class ScriptEngineContext : public QObject, public ICollectionContainer
{
Q_OBJECT
Q_PROPERTY(ACollectionProperty dialogs READ fakeCollectionReader)
Q_PROPERTY(QString initScript READ initScript WRITE setInitScript)
public:
#ifdef HAVE_UI_LOADER
typedef QSharedPointer<QDialog> DialogPtr;
#endif
2017-08-25 18:01:59 +03:00
explicit ScriptEngineContext(QObject* parent=0):QObject(parent), m_tableOfContens(new TableOfContens(this)){}
2016-06-10 18:05:18 +03:00
#ifdef HAVE_UI_LOADER
void addDialog(const QString& name, const QByteArray& description);
bool changeDialog(const QString& name, const QByteArray &description);
bool changeDialogName(const QString& oldName, const QString& newName);
2016-06-10 18:05:18 +03:00
bool previewDialog(const QString& dialogName);
bool containsDialog(const QString& dialogName);
const QVector<DialogDescriber::Ptr>& dialogDescribers(){return m_dialogs;}
2016-06-10 18:05:18 +03:00
void deleteDialog(const QString& dialogName);
QDialog *getDialog(const QString &dialogName);
QString getNewDialogName();
void initDialogs();
2016-06-10 18:05:18 +03:00
#endif
2017-08-18 22:55:29 +03:00
void baseDesignIntfToScript(const QString& pageName, BaseDesignIntf *item);
void qobjectToScript(const QString &name, QObject* item);
void clear();
2016-06-10 18:05:18 +03:00
QString initScript() const;
void setInitScript(const QString& initScript);
bool runInitScript();
2017-08-25 18:01:59 +03:00
BandDesignIntf* getCurrentBand() const;
void setCurrentBand(BandDesignIntf* currentBand);
PageItemDesignIntf* getCurrentPage() const;
void setCurrentPage(PageItemDesignIntf* currentPage);
TableOfContens* tableOfContens() const;
void setTableOfContens(TableOfContens* tableOfContens);
#ifdef HAVE_UI_LOADER
signals:
void dialogNameChanged(QString dialogName);
void dialogDeleted(QString dialogName);
void dialogAdded(QString dialogName);
#endif
2016-06-10 18:05:18 +03:00
protected:
QObject* createElement(const QString& collectionName,const QString& elementType);
int elementsCount(const QString& collectionName);
2016-06-10 18:05:18 +03:00
QObject* elementAt(const QString& collectionName,int index);
void collectionLoadFinished(const QString &collectionName);
2016-06-10 18:05:18 +03:00
#ifdef HAVE_UI_LOADER
QDialog *createDialog(DialogDescriber *cont);
QDialog *findDialog(const QString &dialogName);
DialogDescriber* findDialogContainer(const QString& dialogName);
#endif
private:
#ifdef HAVE_UI_LOADER
QVector<DialogDescriber::Ptr> m_dialogs;
QList<DialogPtr> m_createdDialogs;
#endif
QString m_lastError;
QString m_initScript;
2017-08-25 18:01:59 +03:00
BandDesignIntf* m_currentBand;
PageItemDesignIntf* m_currentPage;
TableOfContens* m_tableOfContens;
2016-06-10 18:05:18 +03:00
};
2016-11-01 20:42:45 +03:00
class JSFunctionDesc{
public:
JSFunctionDesc(){}
JSFunctionDesc(const QString& functionName,
const QString& functionCategory,
const QString& functionDescription,
const QString& functionManagerName,
QObject* functionManger,
const QString& functionScriptWrapper
): m_name(functionName), m_category(functionCategory), m_description(functionDescription),
m_managerName(functionManagerName), m_manager(functionManger), m_scriptWrapper(functionScriptWrapper)
{}
QString name() const;
void setName(const QString &name);
QString category() const;
void setCategory(const QString &category);
QString description() const;
void setDescription(const QString &description);
QString managerName() const;
void setManagerName(const QString &managerName);
QObject *manager() const;
void setManager(QObject *manager);
QString scriptWrapper() const;
void setScriptWrapper(const QString &scriptWrapper);
private:
QString m_name;
QString m_category;
QString m_description;
QString m_managerName;
QObject* m_manager;
QString m_scriptWrapper;
};
#ifndef USE_QJSENGINE
class ComboBoxPrototype : public QObject, public QScriptable{
Q_OBJECT
public:
ComboBoxPrototype(QObject* parent = 0):QObject(parent){}
public slots:
void addItem( const QString& text);
void addItems(const QStringList& texts);
};
#endif
#ifdef USE_QJSENGINE
class IWrapperCreator{
public:
virtual QObject* createWrapper(QObject* item) = 0;
virtual ~IWrapperCreator(){}
};
class ComboBoxWrapper : public QObject{
Q_OBJECT
public:
ComboBoxWrapper(QComboBox* comboBox, QObject* parent = 0) : QObject(parent), m_comboBox(comboBox){}
Q_INVOKABLE void addItems(const QStringList& texts){ m_comboBox->addItems(texts);}
Q_INVOKABLE void addItem(const QString& text){ m_comboBox->addItem(text);}
private:
QComboBox* m_comboBox;
};
class ComboBoxWrapperCreator: public IWrapperCreator{
private:
QObject* createWrapper(QObject* item);
};
#endif
2016-11-01 20:42:45 +03:00
class ScriptFunctionsManager : public QObject{
Q_OBJECT
public:
2017-10-26 12:24:06 +03:00
explicit ScriptFunctionsManager(QObject* parent = 0):QObject(parent){
#ifdef USE_QJSENGINE
m_wrappersFactory.insert("QComboBox",new ComboBoxWrapperCreator());
#endif
}
~ScriptFunctionsManager(){
#ifdef USE_QJSENGINE
foreach(IWrapperCreator* wrapper, m_wrappersFactory.values()){ delete wrapper;} m_wrappersFactory.clear();
#endif
}
2017-02-11 00:21:03 +03:00
Q_INVOKABLE QVariant calcGroupFunction(const QString& name, const QString& expressionID, const QString& bandName);
2016-11-01 20:42:45 +03:00
Q_INVOKABLE QVariant line(const QString& bandName);
Q_INVOKABLE QVariant numberFormat(QVariant value, const char &format, int precision, const QString &locale);
Q_INVOKABLE QVariant dateFormat(QVariant value, const QString& format);
Q_INVOKABLE QVariant timeFormat(QVariant value, const QString& format);
Q_INVOKABLE QVariant dateTimeFormat(QVariant value, const QString& format);
Q_INVOKABLE QVariant date();
Q_INVOKABLE QVariant now();
Q_INVOKABLE QVariant currencyFormat(QVariant value, const QString& locale);
Q_INVOKABLE QVariant currencyUSBasedFormat(QVariant value, const QString& currencySymbol);
2017-02-11 00:21:03 +03:00
Q_INVOKABLE void setVariable(const QString& name, QVariant value);
Q_INVOKABLE QVariant getVariable(const QString& name);
Q_INVOKABLE QVariant getField(const QString& field);
2017-08-31 02:53:34 +03:00
Q_INVOKABLE QVariant getFieldByKeyField(const QString& datasourceName, const QString& valueFieldName, const QString& keyFieldName, QVariant keyValue);
Q_INVOKABLE void reopenDatasource(const QString& datasourceName);
2017-08-18 22:55:29 +03:00
Q_INVOKABLE QVariant color(const QString& color){ return QColor(color);}
2017-08-31 02:53:34 +03:00
Q_INVOKABLE void addTableOfContensItem(const QString& uniqKey, const QString& content, int indent = 0);
2017-08-18 22:55:29 +03:00
Q_INVOKABLE void clearTableOfContens();
2016-11-01 20:42:45 +03:00
#ifdef USE_QJSENGINE
Q_INVOKABLE QFont font(const QString& family, int pointSize = -1, bool bold = false, bool italic = false, bool underLine = false);
Q_INVOKABLE void addItemsToComboBox(QJSValue object, const QStringList& values);
Q_INVOKABLE void addItemToComboBox(QJSValue object, const QString& value);
Q_INVOKABLE QJSValue createComboBoxWrapper(QJSValue comboBox);
Q_INVOKABLE QJSValue createWrapper(QJSValue item);
2016-11-01 20:42:45 +03:00
#endif
Q_INVOKABLE QFont font(QVariantMap params);
ScriptEngineManager *scriptEngineManager() const;
void setScriptEngineManager(ScriptEngineManager *scriptEngineManager);
static QColor createQColor(const QString& color){ return QColor(color);}
private:
ScriptEngineManager* m_scriptEngineManager;
2017-10-26 12:24:06 +03:00
#ifdef USE_QJSENGINE
QMap<QString, IWrapperCreator*> m_wrappersFactory;
2017-10-26 12:24:06 +03:00
#endif
2016-11-01 20:42:45 +03:00
};
2016-02-17 10:11:00 +03:00
class ScriptEngineManager : public QObject, public Singleton<ScriptEngineManager>, public IScriptEngineManager
{
Q_OBJECT
public:
friend class Singleton<ScriptEngineManager>;
2016-11-01 20:42:45 +03:00
ScriptEngineType* scriptEngine(){return m_scriptEngine;}
~ScriptEngineManager();
2016-02-17 10:28:27 +03:00
bool isFunctionExists(const QString& functionName) const;
void deleteFunction(const QString& functionsName);
2016-11-01 20:42:45 +03:00
bool addFunction(const JSFunctionDesc& functionsDescriber);
#ifndef USE_QJSENGINE
bool addFunction(const QString &name, QScriptEngine::FunctionSignature function, const QString &category, const QString &description);
#endif
bool addFunction(const QString &name, const QString& script,
2016-02-17 10:11:00 +03:00
const QString &category="", const QString &description="");
const QString& lastError() const {return m_lastError;}
QStringList functionsNames();
2016-11-01 20:42:45 +03:00
const QList<ScriptFunctionDesc>& functionsDescribers(){return m_functions;}
2016-02-17 10:11:00 +03:00
ScriptEngineModel* model(){return m_model;}
2016-06-10 18:05:18 +03:00
void setContext(ScriptEngineContext* context){m_context=context;}
2016-02-17 10:28:27 +03:00
DataSourceManager* dataManager() const {return m_dataManager;}
void setDataManager(DataSourceManager* dataManager);
QString expandUserVariables(QString context, RenderPass pass, ExpandType expandType, QVariant &varValue);
QString expandDataFields(QString context, ExpandType expandType, QVariant &varValue, QObject* reportItem);
QString expandScripts(QString context, QVariant &varValue, QObject* reportItem);
QVariant evaluateScript(const QString &script);
2017-08-31 02:53:34 +03:00
void addTableOfContensItem(const QString& uniqKey, const QString& content, int indent);
2017-08-25 18:01:59 +03:00
void clearTableOfContens();
2016-06-10 18:05:18 +03:00
protected:
void updateModel();
bool containsFunction(const QString &functionName);
2016-02-17 10:11:00 +03:00
private:
Q_DISABLE_COPY(ScriptEngineManager)
2016-11-01 20:42:45 +03:00
bool createLineFunction();
bool createNumberFomatFunction();
bool createDateFormatFunction();
bool createTimeFormatFunction();
bool createDateTimeFormatFunction();
bool createDateFunction();
bool createNowFunction();
bool createCurrencyFormatFunction();
bool createCurrencyUSBasedFormatFunction();
bool createSetVariableFunction();
2017-02-11 00:21:03 +03:00
bool createGetVariableFunction();
bool createGetFieldFunction();
2017-08-31 02:53:34 +03:00
bool createGetFieldByKeyFunction();
2017-08-18 22:55:29 +03:00
bool createAddTableOfContensItemFunction();
bool createClearTableOfContensFunction();
bool createReopenDatasourceFunction();
2016-02-17 10:11:00 +03:00
private:
ScriptEngineManager();
2016-11-01 20:42:45 +03:00
ScriptEngineType* m_scriptEngine;
2016-02-17 10:11:00 +03:00
QString m_lastError;
QList<ScriptFunctionDesc> m_functions;
ScriptEngineModel* m_model;
2016-06-10 18:05:18 +03:00
ScriptEngineContext* m_context;
2016-02-17 10:28:27 +03:00
DataSourceManager* m_dataManager;
2016-11-01 20:42:45 +03:00
ScriptFunctionsManager* m_functionManager;
2016-02-17 10:11:00 +03:00
};
class ScriptExtractor
{
public:
enum State{None,BuksFound,SFound,StartScriptFound,OpenBracketFound,CloseBracketFound,DFound,VFound, SignFound};
explicit ScriptExtractor(const QString& value):m_context(value){}
bool parse();
int count(){return m_scriptsBody.count();}
QString bodyAt(int index){return m_scriptsBody[index];}
QString scriptAt(int index){return m_scriptsStartLex[index]+m_scriptsBody[index]+'}';}
private:
static const char SCRIPT_SIGN = 'S';
static const char FIELD_SIGN = 'D';
static const char VARIABLE_SIGN = 'V';
bool isStartLexem(int &curPos, QChar value);
bool parse(int& curPos, const State &state);
void skipField(int &curPos);
void extractScript(int& curPos, const QString &startStr);
bool extractBracket(int& curPos);
bool isStartScriptLexem(int &curPos);
bool isStartFieldLexem(int &curPos);
bool isStartVariableLexem(int &curPos);
QString substring(const QString& value, int start, int end);
private:
QString m_context;
QVector<QString> m_scriptsBody;
QVector<QString> m_scriptsStartLex;
};
class QFontPrototype : public QObject, public QScriptable {
Q_OBJECT
Q_PROPERTY(QString family READ family)
Q_PROPERTY(int size READ size)
Q_PROPERTY(bool bold READ bold)
Q_PROPERTY(bool italic READ italic)
Q_PROPERTY(bool underline READ underline)
public:
QFontPrototype(QObject * parent = NULL) : QObject(parent) , QScriptable() {
this->setObjectName("QFontPrototype");
}
QString family() const {
QFont font(qScriptValueToValue<QFont>(this->thisObject()));
return font.family();
}
int size(){
QFont font = qScriptValueToValue<QFont>(thisObject());
return font.pointSize();
}
bool bold(){
QFont font = qScriptValueToValue<QFont>(thisObject());
return font.bold();
}
bool italic(){
QFont font = qScriptValueToValue<QFont>(thisObject());
return font.italic();
}
bool underline(){
QFont font = qScriptValueToValue<QFont>(thisObject());
return font.underline();
}
static QScriptValue constructorQFont(QScriptContext * context, QScriptEngine * engine) {
QFont font;
switch (context->argumentCount()) {
case 5: font.setUnderline(qScriptValueToValue<bool>(context->argument(4)));
case 4: font.setBold(qScriptValueToValue<bool>(context->argument(3)));
case 3: font.setItalic(qScriptValueToValue<bool>(context->argument(2)));
case 2: font.setPointSize(qScriptValueToValue<int>(context->argument(1)));
case 1: font.setFamily(qScriptValueToValue<QString>(context->argument(0)));
case 0: break;
default:
break;
}
return qScriptValueFromValue<QFont>(engine, font);
}
};
}
#ifndef USE_QJSENGINE
2017-10-26 12:24:06 +03:00
Q_DECLARE_METATYPE(LimeReport::ComboBoxPrototype*)
Q_DECLARE_METATYPE(QComboBox*)
#endif
2016-02-17 10:11:00 +03:00
#endif // LRSCRIPTENGINEMANAGER_H