0
0
mirror of https://github.com/fralx/LimeReport.git synced 2024-12-23 16:22:58 +03:00
LimeReport/limereport/lrscriptenginemanager.h
Андрей Лухнов 0fca7169d3 Define code style and format all source file using clang-format-14
except those placed in 3rdparty directories.
2024-09-19 21:09:38 +03:00

700 lines
26 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/***************************************************************************
* This file is part of the Lime Report project *
* Copyright (C) 2021 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
#ifdef USE_QTSCRIPTENGINE
#include <QScriptable>
#include <QtScript/QScriptEngine>
#endif
#include <QAbstractItemModel>
#include <QComboBox>
#include <QDebug>
#include <QFont>
#include <QIcon>
#include <QVector>
#include <QtGlobal>
//#include <QJSEngine>
#ifdef HAVE_UI_LOADER
#include <QDialog>
#endif
#include "base/lrsingleton.h"
#include "lrcallbackdatasourceintf.h"
#include "lrcollection.h"
#include "lrdatasourceintf.h"
#include "lrdatasourcemanagerintf.h"
#include "lrglobal.h"
#include "lrhorizontallayout.h"
#include "lrscriptenginemanagerintf.h"
#include "lrverticallayout.h"
namespace LimeReport {
class DataSourceManager;
class BaseDesignIntf;
class PageItemDesignIntf;
class BandDesignIntf;
struct ContentItem {
QString content;
int indent;
int pageNumber;
QString uniqKey;
};
class TableOfContents: public QObject {
Q_OBJECT
public:
TableOfContents(QObject* parent = 0): QObject(parent) { }
~TableOfContents();
void setItem(const QString& uniqKey, const QString& content, int pageNumber, int indent = 0);
void clear();
bool isEmpty() { return m_tableOfContents.isEmpty(); }
private slots:
void slotOneSlotDS(LimeReport::CallbackInfo info, QVariant& data);
private:
QVector<ContentItem*> m_tableOfContents;
QHash<QString, ContentItem*> m_hash;
};
struct ScriptFunctionDesc {
enum FuncType {
Native,
Script
};
ScriptValueType scriptValue;
QString name;
QString description;
QString category;
FuncType type;
};
class ScriptEngineNode {
public:
enum NodeType {
Root,
Category,
Function,
Dialog,
DialogElement
};
ScriptEngineNode(const QString& name = "", const QString& description = "",
NodeType type = Root, ScriptEngineNode* parent = 0,
const QIcon& icon = QIcon());
virtual ~ScriptEngineNode();
int childCount() { return m_childs.count(); }
ScriptEngineNode* child(int index) { return m_childs[index]; }
ScriptEngineNode* parent() { return m_parent; }
ScriptEngineNode* addChild(const QString& name = "", const QString& description = "",
NodeType type = Root, const QIcon& icon = QIcon());
int row();
QString name() { return m_name; }
QString description() { return m_description; }
QIcon icon() { return m_icon; }
void clear();
NodeType type() { return m_type; }
private:
QString m_name;
QString m_description;
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()) { }
explicit ScriptEngineModel(ScriptEngineManager* scriptManager);
~ScriptEngineModel();
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);
inline ScriptEngineManager* scriptEngineManager() { return m_scriptManager; }
private slots:
void slotScriptEngineChanged();
private:
ScriptEngineNode* nodeFromIndex(const QModelIndex& index) const;
void updateModel();
private:
ScriptEngineManager* m_scriptManager;
ScriptEngineNode* m_rootNode;
};
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;
};
typedef QList<QSharedPointer<PageItemDesignIntf>> ReportPages;
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
explicit ScriptEngineContext(QObject* parent = 0):
QObject(parent),
m_currentBand(0),
m_currentPage(0),
m_tableOfContents(new TableOfContents(this)),
m_hasChanges(false)
{
}
#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);
bool previewDialog(const QString& dialogName);
bool containsDialog(const QString& dialogName);
const QVector<DialogDescriber::Ptr>& dialogDescribers() { return m_dialogs; }
void deleteDialog(const QString& dialogName);
QDialog* getDialog(const QString& dialogName);
QString getNewDialogName();
void initDialogs();
#endif
void baseDesignIntfToScript(const QString& pageName, BaseDesignIntf* item);
void qobjectToScript(const QString& name, QObject* item);
void clear();
QString initScript() const;
void setInitScript(const QString& initScript);
bool runInitScript();
BandDesignIntf* currentBand() const;
void setCurrentBand(BandDesignIntf* currentBand);
PageItemDesignIntf* currentPage() const;
void setCurrentPage(PageItemDesignIntf* currentPage);
TableOfContents* tableOfContents() const;
void setTableOfContents(TableOfContents* tableOfContents);
void dropChanges() { m_hasChanges = false; }
bool hasChanges() { return m_hasChanges; }
ReportPages* reportPages() const;
void setReportPages(ReportPages* value);
#ifdef HAVE_UI_LOADER
signals:
void dialogNameChanged(QString dialogName);
void dialogDeleted(QString dialogName);
void dialogAdded(QString dialogName);
#endif
protected:
QObject* createElement(const QString& collectionName, const QString& elementType);
int elementsCount(const QString& collectionName);
QObject* elementAt(const QString& collectionName, int index);
void collectionLoadFinished(const QString& collectionName);
#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;
BandDesignIntf* m_currentBand;
PageItemDesignIntf* m_currentPage;
TableOfContents* m_tableOfContents;
bool m_hasChanges;
ReportPages* m_reportPages;
};
class JSFunctionDesc {
public:
JSFunctionDesc() { }
JSFunctionDesc(const QString& functionName, const QString& functionCategory,
const QString& functionDescription, const QString& functionManagerName,
QObject* functionManager, const QString& functionScriptWrapper):
m_name(functionName),
m_category(functionCategory),
m_description(functionDescription),
m_managerName(functionManagerName),
m_manager(functionManager),
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;
};
#ifdef USE_QTSCRIPTENGINE
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
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);
};
class TableBuilder: public QObject {
Q_OBJECT
public:
TableBuilder(LimeReport::HorizontalLayout* layout, DataSourceManager* dataManager);
~TableBuilder() { delete m_patternLayout; }
Q_INVOKABLE QObject* addRow();
Q_INVOKABLE QObject* currentRow();
Q_INVOKABLE void fillInRowData(QObject* row);
Q_INVOKABLE void buildTable(const QString& datasourceName);
private:
void checkBaseLayout();
private:
LimeReport::HorizontalLayout* m_horizontalLayout;
LimeReport::HorizontalLayout* m_patternLayout;
LimeReport::VerticalLayout* m_baseLayout;
DataSourceManager* m_dataManager;
};
class DatasourceFunctions: public QObject {
Q_OBJECT
public:
explicit DatasourceFunctions(IDataSourceManager* dataManager):
m_dataManager(dynamic_cast<DataSourceManager*>(dataManager))
{
}
Q_INVOKABLE bool first(const QString& datasourceName);
Q_INVOKABLE bool next(const QString& datasourceName);
Q_INVOKABLE bool prior(const QString& datasourceName);
Q_INVOKABLE bool isEOF(const QString& datasourceName);
Q_INVOKABLE int rowCount(const QString& datasourceName);
Q_INVOKABLE bool invalidate(const QString& datasourceName);
Q_INVOKABLE QObject* createTableBuilder(QObject* horizontalLayout);
private:
DataSourceManager* m_dataManager;
};
class ScriptFunctionsManager: public QObject {
Q_OBJECT
public:
explicit ScriptFunctionsManager(QObject* parent = 0): QObject(parent)
{
m_wrappersFactory.insert("QComboBox", new ComboBoxWrapperCreator());
}
~ScriptFunctionsManager()
{
foreach (IWrapperCreator* wrapper, m_wrappersFactory.values()) {
delete wrapper;
}
m_wrappersFactory.clear();
}
Q_INVOKABLE QVariant calcGroupFunction(const QString& name, const QString& expressionID,
const QString& bandName, QObject* currentPage);
Q_INVOKABLE QVariant calcGroupFunction(const QString& name, const QString& expressionID,
const QString& bandName);
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, const QString& locale);
Q_INVOKABLE QVariant timeFormat(QVariant value, const QString& format);
Q_INVOKABLE QVariant dateTimeFormat(QVariant value, const QString& format,
const QString& locale);
Q_INVOKABLE QVariant sectotimeFormat(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);
Q_INVOKABLE void setVariable(const QString& name, QVariant value);
Q_INVOKABLE QVariant getVariable(const QString& name);
Q_INVOKABLE QVariant getField(const QString& field);
Q_INVOKABLE QVariant getFieldByKeyField(const QString& datasourceName,
const QString& valueFieldName,
const QString& keyFieldName, QVariant keyValue);
Q_INVOKABLE QVariant getFieldByRowIndex(const QString& fieldName, int rowIndex);
Q_INVOKABLE void reopenDatasource(const QString& datasourceName);
Q_INVOKABLE QVariant color(const QString& color) { return QColor(color); }
Q_INVOKABLE void addBookmark(const QString& uniqKey, const QString& content);
Q_INVOKABLE int findPageIndexByBookmark(const QString& uniqKey);
Q_INVOKABLE void addTableOfContentsItem(const QString& uniqKey, const QString& content,
int indent = 0);
Q_INVOKABLE void clearTableOfContents();
Q_INVOKABLE QFont font(const QString& family, int pointSize = -1, bool bold = false,
bool italic = false, bool underLine = false);
/*!
* \brief getFieldByRowIndexEx Выдает для поля значение заданной роли
* \param fieldName имя источника данных + имя поля
* \param rowIndex индекс строки
* \param role код роли
* \return
*/
Q_INVOKABLE QVariant getFieldByRowIndexEx(const QString& fieldName, int rowIndex,
const int role);
/*!
* \brief getFieldByRowIndexEx2 Выдает для поля значение заданной роли
* \param fieldName имя источника данных + имя поля
* \param rowIndex индекс строки
* \param roleName имя роли из roleNames()
* \return
*/
Q_INVOKABLE QVariant getFieldByRowIndexEx2(const QString& fieldName, int rowIndex,
const QString& roleName);
/*!
* \brief getHeaderData Выдает для поля заголовка значение заданной роли
* \param fieldName имя источника данных + имя поля
* \param role имя роли из roleNames()
* \return
*/
Q_INVOKABLE QVariant getHeaderData(const QString& fieldName, const QString& roleName);
/*!
* \brief getHeaderColumnNameByIndex Выдает имя колонки по ее индексу (имя используемое LR)
* \param datasourceName имя источника данных
* \param columnIndex индекс колонки
* \return
*/
Q_INVOKABLE QVariant getHeaderColumnNameByIndex(const QString& datasourceName,
const int columnIndex);
/*!
* \brief getColumnCount Выдает число столбцов в источнике данных
* \param datasourceName имя источника данных
* \return возможно -1 при ошибке
*/
Q_INVOKABLE int getColumnCount(const QString& datasourceName);
#ifdef USE_QJSENGINE
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);
#else
Q_INVOKABLE void addItemsToComboBox(QScriptValue object, const QStringList& values);
Q_INVOKABLE void addItemToComboBox(QScriptValue object, const QString& value);
Q_INVOKABLE QScriptValue createComboBoxWrapper(QScriptValue comboBox);
Q_INVOKABLE QScriptValue createWrapper(QScriptValue item);
#endif
Q_INVOKABLE QFont font(QVariantMap params);
Q_INVOKABLE int getPageFreeSpace(QObject* page);
ScriptEngineManager* scriptEngineManager() const;
void setScriptEngineManager(ScriptEngineManager* scriptEngineManager);
static QColor createQColor(const QString& color) { return QColor(color); }
private:
ScriptEngineManager* m_scriptEngineManager;
QMap<QString, IWrapperCreator*> m_wrappersFactory;
};
class ScriptNode {
public:
typedef QSharedPointer<ScriptNode> Ptr;
QString body()
{
if (m_body.isEmpty() && m_children.count() > 0)
return m_children.at(0)->body();
return m_body;
}
void setBody(const QString& body) { m_body = body; }
void setStartLex(const QString startLex) { m_startLex = startLex; }
QString script() { return m_startLex + m_body + '}'; }
Ptr createChildNode()
{
Ptr result = Ptr(new ScriptNode());
m_children.append(result);
return result;
}
QVector<Ptr> children() const { return m_children; }
private:
QVector<Ptr> m_children;
QString m_body;
QString m_startLex;
};
class ScriptExtractor {
public:
enum State {
None,
BuksFound,
SFound,
StartScriptFound,
OpenBracketFound,
CloseBracketFound,
DFound,
VFound,
SignFound
};
explicit ScriptExtractor(const QString& value):
m_context(value),
m_scriptTree(ScriptNode::Ptr(new ScriptNode()))
{
}
bool parse();
ScriptNode::Ptr scriptTree() { return m_scriptTree; }
private:
bool isStartLexem(int& curPos, QChar value);
bool parse(int& curPos, const State& state, ScriptNode::Ptr scriptNode);
void skipField(int& curPos);
void extractScript(int& curPos, const QString& startStr, ScriptNode::Ptr scriptNode);
bool extractBracket(int& curPos, ScriptNode::Ptr scriptNode);
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;
ScriptNode::Ptr m_scriptTree;
};
class ScriptEngineManager:
public QObject,
public Singleton<ScriptEngineManager>,
public IScriptEngineManager {
Q_OBJECT
public:
friend class Singleton<ScriptEngineManager>;
ScriptEngineType* scriptEngine() { return m_scriptEngine; }
~ScriptEngineManager();
bool isFunctionExists(const QString& functionName) const;
void deleteFunction(const QString& functionsName);
bool addFunction(const JSFunctionDesc& functionsDescriber);
#ifdef USE_QTSCRIPTENGINE
bool addFunction(const QString& name, QScriptEngine::FunctionSignature function,
const QString& category, const QString& description);
#endif
bool addFunction(const QString& name, const QString& script, const QString& category = "",
const QString& description = "");
const QString& lastError() const { return m_lastError; }
QStringList functionsNames();
const QHash<QString, ScriptFunctionDesc>& functionsDescribers() { return m_functions; }
ScriptEngineModel* model() { return m_model; }
void setContext(ScriptEngineContext* context) { m_context = context; }
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);
QString replaceScripts(QString context, QVariant& varValue, QObject* reportItem,
ScriptEngineType* se, ScriptNode::Ptr scriptTree);
QVariant evaluateScript(const QString& script);
void addBookMark(const QString& uniqKey, const QString& content);
int findPageIndexByBookmark(const QString& uniqKey);
void addTableOfContentsItem(const QString& uniqKey, const QString& content, int indent);
void clearTableOfContents();
int getPageFreeSpace(PageItemDesignIntf* page);
ScriptValueType moveQObjectToScript(QObject* object, const QString objectName);
protected:
void updateModel();
private:
Q_DISABLE_COPY(ScriptEngineManager)
bool createLineFunction();
bool createNumberFomatFunction();
bool createDateFormatFunction();
bool createTimeFormatFunction();
bool createDateTimeFormatFunction();
bool createSectotimeFormatFunction();
bool createDateFunction();
bool createNowFunction();
bool createCurrencyFormatFunction();
bool createCurrencyUSBasedFormatFunction();
bool createSetVariableFunction();
bool createGetVariableFunction();
bool createGetFieldFunction();
bool createGetFieldByKeyFunction();
bool createGetFieldByRowIndex();
bool createAddBookmarkFunction();
bool createFindPageIndexByBookmark();
bool createAddTableOfContentsItemFunction();
bool createClearTableOfContentsFunction();
bool createReopenDatasourceFunction();
bool createGetFieldByRowIndexEx();
bool createGetFieldByRowIndexEx2();
bool createHeaderData();
bool createHeaderColumnNameByIndex();
bool createColumnCount();
private:
ScriptEngineManager();
ScriptEngineType* m_scriptEngine;
QString m_lastError;
QHash<QString, ScriptFunctionDesc> m_functions;
ScriptEngineModel* m_model;
ScriptEngineContext* m_context;
DataSourceManager* m_dataManager;
ScriptFunctionsManager* m_functionManager;
};
#ifdef USE_QTSCRIPTENGINE
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);
}
};
#endif
} // namespace LimeReport
#ifdef USE_QTSCRIPTENGINE
Q_DECLARE_METATYPE(LimeReport::ComboBoxPrototype*)
Q_DECLARE_METATYPE(QComboBox*)
#endif
#endif // LRSCRIPTENGINEMANAGER_H