#include "sysmacroconsole.h" #include "widgetcontainer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SysMacroConsole::SysMacroConsole(const QString &iModuleNameStr, const QVariantMap iUrlPars, QWidget *iParent) : TopClassAbs(iParent), mScriptFile("") { this->setLicenseKey("sys_common"); this->initModule(iModuleNameStr, iUrlPars); constructMyselfScriptEngine(); attachDebugger(); mFileWatcher = new QFileSystemWatcher(this); mCodeEdit = new TCodeEdit(this); connect(mCodeEdit, SIGNAL(textChanged()), this, SLOT(onCodeEditTextChanged())); mBodySplitter = new TSplitter(this); mBodySplitter->setOrientation(Qt::Vertical); mBodyWidget = new QWidget(this); QVBoxLayout *vboxlayout = new QVBoxLayout(mBodyWidget); vboxlayout->setMargin(0); vboxlayout->setSpacing(0); this->setCentralWidget(mBodyWidget); mModuleName = new TLineEdit(this); mModuleName->setMaximumWidth(TTHEME_DP(300)); if (QToolBar *toolbar = qobject_cast(uim()->getWidget("MAIN_TOOLBAR"))) { vboxlayout->addWidget(toolbar, 0); QWidget *ph = qobject_cast(uim()->getWidget("MAIN_TOOLBAR/module_name_ph")); if (nullptr != ph) { QHBoxLayout *vlayout = new QHBoxLayout(ph); vlayout->setMargin(0); vlayout->setSpacing(0); QLabel *label = new QLabel(ph); label->setText(ttr("Context:")); vlayout->addWidget(label); vlayout->addWidget(mModuleName, 0, Qt::AlignLeft); } } mBodySplitter->addWidget(mCodeEdit); mBodySplitter->addWidget(mDebugTabWgt); vboxlayout->addWidget(mBodySplitter, 1); connect(mFileWatcher, SIGNAL(fileChanged(QString)), this, SLOT(onFileChanged(QString))); this->restoreSizeState(); refreshActionState(); mExternScriptFile = APP->getSetting(moduleName() + "/" + "temp_file").toString().trimmed(); mCodeEdit->setPlainText(TFileIo::readFileString(mExternScriptFile)); setDataModified(false); refreshActionState(); } SysMacroConsole::~SysMacroConsole() { this->saveSizeState(); detachDebugger(); if (!mExternScriptFile.isEmpty()) { APP->saveSetting(moduleName() + "/" + "temp_file", mExternScriptFile); } } bool SysMacroConsole::runScript(const QString &iRunMode) { // 原有的方式在调试时,如果点击运行到最后,关闭调试界面后,点击运行脚本会再次弹出调试界面。 mScriptDebugger->detach(); mScriptDebugger->attachTo(mScriptEngine); QString scripts = getScriptString(); if (iRunMode.trimmed().toLower() == QStringLiteral("debug")) { scripts = " debugger;\n" + scripts; } QScriptValue thisObject; if (!mModuleName->text().trimmed().isEmpty()) { TopClassAbs *pModule = getModule(mModuleName->text().trimmed()); if (nullptr == pModule) { pModule = qobject_cast(this); } thisObject = mScriptEngine->newQObject(pModule); } else { thisObject = mScriptEngine->newQObject(this); } mScriptEngine->pushContext(); QScriptValue func = mScriptEngine->evaluate("(function(){\n" + scripts + "\n})", "SCRIPT"); func.call(thisObject); mScriptEngine->popContext(); mScriptEngine->collectGarbage(); return true; } bool SysMacroConsole::openScript(const QString &iFileNameStr) { QString file = iFileNameStr; if (APP->isUiEnabled() && file.isEmpty()) { file = QFileDialog::getOpenFileName(this, ttr("Open Script"), "", ttr("JavaScript") + "(*.js);;" + ttr("All Files") + "(*.*)"); } if (file.isEmpty()) { return false; } mScriptFile = file; TError err; QString content = TFileIo::readFileString(file, "UTF-8", &err); if (err.isValid()) { alertError(ttr("Open file failed!"), err.text()); return false; } else { mCodeEdit->setPlainText(content); mScriptFile = file; mFileWatcher->removePaths(mFileWatcher->files()); mFileWatcher->addPath(mScriptFile); setDataModified(false); refreshActionState(); return true; } } bool SysMacroConsole::saveScript(const QString &iFileNameStr, bool iSaveAsBol) { QString file = iFileNameStr; if (file.isEmpty()) { if (!iSaveAsBol && !mScriptFile.isEmpty()) { file = mScriptFile; } else if (APP->isUiEnabled()) { file = QFileDialog::getSaveFileName(this, ttr("Save Script"), "", ttr("JavaScript") + "(*.js);;" + ttr("All Files") + "(*.*)"); } } if (file.isEmpty()) { return false; } TError err; TFileIo::writeFileString(mCodeEdit->toPlainText(), file, "UTF-8", true, &err); if (err.isValid()) { alertError(ttr("Save file failed!"), err.text()); return false; } else { mScriptFile = file; mFileWatcher->removePaths(mFileWatcher->files()); mFileWatcher->addPath(mScriptFile); alertOk(ttr("Save file successful!")); setDataModified(false); refreshActionState(); return true; } } bool SysMacroConsole::useExternProgram(const QString &iProgramPath) { #ifdef Q_OS_WIN32 if (!QFile::exists(iProgramPath)) { alertError(ttr("Extern program doesn't exists!")); return false; } if (mExternScriptFile.isEmpty()) { QString tempFileName = "SysMacroConsole_tempfile_{" + APP->getNow().replace(QRegularExpression("[\\s\\-\\:]"), "") + "}" + ".js"; mExternScriptFile = APP->appTempPath() + "/" + tempFileName; } if (!TFileIo::writeFileString(mCodeEdit->toPlainText(), mExternScriptFile)) { alertError(ttr("Fail to create temporary file"), mExternScriptFile); return false; } WidgetContainer *container = new WidgetContainer(this); if (!container->createContainer(iProgramPath, QStringList() << mExternScriptFile, true)) { alertError(ttr("Fail to open extern program!")); return false; } mCodeEdit->hide(); if (nullptr != mExternWindowContainer) { mExternWindowContainer->hide(); mExternWindowContainer->deleteLater(); mExternWindowContainer = nullptr; } mExternWindowContainer = container; mBodySplitter->insertWidget(0, mExternWindowContainer); mBodySplitter->installEventFilter(mExternWindowContainer); mUseExternProgram = true; refreshActionState(); return true; #else Q_UNUSED(iProgramPath); return false; #endif } bool SysMacroConsole::exitExternProgram() { #ifdef Q_OS_WIN32 if (!mUseExternProgram) { return !mUseExternProgram; } mCodeEdit->setPlainText(TFileIo::readFileString(mExternScriptFile)); if (nullptr != mExternWindowContainer) { mExternWindowContainer->hide(); mExternWindowContainer->deleteLater(); mExternWindowContainer = nullptr; } mCodeEdit->show(); mUseExternProgram = false; refreshActionState(); return !mUseExternProgram; #else return false; #endif } bool SysMacroConsole::isUsingExternProgram() { return mUseExternProgram; } bool SysMacroConsole::win32() { #ifdef Q_OS_WIN32 return true; #else return false; #endif } void SysMacroConsole::onFileChanged(const QString &iFileNameStr) { openScript(iFileNameStr); } void SysMacroConsole::redirectOutput() { if (nullptr == mDebugTabWgt) { mDebugTabWgt = new TTabWidget(this); mDebugTabWgt->setTabPosition(TTabWidget::South); mDebugTabWgt->setMaximumHeight(300); } if (nullptr == mOutputWgt) { mOutputWgt = new QPlainTextEdit(mDebugTabWgt); } if (nullptr == mErrorLogWgt) { mErrorLogWgt = new QPlainTextEdit(mDebugTabWgt); } mOutputWgt->clear(); mErrorLogWgt->clear(); mDebugTabWgt->addTab(mOutputWgt, this->ttr("Debug Output")); mDebugTabWgt->addTab(mErrorLogWgt, this->ttr("Error Log")); QWidget *pWgt = mScriptDebugger->widget(QScriptEngineDebugger::DebugOutputWidget); for (QWidget *children : pWgt->findChildren()) { if (nullptr != children) { if (QString("QPlainTextEdit") == QString(children->metaObject()->className())) { connect((QPlainTextEdit*)children, &QPlainTextEdit::textChanged, this, [this, children](){ //错误用法, 应该使用一个共享的QMutex, 在所有需要执行锁定的地方 // QMutex mutex; // mutex.lock(); mDebugOutputStr = ((QPlainTextEdit*)children)->toPlainText(); // mutex.unlock(); mOutputWgt->blockSignals(true); mOutputWgt->setPlainText(mDebugOutputStr); mOutputWgt->blockSignals(false); }); connect(mOutputWgt, &QPlainTextEdit::textChanged, this, [this, children]() { // QMutex mutex; // mutex.lock(); mDebugOutputStr = mOutputWgt->toPlainText(); // mutex.unlock(); children->blockSignals(true); ((QPlainTextEdit*)children)->setPlainText(mDebugOutputStr); children->blockSignals(false); }); break; } } } pWgt = mScriptDebugger->widget(QScriptEngineDebugger::ErrorLogWidget); for (QWidget *children : pWgt->findChildren()) { if (nullptr != children) { if (QString("QPlainTextEdit") == QString(children->metaObject()->className())) { connect((QPlainTextEdit*)children, &QPlainTextEdit::textChanged, this, [this, children](){ // QMutex mutex; // mutex.lock(); mErrorLogStr = ((QPlainTextEdit*)children)->toPlainText(); // mutex.unlock(); mErrorLogWgt->blockSignals(true); mErrorLogWgt->setPlainText(mErrorLogStr); mErrorLogWgt->blockSignals(false); }); connect(mErrorLogWgt, &QPlainTextEdit::textChanged, this, [this, children](){ // QMutex mutex; // mutex.lock(); mErrorLogStr = mErrorLogWgt->toPlainText(); // mutex.unlock(); children->blockSignals(true); ((QPlainTextEdit*)children)->setPlainText(mErrorLogStr); children->blockSignals(false); }); break; } } } } void SysMacroConsole::onCodeEditTextChanged() { setDataModified(true); refreshActionState(); } TopClassAbs *SysMacroConsole::getModule(const QString &iModuleName, bool iAutoOpen) { QString mdName = iModuleName.split("/").first(); QString uid = iModuleName.split("/").last(); if (uid.trimmed().isEmpty()) { uid = uid.number(0); } TopClassAbs *pModule = APP->getModule(mdName, uid); if (iAutoOpen && nullptr == pModule) { pModule = APP->openModule(mdName + "/" + uid); if (nullptr != pModule) { APP->notify(A_CORE_PUSH_MODULE_TO_DESKTOP, QVariantMap{ {"moduleName", mdName}, {"uid", uid} }); } } return pModule; } void SysMacroConsole::attachDebugger() { /*20170922 Tony Guo 由于ScriptEngineDebugger会造成运行GUI.showForm时崩溃, * 因此在未找到原因前先去除Debugger功能 * 20180525 Mark 原因找到, 启用 Debugger功能 */ if (nullptr == mScriptDebugger) { mScriptDebugger = new QScriptEngineDebugger(this); mScriptDebugger->setAutoShowStandardWindow(true); } if (!debuggerAttached) { mScriptDebugger->attachTo((QScriptEngine*)mScriptEngine); debuggerAttached = true; } redirectOutput(); } void SysMacroConsole::detachDebugger() { if (nullptr != mScriptDebugger && debuggerAttached) { mScriptDebugger->action(QScriptEngineDebugger::RunToNewScriptAction)->trigger(); mScriptDebugger->detach(); debuggerAttached = false; } } QString SysMacroConsole::getScriptString() const { if (mUseExternProgram) { if (!QFile::exists(mExternScriptFile)) { return QString(); } else { return TFileIo::readFileString(mExternScriptFile); } } else { return mCodeEdit->toPlainText(); } } void SysMacroConsole::constructMyselfScriptEngine() { mScriptEngine = new TScriptEngine(this); mScriptEngine->importExtension("lodash"); for (const QString &extension: APP->scriptEngine()->importedExtensions()) { mScriptEngine->importExtension(extension); } }