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;
}
Beispiel #4
0
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"));
}
Beispiel #5
0
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];
}
Beispiel #6
0
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);
}
Beispiel #8
0
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();
}
Beispiel #9
0
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;
}
Beispiel #10
0
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;
			}
		}
	}
Beispiel #11
0
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));
			}
		}
	}
}
Beispiel #12
0
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);
	}
}
Beispiel #14
0
int ModelsAssistApi::roleIndexByName(Id const &elem, QString const &roleName) const
{
	QStringList const properties = editorManagerInterface().propertyNames(elem.type());
	return properties.indexOf(roleName) + roles::customPropertiesBeginRole;
}
Beispiel #15
0
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();
}
Beispiel #18
0
void RobotsPlugin::activeTabChanged(Id const &rootElementId)
{
	bool const enabled = rootElementId.type() == robotDiagramType || rootElementId.type() == oldRobotDiagramType;
	changeActiveTab(mActionInfos, enabled);
	mInterpreter.onTabChanged(rootElementId, enabled);
}
Beispiel #19
0
IdList LogicalModelAssistApi::diagramsAbleToBeConnectedTo(Id const &element) const
{
	return diagramsFromList(editorManager().getConnectedTypes(element.type()));
}