void ExtModelReferenceCycles::determineCycles(const Model& m) { IdIter it; IdRange range; IdList variables; IdMap logged; std::string id; variables.clear(); /* create a list of variables that are cycles ie (x, x) */ for (it = mIdMap.begin(); it != mIdMap.end(); it++) { if ((*it).first == (*it).second) { id = (*it).first; if (!variables.contains(id)) { variables.append(id); } } } /* loop thru other dependencies for each; if the dependent is also * in the list then this is the cycle * keep a record of logged dependencies to avoid logging twice */ for (unsigned int n = 0; n < variables.size(); n++) { id = variables.at((int)n); range = mIdMap.equal_range(id); for (it = range.first; it != range.second; it++) { if (((*it).second == id) && !alreadyExistsInMap(logged, pair<const std::string, std::string>(id, (*it).second)) && !alreadyExistsInMap(logged, pair<const std::string, std::string>((*it).second, id))) { logCycle(m, id, (*it).second); logged.insert(pair<const std::string, std::string>(id, (*it).second)); } } } }
void QWizardContainer::insertWidget(int index, QWidget *widget) { enum { delta = 5 }; QWizardPage *newPage = qobject_cast<QWizardPage *>(widget); if (!newPage) { qWarning("%s", msgWrongType); return; } const IdList idList = m_wizard->pageIds(); const int pageCount = idList.size(); if (index >= pageCount) { addWidget(widget); return; } // Insert before, reshuffle ids if required const int idBefore = idList.at(index); const int newId = idBefore - 1; const bool needsShuffle = (index == 0 && newId < 0) // At start: QWizard refuses to insert id -1 || (index > 0 && idList.at(index - 1) == newId); // In-between if (needsShuffle) { // Create a gap by shuffling pages WizardPageList pageList; pageList.push_back(newPage); for (int i = index; i < pageCount; i++) { pageList.push_back(m_wizard->page(idList.at(i))); m_wizard->removePage(idList.at(i)); } int newId = idBefore + delta; const WizardPageList::const_iterator wcend = pageList.constEnd(); for (WizardPageList::const_iterator it = pageList.constBegin(); it != wcend; ++it) { m_wizard->setPage(newId, *it); newId += delta; } } else { // Gap found, just insert m_wizard->setPage(newId, newPage); } // Might be at -1 after adding the first page setCurrentIndex(index); }
DispatcherGenerator::CodeBranchGenerationResult DispatcherGenerator::generateReturnActionCode( qReal::Id const ¤tNode) const { QString const returnValue = mApi.name(currentNode).isEmpty() ? "" : (" " + mApi.name(currentNode)) ; QString returnWithValueTemplate = mTemplateUtils["@@Return@@"]; returnWithValueTemplate.replace("@@OptionalReturnValue@@", returnValue); IdList const links = mApi.outgoingLinks(currentNode); if (links.size() == 0) { return CodeBranchGenerationResult(returnWithValueTemplate, currentNode); } else { mErrorReporter.addError(QObject::tr("ReturnAction node shall have no outgoing links"), currentNode); return CodeBranchGenerationResult("", currentNode); } }
void MetaEditorSupportPlugin::generateEditorWithQrmc() { qrmc::MetaCompiler metaCompiler(*mLogicalRepoApi, "."); IdList const metamodels = mLogicalRepoApi->children(Id::rootId()); QProgressBar *progress = new QProgressBar(mMainWindowInterface->windowWidget()); progress->show(); int const progressBarWidth = 240; int const progressBarHeight = 20; QApplication::processEvents(); QRect const screenRect = qApp->desktop()->availableGeometry(); progress->move(screenRect.width() / 2 - progressBarWidth / 2, screenRect.height() / 2 - progressBarHeight / 2); progress->setFixedWidth(progressBarWidth); progress->setFixedHeight(progressBarHeight); progress->setRange(0, 100); int forEditor = 60 / metamodels.size(); foreach (Id const &key, metamodels) { QString const objectType = key.element(); if (objectType == "MetamodelDiagram" && mLogicalRepoApi->isLogicalElement(key)) { QString nameOfTheDirectory = mLogicalRepoApi->stringProperty(key, "name of the directory"); QString nameOfMetamodel = mLogicalRepoApi->stringProperty(key, "name"); QString nameOfPlugin = nameOfTheDirectory.split("/").last(); if (QMessageBox::question(mMainWindowInterface->windowWidget() , tr("loading..") , QString(tr("Do you want to compile and load editor %1?")).arg(nameOfPlugin) , QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) { continue; } progress->setValue(5); const QString normalizedName = nameOfMetamodel.at(0).toUpper() + nameOfMetamodel.mid(1); const bool stateOfLoad = mMainWindowInterface->pluginLoaded(normalizedName); if (!mMainWindowInterface->unloadPlugin(normalizedName)) { progress->close(); delete progress; return; } if (!metaCompiler.compile(nameOfMetamodel)) { // generating source code for all metamodels QMessageBox::warning(mMainWindowInterface->windowWidget() , tr("error") , tr("Cannot generate source code for editor ") + nameOfPlugin); continue; } progress->setValue(20); QStringList qmakeArgs; qmakeArgs.append("CONFIG+=" + mLogicalRepoApi->stringProperty(key, "buildConfiguration")); qmakeArgs.append(nameOfMetamodel + ".pro"); QProcess builder; builder.setWorkingDirectory(nameOfTheDirectory); const QStringList environment = QProcess::systemEnvironment(); builder.setEnvironment(environment); builder.start(SettingsManager::value("pathToQmake").toString(), qmakeArgs); qDebug() << "qmake"; if ((builder.waitForFinished()) && (builder.exitCode() == 0)) { progress->setValue(40); builder.start(SettingsManager::value("pathToMake").toString()); bool finished = builder.waitForFinished(100000); qDebug() << "make"; if (finished && (builder.exitCode() == 0)) { if (stateOfLoad) { QMessageBox::warning(mMainWindowInterface->windowWidget() , tr("Attention!"), tr("Please restart QReal.")); progress->close(); delete progress; return; } qDebug() << "make ok"; progress->setValue(progress->value() + forEditor / 2); if (!nameOfMetamodel.isEmpty()) { if (!mMainWindowInterface->unloadPlugin(normalizedName)) { QMessageBox::warning(mMainWindowInterface->windowWidget() , tr("error") , tr("cannot unload plugin ") + normalizedName); progress->close(); delete progress; continue; } } QString suffix = ""; if (mLogicalRepoApi->stringProperty(key, "buildConfiguration") == "debug") { suffix = "-d"; } QString const generatedPluginFileName = SettingsManager::value("prefix").toString() + nameOfMetamodel + suffix + "." + SettingsManager::value("pluginExtension").toString() ; if (mMainWindowInterface->loadPlugin(generatedPluginFileName, normalizedName)) { progress->setValue(progress->value() + forEditor / 2); } } progress->setValue(100); } } }
DispatcherGenerator::CodeBranchGenerationResult DispatcherGenerator::generateDecisionNodeCode( qReal::Id const ¤tNode) const { Id thenBranch; Id elseBranch; Id *currentBranch = nullptr; for (Id const &link : mApi.outgoingLinks(currentNode)) { if (!mApi.stringProperty(link, "guard").isEmpty()) { currentBranch = &thenBranch; } else { currentBranch = &elseBranch; } if (*currentBranch == Id()) { *currentBranch = link; } else { mErrorReporter.addError(QObject::tr("Decision node shall have exactly one outgoing link without guard") , currentNode); return CodeBranchGenerationResult("", currentNode); } } if (thenBranch == Id()) { mErrorReporter.addError(QObject::tr("Decision node shall have exactly one outgoing link with guard") , currentNode); return CodeBranchGenerationResult("", currentNode); } if (elseBranch == Id()) { mErrorReporter.addError(QObject::tr("Decision node shall have exactly one outgoing link without guard") , currentNode); return CodeBranchGenerationResult("", currentNode); } QString const guard = mApi.stringProperty(thenBranch, "guard"); QString ifTemplate = mTemplateUtils["@@If@@"]; CodeBranchGenerationResult thenBranchGenerationResult = generateOperatorCode(mApi.otherEntityFromLink(thenBranch , currentNode)); CodeBranchGenerationResult elseBranchGenerationResult = generateOperatorCode(mApi.otherEntityFromLink(elseBranch , currentNode)); if (thenBranchGenerationResult.text.endsWith('\n')) { thenBranchGenerationResult.text.chop(1); } if (elseBranchGenerationResult.text.endsWith('\n')) { elseBranchGenerationResult.text.chop(1); } Id nextNode; if (thenBranchGenerationResult.stopNode.element() == "MergeNode") { nextNode = thenBranchGenerationResult.stopNode; } if (elseBranchGenerationResult.stopNode.element() == "MergeNode") { if (elseBranchGenerationResult.stopNode != nextNode) { mErrorReporter.addError(QObject::tr("Decision branches shall end on the same merge node"), currentNode); return CodeBranchGenerationResult("", currentNode); } } if (elseBranchGenerationResult.text.trimmed().isEmpty()) { ifTemplate = mTemplateUtils["@@IfWithoutElse@@"]; } ifTemplate.replace("@@Condition@@", guard) .replace("@@Then@@", thenBranchGenerationResult.text) .replace("@@Else@@", elseBranchGenerationResult.text) ; if (nextNode == Id()) { return CodeBranchGenerationResult(ifTemplate, nextNode); } IdList const links = mApi.outgoingLinks(nextNode); if (links.size() == 0) { return CodeBranchGenerationResult(ifTemplate, nextNode); } else if (links.size() > 1) { mErrorReporter.addError(QObject::tr("Branches merge node should have no more than 1 outgoing link") , currentNode); return CodeBranchGenerationResult("", nextNode); } Id const nextNodeToGenerate = mApi.otherEntityFromLink(links.at(0), nextNode); CodeBranchGenerationResult result = generateOperatorCode(nextNodeToGenerate); result.text = ifTemplate + "\n" + result.text; return result; }
DispatcherGenerator::CodeBranchGenerationResult DispatcherGenerator::generateFunctionCallCode( qReal::Id const ¤tNode) const { QString operatorCode = mTemplateUtils["@@CaseCode@@"]; QString code = mApi.name(currentNode) + "("; for (Id const &argument : mApi.children(currentNode)) { if (!mApi.isLogicalElement(argument) || (argument.element() != "ActualParameter")) { continue; } code += (mApi.name(argument) + ", "); } code.chop(2); // terminating space and comma code += ")"; QString returnValue; for (Id const &argument : mApi.children(currentNode)) { if (!mApi.isLogicalElement(argument) || (argument.element() != "ReturnValue")) { continue; } if (!returnValue.isEmpty()) { mErrorReporter.addError(QObject::tr("FunctionCall shall have no more than one return value"), currentNode); return CodeBranchGenerationResult("", currentNode); } QString returnValueTemplate = mTemplateUtils["@@ReturnValue@@"]; QString const type = mApi.stringProperty(argument, "type").isEmpty() ? "" : mApi.stringProperty(argument, "type") + " "; returnValueTemplate.replace("@@OptionalType@@", type) .replace("@@Name@@", mApi.name(argument)) ; returnValue += returnValueTemplate; } if (returnValue.endsWith('\n')) { returnValue.chop(1); } code = returnValue + code; operatorCode.replace("@@Command@@", code); IdList const links = mApi.outgoingLinks(currentNode); if (links.size() == 0) { return CodeBranchGenerationResult(operatorCode, currentNode); } else if (links.size() > 1) { mErrorReporter.addError(QObject::tr("FunctionCall node should have exactly 1 outgoing link"), currentNode); return CodeBranchGenerationResult("", currentNode); } Id const nextNode = mApi.otherEntityFromLink(links.at(0), currentNode); CodeBranchGenerationResult result = generateOperatorCode(nextNode); result.text = operatorCode + result.text; return result; }
/* * Checks that the units of the result of the assignment rule * are consistent with variable being assigned * * @return @c true if units are consistent, false otherwise. */ void KineticLawUnitsCheck::check_ (const Model& m, const Model&) { unsigned int n, p; IdList matched; IdList unmatched; const UnitDefinition *ud1=NULL, *ud2=NULL; if (m.getLevel() < 3) return; if (m.getNumReactions() < 2) return; /* log first KL with units declared*/ for (n = 0; n < m.getNumReactions(); n++) { if (m.getReaction(n)->isSetKineticLaw()) { if (m.getReaction(n)->getKineticLaw()->isSetMath()) { if (!(m.getReaction(n)->getKineticLaw()->containsUndeclaredUnits())) { ud1 = m.getReaction(n)->getKineticLaw()->getDerivedUnitDefinition(); matched.append(m.getReaction(n)->getId()); break; } } } } /* loop thru remaining kl - if they are fully declared check that they match * and add to matched or unmatch as appropriate */ for (p = n+1; p < m.getNumReactions(); p++) { if (m.getReaction(p)->isSetKineticLaw()) { if (m.getReaction(p)->getKineticLaw()->isSetMath()) { if (!(m.getReaction(p)->getKineticLaw()->containsUndeclaredUnits())) { ud2 = m.getReaction(p)->getKineticLaw()->getDerivedUnitDefinition(); if (UnitDefinition::areEquivalent(ud1, ud2)) { matched.append(m.getReaction(p)->getId()); } else { unmatched.append(m.getReaction(p)->getId()); } } } } } /* see if we have any unmatched */ for (n = 0; n < unmatched.size(); n++) { logKLConflict(*(m.getReaction(unmatched.at((int)n))->getKineticLaw()->getMath()), *(static_cast<const SBase *>(m.getReaction(unmatched.at((int)n))))); } }