void Executer::executeCurrentAction() { //Skip disabled actions if(mCurrentActionIndex >= 0) { while(mCurrentActionIndex < mScript->actionCount() && canExecuteAction(mCurrentActionIndex) != CanExecute) ++mCurrentActionIndex; } if(mCurrentActionIndex < 0 || mCurrentActionIndex >= mScript->actionCount()) { stopExecution(); return; } int nextLine = mCurrentActionIndex + 2; if(nextLine > mScript->actionCount()) nextLine = -1; QScriptValue script = mScriptEngine->globalObject().property("Script"); script.setProperty("nextLine", mScriptEngine->newVariant(QVariant(nextLine))); script.setProperty("line", mCurrentActionIndex + 1, QScriptValue::ReadOnly); ActionTools::ActionInstance *actionInstance = currentActionInstance(); const ActionTools::ExceptionActionInstancesHash &exceptionActionInstancesHash = actionInstance->exceptionActionInstances(); const ActionTools::ActionException::ExceptionActionInstance &exceptionAction = exceptionActionInstancesHash.value(ActionTools::ActionException::CodeErrorException); mShowDebuggerOnCodeError = (exceptionAction.action() == ActionTools::ActionException::StopExecutionExceptionAction); mExecutionWindow->setCurrentActionName(actionInstance->definition()->name()); mExecutionWindow->setCurrentActionColor(actionInstance->color()); connect(actionInstance, SIGNAL(executionEnded()), this, SLOT(actionExecutionEnded())); connect(actionInstance, SIGNAL(executionException(int,QString)), this, SLOT(executionException(int,QString))); connect(actionInstance, SIGNAL(disableAction(bool)), this, SLOT(disableAction(bool))); connect(actionInstance, SIGNAL(showProgressDialog(QString,int)), this, SLOT(showProgressDialog(QString,int))); connect(actionInstance, SIGNAL(updateProgressDialog(int)), this, SLOT(updateProgressDialog(int))); connect(actionInstance, SIGNAL(updateProgressDialog(QString)), this, SLOT(updateProgressDialog(QString))); connect(actionInstance, SIGNAL(hideProgressDialog()), this, SLOT(hideProgressDialog())); connect(actionInstance, SIGNAL(consolePrint(QString)), this, SLOT(consolePrint(QString))); connect(actionInstance, SIGNAL(consolePrintWarning(QString)), this, SLOT(consolePrintWarning(QString))); connect(actionInstance, SIGNAL(consolePrintError(QString)), this, SLOT(consolePrintError(QString))); mExecutionStatus = PrePause; mExecutionTimer.start(); mExecutionTime.start(); if(currentActionInstance()->pauseBefore() + mPauseBefore > 0) { mExecutionWindow->setProgressEnabled(true); mExecutionWindow->setProgressMinimum(0); mExecutionWindow->setProgressMaximum(currentActionInstance()->pauseBefore() + mPauseBefore); mExecutionWindow->setProgressValue(0); } else mExecutionWindow->setProgressEnabled(false); mExecutionEnded = true; }
QMimeData* ScriptModel::mimeData(const QModelIndexList &indexes) const { if(indexes.isEmpty()) return 0; QMimeData *mimeDataPtr = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); QList<int> rowIdList; for(const QModelIndex &index: indexes) { if(!index.isValid() || index.column() != ColumnLabel) continue; if(!rowIdList.contains(index.row())) rowIdList << index.row(); } std::sort(rowIdList.begin(), rowIdList.end(), qGreater<int>()); for(int row: rowIdList) { ActionTools::ActionInstance *actionInstance = mScript->actionAt(row); if(!actionInstance) continue; stream << row; stream << ActionTools::ActionInstanceBuffer(actionInstance->definition()->id(), *actionInstance); } mimeDataPtr->setData("application/actiona.action", encodedData); return mimeDataPtr; }
QVariant ScriptModel::data(const QModelIndex &index, int role) const { if(!index.isValid()) return QVariant(); ActionTools::ActionInstance *actionInstance = mScript->actionAt(index.row()); if(!actionInstance) return QVariant(); switch(role) { case ActionDataRole: return QVariant::fromValue(*actionInstance); case ActionIdRole: return actionInstance->definition()->id(); case Qt::BackgroundRole: { const QColor &color = actionInstance->color(); if(color.isValid()) return QBrush(color); return QBrush(); } case Qt::FontRole: { if(!actionInstance->definition()->worksUnderThisOS()) { QFont font = QApplication::font(); font.setItalic(true); return font; } return QFont(); } case Qt::ForegroundRole: { const QColor &color = actionInstance->color(); if(color.isValid()) { if(color.lightness() < 128) return QBrush(Qt::white); else return QBrush(Qt::black); } else { const QPalette &palette = QApplication::palette(); if(!actionInstance->isEnabled()) return QBrush(palette.color(QPalette::Disabled, QPalette::WindowText)); return QBrush(); } } } switch(index.column()) { case ColumnLabel: switch(role) { case Qt::CheckStateRole: return QVariant(actionInstance->isEnabled() ? Qt::Checked : Qt::Unchecked); case Qt::DisplayRole: { QString labelString = actionInstance->label(); if(!labelString.isNull() && !labelString.isEmpty()) return labelString; return QString("%1").arg(index.row() + 1, 3, 10, QChar('0')); } case Qt::EditRole: return actionInstance->label(); } break; case ColumnActionName: switch(role) { case Qt::ToolTipRole: return tr("Double-clic to edit the action"); case Qt::DisplayRole: return actionInstance->definition()->name(); case Qt::DecorationRole: return QIcon(actionInstance->definition()->icon()); case Qt::TextAlignmentRole: return Qt::AlignCenter; } break; case ColumnComment: switch(role) { case Qt::DisplayRole: case Qt::EditRole: return actionInstance->comment(); } break; } return QVariant(); }
void Executer::executionException(int exception, const QString &message) { ActionTools::ActionInstance *actionInstance = currentActionInstance(); bool standardException = (exception >= 0 && exception < ActionTools::ActionException::ExceptionCount); bool customException = false; for(ActionTools::ActionException *actionException: actionInstance->definition()->exceptions()) { if(actionException->id() == exception) { customException = true; break; } } if(!standardException && !customException) { mConsoleWidget->addDesignErrorLine(tr("Action design error: Invalid exception emitted (%1, line %2)") .arg(actionInstance->definition()->name()) .arg(mCurrentActionIndex+1), ActionTools::ConsoleWidget::Error); stopExecution(); return; } ActionTools::ActionException::ExceptionActionInstance exceptionActionInstance = actionInstance->exceptionActionInstance(static_cast<ActionTools::ActionException::Exception>(exception)); ActionTools::ConsoleWidget::Type exceptionType; bool shouldStopExecution; switch(exceptionActionInstance.action()) { case ActionTools::ActionException::SkipExceptionAction: exceptionType = ActionTools::ConsoleWidget::Information; actionExecutionEnded(); shouldStopExecution = false; break; case ActionTools::ActionException::GotoLineExceptionAction: { exceptionType = ActionTools::ConsoleWidget::Information; if(canExecuteAction(exceptionActionInstance.line()) != CanExecute) { ActionTools::ActionInstance *currentAction = mScript->actionAt(mCurrentActionIndex); qint64 currentActionRuntimeId = -1; if(currentAction) currentActionRuntimeId = currentAction->runtimeId(); mConsoleWidget->addExceptionLine(tr("Invalid exception line: %1").arg(exceptionActionInstance.line()), currentActionRuntimeId, exception, ActionTools::ConsoleWidget::Error); shouldStopExecution = true; } else { QScriptValue script = mScriptEngine->globalObject().property("Script"); script.setProperty("nextLine", mScriptEngine->newVariant(QVariant(exceptionActionInstance.line()))); actionExecutionEnded(); shouldStopExecution = false; } } break; default: exceptionType = ActionTools::ConsoleWidget::Error; shouldStopExecution = true; } if(shouldStopExecution) { QString finalMessage = tr("Script line %1: ").arg(mCurrentActionIndex+1); ActionTools::ActionInstance *currentAction = mScript->actionAt(mCurrentActionIndex); qint64 currentActionRuntimeId = -1; if(currentAction) currentActionRuntimeId = currentAction->runtimeId(); mConsoleWidget->addActionLine(finalMessage + message, currentActionRuntimeId, mScriptEngine->globalObject().property("currentParameter").toString(), mScriptEngine->globalObject().property("currentSubParameter").toString(), mScriptAgent->currentLine(), mScriptAgent->currentColumn(), exceptionType); stopExecution(); } }
bool Executer::startExecution(bool onlySelection) { Q_ASSERT(mScriptAgent); Q_ASSERT(mScriptEngine); #ifdef ACT_PROFILE Tools::HighResolutionTimer timer("Executer::startExecution"); #endif Code::CodeTools::addClassToScriptEngine<CodeActiona>("Actiona", mScriptEngine); CodeActiona::setActExec(mIsActExec); CodeActiona::setActionaVersion(mActionaVersion); CodeActiona::setScriptVersion(mScriptVersion); Code::CodeTools::addClassGlobalFunctionToScriptEngine("Actiona", &CodeActiona::version, "version", mScriptEngine); Code::CodeTools::addClassGlobalFunctionToScriptEngine("Actiona", &CodeActiona::scriptVersion, "scriptVersion", mScriptEngine); Code::CodeTools::addClassGlobalFunctionToScriptEngine("Actiona", &CodeActiona::isActExec, "isActExec", mScriptEngine); Code::CodeTools::addClassGlobalFunctionToScriptEngine("Actiona", &CodeActiona::isActiona, "isActiona", mScriptEngine); mScriptAgent->setContext(ScriptAgent::ActionInit); CodeInitializer::initialize(mScriptEngine, mScriptAgent, mActionFactory); mScriptAgent->setContext(ScriptAgent::Parameters); QScriptValue script = mScriptEngine->newObject(); mScriptEngine->globalObject().setProperty("Script", script, QScriptValue::ReadOnly); script.setProperty("nextLine", 1); script.setProperty("line", 1, QScriptValue::ReadOnly); QScriptValue callProcedureFun = mScriptEngine->newFunction(callProcedureFunction); callProcedureFun.setData(mScriptEngine->newQObject(this)); script.setProperty("callProcedure", callProcedureFun); QScriptValue console = mScriptEngine->newObject(); mScriptEngine->globalObject().setProperty("Console", console, QScriptValue::ReadOnly); QScriptValue function = mScriptEngine->newFunction(printFunction); function.setData(mScriptEngine->newQObject(this)); console.setProperty("print", function); function = mScriptEngine->newFunction(printWarningFunction); function.setData(mScriptEngine->newQObject(this)); console.setProperty("printWarning", function); function = mScriptEngine->newFunction(printErrorFunction); function.setData(mScriptEngine->newQObject(this)); console.setProperty("printError", function); function = mScriptEngine->newFunction(clearConsoleFunction); function.setData(mScriptEngine->newQObject(this)); console.setProperty("clear", function); mExecuteOnlySelection = onlySelection; mCurrentActionIndex = 0; mActiveActionsCount = 0; mExecutionPaused = false; bool initSucceeded = true; int lastBeginProcedure = -1; mScript->clearProcedures(); mScript->clearCallStack(); const QHash<QString, ActionTools::Resource> &resources = mScript->resources(); for(const QString &key: resources.keys()) { const ActionTools::Resource &resource = resources.value(key); QScriptValue value; switch(resource.type()) { case ActionTools::Resource::BinaryType: case ActionTools::Resource::TypeCount: value = Code::RawData::constructor(resource.data(), mScriptEngine); break; case ActionTools::Resource::TextType: value = QString::fromUtf8(resource.data(), resource.data().size()); break; case ActionTools::Resource::ImageType: { QImage image; if(!image.loadFromData(resource.data())) { mConsoleWidget->addResourceLine(tr("Invalid image resource"), key, ActionTools::ConsoleWidget::Error); return false; } value = Code::Image::constructor(image, mScriptEngine); } break; } mScriptEngine->globalObject().setProperty(key, value, QScriptValue::ReadOnly | QScriptValue::Undeletable); } for(int actionIndex = 0; actionIndex < mScript->actionCount(); ++actionIndex) { ActionTools::ActionInstance *actionInstance = mScript->actionAt(actionIndex); actionInstance->reset(); actionInstance->clearRuntimeParameters(); actionInstance->setupExecution(mScriptEngine, mScript, actionIndex); mActionEnabled.append(true); qint64 currentActionRuntimeId = -1; if(actionInstance) currentActionRuntimeId = actionInstance->runtimeId(); if(canExecuteAction(actionIndex) == CanExecute) { ++mActiveActionsCount; if(actionInstance->definition()->id() == "ActionBeginProcedure") { if(lastBeginProcedure != -1) { mConsoleWidget->addActionLine(tr("Invalid Begin procedure action, you have to end the previous procedure before starting another one"), currentActionRuntimeId, QString(), QString(), -1, -1, ActionTools::ConsoleWidget::Error); return false; } lastBeginProcedure = actionIndex; const ActionTools::SubParameter &nameParameter = actionInstance->subParameter("name", "value"); const QString &procedureName = nameParameter.value().toString(); if(procedureName.isEmpty()) { mConsoleWidget->addActionLine(tr("A procedure name cannot be empty"), currentActionRuntimeId, QString(), QString(), -1, -1, ActionTools::ConsoleWidget::Error); return false; } if(mScript->findProcedure(procedureName) != -1) { mConsoleWidget->addActionLine(tr("A procedure with the name \"%1\" has already been declared").arg(procedureName), currentActionRuntimeId, QString(), QString(), -1, -1, ActionTools::ConsoleWidget::Error); return false; } mScript->addProcedure(procedureName, actionIndex); } else if(actionInstance->definition()->id() == "ActionEndProcedure") { if(lastBeginProcedure == -1) { mConsoleWidget->addActionLine(tr("Invalid End procedure"), currentActionRuntimeId, QString(), QString(), -1, -1, ActionTools::ConsoleWidget::Error); return false; } ActionTools::ActionInstance *beginProcedureActionInstance = mScript->actionAt(lastBeginProcedure); actionInstance->setRuntimeParameter("procedureBeginLine", lastBeginProcedure); beginProcedureActionInstance->setRuntimeParameter("procedureEndLine", actionIndex); lastBeginProcedure = -1; } } } if(lastBeginProcedure != -1) { ActionTools::ActionInstance *actionInstance = mScript->actionAt(lastBeginProcedure); qint64 actionRuntimeId = -1; if(actionInstance) actionRuntimeId = actionInstance->runtimeId(); mConsoleWidget->addActionLine(tr("Begin procedure action without end procedure"), actionRuntimeId, QString(), QString(), -1, -1, ActionTools::ConsoleWidget::Error); return false; } for(int parameterIndex = 0; parameterIndex < mScript->parameterCount(); ++parameterIndex) { mScriptAgent->setCurrentParameter(parameterIndex); const ActionTools::ScriptParameter &scriptParameter = mScript->parameter(parameterIndex); QRegExp nameRegExp("[a-z_][a-z0-9_]*", Qt::CaseInsensitive); if(!nameRegExp.exactMatch(scriptParameter.name())) { mConsoleWidget->addScriptParameterLine(tr("Incorrect parameter name: \"%1\"").arg(scriptParameter.name()), parameterIndex, -1, -1, ActionTools::ConsoleWidget::Error); initSucceeded = false; continue; } QString value; if(scriptParameter.isCode()) { QScriptValue result = mScriptEngine->evaluate(scriptParameter.value()); if(result.isError()) { mConsoleWidget->addScriptParameterLine(tr("Error while evaluating parameter \"%1\", error message: \"%2\"") .arg(scriptParameter.name()) .arg(result.toString()), parameterIndex, -1, -1, ActionTools::ConsoleWidget::Error); initSucceeded = false; continue; } else value = result.toString(); } else value = scriptParameter.value(); mScriptEngine->globalObject().setProperty(scriptParameter.name(), value, QScriptValue::ReadOnly | QScriptValue::Undeletable); } if(!initSucceeded || mScript->actionCount() == 0) return false; if(mShowExecutionWindow) { QRect screenRect = QApplication::desktop()->availableGeometry(mExecutionWindowScreen); QPoint position; if(mExecutionWindowPosition >= 0 && mExecutionWindowPosition <= 2)//Left position.setX(screenRect.left()); else if(mExecutionWindowPosition >= 3 && mExecutionWindowPosition <= 5)//HCenter position.setX(screenRect.left() + screenRect.width() / 2 - mExecutionWindow->width() / 2); else if(mExecutionWindowPosition >= 6 && mExecutionWindowPosition <= 8)//Right position.setX(screenRect.left() + screenRect.width() - mExecutionWindow->width()); if(mExecutionWindowPosition == 0 || mExecutionWindowPosition == 3 || mExecutionWindowPosition == 6)//Up position.setY(screenRect.top()); else if(mExecutionWindowPosition == 1 || mExecutionWindowPosition == 4 || mExecutionWindowPosition == 7)//VCenter position.setY(screenRect.top() + screenRect.height() / 2 - mExecutionWindow->height() / 2); else if(mExecutionWindowPosition == 2 || mExecutionWindowPosition == 5 || mExecutionWindowPosition == 8)//Down position.setY(screenRect.top() + screenRect.height() - mExecutionWindow->height()); mExecutionWindow->setPauseStatus(false); mExecutionWindow->move(position); mExecutionWindow->show(); } if(mShowConsoleWindow) { QRect screenRect = QApplication::desktop()->availableGeometry(mConsoleWindowScreen); QPoint position; if(mConsoleWindowPosition >= 0 && mConsoleWindowPosition <= 2)//Left position.setX(screenRect.left()); else if(mConsoleWindowPosition >= 3 && mConsoleWindowPosition <= 5)//HCenter position.setX(screenRect.left() + screenRect.width() / 2 - mConsoleWidget->width() / 2); else if(mConsoleWindowPosition >= 6 && mConsoleWindowPosition <= 8)//Right position.setX(screenRect.left() + screenRect.width() - mConsoleWidget->width()); if(mConsoleWindowPosition == 0 || mConsoleWindowPosition == 3 || mConsoleWindowPosition == 6)//Up position.setY(screenRect.top()); else if(mConsoleWindowPosition == 1 || mConsoleWindowPosition == 4 || mConsoleWindowPosition == 7)//VCenter position.setY(screenRect.top() + screenRect.height() / 2 - mConsoleWidget->height() / 2); else if(mConsoleWindowPosition == 2 || mConsoleWindowPosition == 5 || mConsoleWindowPosition == 8)//Down position.setY(screenRect.top() + screenRect.height() - mConsoleWidget->height()); mConsoleWidget->move(position); mConsoleWidget->show(); } mExecutionStarted = true; mScriptAgent->setContext(ScriptAgent::Actions); mHasExecuted = true; executeCurrentAction(); return true; }