From 18b64eb61e3f58098dbfdd54d6401882b1000dab Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Tue, 9 Oct 2018 15:06:10 +0200
Subject: [PATCH] reaction line color is export/imported properly

---
 .../model/sbml/SbmlBioEntityParser.java       |  4 +-
 .../sbml/reaction/SbmlReactionExporter.java   |  6 ++
 .../sbml/reaction/SbmlReactionParser.java     | 85 ++++++++++++-------
 .../model/sbml/SbmlExporterTest.java          | 13 +++
 4 files changed, 77 insertions(+), 31 deletions(-)

diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityParser.java
index b87599f0e2..f7ce691c21 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityParser.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityParser.java
@@ -100,7 +100,7 @@ public class SbmlBioEntityParser extends XmlParser {
    *          object role identifier
    * @return {@link LocalStyle} from the layout data
    */
-  LocalStyle getStyleForRole(String objectRole) {
+  protected LocalStyle getStyleForRole(String objectRole) {
     RenderLayoutPlugin renderPlugin = (RenderLayoutPlugin) layout.getExtension("render");
     for (LocalRenderInformation lri : renderPlugin.getListOfLocalRenderInformation()) {
       for (LocalStyle style : lri.getListOfLocalStyles()) {
@@ -112,7 +112,7 @@ public class SbmlBioEntityParser extends XmlParser {
     return null;
   }
 
-  Color getColorByColorDefinition(String fill) {
+  protected Color getColorByColorDefinition(String fill) {
     RenderLayoutPlugin renderPlugin = (RenderLayoutPlugin) layout.getExtension("render");
     for (LocalRenderInformation lri : renderPlugin.getListOfLocalRenderInformation()) {
       if (lri.getColorDefinition(fill) != null) {
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java
index da286cb62b..d84408a695 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java
@@ -245,6 +245,12 @@ public class SbmlReactionExporter extends SbmlBioEntityExporter<Reaction, org.sb
       }
     }
     
+    LocalStyle style = createStyle(reaction);
+    ColorDefinition color = getColorDefinition(reaction.getReactants().get(0).getLine().getColor());
+    style.getGroup().setFill(color.getId());
+
+    assignStyleToGlyph(reactionGlyph, style);
+    
   }
 
   private void addOperatorLineToGlyph(ReactionGlyph reactantGlyph, NodeOperator operator, boolean reverse) {
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java
index add9c0916d..2fba4974ab 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java
@@ -1,5 +1,6 @@
 package lcsb.mapviewer.converter.model.sbml.reaction;
 
+import java.awt.Color;
 import java.awt.geom.Point2D;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
@@ -22,6 +23,9 @@ import org.sbml.jsbml.ext.layout.Layout;
 import org.sbml.jsbml.ext.layout.ReactionGlyph;
 import org.sbml.jsbml.ext.layout.SpeciesGlyph;
 import org.sbml.jsbml.ext.layout.SpeciesReferenceGlyph;
+import org.sbml.jsbml.ext.render.LocalStyle;
+import org.sbml.jsbml.ext.render.RenderConstants;
+import org.sbml.jsbml.ext.render.RenderGraphicalObjectPlugin;
 import org.w3c.dom.Node;
 
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
@@ -41,6 +45,7 @@ import lcsb.mapviewer.model.map.kinetics.SbmlKinetics;
 import lcsb.mapviewer.model.map.modifier.Inhibition;
 import lcsb.mapviewer.model.map.modifier.Modulation;
 import lcsb.mapviewer.model.map.modifier.Trigger;
+import lcsb.mapviewer.model.map.reaction.AbstractNode;
 import lcsb.mapviewer.model.map.reaction.AndOperator;
 import lcsb.mapviewer.model.map.reaction.Modifier;
 import lcsb.mapviewer.model.map.reaction.NodeOperator;
@@ -56,8 +61,6 @@ import lcsb.mapviewer.modelutils.map.ElementUtils;
 public class SbmlReactionParser extends SbmlBioEntityParser {
   Logger logger = Logger.getLogger(SbmlReactionParser.class);
 
-  Layout layout;
-
   lcsb.mapviewer.model.map.model.Model minervaModel;
   ElementUtils eu = new ElementUtils();
 
@@ -108,33 +111,7 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
         for (SpeciesReferenceGlyph speciesRefernceGlyph : glyph.getListOfSpeciesReferenceGlyphs()) {
           SpeciesGlyph speciesGlyph = layout.getSpeciesGlyph(speciesRefernceGlyph.getSpeciesGlyph());
           ReactionNode minervaNode = null;
-          Class<? extends ReactionNode> nodeClass = null;
-          if (speciesRefernceGlyph.getRole() != null) {
-            switch (speciesRefernceGlyph.getRole()) {
-            case ACTIVATOR:
-              nodeClass = Trigger.class;
-              break;
-            case INHIBITOR:
-              nodeClass = Inhibition.class;
-              break;
-            case PRODUCT:
-              nodeClass = Product.class;
-              break;
-            case SIDEPRODUCT:
-              nodeClass = Product.class;
-              break;
-            case SIDESUBSTRATE:
-              nodeClass = Reactant.class;
-              break;
-            case SUBSTRATE:
-              nodeClass = Reactant.class;
-              break;
-            case UNDEFINED:
-            case MODIFIER:
-              nodeClass = null;
-              break;
-            }
-          }
+          Class<? extends ReactionNode> nodeClass = getReactionNodeClass(speciesRefernceGlyph);
 
           if (reactionWithLayout.isReversible() && (nodeClass == Reactant.class || nodeClass == Product.class)) {
             nodeClass = null;
@@ -233,6 +210,8 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
           operator.setLine(line);
           reactionWithLayout.addNode(operator);
         }
+        assignColorToReaction(glyph, reactionWithLayout);
+
         minervaModel.addReaction(reactionWithLayout);
       } catch (InvalidArgumentException e) {
         throw new InvalidInputDataExecption(e);
@@ -255,6 +234,54 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
     }
   }
 
+  private Class<? extends ReactionNode> getReactionNodeClass(SpeciesReferenceGlyph speciesRefernceGlyph) {
+    Class<? extends ReactionNode> nodeClass = null;
+    if (speciesRefernceGlyph.getRole() != null) {
+      switch (speciesRefernceGlyph.getRole()) {
+      case ACTIVATOR:
+        nodeClass = Trigger.class;
+        break;
+      case INHIBITOR:
+        nodeClass = Inhibition.class;
+        break;
+      case PRODUCT:
+        nodeClass = Product.class;
+        break;
+      case SIDEPRODUCT:
+        nodeClass = Product.class;
+        break;
+      case SIDESUBSTRATE:
+        nodeClass = Reactant.class;
+        break;
+      case SUBSTRATE:
+        nodeClass = Reactant.class;
+        break;
+      case UNDEFINED:
+      case MODIFIER:
+        nodeClass = null;
+        break;
+      }
+    }
+    return nodeClass;
+  }
+
+  private void assignColorToReaction(ReactionGlyph glyph, Reaction reactionWithLayout)
+      throws InvalidInputDataExecption {
+    RenderGraphicalObjectPlugin rgop = (RenderGraphicalObjectPlugin) glyph.getExtension(RenderConstants.shortLabel);
+    if (rgop != null) {
+      LocalStyle style = getStyleForRole(rgop.getObjectRole());
+      if (style == null) {
+        throw new InvalidInputDataExecption("Style " + rgop.getObjectRole() + " is not defined");
+      }
+      if (style.getGroup().getFill() != null) {
+        Color color = getColorByColorDefinition(style.getGroup().getFill());
+        for (AbstractNode node : reactionWithLayout.getNodes()) {
+          node.getLine().setColor(color);
+        }
+      }
+    }
+  }
+
   private PolylineData getLineFromReferenceGlyph(SpeciesReferenceGlyph speciesRefernceGlyph) {
     PolylineData line = null;
     for (CurveSegment segment : speciesRefernceGlyph.getCurve().getListOfCurveSegments()) {
diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java
index abe75da28a..df98e6f93a 100644
--- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java
+++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java
@@ -26,6 +26,7 @@ import lcsb.mapviewer.model.map.compartment.Compartment;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.model.ModelComparator;
 import lcsb.mapviewer.model.map.model.ModelFullIndexed;
+import lcsb.mapviewer.model.map.reaction.AbstractNode;
 import lcsb.mapviewer.model.map.reaction.Product;
 import lcsb.mapviewer.model.map.reaction.Reactant;
 import lcsb.mapviewer.model.map.reaction.Reaction;
@@ -285,4 +286,16 @@ public class SbmlExporterTest {
     assertEquals(0, comparator.compare(model, model2));
   }
 
+  @Test
+  public void testReactionColorParsing() throws Exception {
+    Model model = parser.createModel(new ConverterParams().filename("testFiles/layoutExample/example1.xml"));
+    for (Reaction element : model.getReactions()) {
+      for (AbstractNode node: element.getNodes()) {
+        node.getLine().setColor(Color.BLUE);
+      }
+    }
+    Model model2 = getModelAfterSerializing(model);
+    assertEquals(0, comparator.compare(model, model2));
+  }
+
 }
-- 
GitLab