diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,6 +116,15 @@ find_package(Qt5 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Core Gui Widgets Xml Network PrintSupport Test) find_package(Qt5 ${REQUIRED_QT_VERSION} COMPONENTS UiTools WebKit WebKitWidgets) +if(KEXI_SCRIPTS_SUPPORT) + find_package(Qt5 5.8.0 COMPONENTS Qml) + set_package_properties(Qt5Qml PROPERTIES + DESCRIPTION "A framework for developing applications and libraries with the QML and JavaScript language." + URL "http://qt.io" + TYPE REQUIRED PURPOSE "Required by Kexi scripting (JavaScript)" + ) +endif() + # use sane compile flags add_definitions( -DQT_NO_CAST_TO_ASCII diff --git a/KexiProducts.cmake b/KexiProducts.cmake --- a/KexiProducts.cmake +++ b/KexiProducts.cmake @@ -59,9 +59,6 @@ # TODO: some products have multiple optional requirements, but need at least one. # See APP_CONVERTER, FILEMANAGER_* -# features -calligra_define_feature(FEATURE_SCRIPTING "Scripting feature" UNPORTED) # TODO - # products calligra_define_product(KEXI_CORE_APP "Kexi core app" REQUIRES) calligra_define_product(KEXI_DESKTOP_APP "Kexi for desktop" REQUIRES KEXI_CORE_APP) diff --git a/cmake/productsets/desktop.cmake b/cmake/productsets/desktop.cmake --- a/cmake/productsets/desktop.cmake +++ b/cmake/productsets/desktop.cmake @@ -4,6 +4,5 @@ REQUIRES KEXI_DESKTOP_APP OPTIONAL - FEATURE_SCRIPTING PLUGIN_KEXI_SPREADSHEETMIGRATION ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,7 +22,7 @@ endif(NOT KEXI_MOBILE) # Experimental: -option(KEXI_SCRIPTS_SUPPORT "Experimental: Enable scripting in Kexi" ON) +option(KEXI_SCRIPTS_SUPPORT "Experimental: Enable scripting in Kexi" OFF) # Broken: option(KEXI_FORM_CURSOR_PROPERTY_SUPPORT "Broken: Enable \"cursor\" property in the form designer" OFF) diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -8,7 +8,7 @@ add_subdirectory( migration ) add_subdirectory( importexport ) - if(SHOULD_BUILD_FEATURE_SCRIPTING AND KEXI_SCRIPTS_SUPPORT) - # KEXI3 TODO add_subdirectory(scripting) + if(KEXI_SCRIPTS_SUPPORT) + add_subdirectory(scripting) endif() endif () diff --git a/src/plugins/reports/KexiDBReportDataSource.h b/src/plugins/reports/KexiDBReportDataSource.h --- a/src/plugins/reports/KexiDBReportDataSource.h +++ b/src/plugins/reports/KexiDBReportDataSource.h @@ -66,8 +66,6 @@ virtual qint64 recordCount() const; //Utility Functions - virtual QStringList scriptList() const; - virtual QString scriptCode(const QString& script) const; virtual QStringList dataSourceNames() const; virtual KReportDataSource* create(const QString& source) const Q_REQUIRED_RESULT; diff --git a/src/plugins/reports/KexiDBReportDataSource.cpp b/src/plugins/reports/KexiDBReportDataSource.cpp --- a/src/plugins/reports/KexiDBReportDataSource.cpp +++ b/src/plugins/reports/KexiDBReportDataSource.cpp @@ -302,102 +302,6 @@ return 1; } -static bool isInterpreterSupported(const QString &interpreterName) -{ - return 0 == interpreterName.compare(QLatin1String("javascript"), Qt::CaseInsensitive) - || 0 == interpreterName.compare(QLatin1String("qtscript"), Qt::CaseInsensitive); -} - -QStringList KexiDBReportDataSource::scriptList() const -{ - QStringList scripts; - - if( d->connection) { - QList scriptids = d->connection->objectIds(KexiPart::ScriptObjectType); - QStringList scriptnames = d->connection->objectNames(KexiPart::ScriptObjectType); - - qDebug() << scriptids << scriptnames; - - //A blank entry - scripts << ""; - int i = 0; - foreach(int id, scriptids) { - qDebug() << "ID:" << id; - tristate res; - QString script; - res = d->connection->loadDataBlock(id, &script, QString()); - if (res == true) { - QDomDocument domdoc; - bool parsed = domdoc.setContent(script, false); - - QDomElement scriptelem = domdoc.namedItem("script").toElement(); - if (parsed && !scriptelem.isNull()) { - if (scriptelem.attribute("scripttype") == "object" - && isInterpreterSupported(scriptelem.attribute("language"))) - { - scripts << scriptnames[i]; - } - } else { - qDebug() << "Unable to parse script"; - } - } else { - qDebug() << "Unable to loadDataBlock"; - } - ++i; - } - - qDebug() << scripts; - } - return scripts; -} - -QString KexiDBReportDataSource::scriptCode(const QString& scriptname) const -{ - QString scripts; - - if (d->connection) { - QList scriptids = d->connection->objectIds(KexiPart::ScriptObjectType); - QStringList scriptnames = d->connection->objectNames(KexiPart::ScriptObjectType); - - int i = 0; - foreach(int id, scriptids) { - qDebug() << "ID:" << id; - tristate res; - QString script; - res = d->connection->loadDataBlock(id, &script, QString()); - if (res == true) { - QDomDocument domdoc; - bool parsed = domdoc.setContent(script, false); - - if (! parsed) { - qDebug() << "XML parsing error"; - return QString(); - } - - QDomElement scriptelem = domdoc.namedItem("script").toElement(); - if (scriptelem.isNull()) { - qDebug() << "script domelement is null"; - return QString(); - } - - QString interpretername = scriptelem.attribute("language"); - qDebug() << scriptelem.attribute("scripttype"); - qDebug() << scriptname << scriptnames[i]; - - if ((isInterpreterSupported(interpretername) && scriptelem.attribute("scripttype") == "module") - || scriptname == scriptnames[i]) - { - scripts += '\n' + scriptelem.text().toUtf8(); - } - ++i; - } else { - qDebug() << "Unable to loadDataBlock"; - } - } - } - return scripts; -} - QStringList KexiDBReportDataSource::dataSourceNames() const { //Get the list of queries in the database diff --git a/src/plugins/reports/kexireportdesignview.cpp b/src/plugins/reports/kexireportdesignview.cpp --- a/src/plugins/reports/kexireportdesignview.cpp +++ b/src/plugins/reports/kexireportdesignview.cpp @@ -163,6 +163,7 @@ m_reportDesigner = new KReportDesigner(this, tempData()->reportDefinition); m_sourceSelector->setConnectionData(tempData()->connectionDefinition); + m_reportDesigner->setScriptSource(qobject_cast(part())); } connect(m_reportDesigner, SIGNAL(itemInserted(QString)), this, SIGNAL(itemInserted(QString))); diff --git a/src/plugins/reports/kexireportpart.h b/src/plugins/reports/kexireportpart.h --- a/src/plugins/reports/kexireportpart.h +++ b/src/plugins/reports/kexireportpart.h @@ -24,6 +24,7 @@ #include #include +#include #include class KexiReportPartTempData : public KexiWindowData @@ -42,7 +43,7 @@ /** * @short Application Main Window */ -class KexiReportPart : public KexiPart::Part +class KexiReportPart : public KexiPart::Part, public KReportScriptSource { Q_OBJECT public: @@ -61,6 +62,9 @@ virtual KLocalizedString i18nMessage(const QString& englishMessage, KexiWindow* window) const; + QStringList scriptList() const override; + QString scriptCode(const QString& script) const override; + protected: virtual KexiView* createView(QWidget *parent, KexiWindow* win, KexiPart::Item *item, Kexi::ViewMode = Kexi::DataViewMode, diff --git a/src/plugins/reports/kexireportpart.cpp b/src/plugins/reports/kexireportpart.cpp --- a/src/plugins/reports/kexireportpart.cpp +++ b/src/plugins/reports/kexireportpart.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include #include @@ -48,6 +50,12 @@ QMap toolboxActionsByName; }; +static bool isInterpreterSupported(const QString &interpreterName) +{ + return 0 == interpreterName.compare(QLatin1String("javascript"), Qt::CaseInsensitive) + || 0 == interpreterName.compare(QLatin1String("qtscript"), Qt::CaseInsensitive); +} + KexiReportPart::KexiReportPart(QObject *parent, const QVariantList &l) : KexiPart::Part(parent, xi18nc("Translate this word using only lowercase alphanumeric characters (a..z, 0..9). " @@ -201,3 +209,93 @@ } } +QStringList KexiReportPart::scriptList() const +{ + QStringList scripts; + + KexiMainWindowIface *win = KexiMainWindowIface::global(); + + if (win->project() && win->project()->dbConnection()) { + QList scriptids = win->project()->dbConnection()->objectIds(KexiPart::ScriptObjectType); + QStringList scriptnames = win->project()->dbConnection()->objectNames(KexiPart::ScriptObjectType); + + qDebug() << scriptids << scriptnames; + + int i = 0; + foreach(int id, scriptids) { + qDebug() << "ID:" << id; + tristate res; + QString script; + res = win->project()->dbConnection()->loadDataBlock(id, &script, QString()); + if (res == true) { + QDomDocument domdoc; + bool parsed = domdoc.setContent(script, false); + + QDomElement scriptelem = domdoc.namedItem("script").toElement(); + if (parsed && !scriptelem.isNull()) { + if (scriptelem.attribute("scripttype") == "object" + && isInterpreterSupported(scriptelem.attribute("language"))) + { + scripts << scriptnames[i]; + } + } else { + qWarning() << "Unable to parse script"; + } + } else { + qWarning() << "Unable to loadDataBlock"; + } + ++i; + } + + qDebug() << scripts; + } + return scripts; +} + +QString KexiReportPart::scriptCode(const QString& scriptname) const +{ + QString scripts; + + KexiMainWindowIface *win = KexiMainWindowIface::global(); + + if (win->project() && win->project()->dbConnection()) { + QList scriptids = win->project()->dbConnection()->objectIds(KexiPart::ScriptObjectType); + QStringList scriptnames = win->project()->dbConnection()->objectNames(KexiPart::ScriptObjectType); + + int i = 0; + foreach(int id, scriptids) { + qDebug() << "ID:" << id; + tristate res; + QString script; + res = win->project()->dbConnection()->loadDataBlock(id, &script, QString()); + if (res == true) { + QDomDocument domdoc; + bool parsed = domdoc.setContent(script, false); + + if (! parsed) { + qWarning() << "XML parsing error"; + return QString(); + } + + QDomElement scriptelem = domdoc.namedItem("script").toElement(); + if (scriptelem.isNull()) { + qWarning() << "script domelement is null"; + return QString(); + } + + QString interpretername = scriptelem.attribute("language"); + qDebug() << scriptelem.attribute("scripttype"); + qDebug() << scriptname << scriptnames[i]; + + if ((isInterpreterSupported(interpretername) && scriptelem.attribute("scripttype") == "module") || scriptname == scriptnames[i]) + { + scripts += '\n' + scriptelem.text().toUtf8(); + } + ++i; + } else { + qWarning() << "Unable to loadDataBlock"; + } + } + } + return scripts; +} diff --git a/src/plugins/reports/kexireportview.cpp b/src/plugins/reports/kexireportview.cpp --- a/src/plugins/reports/kexireportview.cpp +++ b/src/plugins/reports/kexireportview.cpp @@ -367,6 +367,7 @@ reportData = createSourceData(tempData()->connectionDefinition); } m_preRenderer->setSourceData(reportData); + m_preRenderer->setScriptSource(qobject_cast(part())); m_preRenderer->setName(window()->partItem()->name()); diff --git a/src/plugins/scripting/kexidb/CMakeLists.txt b/src/plugins/scripting/kexidb/CMakeLists.txt --- a/src/plugins/scripting/kexidb/CMakeLists.txt +++ b/src/plugins/scripting/kexidb/CMakeLists.txt @@ -1,15 +1,15 @@ -set(krossmodulekexidb_PART_SRCS - kexidbmodule.cpp - kexidbfield.cpp - kexidbfieldlist.cpp - kexidbschema.cpp - kexidbparser.cpp - kexidbcursor.cpp - kexidbconnectiondata.cpp - kexidbconnection.cpp - kexidbdriver.cpp ) - -add_library(krossmodulekexidb MODULE ${krossmodulekexidb_PART_SRCS}) - -target_link_libraries(krossmodulekexidb KDb) -install(TARGETS krossmodulekexidb DESTINATION ${KEXI_PLUGIN_INSTALL_DIR}) +#set(krossmodulekexidb_PART_SRCS +# kexidbmodule.cpp +# kexidbfield.cpp +# kexidbfieldlist.cpp +# kexidbschema.cpp +# kexidbparser.cpp +# kexidbcursor.cpp +# kexidbconnectiondata.cpp +# kexidbconnection.cpp +# kexidbdriver.cpp ) +# +#add_library(krossmodulekexidb MODULE ${krossmodulekexidb_PART_SRCS}) +# +#target_link_libraries(krossmodulekexidb KDb KF5::ConfigCore KF5::ConfigGui) +#install(TARGETS krossmodulekexidb DESTINATION ${KEXI_PLUGIN_INSTALL_DIR}) diff --git a/src/plugins/scripting/kexidb/kexidbconnection.h b/src/plugins/scripting/kexidb/kexidbconnection.h --- a/src/plugins/scripting/kexidb/kexidbconnection.h +++ b/src/plugins/scripting/kexidb/kexidbconnection.h @@ -26,12 +26,13 @@ #include +#include "kexidbconnectiondata.h" + namespace Scripting { // Forward declarations. class KexiDBDriver; -class KexiDBConnectionData; class KexiDBCursor; class KexiDBTableSchema; class KexiDBQuerySchema; @@ -64,15 +65,16 @@ { Q_OBJECT public: - KexiDBConnection(KDbConnection* connection, KexiDBDriver* driver = 0, KexiDBConnectionData* connectiondata = 0); + KexiDBConnection(KDbConnection* connection, KexiDBConnectionData* connectiondata, KexiDBDriver* driver = 0); + KexiDBConnection(KDbConnection* connection, KexiDBDriver* driver = 0); virtual ~KexiDBConnection(); public Q_SLOTS: /** Return true if there was an error during last operation on the database. */ bool hadError() const; /** Return the last errormessage. */ - const QString lastError() const; + QString lastError() const; /** Return the \a KexiDBConnectionData object used to create this connection. */ QObject* data(); @@ -93,7 +95,7 @@ bool databaseExists(const QString& dbname); /** Return the name of currently used database for this connection or empty string if there is no used database. */ - const QString currentDatabase() const; + QString currentDatabase() const; /** Return list of database names for opened connection. */ const QStringList databaseNames() const; /** Return true if connection is properly established. */ @@ -158,7 +160,7 @@ private: KDbConnection* m_connection; - QPointer m_connectiondata; + KexiDBConnectionData* m_connectiondata; QPointer m_driver; }; diff --git a/src/plugins/scripting/kexidb/kexidbconnection.cpp b/src/plugins/scripting/kexidb/kexidbconnection.cpp --- a/src/plugins/scripting/kexidb/kexidbconnection.cpp +++ b/src/plugins/scripting/kexidb/kexidbconnection.cpp @@ -24,17 +24,27 @@ #include "kexidbfieldlist.h" #include "kexidbschema.h" #include "kexidbparser.h" +#include "KexiScriptingDebug.h" #include +#include #include using namespace Scripting; -KexiDBConnection::KexiDBConnection(KDbConnection* connection, KexiDBDriver* driver, KexiDBConnectionData* connectiondata) +KexiDBConnection::KexiDBConnection(KDbConnection* connection, KexiDBConnectionData* connectiondata, KexiDBDriver* driver) + : QObject() + , m_connection(connection) + , m_driver(driver ? driver : new KexiDBDriver(this, connection->driver())) +{ + m_connectiondata = connectiondata; + setObjectName("KexiDBConnection"); +} + +KexiDBConnection::KexiDBConnection(KDbConnection* connection, KexiDBDriver* driver) : QObject() , m_connection(connection) - , m_connectiondata(connectiondata ? connectiondata : new KexiDBConnectionData(this, connection->data(), false)) , m_driver(driver ? driver : new KexiDBDriver(this, connection->driver())) { setObjectName("KexiDBConnection"); @@ -46,11 +56,11 @@ bool KexiDBConnection::hadError() const { - return m_connection->error(); + return m_connection->result().isError(); } -const QString KexiDBConnection::lastError() const +QString KexiDBConnection::lastError() const { - return m_connection->errorMsg(); + return m_connection->result().message(); } QObject* KexiDBConnection::data() @@ -77,14 +87,14 @@ bool KexiDBConnection::isReadOnly() const { - return m_connection->isReadOnly(); + return m_connection->options()->isReadOnly(); } bool KexiDBConnection::databaseExists(const QString& dbname) { return m_connection->databaseExists(dbname); } -const QString KexiDBConnection::currentDatabase() const +QString KexiDBConnection::currentDatabase() const { return m_connection->currentDatabase(); } @@ -119,7 +129,7 @@ bool ok = true; QStringList queries = m_connection->objectNames(KDb::QueryObjectType, &ok); if (! ok) { - qDebug() << QString("Failed to determinate querynames."); + KexiScriptingWarning() << "Failed to determinate querynames."; return QStringList(); } return queries; @@ -130,15 +140,15 @@ // The KDbConnection::executeQuery() method does not check if we pass a valid SELECT-statement // or e.g. a DROP TABLE operation. So, let's check for such dangerous operations right now. KDbParser parser(m_connection); - if (! parser.parse(sqlquery)) { - qDebug() << QString("Failed to parse query: %1 %2").arg(parser.error().type()).arg(parser.error().error()); + if (! parser.parse(KDbEscapedString(sqlquery))) { + KexiScriptingWarning() << "Failed to parse query: "<< parser.error().type() << parser.error().message(); return 0; } - if (parser.query() == 0 || parser.operation() != KDbParser::OP_Select) { - qDebug() << QString("Invalid query operation \"%1\"").arg(parser.operationString()); + if (parser.query() == 0 || parser.statementType() != KDbParser::Select) { + KexiScriptingWarning() << "Invalid query operation " << parser.statementTypeString(); return 0; } - KDbCursor* cursor = m_connection->executeQuery(sqlquery); + KDbCursor* cursor = m_connection->executeQuery(KDbEscapedString(sqlquery)); return cursor ? new KexiDBCursor(this, cursor, true) : 0; } @@ -152,10 +162,10 @@ { KexiDBFieldList* fieldlist = dynamic_cast< KexiDBFieldList* >(obj); if (fieldlist) - return m_connection->insertRecord(*fieldlist->fieldlist(), values); + return m_connection->insertRecord(fieldlist->fieldlist(), values); KexiDBTableSchema* tableschema = dynamic_cast< KexiDBTableSchema* >(obj); if (tableschema) - return m_connection->insertRecord(*tableschema->tableschema(), values); + return m_connection->insertRecord(tableschema->tableschema(), values); return false; } @@ -170,19 +180,19 @@ bool KexiDBConnection::createTable(KexiDBTableSchema* tableschema) { - return m_connection->createTable(tableschema->tableschema(), false); + return m_connection->createTable(tableschema->tableschema()); } bool KexiDBConnection::dropTable(const QString& tablename) { return true == m_connection->dropTable(tablename); } bool KexiDBConnection::alterTable(KexiDBTableSchema* fromschema, KexiDBTableSchema* toschema) { - return true == m_connection->alterTable(*fromschema->tableschema(), *toschema->tableschema()); + return true == m_connection->alterTable(fromschema->tableschema(), toschema->tableschema()); } bool KexiDBConnection::alterTableName(KexiDBTableSchema* tableschema, const QString& newtablename) { - return m_connection->alterTableName(*tableschema->tableschema(), newtablename); + return m_connection->alterTableName(tableschema->tableschema(), newtablename); } QObject* KexiDBConnection::tableSchema(const QString& tablename) @@ -193,9 +203,7 @@ bool KexiDBConnection::isEmptyTable(KexiDBTableSchema* tableschema) const { - bool success; - bool notempty = m_connection->isEmpty(*tableschema->tableschema(), success); - return (!(success && notempty)); + return m_connection->isEmpty(tableschema->tableschema()) == true; } QObject* KexiDBConnection::querySchema(const QString& queryname) diff --git a/src/plugins/scripting/kexidb/kexidbconnectiondata.h b/src/plugins/scripting/kexidb/kexidbconnectiondata.h --- a/src/plugins/scripting/kexidb/kexidbconnectiondata.h +++ b/src/plugins/scripting/kexidb/kexidbconnectiondata.h @@ -37,7 +37,8 @@ { Q_OBJECT public: - KexiDBConnectionData(QObject* parent, KDbConnectionData* data, bool owner); + KexiDBConnectionData(); + KexiDBConnectionData(QObject* parent, KDbConnectionData* data); virtual ~KexiDBConnectionData(); KDbConnectionData* data() { return m_data; @@ -95,26 +96,12 @@ const QString userName() const; /** Set the username. */ void setUserName(const QString& username); - - // For filebased drivers - - /** Return the filename. */ - const QString fileName() const; - /** Set the filename. */ - void setFileName(const QString& filename); - - /** Return the database path. */ - const QString dbPath() const; - /** Return the database filename. */ - const QString databaseName() const; - + /** Return a user-friendly string representation. */ const QString toUserVisibleString() const; private: - KDbConnectionData* m_data; - QString m_dbname; - bool m_owner; + KDbConnectionData *m_data = nullptr; }; } diff --git a/src/plugins/scripting/kexidb/kexidbconnectiondata.cpp b/src/plugins/scripting/kexidb/kexidbconnectiondata.cpp --- a/src/plugins/scripting/kexidb/kexidbconnectiondata.cpp +++ b/src/plugins/scripting/kexidb/kexidbconnectiondata.cpp @@ -22,121 +22,104 @@ using namespace Scripting; -KexiDBConnectionData::KexiDBConnectionData(QObject* parent, KDbConnectionData* data, bool owner) +KexiDBConnectionData::KexiDBConnectionData() : QObject() { + m_data = new KDbConnectionData(); +} + +KexiDBConnectionData::KexiDBConnectionData(QObject* parent, KDbConnectionData* data) : QObject(parent) , m_data(data) - , m_owner(owner) { setObjectName("KexiDBConnectionData"); } KexiDBConnectionData::~KexiDBConnectionData() { - if (m_owner) - delete m_data; } const QString KexiDBConnectionData::caption() const { - return m_data->caption; + return m_data->caption(); } void KexiDBConnectionData::setCaption(const QString& name) { - m_data->caption = name; + m_data->setCaption(name); } const QString KexiDBConnectionData::description() const { - return m_data->description; + return m_data->description(); } void KexiDBConnectionData::setDescription(const QString& desc) { - m_data->description = desc; + m_data->setDescription(desc); } const QString KexiDBConnectionData::driverName() const { - return m_data->driverName; + return m_data->driverId(); } void KexiDBConnectionData::setDriverName(const QString& driver) { - m_data->driverName = driver; + m_data->setDriverId(driver); } bool KexiDBConnectionData::localSocketFileUsed() const { - return m_data->useLocalSocketFile; + return m_data->useLocalSocketFile(); } void KexiDBConnectionData::setLocalSocketFileUsed(bool used) { - m_data->useLocalSocketFile = used; + m_data->setUseLocalSocketFile(used); } const QString KexiDBConnectionData::localSocketFileName() const { - return m_data->localSocketFileName; + return m_data->localSocketFileName(); } void KexiDBConnectionData::setLocalSocketFileName(const QString& socketfilename) { - m_data->localSocketFileName = socketfilename; + m_data->setLocalSocketFileName(socketfilename); } -const QString KexiDBConnectionData::databaseName() const -{ - return m_dbname; -} void KexiDBConnectionData::setDatabaseName(const QString& dbname) { - m_dbname = dbname; + m_data->setDatabaseName(dbname); } const QString KexiDBConnectionData::hostName() const { - return m_data->hostName; + return m_data->hostName(); } void KexiDBConnectionData::setHostName(const QString& hostname) { - m_data->hostName = hostname; + m_data->setHostName(hostname); } int KexiDBConnectionData::port() const { - return m_data->port; + return m_data->port(); } void KexiDBConnectionData::setPort(int p) { - m_data->port = p; + m_data->setPort(p); } const QString KexiDBConnectionData::password() const { - return m_data->password; + return m_data->password(); } void KexiDBConnectionData::setPassword(const QString& passwd) { - m_data->password = passwd; + m_data->setPassword(passwd); } const QString KexiDBConnectionData::userName() const { - return m_data->userName; + return m_data->userName(); } void KexiDBConnectionData::setUserName(const QString& username) { - m_data->userName = username; -} - -const QString KexiDBConnectionData::fileName() const -{ - return m_data->fileName(); -} -void KexiDBConnectionData::setFileName(const QString& filename) -{ - m_data->setFileName(filename); -} - -const QString KexiDBConnectionData::dbPath() const -{ - return m_data->dbPath(); + m_data->setUserName(username); } const QString KexiDBConnectionData::databaseName() const { diff --git a/src/plugins/scripting/kexidb/kexidbcursor.h b/src/plugins/scripting/kexidb/kexidbcursor.h --- a/src/plugins/scripting/kexidb/kexidbcursor.h +++ b/src/plugins/scripting/kexidb/kexidbcursor.h @@ -24,6 +24,7 @@ #include #include +#include namespace Scripting { @@ -134,7 +135,7 @@ KDbRecordEditBuffer* buffer; Record(KDbCursor* cursor) : buffer(new KDbRecordEditBuffer(true)) { - cursor->storeCurrentRow(rowdata); + cursor->storeCurrentRecord(&rowdata); } ~Record() { delete buffer; diff --git a/src/plugins/scripting/kexidb/kexidbcursor.cpp b/src/plugins/scripting/kexidb/kexidbcursor.cpp --- a/src/plugins/scripting/kexidb/kexidbcursor.cpp +++ b/src/plugins/scripting/kexidb/kexidbcursor.cpp @@ -40,7 +40,6 @@ clearBuffers(); if (m_owner) { m_cursor->close(); - delete m_cursor; } } @@ -127,7 +126,7 @@ const qint64 position = m_cursor->at(); if (! m_modifiedrecords.contains(position)) m_modifiedrecords.insert(position, new Record(m_cursor)); - m_modifiedrecords[position]->buffer->insert(*column, value); + m_modifiedrecords[position]->buffer->insert(column, value); return true; } @@ -146,7 +145,7 @@ QMap::ConstIterator it(m_modifiedrecords.constBegin()), end(m_modifiedrecords.constEnd()); for (; it != end; ++it) { - bool b = m_cursor->updateRow(it.value()->rowdata, * it.value()->buffer, m_cursor->isBuffered()); + bool b = m_cursor->updateRecord(&it.value()->rowdata, it.value()->buffer, m_cursor->isBuffered()); if (ok) { ok = b; //break; diff --git a/src/plugins/scripting/kexidb/kexidbdriver.h b/src/plugins/scripting/kexidb/kexidbdriver.h --- a/src/plugins/scripting/kexidb/kexidbdriver.h +++ b/src/plugins/scripting/kexidb/kexidbdriver.h @@ -71,11 +71,11 @@ QString escapeString(const QString& s); /** Returns true if this driver is file-based. */ bool isFileDriver(); - /** Return a name of MIME type of files handled by this driver if it is a - file-based database's driver otherwise returns null string. */ - QString fileDBDriverMimeType(); + /** Return a list of MIME types of files handled by this driver if it is a + file-based database's driver otherwise returns an empty list */ + QStringList fileDBDriverMimeTypes(); /** Returns true if the passed string is a system object's name, eg. name - of build-in system table that cannot be used or created by a user. */ + of build-in system table that cannot be used or creataned by a user. */ bool isSystemObjectName(const QString& name); /** Returns true if the passed string is a system database's name, eg. name of build-in, system database that cannot be used or created by a user. */ diff --git a/src/plugins/scripting/kexidb/kexidbdriver.cpp b/src/plugins/scripting/kexidb/kexidbdriver.cpp --- a/src/plugins/scripting/kexidb/kexidbdriver.cpp +++ b/src/plugins/scripting/kexidb/kexidbdriver.cpp @@ -22,6 +22,7 @@ #include "kexidbconnectiondata.h" #include +#include using namespace Scripting; @@ -38,20 +39,20 @@ bool KexiDBDriver::isValid() { - return m_driver->isValid(); + return !m_driver->result().isError(); } QString KexiDBDriver::escapeString(const QString& s) { - return m_driver->escapeString(s); + return m_driver->escapeString(KDbEscapedString(s).toString()).toString(); } bool KexiDBDriver::isFileDriver() { - return m_driver->isFileDriver(); + return m_driver->metaData()->isFileBased(); } -QString KexiDBDriver::fileDBDriverMimeType() +QStringList KexiDBDriver::fileDBDriverMimeTypes() { - return m_driver->fileDBDriverMimeType(); + return m_driver->metaData()->mimeTypes(); } bool KexiDBDriver::isSystemObjectName(const QString& name) { @@ -67,7 +68,7 @@ } QString KexiDBDriver::valueToSql(const QString& fieldtype, const QVariant& value) { - return m_driver->valueToSql(fieldtype, value); + return m_driver->valueToSql(KDbField::typeForString(fieldtype), value).toString(); } QObject* KexiDBDriver::createConnection(QObject* data) diff --git a/src/plugins/scripting/kexidb/kexidbfieldlist.h b/src/plugins/scripting/kexidb/kexidbfieldlist.h --- a/src/plugins/scripting/kexidb/kexidbfieldlist.h +++ b/src/plugins/scripting/kexidb/kexidbfieldlist.h @@ -76,7 +76,7 @@ /** Returns true if the passed \a KexiDBField \p field object is in the field list. */ bool hasField(QObject* field); /** Return a list of field names. */ - const QStringList names() const; + QStringList names() const; /** Adds the \a KexiDBField object passed as an argument to the field list. */ bool addField(QObject* field); diff --git a/src/plugins/scripting/kexidb/kexidbfieldlist.cpp b/src/plugins/scripting/kexidb/kexidbfieldlist.cpp --- a/src/plugins/scripting/kexidb/kexidbfieldlist.cpp +++ b/src/plugins/scripting/kexidb/kexidbfieldlist.cpp @@ -56,10 +56,10 @@ bool KexiDBFieldList::hasField(QObject* field) { KexiDBField* f = dynamic_cast(field); - return f ? m_fieldlist->hasField(f->field()) : false; + return f ? m_fieldlist->hasField(*f->field()) : false; } -const QStringList KexiDBFieldList::names() const +QStringList KexiDBFieldList::names() const { return m_fieldlist->names(); } diff --git a/src/plugins/scripting/kexidb/kexidbmodule.h b/src/plugins/scripting/kexidb/kexidbmodule.h --- a/src/plugins/scripting/kexidb/kexidbmodule.h +++ b/src/plugins/scripting/kexidb/kexidbmodule.h @@ -24,6 +24,7 @@ #include #include +#include namespace Scripting { @@ -43,49 +44,48 @@ { Q_OBJECT public: - explicit KexiDBModule(QObject* parent = 0); + Q_INVOKABLE explicit KexiDBModule(QObject* parent = 0); virtual ~KexiDBModule(); -public Q_SLOTS: - /** Returns the version number the KexiDB module defines. */ - int version(); + Q_INVOKABLE int version(); /** Returns a list with available drivernames. */ - const QStringList driverNames(); + Q_INVOKABLE QStringList driverNames(); /** Return the to the defined \p drivername matching \a KexiDBDriver object. */ - QObject* driver(const QString& drivername); + Q_INVOKABLE QObject* driver(const QString& drivername); /** Return the to the defined mimetype-string matching drivername. */ - const QString lookupByMime(const QString& mimetype); + Q_INVOKABLE QString lookupByMime(const QString& mimetype); /** Return the matching mimetype for the defined file. */ - const QString mimeForFile(const QString& filename); + Q_INVOKABLE QString mimeForFile(const QString& filename); /** Return a new \a KexiDBConnectionData object. */ - QObject* createConnectionData(); + Q_INVOKABLE QObject* createConnectionData(); /** Create and return a \a KexiDBConnectionData object. Fill the content of the KexiDBConnectionData object with the defined file as. The file could be e.g. a *.kexi file or a *.kexis file. */ - QObject* createConnectionDataByFile(const QString& filename); + Q_INVOKABLE QObject* createConnectionDataByFile(const QString& filename); /** Return a new \a KexiDBField object. */ - QObject* field(); + Q_INVOKABLE QObject* field(); /** Return a new \a KexiDBTableSchema object. */ - QObject* tableSchema(const QString& tablename); + Q_INVOKABLE QObject* tableSchema(const QString& tablename); /** Return a new \a KexiDBQuerySchema object. */ - QObject* querySchema(); + Q_INVOKABLE QObject* querySchema(); private Q_SLOTS: //! Wraps a KDbConnection into a KexiDBConnection - QObject* connectionWrapper(QObject* connection); + QObject* connectionWrapper(KDbConnection* connection); private: KDbDriverManager m_drivermanager; + }; } diff --git a/src/plugins/scripting/kexidb/kexidbmodule.cpp b/src/plugins/scripting/kexidb/kexidbmodule.cpp --- a/src/plugins/scripting/kexidb/kexidbmodule.cpp +++ b/src/plugins/scripting/kexidb/kexidbmodule.cpp @@ -23,17 +23,20 @@ #include "kexidbconnectiondata.h" #include "kexidbfield.h" #include "kexidbschema.h" +#include "KexiScriptingDebug.h" #include #include #include #include #include #include +#include #include #include +#include // The as version() published versionnumber of this kross-module. #define KROSS_KEXIDB_VERSION 1 @@ -44,7 +47,7 @@ * Exported an loadable function as entry point to use * the \a KexiDBModule. */ - KDE_EXPORT QObject* krossmodule() { + /*KEXI_EXPORT*/ QObject* krossmodule() { return new Scripting::KexiDBModule(); } } @@ -66,52 +69,56 @@ return KROSS_KEXIDB_VERSION; } -const QStringList KexiDBModule::driverNames() +QStringList KexiDBModule::driverNames() { - return m_drivermanager.driverNames(); + return m_drivermanager.driverIds(); } QObject* KexiDBModule::driver(const QString& drivername) { QPointer< KDbDriver > driver = m_drivermanager.driver(drivername); // caching is done by the DriverManager if (! driver) { - qWarning() << "No such driver '%1'" << drivername; + KexiScriptingWarning() << "No such driver:" << drivername; return 0; } - if (driver->error()) { - qWarning() << "Error for drivername" << drivername << driver->errorMsg(); + if (driver->result().isError()) { + KexiScriptingWarning() << "Error for drivername" << drivername << driver->result().message(); return 0; } return new KexiDBDriver(this, driver); } -const QString KexiDBModule::lookupByMime(const QString& mimetype) +QString KexiDBModule::lookupByMime(const QString& mimetype) { - return m_drivermanager.lookupByMime(mimetype); + QStringList ids = m_drivermanager.driverIdsForMimeType(mimetype); + if (ids.size() > 0) { + return ids.at(0); + } + return QString(); } -const QString KexiDBModule::mimeForFile(const QString& filename) +QString KexiDBModule::mimeForFile(const QString& filename) { QMimeDatabase db; QString mimename = db.mimeTypeForFile(filename, QMimeDatabase::MatchContent).name(); if (mimename.isEmpty() || mimename == "application/octet-stream" || mimename == "text/plain") { - mimename = db.mimeTypeForUrl(filename).name(); + mimename = db.mimeTypeForUrl(QUrl::fromLocalFile(filename)).name(); } return mimename; } QObject* KexiDBModule::createConnectionData() { - return new KexiDBConnectionData(this, new KDbConnectionData(), true); + return new KexiDBConnectionData(); } QObject* KexiDBModule::createConnectionDataByFile(const QString& filename) { //! @todo reuse the original code! QMimeDatabase db; QString mimename = db.mimeTypeForFile(filename, QMimeDatabase::MatchContent).name(); if (mimename.isEmpty() || mimename == "application/octet-stream" || mimename == "text/plain") { - mimename = db.mimeTypeForUrl(filename).name(); + mimename = db.mimeTypeForUrl(QUrl::fromLocalFile(filename)).name(); } if (mimename == "application/x-kexiproject-shortcut" || mimename == "application/x-kexi-connectiondata") { KConfig _config(filename, KConfig::NoGlobals); @@ -123,8 +130,9 @@ break; } } + if (groupkey.isNull()) { - qDebug() << "No groupkey, filename=" << filename; + KexiScriptingWarning() << "No groupkey, filename=" << filename; return 0; } @@ -156,22 +164,22 @@ data->setSavePassword(!data->password().isEmpty()); data->setUserName(config.readEntry("user")); - KexiDBConnectionData* c = new KexiDBConnectionData(this, data, true); + KexiDBConnectionData* c = new KexiDBConnectionData(this, data); c->setDatabaseName(dbname); return c; } const QStringList driverIds = m_drivermanager.driverIdsForMimeType(mimename); if (driverIds.isEmpty()) { - qDebug() << "No driver, filename=" << filename << "mimename=" << mimename; + KexiScriptingWarning() << "No driver, filename=" << filename << "mimename=" << mimename; return 0; } KDbConnectionData* data = new KDbConnectionData(); data->setDatabaseName(filename); //! @todo there can be more than one driver data->setDriverId(driverIds.first()); - return new KexiDBConnectionData(this, data, true); + return new KexiDBConnectionData(this, data); } QObject* KexiDBModule::field() @@ -189,9 +197,8 @@ return new KexiDBQuerySchema(this, new KDbQuerySchema(), true); } -QObject* KexiDBModule::connectionWrapper(QObject* connection) +QObject* KexiDBModule::connectionWrapper(KDbConnection* connection) { - KDbConnection* c = dynamic_cast< KDbConnection* >(connection); - return c ? new KexiDBConnection(c) : 0; + return new KexiDBConnection(connection); } diff --git a/src/plugins/scripting/kexidb/kexidbparser.h b/src/plugins/scripting/kexidb/kexidbparser.h --- a/src/plugins/scripting/kexidb/kexidbparser.h +++ b/src/plugins/scripting/kexidb/kexidbparser.h @@ -58,30 +58,30 @@ KexiDBParser(KexiDBConnection* connection, KDbParser* parser, bool owner); virtual ~KexiDBParser(); -public Q_SLOTS: +public: /** Clears previous results and runs the parser on the SQL statement passed as an argument. */ - bool parse(const QString& sql); + Q_INVOKABLE bool parse(const QString& sql); /** Clears parsing results. */ - void clear(); + Q_INVOKABLE void clear(); /** Returns the resulting operation. */ - const QString operation(); + Q_INVOKABLE QString operation() const; /** Returns the \a KexiDBTableSchema object on a CREATE TABLE operation. */ - QObject* table(); + Q_INVOKABLE QObject* table(); /** Returns the \a KexiDBQuerySchema object on a SELECT operation. */ - QObject* query(); + Q_INVOKABLE QObject* query(); /** Returns the \a KexiDBConnection object pointing to the used database connection. */ - QObject* connection(); + Q_INVOKABLE QObject* connection(); /** Returns the SQL query statement. */ - const QString statement(); + Q_INVOKABLE QString statement() const; /** Returns the type string of the last error. */ - const QString errorType(); + Q_INVOKABLE QString errorType() const; /** Returns the message of the last error. */ - const QString errorMsg(); + Q_INVOKABLE QString errorMsg() const; /** Returns the position where the last error occurred. */ - int errorAt(); + Q_INVOKABLE int errorAt() const; private: QPointer m_connection; diff --git a/src/plugins/scripting/kexidb/kexidbparser.cpp b/src/plugins/scripting/kexidb/kexidbparser.cpp --- a/src/plugins/scripting/kexidb/kexidbparser.cpp +++ b/src/plugins/scripting/kexidb/kexidbparser.cpp @@ -41,15 +41,15 @@ bool KexiDBParser::parse(const QString& sql) { - return m_parser->parse(sql); + return m_parser->parse(KDbEscapedString(sql)); } void KexiDBParser::clear() { - m_parser->clear(); + m_parser->reset(); } -const QString KexiDBParser::operation() +QString KexiDBParser::operation() const { - return m_parser->operationString(); + return m_parser->statementTypeString(); } QObject* KexiDBParser::table() @@ -68,21 +68,21 @@ { return m_connection; } -const QString KexiDBParser::statement() +QString KexiDBParser::statement() const { - return m_parser->statement(); + return m_parser->statement().toString(); } -const QString KexiDBParser::errorType() +QString KexiDBParser::errorType() const { return m_parser->error().type(); } -const QString KexiDBParser::errorMsg() +QString KexiDBParser::errorMsg() const { - return m_parser->error().error(); + return m_parser->error().message(); } -int KexiDBParser::errorAt() +int KexiDBParser::errorAt() const { - return m_parser->error().at(); + return m_parser->error().position(); } diff --git a/src/plugins/scripting/kexidb/kexidbschema.h b/src/plugins/scripting/kexidb/kexidbschema.h --- a/src/plugins/scripting/kexidb/kexidbschema.h +++ b/src/plugins/scripting/kexidb/kexidbschema.h @@ -61,25 +61,25 @@ KexiDBSchema(QObject* parent, const QString& name, KDbObject* schema, KDbFieldList* fieldlist, bool owner); virtual ~KexiDBSchema(); -public Q_SLOTS: +public: /** Returns the name of the schema. */ - const QString name() const; + Q_INVOKABLE QString name() const; /** Set the name of the schema. */ - void setName(const QString& name); + Q_INVOKABLE void setName(const QString& name); /** Returns the caption of the schema. */ - const QString caption() const; + Q_INVOKABLE QString caption() const; /** Set the caption of the schema. */ - void setCaption(const QString& caption); + Q_INVOKABLE void setCaption(const QString& caption); /** Returns a description of the schema. */ - const QString description() const; + Q_INVOKABLE QString description() const; /** Set a description of the schema. */ - void setDescription(const QString& description); + Q_INVOKABLE void setDescription(const QString& description); /** Returns the \a KexiDBFieldList object this schema has. */ - QObject* fieldlist(); + Q_INVOKABLE QObject* fieldlist(); protected: KDbObject* m_schema; @@ -117,7 +117,7 @@ private: /** Returns the SQL-statement of this query schema. */ - const QString statement() const; + QString statement() const; /** Set the SQL-statement of this query schema. */ void setStatement(const QString& statement); /** Set the where-expression. */ diff --git a/src/plugins/scripting/kexidb/kexidbschema.cpp b/src/plugins/scripting/kexidb/kexidbschema.cpp --- a/src/plugins/scripting/kexidb/kexidbschema.cpp +++ b/src/plugins/scripting/kexidb/kexidbschema.cpp @@ -23,6 +23,8 @@ #include #include +#include + using namespace Scripting; /*************************************************************************** @@ -42,23 +44,23 @@ { } -const QString KexiDBSchema::name() const +QString KexiDBSchema::name() const { return m_schema->name(); } void KexiDBSchema::setName(const QString& name) { m_schema->setName(name); } -const QString KexiDBSchema::caption() const +QString KexiDBSchema::caption() const { return m_schema->caption(); } void KexiDBSchema::setCaption(const QString& caption) { m_schema->setCaption(caption); } -const QString KexiDBSchema::description() const +QString KexiDBSchema::description() const { return m_schema->description(); } @@ -116,21 +118,18 @@ return static_cast< KDbQuerySchema* >(m_schema); } -const QString KexiDBQuerySchema::statement() const +QString KexiDBQuerySchema::statement() const { - return static_cast< KDbQuerySchema* >(m_schema)->statement(); + return static_cast< KDbQuerySchema* >(m_schema)->statement().toString(); } void KexiDBQuerySchema::setStatement(const QString& statement) { - static_cast< KDbQuerySchema* >(m_schema)->setStatement(statement); + static_cast< KDbQuerySchema* >(m_schema)->setStatement(KDbEscapedString(statement)); } bool KexiDBQuerySchema::setWhereExpression(const QString& whereexpression) { - KDbExpression* oldexpr = static_cast< KDbQuerySchema* >(m_schema)->whereExpression(); - Q_UNUSED(oldexpr); - ///@todo use KDbParser for such kind of parser-functionality. QString s = whereexpression; QRegularExpression re("[\"',]{1,1}"); @@ -142,13 +141,15 @@ s = s.mid(pos + 1).trimmed(); QString value; + QRegularExpressionMatch match = re.match(s); int sp = s.indexOf(re); - if (sp >= 0) { - if (re.cap(0) == ",") { + + if (match.hasMatch()) { + if (match.captured(1) == ",") { value = s.left(sp).trimmed(); s = s.mid(sp + 1).trimmed(); } else { - int ep = s.indexOf(re.cap(0), sp + 1); + int ep = s.indexOf(match.captured(1), sp + 1); value = s.mid(sp + 1, ep - 1); s = s.mid(ep + 1); } @@ -171,8 +172,7 @@ QString errorMessage; QString errorDescription; - if (!static_cast(m_schema)->addToWhereExpression( - field, v, &errorMessage, &errorDescription)) + if (!static_cast(m_schema)->addToWhereExpression(field, v, KDbToken('='), &errorMessage, &errorDescription)) { qWarning() << "addToWhereExpression() failed, message=" << errorMessage << "description=" << errorDescription; diff --git a/src/plugins/scripting/kexiscripting/CMakeLists.txt b/src/plugins/scripting/kexiscripting/CMakeLists.txt --- a/src/plugins/scripting/kexiscripting/CMakeLists.txt +++ b/src/plugins/scripting/kexiscripting/CMakeLists.txt @@ -1,8 +1,16 @@ +remove_definitions( -DKDE_DEFAULT_DEBUG_AREA=44021 ) +add_definitions(-DKDE_DEFAULT_DEBUG_AREA=44025) + +option(KEXI_SCRIPTING_DEBUG "Enable debugging for the scripting plugin" OFF) + +if (KEXI_SCRIPTING_DEBUG) + add_definitions(-DKEXI_SCRIPTING_DEBUG) +endif() + include_directories( ${CMAKE_SOURCE_DIR}/src/core ${CMAKE_SOURCE_DIR}/src/widget - - ${KOKROSS_INCLUDES} + ${CMAKE_SOURCE_DIR}/src/plugins/scripting/kexiscripting ) # the main plugin @@ -12,17 +20,31 @@ kexiscriptdesignview.cpp ) +set(krossmodulekexidb_PART_SRCS + ../kexidb/kexidbmodule.cpp + ../kexidb/kexidbfield.cpp + ../kexidb/kexidbfieldlist.cpp + ../kexidb/kexidbschema.cpp + ../kexidb/kexidbparser.cpp + ../kexidb/kexidbcursor.cpp + ../kexidb/kexidbconnectiondata.cpp + ../kexidb/kexidbconnection.cpp + ../kexidb/kexidbdriver.cpp ) + + qt5_wrap_cpp(kexi_scriptplugin_SRCS kexiscriptadaptor.h) -add_library(kexi_scriptplugin MODULE ${kexi_scriptplugin_SRCS}) +add_library(kexi_scriptplugin MODULE ${kexi_scriptplugin_SRCS} ${krossmodulekexidb_PART_SRCS}) kcoreaddons_desktop_to_json(kexi_scriptplugin kexi_scriptplugin.desktop) target_link_libraries(kexi_scriptplugin PRIVATE kexiextendedwidgets - kokross kexicore - + Qt5::Qml KF5::KIOWidgets + KDb + KF5::ConfigCore + KF5::ConfigGui ) install(TARGETS kexi_scriptplugin DESTINATION ${KEXI_PLUGIN_INSTALL_DIR}) diff --git a/src/plugins/scripting/kexiscripting/KexiScriptingDebug.h b/src/plugins/scripting/kexiscripting/KexiScriptingDebug.h new file mode 100644 --- /dev/null +++ b/src/plugins/scripting/kexiscripting/KexiScriptingDebug.h @@ -0,0 +1,33 @@ +/* This file is part of the KDE project + Copyright (C) 2017 Adam Pigg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef KEXISCRIPTDEBUG_H +#define KEXISCRIPTDEBUG_H +#include + + +#ifdef KEXI_SCRIPTING_DEBUG +#define KexiScriptingDebug qDebug +#define KexiScriptingWarning qWarning +#else +#define KexiScriptingDebug while (0) qDebug +#define KexiScriptingWarning while (0) qWarning +#endif + +#endif diff --git a/src/plugins/scripting/kexiscripting/kexiscripthandler.desktop b/src/plugins/scripting/kexiscripting/kexi_scriptplugin.desktop rename from src/plugins/scripting/kexiscripting/kexiscripthandler.desktop rename to src/plugins/scripting/kexiscripting/kexi_scriptplugin.desktop --- a/src/plugins/scripting/kexiscripting/kexiscripthandler.desktop +++ b/src/plugins/scripting/kexiscripting/kexi_scriptplugin.desktop @@ -1,7 +1,4 @@ [Desktop Entry] -Type=Service -X-KDE-ServiceTypes=Kexi/Handler - GenericName=Scripts GenericName[ca]=Scripts GenericName[ca@valencia]=Scripts @@ -18,6 +15,7 @@ GenericName[nb]=Skripter GenericName[nl]=Scripts GenericName[pl]=Skrypty + GenericName[pt]=Programas GenericName[pt_BR]=Scripts GenericName[se]=Skriptat @@ -49,15 +47,28 @@ Name[uk]=Скрипт Name[x-test]=xxScriptxx Name[zh_CN]=脚本 -X-KDE-Library=kexihandler_script -X-KDE-ParentApp=kexi -X-Kexi-PartVersion=2 + +Type=Service +Icon=script +Encoding=UTF-8 + +X-KDE-Library=kexi_scriptplugin +X-KDE-ServiceTypes=Kexi/Editor +X-KDE-PluginInfo-Author=Kexi Team +X-KDE-PluginInfo-Email=kexi@kde.org +X-KDE-PluginInfo-Name=org.kexi-project.script +X-KDE-PluginInfo-Version=3.1 +X-KDE-PluginInfo-Website=http://kexi-project.org +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true + +X-Kexi-GroupName=Scripts X-Kexi-TypeName=script -X-Kexi-Class=org.kexi-project.script -X-Kexi-ItemIcon=script -X-Kexi-SupportsDataView=false -X-Kexi-SupportsDesignView=true -X-Kexi-SupportsDataViewInUserMode=false -X-Kexi-SupportsExecution=true +X-Kexi-ServiceTypesInUserMode=Kexi/Editor +X-Kexi-VisibleInProjectNavigator=true X-Kexi-SupportsDataExport=false X-Kexi-SupportsPrinting=false +X-Kexi-SupportsExecution=true + diff --git a/src/plugins/scripting/kexiscripting/kexiscriptadaptor.h b/src/plugins/scripting/kexiscripting/kexiscriptadaptor.h --- a/src/plugins/scripting/kexiscripting/kexiscriptadaptor.h +++ b/src/plugins/scripting/kexiscripting/kexiscriptadaptor.h @@ -23,8 +23,8 @@ #include #include #include - -#include +#include +#include #include @@ -35,31 +35,33 @@ #include #include +#include "../kexidb/kexidbmodule.h" +#include "KexiScriptingDebug.h" + /** * Adaptor class that provides Kexi specific functionality to * the scripting world. */ class KexiScriptAdaptor : public QObject { Q_OBJECT public: - explicit KexiScriptAdaptor() : m_kexidbmodule(0) { - setObjectName("Kexi"); + Q_INVOKABLE KexiScriptAdaptor() { + KexiScriptingDebug() << "Created Script Adaptor"; } virtual ~KexiScriptAdaptor() {} -public Q_SLOTS: /** * Returns the current KexiWindow widget. */ - QWidget* windowWidget() const { + Q_INVOKABLE QWidget* windowWidget() const { return currentWindow(); } /** * Returns the current KexiView widget. */ - QWidget* viewWidget() const { + Q_INVOKABLE QWidget* viewWidget() const { return currentView(); } @@ -75,7 +77,7 @@ * print "name=%s text=%s" % (a.objectName,a.text) * \endcode */ - QVariantList actions() { + Q_INVOKABLE QVariantList actions() { QVariantList list; foreach(QAction* action, mainWindow()->allActions()) { QVariant v; @@ -89,7 +91,7 @@ * Returns the QAction instance the Kexi main window provides that * has the objectName \p name or NULL if there is no such action. */ - QObject* action(const QString& name) { + Q_INVOKABLE QObject* action(const QString& name) { foreach(QAction* action, mainWindow()->allActions()) { if (action->objectName() == name) return action; @@ -101,22 +103,20 @@ * Returns true if we are connected with a project else false * is returned. */ - bool isConnected() { + Q_INVOKABLE bool isConnected() { return project() ? project()->isConnected() : false; } /** * Returns the KexiDBConnection object that belongs to the opened * project or return NULL if there was no project opened (no * connection established). */ - QObject* getConnection() { - if (! m_kexidbmodule) - m_kexidbmodule = Kross::Manager::self().module("kexidb"); + Q_INVOKABLE QObject* getConnection() { KDbConnection *connection = project() ? project()->dbConnection() : 0; - if (m_kexidbmodule && connection) { + if (connection) { QObject* result = 0; - if (QMetaObject::invokeMethod(m_kexidbmodule, "connectionWrapper", Q_RETURN_ARG(QObject*, result), Q_ARG(QObject*, connection))) + if (QMetaObject::invokeMethod(&m_kexidbmodule, "connectionWrapper", Q_RETURN_ARG(QObject*, result), Q_ARG(KDbConnection*, connection))) return result; } return 0; @@ -133,11 +133,11 @@ * print Kexi.items("table") * \endcode */ - QStringList items(const QString& pluginId) { + Q_INVOKABLE QStringList items(const QString& plugin) { QStringList list; if (project()) { KexiPart::ItemList l; - project()->getSortedItemsForPluginId(&l, pluginId(pluginId).toUtf8()); + project()->getSortedItemsForPluginId(&l, pluginId(plugin).toUtf8()); l.sort(); foreach(KexiPart::Item* i, l) { list << i->name(); @@ -149,32 +149,32 @@ /** * Returns the caption for the item defined with \p pluginId and \p name . */ - QString itemCaption(const QString& pluginId, const QString& name) const { - KexiPart::Item *item = partItem(pluginId(pluginId), name); + Q_INVOKABLE QString itemCaptioq_gadgetn(const QString& plugin, const QString& name) const { + KexiPart::Item *item = partItem(pluginId(plugin), name); return item ? item->caption() : QString(); } /** * Set the caption for the item defined with \p pluginId and \p name . */ - void setItemCaption(const QString& pluginId, const QString& name, const QString& caption) { - if (KexiPart::Item *item = partItem(pluginId(pluginId), name)) + Q_INVOKABLE void setItemCaption(const QString& plugin, const QString& name, const QString& caption) { + if (KexiPart::Item *item = partItem(pluginId(plugin), name)) item->setCaption(caption); } /** * Returns the description for the item defined with \p className and \p name . */ - QString itemDescription(const QString& pluginId, const QString& name) const { - KexiPart::Item *item = partItem(pluginId(pluginId), name); + Q_INVOKABLE QString itemDescription(const QString& plugin, const QString& name) const { + KexiPart::Item *item = partItem(pluginId(plugin), name); return item ? item->description() : QString(); } /** * Set the description for the item defined with \p className and \p name . */ - void setItemDescription(const QString& pluginId, const QString& name, const QString& description) { - if (KexiPart::Item *item = partItem(pluginId(pluginId), name)) + Q_INVOKABLE void setItemDescription(const QString& plugin, const QString& name, const QString& description) { + if (KexiPart::Item *item = partItem(pluginId(plugin), name)) item->setDescription(description); } @@ -192,11 +192,11 @@ * Kexi.windowWidget().setDirty(True) * \endcode */ - bool openItem(const QString& pluginId, const QString& name, const QString& viewmode = QString(), + Q_INVOKABLE bool openItem(const QString& plugin, const QString& name, const QString& viewmode = QString(), QVariantMap args = QVariantMap()) { bool openingCancelled; - KexiPart::Item *item = partItem(pluginId(pluginId), name); + KexiPart::Item *item = partItem(pluginId(plugin), name); KexiWindow* window = item ? mainWindow()->openObject( item, @@ -220,26 +220,26 @@ * Kexi.closeItem("table","table1") * \endcode */ - bool closeItem(const QString& pluginId, const QString& name) { - if (KexiPart::Item *item = partItem(pluginId(pluginId), name)) + Q_INVOKABLE bool closeItem(const QString& plugin, const QString& name) { + if (KexiPart::Item *item = partItem(pluginId(plugin), name)) return mainWindow()->closeObject(item) == true; return false; } /** - * Print the item defined with \p pluginId and \p name . + * Print the item defined with \p plugin and \p name . */ - bool printItem(const QString& pluginId, const QString& name, bool preview = false) { - if (KexiPart::Item *item = partItem(pluginId(pluginId), name)) + Q_INVOKABLE bool printItem(const QString& plugin, const QString& name, bool preview = false) { + if (KexiPart::Item *item = partItem(pluginId(plugin), name)) return (preview ? mainWindow()->printPreviewForItem(item) : mainWindow()->printItem(item)) == true; return false; } /** * Executes custom action for the item defined with \p pluginId and \p name . */ - bool executeItem(const QString& pluginId, const QString& name, const QString& actionName) { - if (KexiPart::Item *item = partItem(pluginId(pluginId), name)) + Q_INVOKABLE bool executeItem(const QString& plugin, const QString& name, const QString& actionName) { + if (KexiPart::Item *item = partItem(pluginId(plugin), name)) return mainWindow()->executeCustomActionForObject(item, actionName) == true; return false; } @@ -249,14 +249,14 @@ * Returns the name of the current viewmode. This could be for example "data", * "design", "text" or just an empty string if there is no view at the moment. */ - QString viewMode() const { + Q_INVOKABLE QString viewMode() const { return currentView() ? viewModeToString(currentView()->viewMode()) : QString(); } /** * Returns a list of names of all available viewmodes the view supports. */ - QStringList viewModes() const { + Q_INVOKABLE QStringList viewModes() const { QStringList list; if (currentWindow()) { Kexi::ViewModes modes = currentWindow()->supportedViewModes(); @@ -274,12 +274,12 @@ * Returns true if there is a current view and those current view is dirty aka * has the dirty-flag set that indicates that something changed. */ - bool viewIsDirty() const { + Q_INVOKABLE bool viewIsDirty() const { return currentView() ? currentView()->isDirty() : false; } private: - QObject* m_kexidbmodule; + Scripting::KexiDBModule m_kexidbmodule; KexiMainWindowIface* mainWindow() const { return KexiMainWindowIface::global(); @@ -293,8 +293,8 @@ KexiView* currentView() const { return currentWindow() ? currentWindow()->selectedView() : 0; } - KexiPart::Item* partItem(const QString& pluginId, const QString& name) const { - return project() ? project()->itemForPluginId(pluginId(pluginId), name) : 0; + KexiPart::Item* partItem(const QString& plugin, const QString& name) const { + return project() ? project()->itemForPluginId(pluginId(plugin), name) : 0; } QString pluginId(const QString& pluginId) const { return pluginId.contains('.') ? pluginId : (QString::fromLatin1("org.kexi-project.")+pluginId); @@ -321,6 +321,7 @@ return Kexi::TextViewMode; return defaultViewMode; } + }; #endif diff --git a/src/plugins/scripting/kexiscripting/kexiscriptdesignview.h b/src/plugins/scripting/kexiscripting/kexiscriptdesignview.h --- a/src/plugins/scripting/kexiscripting/kexiscriptdesignview.h +++ b/src/plugins/scripting/kexiscripting/kexiscriptdesignview.h @@ -27,16 +27,12 @@ #include #include +#include // Forward declarations. class KexiScriptEditor; class KexiScriptDesignViewPrivate; -namespace Kross -{ -class Action; -} - /** * The KexiScriptDesignView class provides the KexiView to * manage script modules in the design-view. The design-view @@ -52,18 +48,18 @@ /** * Constructor. */ - KexiScriptDesignView(QWidget *parent, Kross::Action* scriptaction); + KexiScriptDesignView(QWidget *parent); /** * Destructor. */ virtual ~KexiScriptDesignView(); /** - * \return the \a Kross::Action this \a KexiScriptDesignView + * \return the program string this \a KexiScriptDesignView * is responsible for. */ - Kross::Action* scriptAction() const; +// QString scriptAction() const; /** * \return a property set for this view. @@ -95,7 +91,7 @@ /** * Deferred initialization. */ - void initialize(); + void initialize(const QString &program); void slotImport(); void slotExport(); @@ -118,7 +114,7 @@ private: KexiScriptDesignViewPrivate* d; - + /** * Load the data from XML source and fill the internally * used \a Kross::Action instance. diff --git a/src/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp b/src/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp --- a/src/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp +++ b/src/plugins/scripting/kexiscripting/kexiscriptdesignview.cpp @@ -22,38 +22,50 @@ #include "kexiscriptdesignview.h" #include "kexiscripteditor.h" +#include "kexiscriptadaptor.h" +#include "../kexidb/kexidbmodule.h" +#include "KexiScriptingDebug.h" +#include "kexiscriptpart.h" + #include #include - -#include -#include -#include +#include #include +#include #include #include #include #include #include #include -#include #include +#include +#include +#include +#include + +static QString _stdout; + +void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + if (QString(context.category) == "js") { + _stdout += msg + "\n"; + } else { + fprintf(stderr, "%s\n", msg.toLocal8Bit().constData()); + fflush(stderr); + } +} /// @internal class KexiScriptDesignViewPrivate { public: QSplitter* splitter; - - /** - * The \a Kross::Action instance which provides - * us access to the scripting framework Kross. - */ - Kross::Action* scriptaction; - + /// The \a KexiScriptEditor to edit the scripting code. KexiScriptEditor* editor; @@ -74,15 +86,17 @@ object such as a report or form */ QString scriptType; + + QString factoryConstructors; }; KexiScriptDesignView::KexiScriptDesignView( - QWidget *parent, Kross::Action* scriptaction) + QWidget *parent) : KexiView(parent) , d(new KexiScriptDesignViewPrivate()) { setObjectName("KexiScriptDesignView"); - d->scriptaction = scriptaction; + d->updatesProperties = false; d->splitter = new QSplitter(this); @@ -173,82 +187,65 @@ setMainMenuActions(mainMenuActions); - loadData(); - d->properties = new KPropertySet(this); connect(d->properties, SIGNAL(propertyChanged(KPropertySet&,KProperty&)), this, SLOT(slotPropertyChanged(KPropertySet&,KProperty&))); - // To schedule the initialize fixes a crasher in Kate. - QTimer::singleShot(50, this, SLOT(initialize())); + initialize(""); + loadData(); } KexiScriptDesignView::~KexiScriptDesignView() { delete d->properties; delete d; } -Kross::Action* KexiScriptDesignView::scriptAction() const +#if 0 +QString KexiScriptDesignView::scriptAction() const { return d->scriptaction; } +#endif -void KexiScriptDesignView::initialize() +void KexiScriptDesignView::initialize(const QString &program) { setDirty(false); updateProperties(); - d->editor->initialize(d->scriptaction); + d->editor->initialize(program); connect(d->editor, SIGNAL(textChanged()), this, SLOT(setDirty())); d->splitter->setSizes( QList() << height() * 2 / 3 << height() * 1 / 3 ); } void KexiScriptDesignView::slotImport() { - QStringList filters; - foreach(const QString &interpreter, Kross::Manager::self().interpreters()) { - filters << Kross::Manager::self().interpreterInfo(interpreter)->mimeTypes(); - } - //! @todo KEXI3 add equivalent of kfiledialog:/// - //! @todo KEXI3 multiple filters - // for now support jsut one filter - QString filterString; - if (filters.count() == 1) { - const QMimeDatabase db; - const QString filterString = db.mimeTypeForName(filters.first()).filterString(); - } //QUrl("kfiledialog:///kexiscriptingdesigner"), const QUrl result = QFileDialog::getOpenFileUrl(this, xi18nc("@title:window", "Import Script"), - QUrl(), filterString); + QUrl(), "Javascript (*.js)"); if (!result.isValid()) { return; } //! @todo support remote files? QFile f(result.toLocalFile()); if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { KMessageBox::sorry(this, - xi18nc("@info", "Could not read %1.", file)); + xi18nc("@info", "Could not read %1.", result.toLocalFile())); return; } d->editor->setText(f.readAll()); f.close(); } void KexiScriptDesignView::slotExport() { - QStringList filters; - foreach(const QString &interpreter, Kross::Manager::self().interpreters()) { - filters << Kross::Manager::self().interpreterInfo(interpreter)->mimeTypes(); - } - const QString file = KFileDialog::getSaveFileName( - QUrl("kfiledialog:///kexiscriptingdesigner"), - filters.join(" "), this, xi18nc("@title:window", "Export Script")); - if (file.isEmpty()) + const QUrl result = QFileDialog::getSaveFileUrl(this, xi18nc("@title:window", "Export Script"), + QUrl("kfiledialog:///kexiscriptingdesigner"), "Javascript (*.js)" ); + if (!result.isValid()) return; - QFile f(file); + QFile f(result.toLocalFile()); if (! f.open(QIODevice::WriteOnly | QIODevice::Text)) { KMessageBox::sorry(this, - xi18nc("@info", "Could not write %1.", file)); + xi18nc("@info", "Could not write %1.", result.toLocalFile())); return; } f.write(d->editor->text().toUtf8()); @@ -261,29 +258,6 @@ return; d->updatesProperties = true; - Kross::Manager* manager = &Kross::Manager::self(); - - QString interpretername = d->scriptaction->interpreter(); - Kross::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->interpreterInfo(interpretername); - - if (!info) { - // if interpreter isn't defined or invalid, try to fallback. - foreach (const QString& interpretername, - QStringList() << "python" << "ruby" << "qtscript" << "javascript" << "java") - { - info = manager->interpreterInfo(interpretername); - if (info) { - d->scriptaction->setInterpreter(interpretername); - break; - } - } - } - - if (!info) { - d->updatesProperties = false; - return; - } - d->properties->clear(); QStringList types; @@ -299,35 +273,6 @@ ); d->properties->addProperty(t); - QStringList interpreters = manager->interpreters(); - - qDebug() << interpreters; - - KPropertyListData* proplist = new KPropertyListData(interpreters, interpreters); - KProperty* prop = new KProperty( - "language", // name - proplist, // ListData - d->scriptaction->interpreter(), // value - xi18n("Interpreter"), // caption - xi18n("The used scripting interpreter."), // description - KProperty::List // type - ); - d->properties->addProperty(prop); - - Kross::InterpreterInfo::Option::Map options = info->options(); - Kross::InterpreterInfo::Option::Map::ConstIterator it, end(options.constEnd()); - for (it = options.constBegin(); it != end; ++it) { - Kross::InterpreterInfo::Option* option = it.value(); - KProperty* prop = new KProperty( - it.key().toLatin1(), // name - d->scriptaction->option(it.key(), option->value), // value - it.key(), // caption - option->comment, // description - KProperty::Auto // type - ); - d->properties->addProperty(prop); - } - //propertySetSwitched(); propertySetReloaded(true); d->updatesProperties = false; @@ -343,24 +288,12 @@ if (property.isNull()) return; - if (property.name() == "language") { - QString language = property.value().toString(); - qDebug() << "language:" << language; - d->scriptaction->setInterpreter(language); - // We assume Kross and the HighlightingInterface are using same - // names for the support languages... - d->editor->setHighlightMode(language); - updateProperties(); - } - else if (property.name() == "type") { + if (property.name() == "type") { d->scriptType = property.value().toString(); } else { - bool ok = d->scriptaction->setOption(property.name(), property.value()); - if (! ok) { - qWarning() << "unknown property:" << property.name(); - return; - } + KexiScriptingWarning() << "unknown property:" << property.name(); + return; } setDirty(true); @@ -373,31 +306,37 @@ time.start(); d->statusbrowser->append(xi18nc("@info", "Execution of the script %1 started.", - d->scriptaction->name())); - - d->scriptaction->trigger(); - if (d->scriptaction->hadError()) { - QString errormessage = d->scriptaction->errorMessage(); - d->statusbrowser->append(QString("%2
").arg(errormessage.toHtmlEscaped())); - - QString tracedetails = d->scriptaction->errorTrace(); - d->statusbrowser->append(tracedetails.toHtmlEscaped()); - - long lineno = d->scriptaction->errorLineNo(); - if (lineno >= 0) - d->editor->setLineNo(lineno); - } - else { - // xgettext: no-c-format - d->statusbrowser->append(xi18n("Successfully executed. Time elapsed: %1ms", time.elapsed())); + part()->instanceName())); + + KexiScriptPart *pt = qobject_cast(part()); + + _stdout = QString(); + qInstallMessageHandler(myMessageOutput); + if (pt) { + QJSValue result = pt->execute(d->editor->text().toUtf8()); + + d->statusbrowser->append(_stdout); + if (result.isError()) { + QString errormessage = result.toString(); + d->statusbrowser->append(QString("%2
").arg(errormessage.toHtmlEscaped())); + + long lineno = result.property("lineNumber").toInt(); + if (lineno >= 0) + d->editor->setLineNo(lineno); + } + else { + // xgettext: no-c-format + d->statusbrowser->append(xi18n("Successfully executed. Time elapsed: %1ms", time.elapsed())); + } } + qInstallMessageHandler(0); } bool KexiScriptDesignView::loadData() { QString data; if (!loadDataBlock(&data)) { - qDebug() << "no DataBlock"; + KexiScriptingDebug() << "no DataBlock"; return false; } @@ -409,40 +348,22 @@ bool parsed = domdoc.setContent(data, false, &errMsg, &errLine, &errCol); if (! parsed) { - qDebug() << "XML parsing error line: " << errLine << " col: " << errCol << " message: " << errMsg; + KexiScriptingWarning() << "XML parsing error line: " << errLine << " col: " << errCol << " message: " << errMsg; return false; } QDomElement scriptelem = domdoc.namedItem("script").toElement(); if (scriptelem.isNull()) { - qDebug() << "script domelement is null"; + KexiScriptingWarning() << "script domelement is null"; return false; } d->scriptType = scriptelem.attribute("scripttype"); if (d->scriptType.isEmpty()) { d->scriptType = "executable"; } - QString interpretername = scriptelem.attribute("language"); - Kross::Manager* manager = &Kross::Manager::self(); - Kross::InterpreterInfo* info = interpretername.isEmpty() ? 0 : manager->interpreterInfo(interpretername); - if (info) { - d->scriptaction->setInterpreter(interpretername); - - Kross::InterpreterInfo::Option::Map options = info->options(); - Kross::InterpreterInfo::Option::Map::ConstIterator it, end = options.constEnd(); - for (it = options.constBegin(); it != end; ++it) { - QString value = scriptelem.attribute(it.key()); - if (! value.isNull()) { - QVariant v(value); - if (v.convert(it.value()->value.type())) // preserve the QVariant's type - d->scriptaction->setOption(it.key(), v); - } - } - } - - d->scriptaction->setCode(scriptelem.text().toUtf8()); + initialize(scriptelem.text().toUtf8()); return true; } @@ -457,7 +378,7 @@ delete s; return 0; } - qDebug() << "new id:" << s->id(); + KexiScriptingDebug() << "new id:" << s->id(); if (! storeData()) { qWarning() << "Failed to store the data."; @@ -473,29 +394,17 @@ tristate KexiScriptDesignView::storeData(bool /*dontAsk*/) { + KexiScriptingDebug() << "Saving script" << d->editor->text().toUtf8(); QDomDocument domdoc("script"); QDomElement scriptelem = domdoc.createElement("script"); domdoc.appendChild(scriptelem); - QString language = d->scriptaction->interpreter(); - scriptelem.setAttribute("language", language); + scriptelem.setAttribute("language", "javascript"); //! @todo move different types to their own part?? scriptelem.setAttribute("scripttype", d->scriptType); - Kross::InterpreterInfo* info = Kross::Manager::self().interpreterInfo(language); - if (info) { - Kross::InterpreterInfo::Option::Map defoptions = info->options(); - QMap options = d->scriptaction->options(); - QMap::ConstIterator it, end(options.constEnd()); - for (it = options.constBegin(); it != end; ++it) - if (defoptions.contains(it.key())) // only remember options which the InterpreterInfo knows about... - scriptelem.setAttribute(it.key(), it.value().toString()); - } - - QDomText scriptcode = domdoc.createTextNode(d->scriptaction->code()); + QDomText scriptcode = domdoc.createTextNode(d->editor->text().toUtf8()); scriptelem.appendChild(scriptcode); return storeDataBlock(domdoc.toString()); } - - diff --git a/src/plugins/scripting/kexiscripting/kexiscripteditor.h b/src/plugins/scripting/kexiscripting/kexiscripteditor.h --- a/src/plugins/scripting/kexiscripting/kexiscripteditor.h +++ b/src/plugins/scripting/kexiscripting/kexiscripteditor.h @@ -62,7 +62,7 @@ * highlighter will be reset, undo/redo are cleared and * setDirty(false) is set. */ - void initialize(Kross::Action* scriptaction); + void initialize(const QString &scriptProgram); public Q_SLOTS: void slotTextChanged(); diff --git a/src/plugins/scripting/kexiscripting/kexiscripteditor.cpp b/src/plugins/scripting/kexiscripting/kexiscripteditor.cpp --- a/src/plugins/scripting/kexiscripting/kexiscripteditor.cpp +++ b/src/plugins/scripting/kexiscripting/kexiscripteditor.cpp @@ -22,14 +22,12 @@ #include "kexiscripteditor.h" -#include - /// \internal d-pointer class class Q_DECL_HIDDEN KexiScriptEditor::Private { public: - Kross::Action* scriptaction; - Private() : scriptaction(0) {} + QString scriptaction; + Private() {} }; KexiScriptEditor::KexiScriptEditor(QWidget *parent) @@ -45,18 +43,16 @@ bool KexiScriptEditor::isInitialized() const { - return d->scriptaction != 0; + return !d->scriptaction.isEmpty(); } -void KexiScriptEditor::initialize(Kross::Action* scriptaction) +void KexiScriptEditor::initialize(const QString &scriptaction) { d->scriptaction = scriptaction; - Q_ASSERT(d->scriptaction); disconnect(this, SIGNAL(textChanged()), this, SLOT(slotTextChanged())); - QString code = d->scriptaction->code(); - if (code.isEmpty()) { + if (d->scriptaction.isEmpty()) { // If there is no code we just add some information. ///@todo remove after release #if 0 @@ -71,10 +67,10 @@ "http://www.kexi-project.org/scripting/"), true).join("\n# ") + "\n"; #endif } - KexiEditor::setText(code); + KexiEditor::setText(d->scriptaction); // We assume Kross and the HighlightingInterface are using same // names for the support languages... - setHighlightMode(d->scriptaction->interpreter()); + setHighlightMode("javascript"); clearUndoRedo(); KexiEditor::setDirty(false); @@ -84,9 +80,7 @@ void KexiScriptEditor::slotTextChanged() { KexiEditor::setDirty(true); - if (d->scriptaction) { - d->scriptaction->setCode(KexiEditor::text().toUtf8()); - } + d->scriptaction = KexiEditor::text(); } void KexiScriptEditor::setLineNo(long lineno) diff --git a/src/plugins/scripting/kexiscripting/kexiscriptpart.h b/src/plugins/scripting/kexiscripting/kexiscriptpart.h --- a/src/plugins/scripting/kexiscripting/kexiscriptpart.h +++ b/src/plugins/scripting/kexiscripting/kexiscriptpart.h @@ -25,6 +25,7 @@ #include #include +#include /** * Kexi Scripting Plugin. @@ -55,6 +56,8 @@ */ virtual bool execute(KexiPart::Item* item, QObject* sender = 0); + QJSValue execute(const QString &program); + /** * \return the i18n message for the passed \p englishMessage string. */ @@ -96,6 +99,10 @@ class Private; /// \internal d-pointer instance. Private* const d; + + void registerMetaObjects(); + + QString loadData(KexiPart::Item* item); }; #endif diff --git a/src/plugins/scripting/kexiscripting/kexiscriptpart.cpp b/src/plugins/scripting/kexiscripting/kexiscriptpart.cpp --- a/src/plugins/scripting/kexiscripting/kexiscriptpart.cpp +++ b/src/plugins/scripting/kexiscripting/kexiscriptpart.cpp @@ -22,53 +22,44 @@ #include "kexiscriptpart.h" #include "kexiscriptdesignview.h" #include "kexiscriptadaptor.h" +#include "../kexidb/kexidbmodule.h" +#include "KexiScriptingDebug.h" + #include #include #include #include #include #include #include - -#include -#include +#include #include #include #include #include #include +#include +#include +#include +#include KEXI_PLUGIN_FACTORY(KexiScriptPart, "kexi_scriptplugin.json") /// \internal class Q_DECL_HIDDEN KexiScriptPart::Private { public: explicit Private(KexiScriptPart* p) - : p(p) - , actioncollection(new Kross::ActionCollection("projectscripts")) - , adaptor(0) {} + : p(p) {} ~Private() { - delete actioncollection; delete adaptor; } + QJSEngine engine; KexiScriptPart* p; - Kross::ActionCollection* actioncollection; - KexiScriptAdaptor* adaptor; - - Kross::Action* action(const QString &partname) { - Kross::Action *action = actioncollection->action(partname); - if (! action) { - if (! adaptor) - adaptor = new KexiScriptAdaptor(); - action = new Kross::Action(p, partname); - actioncollection->addAction(action); - action->addObject(adaptor); - } - return action; - } + KexiScriptAdaptor adaptor; + Scripting::KexiDBModule kexidbmodule; }; KexiScriptPart::KexiScriptPart(QObject *parent, const QVariantList& l) @@ -82,6 +73,15 @@ l) , d(new Private(this)) { + d->engine.installExtensions(QJSEngine::ConsoleExtension); + + registerMetaObjects(); + + QJSValueIterator it(d->engine.globalObject()); + while (it.hasNext()) { + it.next(); + KexiScriptingDebug() << it.name() << ": " << it.value().toString(); + } } KexiScriptPart::~KexiScriptPart() @@ -97,96 +97,43 @@ return false; } -#if 0 - KexiDialogBase* dialog = new KexiDialogBase(m_mainWin); - dialog->setId(item->identifier()); - KexiScriptDesignView* view = dynamic_cast( - createView(dialog, dialog, *item, Kexi::DesignViewMode)); - if (! view) { - qWarning() << "Failed to create a view."; - return false; - } + QString p = loadData(item); - Kross::Action* scriptaction = view->scriptAction(); - if (scriptaction) { - - const QString dontAskAgainName = "askExecuteScript"; - KSharedConfig::Ptr config = KSharedConfig::openConfig(); - QString dontask = config->readEntry(dontAskAgainName).toLower(); - - bool exec = (dontask == "yes"); - if (!exec && dontask != "no") { - exec = KMessageBox::Yes == KMessageBox::questionYesNo(view, - futureI18n("Do you want to execute the script \"%1\"?\n\n" - "Scripts obtained from unknown sources can contain dangerous code.", scriptaction->text()), - futureI18n("Execute Script?"), KGuiItem(futureI18nc("@action:button", "Execute"), koIconName("system-run")), - dontAskAgainName, KMessageBox::Notify | KMessageBox::Dangerous - ); - } + QJSValue result = execute(p); + + if (result.isError()) { + QString errormessage = result.toString(); + long lineno = result.property("lineNumber").toInt(); + QMessageBox mb(xi18n("Kexi Script"), xi18n("Error executing script at line %1:\n%2").arg(lineno).arg(errormessage), QMessageBox::Critical, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); + mb.exec(); + return false; + } + return true; +} - if (exec) { - //QTimer::singleShot(10, scriptaction, SLOT(activate())); - d->scriptguiclient->executeScriptAction(scriptaction); - } +QJSValue KexiScriptPart::execute(const QString& program) +{ + QJSValue val; + + if (!d->engine.globalObject().hasProperty("KDb")) { + val = d->engine.newQObject(&d->kexidbmodule); + d->engine.globalObject().setProperty("KDb", val); } - view->deleteLater(); // not needed any longer. -#else - - Kross::Action *action = d->action(item->name()); - Q_ASSERT(action); - action->trigger(); -#endif - return true; + + if (!program.isEmpty()) { + return d->engine.evaluate(program); + } + return QJSValue(); } void KexiScriptPart::initPartActions() { - qDebug() << "............."; -#if 0 - if (m_mainWin) { - // At this stage the KexiPart::Part::m_mainWin should be defined, so - // that we are able to use it's KXMLGUIClient. - - // Initialize the ScriptGUIClient. - d->scriptguiclient = new Kross::Api::ScriptGUIClient(m_mainWin); - - // Publish the KexiMainWindow singelton instance. At least the KexiApp - // scripting-plugin depends on this instance and loading the plugin will - // fail if it's not avaiable. - if (! Kross::Api::Manager::scriptManager()->hasChild("KexiMainWindow")) { - Kross::Api::Manager::scriptManager()->addQObject(m_mainWin, "KexiMainWindow"); - - // Add the QAction's provided by the ScriptGUIClient to the - // KexiMainWindow. - //FIXME: fix+use createSharedPartAction() whyever it doesn't work as expected right now... - Q3PopupMenu* popup = m_mainWin->findPopupMenu("tools"); - if (popup) { - QAction* execscriptaction = d->scriptguiclient->action("executescriptfile"); - if (execscriptaction) - execscriptaction->plug(popup); - QAction* configscriptaction = d->scriptguiclient->action("configurescripts"); - if (configscriptaction) - configscriptaction->plug(popup); - QAction* scriptmenuaction = d->scriptguiclient->action("installedscripts"); - if (scriptmenuaction) - scriptmenuaction->plug(popup); - /* - QAction * execscriptmenuaction = d->scriptguiclient->action("executedscripts"); - if(execscriptmenuaction) - execscriptmenuaction->plug( popup ); - QAction * loadedscriptmenuaction = d->scriptguiclient->action("loadedscripts"); - if(loadedscriptmenuaction) - loadedscriptmenuaction->plug( popup ); - */ - } - } - } -#endif + } void KexiScriptPart::initInstanceActions() { - createSharedAction(Kexi::DesignViewMode, xi18n("Configure Editor..."), + createSharedAction(Kexi::TextViewMode, xi18n("Configure Editor..."), koIconName("configure"), QKeySequence(), "script_config_editor"); } @@ -199,28 +146,11 @@ Q_ASSERT(item); Q_UNUSED(window); Q_UNUSED(staticObjectArgs); - qDebug() << "............. createView"; + QString partname = item->name(); if (! partname.isNull()) { - Kross::Action *action = d->action(partname); -#if 0 - KexiMainWindow *win = dialog->mainWin(); - if (!win || !win->project() || !win->project()->dbConnection()) - return 0; - Kross::Api::ScriptActionCollection* collection = d->scriptguiclient->getActionCollection("projectscripts"); - if (! collection) { - collection = new Kross::Api::ScriptActionCollection(xi18n("Scripts"), d->scriptguiclient->actionCollection(), "projectscripts"); - d->scriptguiclient->addActionCollection("projectscripts", collection); - } - const char* name = partname.toLatin1(); - Kross::Api::ScriptAction::Ptr scriptaction = collection->action(name); - if (! scriptaction) { - scriptaction = new Kross::Api::ScriptAction(partname); - collection->attach(scriptaction); //!< @todo remove again on unload! - } -#endif - if (viewMode == Kexi::DesignViewMode) { - return new KexiScriptDesignView(parent, action); + if (viewMode == Kexi::TextViewMode) { + return new KexiScriptDesignView(parent); } } return 0; @@ -236,4 +166,58 @@ return Part::i18nMessage(englishMessage, window); } +QString KexiScriptPart::loadData(KexiPart::Item* item) +{ + QString data; + if (!item) { + return QString(); + } + + if (true != KexiMainWindowIface::global()->project()->dbConnection()->loadDataBlock( + item->identifier(), &data)) + { + return QString(); + } + + QString errMsg; + int errLine; + int errCol; + + QString scriptType; + + QDomDocument domdoc; + bool parsed = domdoc.setContent(data, false, &errMsg, &errLine, &errCol); + + if (!parsed) { + KexiScriptingWarning() << "XML parsing error line: " << errLine << " col: " << errCol << " message: " << errMsg; + return QString(); + } + + QDomElement scriptelem = domdoc.namedItem("script").toElement(); + if (scriptelem.isNull()) { + KexiScriptingWarning() << "script domelement is null"; + return QString(); + } + + scriptType = scriptelem.attribute("scripttype"); + if (scriptType.isEmpty()) { + scriptType = "executable"; + } + + if (scriptType == "executable") { + return scriptelem.text().toUtf8(); + } else { + return QString(); + } +} + +void KexiScriptPart::registerMetaObjects() +{ + QJSValue meta = d->engine.newQMetaObject(&KexiScriptAdaptor::staticMetaObject); + d->engine.globalObject().setProperty("KexiScriptAdaptor", meta); + + meta = d->engine.newQMetaObject(&Scripting::KexiDBModule::staticMetaObject); + d->engine.globalObject().setProperty("KDb", meta); +} + #include "kexiscriptpart.moc"