/*************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Qt Software Information (qt-info@nokia.com) ** ** ** Non-Open Source Usage ** ** Licensees may use this file in accordance with the Qt Beta Version ** License Agreement, Agreement version 2.2 provided with the Software or, ** alternatively, in accordance with the terms contained in a written ** agreement between you and Nokia. ** ** GNU General Public License Usage ** ** Alternatively, this file may be used under the terms of the GNU General ** Public License versions 2.0 or 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the packaging ** of this file. Please review the following information to ensure GNU ** General Public Licensing requirements will be met: ** ** http://www.fsf.org/licensing/licenses/info/GPLv2.html and ** http://www.gnu.org/copyleft/gpl.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt GPL Exception ** version 1.2, included in the file GPL_EXCEPTION.txt in this package. ** ***************************************************************************/ #include "scriptmanager.h" #include "qworkbench_wrapper.h" #include "metatypedeclarations.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace { enum { debugQWorkbenchWrappers = 0 }; } // Script function template to pop up a message box // with a certain icon and buttons. template static QScriptValue messageBox(QScriptContext *context, QScriptEngine *engine) { if (context->argumentCount() < 3) return QScriptValue(engine, -1); QWidget *parent = qscriptvalue_cast(context->argument(0)); const QString title = context->argument(1).toString(); const QString msg = context->argument(2).toString(); QMessageBox msgBox(static_cast(MsgBoxIcon), title, msg, static_cast(MsgBoxButtons), parent); return QScriptValue(engine, msgBox.exec()); } static QScriptValue inputDialogGetText(QScriptContext *context, QScriptEngine *engine) { const int argumentCount = context->argumentCount(); if (argumentCount < 3) return QScriptValue(engine, QScriptValue::NullValue); QWidget *parent = qscriptvalue_cast(context->argument(0)); const QString title = context->argument(1).toString(); const QString label = context->argument(2).toString(); const QString defaultValue = argumentCount > 3 ? context->argument(3).toString() : QString(); bool ok; const QString rc = QInputDialog::getText(parent, title, label, QLineEdit::Normal, defaultValue, &ok); if (!ok) return QScriptValue(engine, QScriptValue::NullValue); return QScriptValue(engine, rc); } static QScriptValue inputDialogGetInteger(QScriptContext *context, QScriptEngine *engine) { const int argumentCount = context->argumentCount(); if (argumentCount < 3) return QScriptValue(engine, QScriptValue::NullValue); QWidget *parent = qscriptvalue_cast(context->argument(0)); const QString title = context->argument(1).toString(); const QString label = context->argument(2).toString(); const int defaultValue = argumentCount > 3 ? context->argument(3).toInt32() : 0; const int minValue = argumentCount > 4 ? context->argument(4).toInt32() : INT_MIN; const int maxValue = argumentCount > 5 ? context->argument(5).toInt32() : INT_MAX; bool ok; const int rc = QInputDialog::getInteger(parent, title, label, defaultValue, minValue, maxValue, 1, &ok); if (!ok) return QScriptValue(engine, QScriptValue::NullValue); return QScriptValue(engine, rc); } static QScriptValue inputDialogGetDouble(QScriptContext *context, QScriptEngine *engine) { const int argumentCount = context->argumentCount(); if (argumentCount < 3) return QScriptValue(engine, QScriptValue::NullValue); QWidget *parent = qscriptvalue_cast(context->argument(0)); const QString title = context->argument(1).toString(); const QString label = context->argument(2).toString(); const double defaultValue = argumentCount > 3 ? context->argument(3).toNumber() : 0; // Use QInputDialog defaults const double minValue = argumentCount > 4 ? context->argument(4).toNumber() : INT_MIN; const double maxValue = argumentCount > 5 ? context->argument(5).toNumber() : INT_MAX; bool ok; const double rc = QInputDialog::getDouble(parent, title, label, defaultValue, minValue, maxValue, 1, &ok); if (!ok) return QScriptValue(engine, QScriptValue::NullValue); return QScriptValue(engine, rc); } static QScriptValue inputDialogGetItem(QScriptContext *context, QScriptEngine *engine) { const int argumentCount = context->argumentCount(); if (argumentCount < 4) return QScriptValue(engine, QScriptValue::NullValue); QWidget *parent = qscriptvalue_cast(context->argument(0)); const QString title = context->argument(1).toString(); const QString label = context->argument(2).toString(); const QStringList items = qscriptvalue_cast(context->argument(3)); const int defaultItem = argumentCount > 4 ? context->argument(4).toInt32() : 0; const bool editable = argumentCount > 5 ? context->argument(5).toInt32() : 0; bool ok; const QString rc = QInputDialog::getItem (parent, title, label, items, defaultItem, editable, &ok); if (!ok) return QScriptValue(engine, QScriptValue::NullValue); return QScriptValue(engine, rc); } // Script function template to pop up a file box // with a certain icon and buttons. template static QScriptValue fileBox(QScriptContext *context, QScriptEngine *engine) { const int argumentCount = context->argumentCount(); if (argumentCount < 2) return QScriptValue(engine, QScriptValue::NullValue); QWidget *parent = qscriptvalue_cast(context->argument(0)); const QString title = context->argument(1).toString(); const QString directory = argumentCount > 2 ? context->argument(2).toString() : QString(); const QString filter = argumentCount > 3 ? context->argument(3).toString() : QString(); QFileDialog fileDialog(parent, title, directory, filter); fileDialog.setAcceptMode(static_cast(TAcceptMode)); fileDialog.setFileMode (static_cast(TFileMode)); if (fileDialog.exec() == QDialog::Rejected) return QScriptValue(engine, QScriptValue::NullValue); const QStringList rc = fileDialog.selectedFiles(); Q_ASSERT(!rc.empty()); return TFileMode == QFileDialog::ExistingFiles ? engine->toScriptValue(rc) : engine->toScriptValue(rc.front()); } // ------ ScriptManager namespace Core { namespace Internal { ScriptManager::ScriptManager(QObject *parent, ICore *core) : ScriptManagerInterface(parent), m_core(core), m_initialized(false) { } QScriptEngine &ScriptManager::scriptEngine() { ensureEngineInitialized(); return m_engine; } // Split a backtrace of the form: // "(BuildManagerCommand(ls))@:0 // demoProjectExplorer()@:237 // ()@:276 // ()@:0" static void parseBackTrace(const QStringList &backTrace, ScriptManager::Stack &stack) { const QChar at = QLatin1Char('@'); const QChar colon = QLatin1Char(':'); stack.clear(); foreach (const QString &line, backTrace) { const int atPos = line.lastIndexOf(at); if (atPos == -1) continue; const int colonPos = line.indexOf(colon, atPos + 1); if (colonPos == -1) continue; ScriptManager::StackFrame frame; frame.function = line.left(atPos); frame.fileName = line.mid(atPos + 1, colonPos - atPos - 1); frame.lineNumber = line.right(line.size() - colonPos - 1).toInt(); stack.push_back(frame); } } bool ScriptManager::runScript(const QString &script, QString *errorMessage) { Stack stack; return runScript(script, errorMessage, &stack); } bool ScriptManager::runScript(const QString &script, QString *errorMessage, Stack *stack) { ensureEngineInitialized(); stack->clear(); m_engine.pushContext(); m_engine.evaluate(script); const bool failed = m_engine.hasUncaughtException (); if (failed) { const int errorLineNumber = m_engine.uncaughtExceptionLineNumber(); const QStringList backTrace = m_engine.uncaughtExceptionBacktrace(); parseBackTrace(backTrace, *stack); const QString backtrace = backTrace.join(QString(QLatin1Char('\n'))); *errorMessage = QObject::tr("Exception at line %1: %2\n%3").arg(errorLineNumber).arg(engineError(m_engine)).arg(backtrace); } m_engine.popContext(); return !failed; } void ScriptManager::ensureEngineInitialized() { if (m_initialized) return; Q_ASSERT(m_core); // register QObjects that occur as properties SharedTools::registerQObject(m_engine); SharedTools::registerQObject(m_engine); SharedTools::registerQObject(m_engine); SharedTools::registerQObject(m_engine); // WB interfaces // SharedTools::registerQObjectInterface(m_engine); // SharedTools::registerQObjectInterface(m_engine); // qScriptRegisterSequenceMetaType >(&m_engine); // SharedTools::registerQObjectInterface(m_engine); // SharedTools::registerQObjectInterface(m_engine); qScriptRegisterSequenceMetaType >(&m_engine); // SharedTools::registerQObjectInterface(m_engine); qScriptRegisterSequenceMetaType >(&m_engine); SharedTools::registerQObjectInterface(m_engine); // SharedTools::registerQObjectInterface(m_engine); // Make "core" available m_engine.globalObject().setProperty(QLatin1String("core"), qScriptValueFromValue(&m_engine, m_core)); // CLASSIC: registerInterfaceWithDefaultPrototype(m_engine); // Message box conveniences m_engine.globalObject().setProperty(QLatin1String("critical"), m_engine.newFunction(messageBox, 3)); m_engine.globalObject().setProperty(QLatin1String("warning"), m_engine.newFunction(messageBox, 3)); m_engine.globalObject().setProperty(QLatin1String("information"), m_engine.newFunction(messageBox, 3)); // StandardButtons has overloaded operator '|' - grrr. enum { MsgBoxYesNo = 0x00014000 }; m_engine.globalObject().setProperty(QLatin1String("yesNoQuestion"), m_engine.newFunction(messageBox, 3)); m_engine.globalObject().setProperty(QLatin1String("getText"), m_engine.newFunction(inputDialogGetText, 3)); m_engine.globalObject().setProperty(QLatin1String("getInteger"), m_engine.newFunction(inputDialogGetInteger, 3)); m_engine.globalObject().setProperty(QLatin1String("getDouble"), m_engine.newFunction(inputDialogGetDouble, 3)); m_engine.globalObject().setProperty(QLatin1String("getItem"), m_engine.newFunction(inputDialogGetItem, 3)); // file box m_engine.globalObject().setProperty(QLatin1String("getOpenFileNames"), m_engine.newFunction(fileBox , 2)); m_engine.globalObject().setProperty(QLatin1String("getOpenFileName"), m_engine.newFunction(fileBox , 2)); m_engine.globalObject().setProperty(QLatin1String("getSaveFileName"), m_engine.newFunction(fileBox , 2)); m_engine.globalObject().setProperty(QLatin1String("getExistingDirectory"), m_engine.newFunction(fileBox , 2)); m_initialized = true; } QString ScriptManager::engineError(QScriptEngine &scriptEngine) { QScriptValue error = scriptEngine.evaluate(QLatin1String("Error")); if (error.isValid()) return error.toString(); return QObject::tr("Unknown error"); } } // namespace Internal } // namespace Core