|
@@ -60,8 +60,7 @@ WHERE {
|
|
?as_element a ?another_more_concrete_type
|
|
?as_element a ?another_more_concrete_type
|
|
FILTER(?another_more_concrete_type != ?as_type)
|
|
FILTER(?another_more_concrete_type != ?as_type)
|
|
}
|
|
}
|
|
-}
|
|
|
|
-`;
|
|
|
|
|
|
+}`;
|
|
|
|
|
|
const getCellIri = cellId => `\
|
|
const getCellIri = cellId => `\
|
|
PREFIX drawio: <http://ua.be/sdo2l/vocabulary/formalisms/drawio#>
|
|
PREFIX drawio: <http://ua.be/sdo2l/vocabulary/formalisms/drawio#>
|
|
@@ -76,14 +75,13 @@ WHERE {
|
|
?element a ?more_concrete_type .
|
|
?element a ?more_concrete_type .
|
|
FILTER(?more_concrete_type != ?type)
|
|
FILTER(?more_concrete_type != ?type)
|
|
}
|
|
}
|
|
-`;
|
|
|
|
|
|
+}`;
|
|
|
|
|
|
const getAllOutgoingRelations = iri => `\
|
|
const getAllOutgoingRelations = iri => `\
|
|
SELECT DISTINCT ?rel ?other
|
|
SELECT DISTINCT ?rel ?other
|
|
WHERE {
|
|
WHERE {
|
|
<${iri}> ?rel ?other .
|
|
<${iri}> ?rel ?other .
|
|
-}
|
|
|
|
-`;
|
|
|
|
|
|
+}`;
|
|
|
|
|
|
const getOutgoingLink = (iri, link_type) => `\
|
|
const getOutgoingLink = (iri, link_type) => `\
|
|
PREFIX object_diagram: <http://ua.be/sdo2l/vocabulary/formalisms/object_diagram#>
|
|
PREFIX object_diagram: <http://ua.be/sdo2l/vocabulary/formalisms/object_diagram#>
|
|
@@ -99,21 +97,93 @@ WHERE {
|
|
?element a ?more_concrete_type .
|
|
?element a ?more_concrete_type .
|
|
FILTER(?more_concrete_type != ?type)
|
|
FILTER(?more_concrete_type != ?type)
|
|
}
|
|
}
|
|
|
|
+}`;
|
|
|
|
+
|
|
|
|
+const getCellStuff = (cellId) => `\
|
|
|
|
+PREFIX drawio: <http://ua.be/sdo2l/vocabulary/formalisms/drawio#>
|
|
|
|
+PREFIX object_diagram: <http://ua.be/sdo2l/vocabulary/formalisms/object_diagram#>
|
|
|
|
+PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
|
|
|
+
|
|
|
|
+SELECT DISTINCT ?element ?type
|
|
|
|
+WHERE {
|
|
|
|
+ ?element drawio:hasDrawioId "${cellId}" .
|
|
|
|
+ ?element a ?type .
|
|
|
|
+ ?type rdfs:subClassOf object_diagram:Object .
|
|
|
|
+ NOT EXISTS {
|
|
|
|
+ ?more_concrete_type rdfs:subClassOf ?type .
|
|
|
|
+ ?element a ?more_concrete_type .
|
|
|
|
+ FILTER(?more_concrete_type != ?type)
|
|
|
|
+ }
|
|
|
|
+}`;
|
|
|
|
+
|
|
|
|
+const getDiagramAndCellId = cellIri => `\
|
|
|
|
+PREFIX drawio: <http://ua.be/sdo2l/vocabulary/formalisms/drawio#>
|
|
|
|
+PREFIX object_diagram: <http://ua.be/sdo2l/vocabulary/formalisms/object_diagram#>
|
|
|
|
+
|
|
|
|
+SELECT DISTINCT ?diagramName ?cellId
|
|
|
|
+WHERE {
|
|
|
|
+ <${cellIri}> drawio:hasDrawioId ?cellId .
|
|
|
|
+ <${cellIri}> object_diagram:inModel ?model .
|
|
|
|
+ ?model object_diagram:hasName ?diagramName .
|
|
|
|
+}`;
|
|
|
|
+
|
|
|
|
+const getSubClassRelations = `
|
|
|
|
+PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
|
|
|
+
|
|
|
|
+SELECT DISTINCT ?subclass ?superclass
|
|
|
|
+WHERE {
|
|
|
|
+ ?subclass rdfs:subClassOf ?superclass
|
|
|
|
+}`;
|
|
|
|
+
|
|
|
|
+// mapping from class-IRI to array of superclass-IRIs
|
|
|
|
+const superclasses = new Map();
|
|
|
|
+
|
|
|
|
+function getQueries(type) {
|
|
|
|
+ const sups = superclasses.get(type) || [];
|
|
|
|
+ const result = getBaseQueries(type).concat(... sups.map(sup => getBaseQueries(sup)));
|
|
|
|
+ return result;
|
|
}
|
|
}
|
|
-`;
|
|
|
|
|
|
|
|
-function getQueries(element, type) {
|
|
|
|
|
|
+// Some hardcoded relations...
|
|
|
|
+function getBaseQueries(type) {
|
|
|
|
+ const queries = [];
|
|
if (type.endsWith("formalisms/drawio#Cell")) {
|
|
if (type.endsWith("formalisms/drawio#Cell")) {
|
|
- return [
|
|
|
|
- getOutgoingLink(element, "http://ua.be/sdo2l/vocabulary/formalisms/cs_as#parsedAs"),
|
|
|
|
- ]
|
|
|
|
|
|
+ queries.push({
|
|
|
|
+ query: "formalisms/cs_as#parsedAs",
|
|
|
|
+ name: "Is parsed as",
|
|
|
|
+ });
|
|
}
|
|
}
|
|
if (type.endsWith("formalisms/pm#Activity")) {
|
|
if (type.endsWith("formalisms/pm#Activity")) {
|
|
- return [
|
|
|
|
- getOutgoingLink(element, "http://ua.be/sdo2l/vocabulary/formalisms/pm#isTransformation"),
|
|
|
|
- ];
|
|
|
|
|
|
+ queries.push({
|
|
|
|
+ query: "formalisms/pm#isTransformation",
|
|
|
|
+ name: "Is typed by transformation",
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ if (type.endsWith("formalisms/pm#Artifact")) {
|
|
|
|
+ queries.push({
|
|
|
|
+ query: "formalisms/pm#hasType",
|
|
|
|
+ name: "Is typed by formalism",
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ if (type.endsWith("formalisms/object_diagram#Object")) {
|
|
|
|
+ queries.push({
|
|
|
|
+ query: "formalisms/cs_as#renderedAs",
|
|
|
|
+ name: "Is rendered as",
|
|
|
|
+ });
|
|
}
|
|
}
|
|
- return [];
|
|
|
|
|
|
+ if (type.endsWith("base/ftg#Transformation")) {
|
|
|
|
+ queries.push({
|
|
|
|
+ query: "formalisms/pm#occursAsActivity",
|
|
|
|
+ name: "Occurs as activity",
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ if (type.endsWith("base/ftg#Formalism")) {
|
|
|
|
+ queries.push({
|
|
|
|
+ query: "formalisms/pm#occursAsArtifact",
|
|
|
|
+ name: "Occurs as activity",
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ return queries;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -138,6 +208,18 @@ const defaultSettings = {
|
|
|
|
|
|
Draw.loadPlugin(function(ui) {
|
|
Draw.loadPlugin(function(ui) {
|
|
|
|
|
|
|
|
+ executeSPARQL(getSubClassRelations)
|
|
|
|
+ .then(results => {
|
|
|
|
+ for (const {subclass, superclass} of results) {
|
|
|
|
+ const superclasslist = superclasses.get(subclass.value) || (() => {
|
|
|
|
+ const list = [];
|
|
|
|
+ superclasses.set(subclass.value, list);
|
|
|
|
+ return list;
|
|
|
|
+ })();
|
|
|
|
+ superclasslist.push(superclass.value);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
function getSetting(prop) {
|
|
function getSetting(prop) {
|
|
const result = localStorage.getItem("dtdesign-"+prop);
|
|
const result = localStorage.getItem("dtdesign-"+prop);
|
|
if (result !== null) {
|
|
if (result !== null) {
|
|
@@ -243,31 +325,68 @@ Draw.loadPlugin(function(ui) {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- ui.actions.addAction('whatIsThis', mxUtils.bind(this, function() {}));
|
|
|
|
|
|
+ let highlight;
|
|
|
|
+
|
|
|
|
+ // Given a cell IRI, open the diagram that contains the cell
|
|
|
|
+ function goto(cellIri) {
|
|
|
|
+ executeSPARQL(getDiagramAndCellId(cellIri))
|
|
|
|
+ .then(([{diagramName, cellId}]) => {
|
|
|
|
+ // drop the "_drawio" at the end:
|
|
|
|
+ const actualDiagramName = diagramName.value.substring(0, diagramName.value.length-7);
|
|
|
|
+ loadPage(actualDiagramName)
|
|
|
|
+ .then(() => {
|
|
|
|
+ if (highlight) {
|
|
|
|
+ highlight.destroy();
|
|
|
|
+ }
|
|
|
|
+ const [cell] = ui.editor.graph.getCellsById([cellId.value]);
|
|
|
|
+ highlight = new mxCellHighlight(ui.editor.graph, "#eb34e8", 6);
|
|
|
|
+ highlight.highlight(ui.editor.graph.view.getState(cell));
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ // Override context menu when right-clicking somewhere in the diagram:
|
|
const oldFactoryMethod = ui.editor.graph.popupMenuHandler.factoryMethod;
|
|
const oldFactoryMethod = ui.editor.graph.popupMenuHandler.factoryMethod;
|
|
ui.editor.graph.popupMenuHandler.factoryMethod = function(menu, cell, evt) {
|
|
ui.editor.graph.popupMenuHandler.factoryMethod = function(menu, cell, evt) {
|
|
const modelverseMenu = menu.addItem("ModelVerse", null, null);
|
|
const modelverseMenu = menu.addItem("ModelVerse", null, null);
|
|
- const isAMenu = menu.addItem("Is a...", null, null, modelverseMenu);
|
|
|
|
- menu.addSeparator();
|
|
|
|
oldFactoryMethod.apply(this, arguments);
|
|
oldFactoryMethod.apply(this, arguments);
|
|
if (cell && cell.vertex) {
|
|
if (cell && cell.vertex) {
|
|
- executeSPARQL(whatIsCell(cell.id))
|
|
|
|
- .then(json => {
|
|
|
|
- for (const {cell, rel_type, as_type, as_element} of json) {
|
|
|
|
- const tracelink_type = rel_type.value.split("#")[1];
|
|
|
|
- const typeMenu = menu.addItem(dropVocabularyPrefix(as_type.value) + " - " + tracelink_type, null, null, isAMenu);
|
|
|
|
-
|
|
|
|
- const queries = getQueries(as_element.value, as_type.value);
|
|
|
|
- Promise.all(queries.map(q => {
|
|
|
|
- executeSPARQL(q)
|
|
|
|
- .then(json => {
|
|
|
|
- console.log("query", q, "json:", json);
|
|
|
|
- });
|
|
|
|
- }))
|
|
|
|
|
|
+ const alreadyVisited = new Set();
|
|
|
|
+ function getInfo(element, type, maxRecursion, parent, relName) {
|
|
|
|
+ if (alreadyVisited.has(element+'---'+type)) {
|
|
|
|
+ // console.log('alreadyVisited')
|
|
|
|
+ return; // don't go in circles
|
|
}
|
|
}
|
|
- console.log(json);
|
|
|
|
- });
|
|
|
|
|
|
+ const shortType = dropVocabularyPrefix(type);
|
|
|
|
+ // console.log(path, element, type);
|
|
|
|
+ let newParent;
|
|
|
|
+ if (superclasses.get(type).some(t => t.endsWith("drawio#Cell"))) {
|
|
|
|
+ newParent = menu.addItem(relName + ' ' + shortType, null, () => goto(element), parent);
|
|
|
|
+ } else {
|
|
|
|
+ newParent = menu.addItem(relName + ' ' + shortType, null, null, parent);
|
|
|
|
+ }
|
|
|
|
+ alreadyVisited.add(element+'---'+type);
|
|
|
|
+ if (maxRecursion <= 0) {
|
|
|
|
+ // console.log('maxRecursion 0')
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ const queries = getQueries(type);
|
|
|
|
+ for (const {query, name} of queries) {
|
|
|
|
+ executeSPARQL(getOutgoingLink(element, "http://ua.be/sdo2l/vocabulary/"+query))
|
|
|
|
+ .then(results => {
|
|
|
|
+ // console.log(path, name, "results:", results);
|
|
|
|
+ for (const {element, type} of results) {
|
|
|
|
+ getInfo(element.value, type.value, maxRecursion-1, newParent, name);
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ executeSPARQL(getCellStuff(cell.id))
|
|
|
|
+ .then(results => {
|
|
|
|
+ for (const {element, type} of results) {
|
|
|
|
+ getInfo(element.value, type.value, 8, modelverseMenu, "Is a");
|
|
|
|
+ }
|
|
|
|
+ })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -317,6 +436,24 @@ Draw.loadPlugin(function(ui) {
|
|
const modelsDiv = document.createElement('div');
|
|
const modelsDiv = document.createElement('div');
|
|
lsDiv.appendChild(modelsDiv);
|
|
lsDiv.appendChild(modelsDiv);
|
|
|
|
|
|
|
|
+ // Load a model and add it as a new page to the editor
|
|
|
|
+ function loadPage(pageName) {
|
|
|
|
+ return fetch(BACKEND + "/diagrams/" + pageName)
|
|
|
|
+ .then(res => res.text())
|
|
|
|
+ .then(xmltext => {
|
|
|
|
+ // console.log(xmltext);
|
|
|
|
+ const parser = new DOMParser();
|
|
|
|
+ const doc = parser.parseFromString(xmltext, "application/xml");
|
|
|
|
+ const node = doc.documentElement;
|
|
|
|
+ const page = new DiagramPage(node);
|
|
|
|
+ // if page with same name already exists, erase it:
|
|
|
|
+ ui.pages = ui.pages.filter(page => page.node.getAttribute("name") != pageName);
|
|
|
|
+ ui.pages.push(page);
|
|
|
|
+ ui.currentPage = page;
|
|
|
|
+ ui.editor.setGraphXml(node);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
// Refreshes the list of models shown in the ModelVerse window
|
|
// Refreshes the list of models shown in the ModelVerse window
|
|
function refreshModels() {
|
|
function refreshModels() {
|
|
fetch(BACKEND + "/diagrams", {
|
|
fetch(BACKEND + "/diagrams", {
|
|
@@ -327,22 +464,7 @@ Draw.loadPlugin(function(ui) {
|
|
modelsDiv.replaceChildren(...json.map(modelName => {
|
|
modelsDiv.replaceChildren(...json.map(modelName => {
|
|
const div = document.createElement('div');
|
|
const div = document.createElement('div');
|
|
div.style.padding = '3px 0px';
|
|
div.style.padding = '3px 0px';
|
|
- const loadButton = mxUtils.button("Open in New Page", function() {
|
|
|
|
- fetch(BACKEND + "/diagrams/" + modelName)
|
|
|
|
- .then(res => res.text())
|
|
|
|
- .then(xmltext => {
|
|
|
|
- // console.log(xmltext);
|
|
|
|
- const parser = new DOMParser();
|
|
|
|
- const doc = parser.parseFromString(xmltext, "application/xml");
|
|
|
|
- const node = doc.documentElement;
|
|
|
|
- const page = new DiagramPage(node);
|
|
|
|
- // if page with same name already exists, erase it:
|
|
|
|
- ui.pages = ui.pages.filter(page => page.node.getAttribute("name") != modelName);
|
|
|
|
- ui.pages.push(page);
|
|
|
|
- ui.currentPage = page;
|
|
|
|
- ui.editor.setGraphXml(node);
|
|
|
|
- })
|
|
|
|
- });
|
|
|
|
|
|
+ const loadButton = mxUtils.button("Open in New Page", () => loadPage(modelName));
|
|
loadButton.style.marginLeft = "12px";
|
|
loadButton.style.marginLeft = "12px";
|
|
div.appendChild(document.createTextNode(modelName));
|
|
div.appendChild(document.createTextNode(modelName));
|
|
div.appendChild(loadButton);
|
|
div.appendChild(loadButton);
|