QList<qReal::ElementInfo> CreatePatternCommand::parse(models::LogicalModelAssistApi &logicalApi , qReal::models::GraphicalModelAssistApi &graphicalApi, const qReal::ElementInfo &info) { mPattern = graphicalApi.editorManagerInterface().getPatternByName(info.id().element()); QList<qReal::ElementInfo> result; const QPointF size = mPattern.size(); // Pattern nodes create may have hierarchic structure. So we must create them in correct order // (parent first, child after). Cycles in hierarchy and nodes with incorrect parent id are fully ignored QList<GroupNode> toCreate = mPattern.nodes(); QSet<QString> consideredNodes; // If group node has no parent then it has 'global' one mCreatedNodes[QString()] = info.graphicalParent(); bool somethingChangedThisIteration = true; while (!toCreate.isEmpty() && somethingChangedThisIteration) { somethingChangedThisIteration = false; for (const GroupNode &node : toCreate) { if (!node.parent.isEmpty() && !consideredNodes.contains(node.parent)) { continue; } const Id element(info.id().editor(), info.id().diagram(), node.type, QUuid::createUuid().toString()); mCreatedNodes[node.id] = element; if (node.id == mPattern.rootNode()) { mRootId = element; } const QPointF globalPosition = info.position(); const QPointF nodePos(globalPosition.x() - size.x() / 2 + node.position.x() , globalPosition.y() + node.position.y()); const ElementInfo nodeInfo(element, Id(), info.logicalParent(), mCreatedNodes[node.parent] , {{"name", logicalApi.editorManagerInterface().friendlyName(element.type())}} , {{"position", nodePos}}, Id(), false); result << nodeInfo; consideredNodes << node.id; toCreate.removeAll(node); somethingChangedThisIteration = true; } } if (!toCreate.isEmpty()) { qWarning() << "Warning: inconsistent pattern" << info.id().type(); } for (const GroupEdge &edge : mPattern.edges()) { const Id element(info.id().editor(), info.id().diagram(), edge.type, QUuid::createUuid().toString()); const ElementInfo edgeInfo(element, Id(), info.logicalParent(), info.graphicalParent() , {{"name", logicalApi.editorManagerInterface().friendlyName(element.type())}}, {}, Id(), true); result << edgeInfo; mCreatedEdges << element; } return result; }
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.type()); ElementInfo elementInfo(logicalId, logicalId, parentLogicalId, Id(), {{"name", name}}, {}, Id(), isEdge); logicalModel->addElementToModel(elementInfo); } }
QString PropertyEditorModel::propertyName(const QModelIndex &index) const { QString fieldName = mField->child(index.row())->fieldName(); const Id logicalId = mTargetLogicalObject.data(roles::idRole).value<Id>(); const QString dynamicProperties = dynamic_cast<models::details::LogicalModel *>(mTargetLogicalModel)-> logicalModelAssistApi().logicalRepoApi().stringProperty(logicalId, "dynamicProperties"); if (!dynamicProperties.isEmpty()) { int propertiesCount = mEditorManagerInterface.propertyNames(logicalId.type()).count(); QDomDocument dynamProperties; dynamProperties.setContent(dynamicProperties); int i = 0; for (QDomElement element = dynamProperties.firstChildElement("properties").firstChildElement("property"); !element.isNull(); element = element.nextSiblingElement("property")) { if (i == index.row() - propertiesCount) { fieldName = element.attribute("name"); break; } } } return fieldName; }
TEST(IdsTest, gettersTest) { Id id = Id::loadFromString("qrm:/editor/diagram/element/id"); EXPECT_EQ(id.editor(), "editor"); EXPECT_EQ(id.diagram(), "diagram"); EXPECT_EQ(id.element(), "element"); EXPECT_EQ(id.id(), "id"); EXPECT_EQ(id.type() ,Id("editor", "diagram", "element")); }
QString AbstractModel::findPropertyName(Id const &id, int const role) const { //In case of a property described in element itself (in metamodel), // role is simply an index of a property in a list of propertires. // This convention must be obeyed everywhere, otherwise roles will shift. QStringList properties = mEditorManager.getPropertyNames(id.type()); Q_ASSERT(role - roles::customPropertiesBeginRole < properties.count()); return properties[role - roles::customPropertiesBeginRole]; }
QString Model::findPropertyName(Id const &id, int const role) const { // В случае свойства, описанного в самом элементе, роль - просто // порядковый номер свойства в списке свойств. Этого соглашения // надо всюду придерживаться, а то роли "поедут". QStringList properties = mEditorManager.getPropertyNames(id.type()); Q_ASSERT(role - roles::customPropertiesBeginRole < properties.count()); return properties[role - roles::customPropertiesBeginRole]; }
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); }
Id Subprograms::graphicalId(Id const &logicalId) const { IdList const graphicalIds = mRepo.graphicalElements(logicalId.type()); foreach (Id const &id, graphicalIds) { if (mRepo.logicalId(id) == logicalId) { return id; } } return Id(); }
Id LogicalModelAssistApi::createElement(const Id &parent, const Id &type) { Q_ASSERT(type.idSize() == 3); Q_ASSERT(parent.idSize() == 4); const Id newElementId = type.sameTypeId(); const QString elementFriendlyName = mModelsAssistApi.editorManagerInterface().friendlyName(type); const bool isEdge = mModelsAssistApi.editorManagerInterface().isNodeOrEdge(newElementId.type()) == -1; ElementInfo newElement(newElementId, Id(), parent, Id(), {{"name", elementFriendlyName}}, {}, Id(), isEdge); mLogicalModel.addElementToModel(newElement); return newElementId; }
IdList Exploser::elementsWithHardDependencyFrom(Id const &id) const { IdList result; Id const targetType = id.type(); IdList const incomingExplosions = mApi.logicalRepoApi().incomingExplosions(id); foreach (Id const &incoming, incomingExplosions) { QList<Explosion> const explosions = mApi.editorManagerInterface().explosions(incoming.type()); foreach (Explosion const &explosion, explosions) { if (explosion.target() == targetType && explosion.requiresImmediateLinkage()) { result << incoming; } } }
void ExploserView::handleCreationWithExplosion(commands::AbstractCommand *createCommand , const Id &source, const Id &target) { if (target != Id()) { createCommand->addPostAction(mExploser.addExplosionCommand(source, target, &mGraphicalApi)); } else { QList<Explosion> const explosions = mLogicalApi.editorManagerInterface().explosions(source); for (const Explosion &explosion : explosions) { if (explosion.source().type() == source.type() && explosion.requiresImmediateLinkage()) { createCommand->addPostAction(mExploser.createElementWithIncomingExplosionCommand( source, explosion.target(), mGraphicalApi)); } } } }
bool BlocksFactory::elementMetatypeIs(Id const &element, QString const &metatype) { return element.type() == Id("RobotsMetamodel", "RobotsDiagram", metatype); }
CreateGroupCommand::CreateGroupCommand(models::LogicalModelAssistApi &logicalApi , models::GraphicalModelAssistApi &graphicalApi , models::Exploser &exploser , const Id &logicalParent , const Id &graphicalParent , const Id &id , bool isFromLogicalModel , const QPointF &position) : mLogicalApi(logicalApi) , mGraphicalApi(graphicalApi) , mExploser(exploser) , mLogicalParent(logicalParent) , mGraphicalParent(graphicalParent) , mId(id) , mIsFromLogicalModel(isFromLogicalModel) , mPosition(position) , mPattern(graphicalApi.editorManagerInterface().getPatternByName(id.element())) { const QPointF size = mPattern.size(); // Pattern nodes create may have hierarchic structure. So we must create them in correct order // (parent first, child after). Cycles in hierarchy and nodes with incorrect parent id are fully ignored QList<GroupNode> toCreate = mPattern.nodes(); QSet<QString> consideredNodes; QMap<QString, Id> createdNodesIds; // If group node has no parent then it has 'global' one createdNodesIds[QString()] = graphicalParent; bool somethingChangedThisIteration = true; while (!toCreate.isEmpty() && somethingChangedThisIteration) { somethingChangedThisIteration = false; for (const GroupNode &node : toCreate) { if (!node.parent.isEmpty() && !consideredNodes.contains(node.parent)) { continue; } const Id element(id.editor(), id.diagram(), node.type, QUuid::createUuid().toString()); createdNodesIds[node.id] = element; if (node.id == mPattern.rootNode()) { mRootId = element; } const QPointF nodePos(position.x() - size.x() / 2 + node.position.x() , position.y() + node.position.y()); CreateElementCommand *createNodeCommand = new CreateElementCommand( logicalApi, graphicalApi, exploser, logicalParent , createdNodesIds[node.parent], element, isFromLogicalModel , mLogicalApi.editorManagerInterface().friendlyName(element.type()), nodePos); mNodeCommands[node.id] = createNodeCommand; addPreAction(createNodeCommand); consideredNodes << node.id; toCreate.removeAll(node); somethingChangedThisIteration = true; } } // TODO: display here error if toCreate still non-empty for (const GroupEdge &edge : mPattern.edges()) { const Id element(id.editor(), id.diagram(), edge.type, QUuid::createUuid().toString()); CreateElementCommand *createEdgeCommand = new CreateElementCommand( logicalApi, graphicalApi, exploser, logicalParent, graphicalParent, element, isFromLogicalModel , mLogicalApi.editorManagerInterface().friendlyName(element.type()), QPointF()); mEdgeCommands.append(createEdgeCommand); addPreAction(createEdgeCommand); } }
int ModelsAssistApi::roleIndexByName(Id const &elem, QString const &roleName) const { QStringList const properties = editorManagerInterface().propertyNames(elem.type()); return properties.indexOf(roleName) + roles::customPropertiesBeginRole; }
TEST(IdsTest, sameTypeIdTest) { Id const id = Id::loadFromString("qrm:/editor/diagram/element/id"); EXPECT_EQ(id.sameTypeId().type(), id.type()); }
void NxtKitInterpreterPlugin::onActiveTabChanged(Id const &rootElementId) { bool enabled = rootElementId.type() == robotDiagramType || rootElementId.type() == subprogramDiagramType; enabled &= mCurrentlySelectedModelName == mTwoDRobotModel.name(); mTwoDModel->showTwoDModelWidgetActionInfo().action()->setVisible(enabled); }
void PropertyEditorModel::setModelIndexes(const QModelIndex &logicalModelIndex , const QModelIndex &graphicalModelIndex) { beginResetModel(); mField.reset(new Field()); endResetModel(); mTargetLogicalObject = logicalModelIndex; mTargetGraphicalObject = graphicalModelIndex; if (!isValid()) { return; } const Id logicalId = mTargetLogicalObject.data(roles::idRole).value<Id>(); const QString dynamicProperties = dynamic_cast<models::details::LogicalModel *>(mTargetLogicalModel)-> logicalModelAssistApi().logicalRepoApi().stringProperty(logicalId, "dynamicProperties"); if (logicalModelIndex != QModelIndex()) { const QStringList logicalProperties = mEditorManagerInterface.propertyNames(logicalId.type()); int role = roles::customPropertiesBeginRole; QStringList cloneWithRoles; QStringList cloneWithPure; for (const QString &prop : logicalProperties) { if (prop.contains("!")) { cloneWithRoles.append(prop); } else { cloneWithPure.append(prop); } } int i = 0; role = roles::customPropertiesBeginRole; while (cloneWithRoles.size() > 0) { const QString roleName = cloneWithRoles.takeAt(0); const int first = roleName.indexOf("!"); const QString beginPartName = roleName.mid(0, first); mField->appendChild(new Field(beginPartName)); auto parent = mField->child(i); QString endPartName = roleName.mid(first + 1); mField->appendChild( new Field( endPartName , logicalAttribute , role , parent , mTargetLogicalObject , mTargetGraphicalObject) ); ++i; ++role; int j = 0; while (j < cloneWithRoles.size()) { if (cloneWithRoles.at(j).mid(0, first) == beginPartName) { QString roleName = cloneWithRoles.takeAt(j); roleName = roleName.mid(first + 1); mField->appendChild( new Field( roleName , logicalAttribute , role , parent , mTargetLogicalObject , mTargetGraphicalObject) ); ++i; ++role; j = 0; } else { ++j; } } ++i; } while (cloneWithPure.size() > 0) { QString roleName = cloneWithPure.takeAt(0); mField->appendChild( new Field( roleName , logicalAttribute , role , nullptr , mTargetLogicalObject , mTargetGraphicalObject) ); ++i; ++role; } if (!dynamicProperties.isEmpty()) { QDomDocument dynamProperties; dynamProperties.setContent(dynamicProperties); for (QDomElement element = dynamProperties.firstChildElement("properties").firstChildElement("property") ; !element.isNull() ; element = element.nextSiblingElement("property")) { mField->appendChild( new Field( element.attribute("displayedName") , logicalAttribute , role , nullptr , mTargetLogicalObject , mTargetGraphicalObject)); ++role; } } /* * Uncomment to display block Ids in a property editor * mField->appendChild( new Field( "logicalId" , logicalAttribute , roles::idRole , nullptr , mTargetLogicalObject , mTargetGraphicalObject ) ); mField->appendChild( new Field( "graphicalId" , graphicalAttribute , roles::idRole , nullptr , mTargetLogicalObject , mTargetGraphicalObject ) ); /**/ } beginResetModel(); endResetModel(); }
void RobotsPlugin::activeTabChanged(Id const &rootElementId) { bool const enabled = rootElementId.type() == robotDiagramType || rootElementId.type() == oldRobotDiagramType; changeActiveTab(mActionInfos, enabled); mInterpreter.onTabChanged(rootElementId, enabled); }
IdList LogicalModelAssistApi::diagramsAbleToBeConnectedTo(Id const &element) const { return diagramsFromList(editorManager().getConnectedTypes(element.type())); }