void GraphicalModelView::rowsInserted(const QModelIndex &parent, int start, int end) { const QPersistentModelIndex parentIndex = parent.sibling(parent.row(), 0); Id parentLogicalId = parentIndex.data(roles::logicalIdRole).value<Id>(); for (int row = start; row <= end; ++row) { const QPersistentModelIndex current = model()->index(row, 0, parent); const Id logicalId = current.data(roles::logicalIdRole).value<Id>(); if (parentLogicalId.isNull() || parentLogicalId.editor() != "MetaEditor" || logicalId.editor() != "MetaEditor") { parentLogicalId = Id::rootId(); } const QString name = current.data(Qt::DisplayRole).toString(); if (logicalId.isNull()) { // No logical Id for this item, so logical model shouldn't care // about it. continue; } // Add this element to a root for now. To be able to do something // useful, we need to establish a correspondence between logical // and graphical model hierarchy. It is not always easy since // some elements have no correspondences in another model, and tree // structures may be very different by themselves. LogicalModel * const logicalModel = static_cast<LogicalModel *>(mModel); const bool isEdge = mModel->editorManagerInterface().isNodeOrEdge(logicalId.editor(), logicalId.element()); ElementInfo elementInfo(logicalId, logicalId, parentLogicalId, Id(), {{"name", name}}, {}, Id(), isEdge); logicalModel->addElementToModel(elementInfo); } }
QList<QPair<QString, QString>> PropertyEditorModel::enumValues(const QModelIndex &index) const { if (!index.isValid()) { return {}; } const AttributeClassEnum attrClass = mField->child(index.row())->attributeClass(); // metatype, ids and name are definitely not enums if (attrClass != logicalAttribute && attrClass != graphicalAttribute) { return {}; } const Id id = attrClass == logicalAttribute ? mTargetLogicalObject.data(roles::idRole).value<Id>() : mTargetGraphicalObject.data(roles::idRole).value<Id>(); QString propertyName = fullPropertyName(index); if (propertyName == "Error") { return {}; } /// @todo: null id must not be met here but for some reason sometimes it happens. /// This is pretty strange because mTargetLogicalObject without manual modification /// becomes invalid index. return id.isNull() ? QList<QPair<QString, QString>>() : mEditorManagerInterface.enumValues(id, propertyName); }
bool Block::initNextBlocks() { if (id().isNull() || id() == Id::rootId()) { error(tr("Control flow break detected, stopping")); return false; } const IdList links = mGraphicalModelApi->graphicalRepoApi().outgoingLinks(id()); if (links.count() > 1) { error(tr("Too many outgoing links")); return false; } if (links.count() == 0) { error(tr("No outgoing links, please connect this block to something or use Final Node to end program")); return false; } if (links.count() == 1) { const Id nextBlockId = mGraphicalModelApi->graphicalRepoApi().otherEntityFromLink(links[0], id()); if (nextBlockId.isNull() || nextBlockId == Id::rootId()) { error(tr("Outgoing link is not connected")); return false; } mNextBlockId = nextBlockId; } return true; }
void QrsMetamodelLoader::parseObjectsOnDiagram(const qrRepo::RepoApi &repo, Metamodel &metamodel, const Id &diagram) { if (diagram.isNull() || diagram == Id::rootId()) { return; } for (const Id &id : repo.children(diagram)) { if (!repo.isLogicalElement(id)) { continue; } const Id type = id.type(); if (type == metamodelEnumType) { parseEnum(repo, metamodel, id); } else if (type == metamodelPortType) { parsePort(repo, metamodel, id); } else if (type == metamodelGroupType) { parseGroup(repo, metamodel, diagram, id); } else if (type == metamodelImportType) { parseImport(repo, metamodel, id); } else if (type == metamodelNodeType) { parseNode(repo, metamodel, diagram, id); } else if (type == metamodelEdgeType) { parseEdge(repo, metamodel, diagram, id); } } }
void QrsMetamodelLoader::parseContainer(const qrRepo::RepoApi &repo, Metamodel &metamodel , const Id &id, const QString &diagram) { const Id from = repo.from(id); const Id to = repo.to(id); if (from.isNull() || to.isNull()) { qWarning() << "Containment link" << id << "is not connected!"; return; } const QString fromName = validateName(repo, from); const QString toName = validateName(repo, to); ElementType &fromElement = metamodel.elementType(diagram, fromName); ElementType &toElement = metamodel.elementType(diagram, toName); metamodel.produceEdge(fromElement, toElement, ElementType::containmentLinkType); }
void QrsMetamodelLoader::parseExplosion(const qrRepo::RepoApi &repo, Metamodel &metamodel , const Id &id, const QString &diagram) { const Id from = repo.from(id); const Id to = repo.to(id); if (from.isNull() || to.isNull()) { qWarning() << "Explosion" << id << "is not connected!"; return; } const QString fromName = validateName(repo, from); const QString toName = validateName(repo, to); ElementType &fromElement = metamodel.elementType(diagram, fromName); ElementType &toElement = metamodel.elementType(diagram, toName); metamodel.addExplosion(fromElement, toElement, boolProperty(repo, id, "makeReusable") , boolProperty(repo, id, "requireImmediateLinkage")); }
bool PropertyEditorModel::isReference(const QModelIndex &index, const QString &propertyName) { Id id = idByIndex(index); if (id.isNull()) { return false; } return mEditorManagerInterface.referenceProperties(id.type()).contains(propertyName); }
void QrsMetamodelLoader::parseGeneralization(const qrRepo::RepoApi &repo, Metamodel &metamodel, const Id &id , const QString &diagram, ElementType *&fromElement, ElementType *&toElement, QString &overridingProperties) { const Id from = repo.from(id); const Id to = repo.to(id); if (from.isNull() || to.isNull()) { qWarning() << "Generalization" << id << "is not connected!"; return; } const QString fromName = validateName(repo, from); const QString toName = validateName(repo, to); fromElement = &metamodel.elementType(diagram, fromName); toElement = &metamodel.elementType(diagram, toName); metamodel.produceEdge(*toElement, *fromElement, ElementType::generalizationLinkType); overridingProperties = stringProperty(repo, id, "overrides"); }
void Controller::diagramOpened(const Id &diagramId) { if (diagramId.isNull()) { return; } UndoStack *stack = new UndoStack; connectStack(stack); mDiagramStacks.insert(diagramId.toString(), stack); resetAll(); }
QString PropertyEditorModel::typeName(const QModelIndex &index) const { Id id = idByIndex(index); if (id.isNull()) { return ""; } const QString propertyName = fullPropertyName(index); return mEditorManagerInterface.typeName(id, propertyName); }
void ExploserView::createRemoveExplosionMenu(const Element * const element, QMenu &contextMenu , const Id &outgoingConnection) const { if (outgoingConnection.isNull()) { return; } QAction * const action = contextMenu.addAction(mCustomizer.deleteExplosionMenuName()); connect(action, SIGNAL(triggered()), SLOT(removeExplosionActionTriggered())); action->setData(QVariantList() << element->logicalId().toVariant() << outgoingConnection.toVariant()); }
QVariant Block::property(const Id &id, const QString &propertyName) { const Id logicalId = mGraphicalModelApi->logicalId(id); if (logicalId.isNull()) { // If we get here we definitely have such situation: // graphical id existed when this Block instance was constructed (or we just will not get here), // but now the logical instance has suddenly disppeared. error(tr("Block has disappeared!")); return QVariant(); } return mLogicalModelApi->propertyByRoleName(logicalId, propertyName); }
void Controller::diagramClosed(const Id &diagramId) { if (diagramId.isNull() || !mDiagramStacks.keys().contains(diagramId.toString())) { return; } if (mActiveStack == mDiagramStacks[diagramId.toString()]) { mActiveStack = nullptr; } delete mDiagramStacks[diagramId.toString()]; mDiagramStacks.remove(diagramId.toString()); resetAll(); }
SaveConvertionManager::GraphicalFilter SaveConvertionManager::graphicalRecreate( const SaveConvertionManager::GraphicalReplacer &replacer , const SaveConvertionManager::GraphicalConstructor &constructor) { return [replacer, constructor](const Id &block, GraphicalModelAssistInterface &graphicalApi) { // Just iterating throught the elements on some diagram, ignoring the diagram itself. if (isDiagramType(block)) { return false; } // For each element trying to find out what to replace it with. const Id newType = replacer(block, graphicalApi); if (newType.isNull()) { // Not every element be replaced, concrete implementation must decide it. return false; } // Then creating new element of some type... const Id newBlock = Id::createElementId(newType.editor(), newType.diagram(), newType.element()); graphicalApi.createElement(graphicalApi.parent(block) , newBlock , false , graphicalApi.name(block) , graphicalApi.position(block) , graphicalApi.logicalId(block)); // And initializing it... constructor(newBlock, block, graphicalApi); const bool isEdge = isEdgeType(block); if (isEdge) { // If out element is edge then connecting it to same elements as the old one was connected graphicalApi.setFrom(newBlock, graphicalApi.from(block)); graphicalApi.setTo(newBlock, graphicalApi.to(block)); } else { // Replacing old node in all incomming and outgoing edges of the old node with the new one. for (const Id &edge : graphicalApi.graphicalRepoApi().outgoingLinks(block)) { graphicalApi.mutableGraphicalRepoApi().setProperty(edge, "from", newBlock.toVariant()); } for (const Id &edge : graphicalApi.graphicalRepoApi().incomingLinks(block)) { graphicalApi.mutableGraphicalRepoApi().setProperty(edge, "to", newBlock.toVariant()); } } // And finally disposing of outdated entity. graphicalApi.removeElement(block); return true; }; }
QWidget *StartWidget::createProjectsManagementWidget() { mProjectsManagementLayout = new QBoxLayout(QBoxLayout::TopToBottom); mProjectsManagementLayout->addStretch(); mOpenProjectButton = new StyledButton(tr("Open existing project") , ":icons/startTab/open.svg"); connect(mOpenProjectButton, &QPushButton::clicked, this, &StartWidget::openExistingProject); mProjectsManagementLayout->addWidget(mOpenProjectButton); Id const theOnlyDiagram = mMainWindow->editorManager().theOnlyDiagram(); if (!theOnlyDiagram.isNull()) { Id const editor = mMainWindow->editorManager().editors()[0]; QString const diagramIdString = mMainWindow->editorManager().diagramNodeNameString(editor, theOnlyDiagram); mNewProjectButton = new StyledButton(tr("New project"), ":icons/startTab/open.svg"); mProjectsManagementLayout->addWidget(mNewProjectButton); QSignalMapper *newProjectMapper = new QSignalMapper(this); newProjectMapper->setMapping(mNewProjectButton, diagramIdString); connect(mNewProjectButton, SIGNAL(clicked()), newProjectMapper, SLOT(map())); connect(newProjectMapper, SIGNAL(mapped(QString)), this, SLOT(createProjectWithDiagram(QString))); } else { if (!mMainWindow->editorManager().editors().isEmpty()) { QWidget * const pluginsWidget = createPluginsList(); mProjectsManagementLayout->addWidget(pluginsWidget, 1); } else { mOpenProjectButton->hide(); } } mOpenInterpreterButton = new StyledButton(tr("Open interpreted diagram") , ":icons/startTab/openInterpreted.svg"); mCreateInterpreterButton = new StyledButton(tr("Create interpreted diagram") , ":icons/startTab/createInterpreted.svg"); connect(mOpenInterpreterButton, SIGNAL(clicked()), this, SLOT(openInterpretedDiagram())); connect(mCreateInterpreterButton, SIGNAL(clicked()), this, SLOT(createInterpretedDiagram())); mProjectsManagementLayout->addWidget(mCreateInterpreterButton); mProjectsManagementLayout->addWidget(mOpenInterpreterButton); mProjectsManagementLayout->addStretch(); QWidget * const result = new QWidget; result->setLayout(mProjectsManagementLayout); result->setStyleSheet(BrandManager::styles()->startTabProjectsManagementBackgroundStyle()); return result; }
void ExploserView::handleDoubleClick(const Id &id) { Id outgoingLink = mLogicalApi.logicalRepoApi().outgoingExplosion(id); if (outgoingLink.isNull()) { QList<Explosion> const explosions = mLogicalApi.editorManagerInterface().explosions(id); if (!explosions.isEmpty()) { const Id diagramType = mLogicalApi.editorManagerInterface() .findElementByType(explosions[0].target().element()); AbstractCommand *createCommand = mExploser.createElementWithIncomingExplosionCommand( id, diagramType, mModels); mController.executeGlobal(createCommand); outgoingLink = static_cast<CreateElementsCommand *>(createCommand)->results().first().id(); } } goTo(outgoingLink); }
void Thread::stepInto(const Id &diagram) { const Id initialNode = findStartingElement(diagram); BlockInterface * const block = mBlocksTable.block(initialNode); if (initialNode.isNull() || !block) { error(tr("No entry point found, please add Initial Node to a diagram"), diagram); return; } if (mStack.count() >= SettingsManager::value("interpreterStackSize").toInt()) { error(tr("Stack overflow")); return; } turnOn(block); }
void ExploserView::createAddExplosionMenu(const Element * const element , QMenu &contextMenu, QList<Explosion> const &explosions , const Id &alreadyConnectedElement) const { bool hasAnyActions = false; const QString menuName = alreadyConnectedElement.isNull() ? mCustomizer.addExplosionMenuName() : mCustomizer.changeExplosionMenuName(); QMenu *addExplosionMenu = new QMenu(menuName); for (const Explosion &explosion : explosions) { for (const Id &elementId : mLogicalApi.logicalRepoApi().logicalElements(explosion.target())) { if (alreadyConnectedElement == elementId) { continue; } QAction *action = addExplosionMenu->addAction(mLogicalApi.logicalRepoApi().name(elementId)); hasAnyActions = true; connect(action, SIGNAL(triggered()), SLOT(addExplosionActionTriggered())); QList<QVariant> tag; tag << element->logicalId().toVariant() << elementId.toVariant(); action->setData(tag); } } if (hasAnyActions) { addExplosionMenu->addSeparator(); } for (const Explosion &explosion : explosions) { const Id diagramType = mLogicalApi.editorManagerInterface().findElementByType(explosion.target().element()); const QString name = mLogicalApi.editorManagerInterface().friendlyName(diagramType); const QString editorName = mLogicalApi.editorManagerInterface().friendlyName(Id(diagramType.editor())); QAction *action = addExplosionMenu->addAction(tr("New ") + editorName + "/" + name); hasAnyActions = true; connect(action, SIGNAL(triggered()), SLOT(addExplosionActionTriggered())); action->setData(QVariantList() << element->logicalId().toVariant() << diagramType.toVariant()); } contextMenu.addMenu(addExplosionMenu); if (alreadyConnectedElement != Id()) { QAction * const gotoAction = contextMenu.addAction(mCustomizer.goToConnectedMenuName() , this, SLOT(goToActionTriggered())); gotoAction->setData(alreadyConnectedElement.toVariant()); } }
void ExploserView::createExpandAction(const Element * const element, QMenu &contextMenu , const Id &alreadyConnectedElement) const { if (alreadyConnectedElement.isNull()) { return; } const NodeElement * const node = dynamic_cast<const NodeElement * const>(element); if (!node) { return; } QAction *expandAction = contextMenu.addAction(node->isExpanded() ? mCustomizer.collapseExplosionActionText() : mCustomizer.expandExplosionActionText()); connect(expandAction, SIGNAL(triggered()), SLOT(expandExplosionActionTriggered())); expandAction->setData(element->id().toVariant()); }
Subprograms::GenerationResult Subprograms::generate(ControlFlowGeneratorBase *mainGenerator , const QString &indentString) { QMap<Id, QString> declarations; QMap<Id, QString> implementations; Id toGen = firstToGenerate(); while (toGen != Id()) { mDiscoveredSubprograms[toGen] = true; const Id graphicalDiagramId = graphicalId(toGen); if (graphicalDiagramId.isNull()) { mErrorReporter.addError(QObject::tr("Graphical diagram instance not found")); return GenerationResult::fatalError; } const QString rawIdentifier = mRepo.name(toGen); const QString identifier = mNameNormalizer->convert(rawIdentifier); if (!checkIdentifier(identifier, rawIdentifier)) { return GenerationResult::fatalError; } ControlFlowGeneratorBase *generator = mainGenerator->cloneFor(graphicalDiagramId, true); auto readableGenerator = dynamic_cast<ReadableControlFlowGenerator *>(generator); semantics::SemanticTree *controlFlow = generator->generate(Id(), "@@unknown@@"); if (!controlFlow || (readableGenerator && readableGenerator->cantBeGeneratedIntoStructuredCode())) { return GenerationResult::error; } implementations[toGen] = controlFlow->toString(1, indentString); const QString forwardDeclaration = readSubprogramTemplate(toGen, "subprograms/forwardDeclaration.t"); declarations[toGen] = forwardDeclaration; toGen = firstToGenerate(); } obtainCode(declarations, implementations); return GenerationResult::success; }
void QrsMetamodelSaver::saveMetamodel(qrRepo::RepoApi &repo, const Metamodel &metamodel) { const Id metamodelId = metamodelRootDiagramType.sameTypeId(); repo.addChild(Id::rootId(), metamodelId); repo.setName(metamodelId, metamodel.id()); repo.setProperty(metamodelId, "displayedName", metamodel.friendlyName()); repo.setProperty(metamodelId, "version", metamodel.version()); Id lastDiagramId; for (const QString &diagram : metamodel.diagrams()) { saveDiagram(repo, metamodel, diagram, metamodelId, lastDiagramId); } if (lastDiagramId.isNull()) { // Metamodel contained no diagrams, nowhere to save enums and ports, giving up. return; } for (const QString &enumName : metamodel.enumNames()) { saveEnum(repo, metamodel, enumName, lastDiagramId); } }
bool Subprograms::generate(ControlFlowGeneratorBase *mainGenerator) { QMap<Id, QString> declarations; QMap<Id, QString> implementations; Id toGen = firstToGenerate(); while (toGen != Id()) { mDiscoveredSubprograms[toGen] = true; Id const graphicalDiagramId = graphicalId(toGen); if (graphicalDiagramId.isNull()) { mErrorReporter.addError(QObject::tr("Graphical diagram instance not found")); return false; } QString const rawIdentifier = mRepo.name(toGen); QString const identifier = mNameNormalizer->convert(rawIdentifier); if (!checkIdentifier(identifier, rawIdentifier)) { return false; } ControlFlowGeneratorBase *generator = mainGenerator->cloneFor(graphicalDiagramId); semantics::SemanticTree *controlFlow = generator->generate(); if (!controlFlow) { return false; } implementations[toGen] = controlFlow->toString(1); QString const forwardDeclaration = readSubprogramTemplate(toGen, "subprograms/forwardDeclaration.t"); declarations[toGen] = forwardDeclaration; toGen = firstToGenerate(); } mergeCode(declarations, implementations); return true; }
void Repository::addChild(const Id &id, const Id &child, const Id &logicalId) { if (mObjects.contains(id)) { if (!mObjects[id]->children().contains(child)) mObjects[id]->addChild(child); if (mObjects.contains(child)) { // should we move element? mObjects[child]->setParent(id); } else { Object * const object = logicalId.isNull() ? static_cast<Object *>(new LogicalObject(child)) : static_cast<Object *>(new GraphicalObject(child, id, logicalId)) ; object->setParent(id); mObjects.insert(child, object); } } else { throw Exception("Repository: Adding child " + child.toString() + " to nonexistent object " + id.toString()); } }
void ExploserView::createAddExplosionMenu(Element const * const element , QMenu &contextMenu, QList<Explosion> const &explosions , Id const &alreadyConnectedElement) const { bool hasAnyActions = false; QString const menuName = alreadyConnectedElement.isNull() ? mMainWindow->toolManager().customizer()->addExplosionMenuName() : mMainWindow->toolManager().customizer()->changeExplosionMenuName(); QMenu *addExplosionMenu = new QMenu(menuName); foreach (Explosion const &explosion, explosions) { foreach (Id const &elementId, mLogicalApi->logicalRepoApi().logicalElements(explosion.target())) { if (alreadyConnectedElement == elementId) { continue; } QAction *action = addExplosionMenu->addAction(mLogicalApi->logicalRepoApi().name(elementId)); hasAnyActions = true; connect(action, SIGNAL(triggered()), SLOT(addExplosionActionTriggered())); QList<QVariant> tag; tag << element->logicalId().toVariant() << elementId.toVariant(); action->setData(tag); } }
StartDialog::StartDialog(MainWindow &mainWindow, ProjectManager &projectManager) : QDialog(&mainWindow, false) , mMainWindow(mainWindow) , mProjectManager(projectManager) { setMinimumSize(mMinimumSize); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); QTabWidget *tabWidget = new QTabWidget; RecentProjectsListWidget *recentProjects = new RecentProjectsListWidget(this); tabWidget->addTab(recentProjects, tr("&Recent projects")); Id const theOnlyDiagram = mMainWindow.editorManager().theOnlyDiagram(); if (theOnlyDiagram.isNull()) { SuggestToCreateDiagramWidget *diagrams = new SuggestToCreateDiagramWidget(&mMainWindow, this); tabWidget->addTab(diagrams, tr("&New project with diagram")); connect(diagrams, SIGNAL(userDataSelected(QString)), this, SLOT(createProjectWithDiagram(QString))); if (recentProjects->count() == 0) { tabWidget->setCurrentWidget(diagrams); } } QCommandLinkButton *openIDLink = new QCommandLinkButton(tr("&Open interpreted diagram")); QCommandLinkButton *createIDLink = new QCommandLinkButton(tr("&Create interpreted diagram")); QHBoxLayout *openIDLinkLayout = new QHBoxLayout; openIDLinkLayout->addWidget(openIDLink); mInterpreterButton = openIDLink; QHBoxLayout *createIDLinkLayout = new QHBoxLayout; createIDLinkLayout->addWidget(createIDLink); mCreateInterpreterButton = createIDLink; QHBoxLayout *commandLinksLayout = new QHBoxLayout; if (theOnlyDiagram != Id()) { Id const editor = mMainWindow.editorManager().editors()[0]; QString const diagramIdString = mMainWindow.editorManager().diagramNodeNameString(editor, theOnlyDiagram); QSignalMapper *newProjectMapper = new QSignalMapper(this); QCommandLinkButton *newLink = createCommandButton(tr("New project") , newProjectMapper, SLOT(map()), QKeySequence::New); newProjectMapper->setMapping(newLink, diagramIdString); connect(newProjectMapper, SIGNAL(mapped(QString)), this, SLOT(createProjectWithDiagram(QString))); commandLinksLayout->addWidget(newLink); } commandLinksLayout->addWidget(createCommandButton(tr("Open existing project") , this, SLOT(openExistingProject()), QKeySequence::Open)); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(tabWidget); mainLayout->addLayout(openIDLinkLayout); mainLayout->addLayout(createIDLinkLayout); mainLayout->addLayout(commandLinksLayout); setLayout(mainLayout); setWindowTitle(tr("Start page")); connect(openIDLink, SIGNAL(clicked()), this, SLOT(openInterpretedDiagram())); connect(createIDLink, SIGNAL(clicked()), this, SLOT(createInterpretedDiagram())); connect(recentProjects, SIGNAL(userDataSelected(QString)), this, SLOT(openRecentProject(QString))); connect(this, SIGNAL(rejected()), this, SLOT(exitApp())); }