diff --git a/SBOLCanvasBackend/src/utils/MxToSBOL.java b/SBOLCanvasBackend/src/utils/MxToSBOL.java index e5f01a5..bf9b94e 100644 --- a/SBOLCanvasBackend/src/utils/MxToSBOL.java +++ b/SBOLCanvasBackend/src/utils/MxToSBOL.java @@ -406,7 +406,7 @@ private void createComponentDefinition(SBOLDocument document, mxGraph graph, mxG glyphInfo.getDisplayID(), glyphInfo.getVersion(), SBOLData.types.getValue(glyphInfo.getPartType())); if (glyphInfo.getOtherTypes() != null) { for (String type : glyphInfo.getOtherTypes()) { - compDef.addType(new URI(type)); + compDef.addType(SBOLData.types.getValue(type)); } } diff --git a/SBOLCanvasBackend/src/utils/SBOLData.java b/SBOLCanvasBackend/src/utils/SBOLData.java index da040dc..e5fd433 100644 --- a/SBOLCanvasBackend/src/utils/SBOLData.java +++ b/SBOLCanvasBackend/src/utils/SBOLData.java @@ -43,6 +43,7 @@ public class SBOLData { types.put("RNA molecule", ComponentDefinition.RNA_MOLECULE); types.put("RNA region", ComponentDefinition.RNA_REGION); types.put("Small molecule", ComponentDefinition.SMALL_MOLECULE); + types.put("Circular", URI.create("http://identifiers.org/so/SO:0000988")); roles = new BiMap(); roles.put("Gen (Engineered Region)", SequenceOntology.ENGINEERED_REGION); diff --git a/SBOLCanvasBackend/src/utils/SBOLToMx.java b/SBOLCanvasBackend/src/utils/SBOLToMx.java index 889a1dc..b571e27 100644 --- a/SBOLCanvasBackend/src/utils/SBOLToMx.java +++ b/SBOLCanvasBackend/src/utils/SBOLToMx.java @@ -562,10 +562,10 @@ private GlyphInfo genGlyphInfo(ComponentDefinition glyphCD) { // There will only be one important type ArrayList otherTypes = new ArrayList(); for (URI glyphType : glyphCD.getTypes()) { - if (SBOLData.types.containsValue(glyphType)) { + if (SBOLData.types.containsValue(glyphType) && glyphInfo.getPartType() == null) { glyphInfo.setPartType(SBOLData.types.getKey(glyphType)); } else { - otherTypes.add(glyphType.toString()); + otherTypes.add(SBOLData.types.getKey(glyphType)); } } glyphInfo.setOtherTypes(otherTypes.toArray(new String[0])); diff --git a/SBOLCanvasFrontend/src/app/glyphInfo.ts b/SBOLCanvasFrontend/src/app/glyphInfo.ts index 0a586c1..75cca1d 100644 --- a/SBOLCanvasFrontend/src/app/glyphInfo.ts +++ b/SBOLCanvasFrontend/src/app/glyphInfo.ts @@ -38,6 +38,7 @@ export class GlyphInfo extends Info { this.version = version this.partType = partType this.partRole = partRole + this.otherTypes = [] // try to make a prefix from the part role const partRolePrefix = partRole && (partRole.match(/(\w+?) \(/) || [])[1]; diff --git a/SBOLCanvasFrontend/src/app/graph-base.ts b/SBOLCanvasFrontend/src/app/graph-base.ts index 81f1e63..dd35706 100644 --- a/SBOLCanvasFrontend/src/app/graph-base.ts +++ b/SBOLCanvasFrontend/src/app/graph-base.ts @@ -312,7 +312,7 @@ export class GraphBase { } cell.geometry.width = GraphBase.defaultModuleWidth cell.geometry.height = GraphBase.defaultModuleHeight - } else if (glyphDict[cell.value] instanceof GlyphInfo && glyphDict[cell.value].partType === 'DNA region') { + } else if (glyphDict[cell.value] instanceof GlyphInfo && glyphDict[cell.value].partType === 'DNA region' || glyphDict[cell.value].partType === 'Circular') { // sequence feature if (!cell.style) { cell.style = GraphBase.STYLE_SEQUENCE_FEATURE + glyphDict[cell.value].partRole @@ -329,7 +329,7 @@ export class GraphBase { cell.geometry.x = 0 } else{ - cell.style = cell.style = "sequenceFeatureGlyphCir (Circular Backbone Right)" + cell.style = "sequenceFeatureGlyphCir (Circular Backbone Right)" cell.stayAtEnd = true leftCirFound = false } diff --git a/SBOLCanvasFrontend/src/app/graph-helpers.ts b/SBOLCanvasFrontend/src/app/graph-helpers.ts index e245deb..89082f8 100644 --- a/SBOLCanvasFrontend/src/app/graph-helpers.ts +++ b/SBOLCanvasFrontend/src/app/graph-helpers.ts @@ -79,6 +79,11 @@ export class GraphHelpers extends GraphBase { } return glyphInfo } + + protected getGlyphInfo(cell: mxCell): GlyphInfo { + const glyphInfo = this.getFromInfoDict(cell.getValue()) as GlyphInfo + return glyphInfo + } protected async updateSelectedGlyphInfo(this: GraphService, info: GlyphInfo) { this.graph.getModel().beginUpdate() @@ -1877,6 +1882,39 @@ export class GraphHelpers extends GraphBase { return false } + /** + * Made specifically for undo, since it does not affect glyph info. + * Removes "Circular" from the "otherTypes" property of Circuit Containers. + */ + protected removeCircularType() { + let allGraphCells = this.graph.getDefaultParent().children + if (allGraphCells != null) { + for (let i = 0; i < allGraphCells.length; i++) { + if (allGraphCells[i].isCircuitContainer() && !allGraphCells[i].isCircularBackboneOnCircuitContainer()) { + const otherTypes = this.getGlyphInfo(allGraphCells[i]).otherTypes + const index = otherTypes.indexOf("Circular") + otherTypes.splice(index, 1) + } + } + } + } + + /** + * Made specifically for redo. + * Adds the circular type back to Circuit Container if circular is present again. + */ + protected addCircularType() { + let allGraphCells = this.graph.getDefaultParent().children + if (allGraphCells != null) { + for (let i = 0; i < allGraphCells.length; i++) { + if (allGraphCells[i].isCircuitContainer() && allGraphCells[i].isCircularBackboneOnCircuitContainer()) { + const otherTypes = this.getGlyphInfo(allGraphCells[i]).otherTypes + otherTypes.push("Circular") + } + } + } + } + protected flipInteractionEdge(cell) { if (!cell.isInteraction()) { console.error("flipInteraction attempted on something other than an interaction!") diff --git a/SBOLCanvasFrontend/src/app/graph.service.ts b/SBOLCanvasFrontend/src/app/graph.service.ts index 881378c..f47a6e5 100644 --- a/SBOLCanvasFrontend/src/app/graph.service.ts +++ b/SBOLCanvasFrontend/src/app/graph.service.ts @@ -467,8 +467,14 @@ export class GraphService extends GraphHelpers { if (combinatorial) combinatorial.removeVariableComponentInfo(cell.getId()) - if (cell.stayAtBeginning || cell.stayAtEnd) cell.getParent().circularBackbone = false - + if (cell.stayAtBeginning || cell.stayAtEnd) { + cell.getParent().circularBackbone = false + + // remove the circular type from "otherTypes" since circular parts are deleted + const otherTypes = this.getGlyphInfo(cell.getParent()).otherTypes + const index = otherTypes.indexOf("Circular") + otherTypes.splice(index, 1) + } circuitContainers.push(cell.getParent()) } } else if (cell.isCircuitContainer() && this.graph.getCurrentRoot() && this.graph.getCurrentRoot().isComponentView()) @@ -554,6 +560,9 @@ export class GraphService extends GraphHelpers { this.graph.clearSelection() this.editor.execute('undo') + // Undo does not affect glyph info, if circular backbone is not present, remove it from "otherTypes" property + this.removeCircularType() + //console.log(this.editor.undoManager); // If the undo caused scars to become visible, we should update @@ -579,6 +588,9 @@ export class GraphService extends GraphHelpers { // If the undo caused scars to become visible, we should update this.showingScars = this.getScarsVisible() + + // Add Circular type property back if needed + this.addCircularType() // refresh to update cell labels if (this.graph.getCurrentRoot()) { @@ -644,10 +656,9 @@ export class GraphService extends GraphHelpers { const childCellName = childCell.style.split("Glyph")[1]?.split(";")[0]?.trim() - // A circular backbone is considered a sequence feature - // "Cir (Circular Backbone Right/Left)" refers to the connection to the backbone - // It's possible to have a circular backbone as a standalone glyph - if(!childCell.isCircularBackbone() || childCellName === "Cir (Circular Backbone)"){ + // Circular Backbone be added after all other children are created + // Prevents both the left and right side from being added + if(!childCell.isCircularBackbone()){ this.addSequenceFeature(childCellName) } @@ -842,6 +853,12 @@ export class GraphService extends GraphHelpers { const circuitContainer = selection.isCircuitContainer() ? selection : selection.getParent() + // Add additional type to Circuit Container if Circular present + const circuitContainerGlyphInfo = (this.getGlyphInfo(circuitContainer)) + if(!circuitContainerGlyphInfo.otherTypes.includes("Circular")){ + circuitContainerGlyphInfo.otherTypes.push("Circular") + } + // there cannot be more than one circular backbone on a circuit container if(circuitContainer.isCircularBackboneOnCircuitContainer()) return diff --git a/SBOLCanvasFrontend/src/app/info-editor/info-editor.component.html b/SBOLCanvasFrontend/src/app/info-editor/info-editor.component.html index ec3a4eb..30e0364 100644 --- a/SBOLCanvasFrontend/src/app/info-editor/info-editor.component.html +++ b/SBOLCanvasFrontend/src/app/info-editor/info-editor.component.html @@ -10,7 +10,7 @@ - + Part role IDK (Unspecified) @@ -20,7 +20,7 @@ - + Role refinement None