Commit 6b42f429 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge branch '537-allow-to-create-exported-file-with-part-of-the-map' into 'master'

Resolve "Allow to create exported file with part of the map"

Closes #537

See merge request !458
parents 0642fbac e9e5b8cb
Pipeline #6897 failed with stage
in 7 minutes and 42 seconds
......@@ -1937,6 +1937,20 @@ ServerConnector.getImageDownloadUrl = function (params) {
});
};
/**
*
* @param {Object} params
* @param {string} [params.projectId]
* @param {number} params.modelId
* @param {string} [params.polygonString]
* @param {string} params.handlerClass
* @param {number} [params.backgroundOverlayId]
* @param {number} [params.zoomLevel]
* @param {number[]} [params.overlayIds]
* @param {number[]} [params.elementIds]
* @param {number[]} [params.reactionIds]
* @returns {Promise}
*/
ServerConnector.getModelDownloadUrl = function (params) {
var self = this;
var queryParams = {
......@@ -1944,12 +1958,13 @@ ServerConnector.getModelDownloadUrl = function (params) {
modelId: params.modelId
};
var filterParams = {
token: params.token,
polygonString: params.polygonString,
handlerClass: params.handlerClass,
backgroundOverlayId: params.backgroundOverlayId,
zoomLevel: params.zoomLevel,
overlayIds: this.idsToString(params.overlayIds)
overlayIds: this.idsToString(params.overlayIds),
elementIds: this.idsToString(params.elementIds),
reactionIds: this.idsToString(params.reactionIds)
};
return self.getProjectId(params.projectId).then(function (result) {
queryParams.projectId = result;
......@@ -1957,6 +1972,41 @@ ServerConnector.getModelDownloadUrl = function (params) {
});
};
/**
*
* @param {Object} params
* @param {string} [params.projectId]
* @param {number} params.modelId
* @param {string} [params.polygonString]
* @param {string} params.handlerClass
* @param {number} [params.backgroundOverlayId]
* @param {number} [params.zoomLevel]
* @param {number[]} [params.overlayIds]
* @param {number[]} [params.elementIds]
* @param {number[]} [params.reactionIds]
* @returns {Promise}
*/
ServerConnector.getPartOfModelInExportFormat = function (params) {
var self = this;
var queryParams = {
projectId: params.projectId,
modelId: params.modelId
};
var filterParams = {
polygonString: params.polygonString,
handlerClass: params.handlerClass,
backgroundOverlayId: params.backgroundOverlayId,
zoomLevel: params.zoomLevel,
overlayIds: this.idsToString(params.overlayIds),
elementIds: this.idsToString(params.elementIds),
reactionIds: this.idsToString(params.reactionIds)
};
return self.getProjectId(params.projectId).then(function (result) {
queryParams.projectId = result;
return self.sendPostRequest(self.getModelPartUrl(queryParams), filterParams);
});
};
ServerConnector.getImageConverters = function () {
var self = this;
return self.getConfiguration().then(function (configuration) {
......
......@@ -137,6 +137,38 @@ function createProjectData(options) {
}
});
},
/**
* Export part of the map that includes bioEntities into a known format.
*
* @param {Object} param
* @param {string} param.handlerClass format defined in {Configuration#getModelConverters}
* @param {number} param.modelId id of the model
* @param {Array} param.bioEntities
* @returns {Promise}
*/
exportToMapFormat: function (param) {
var exportParams = {
projectId: map.getProject().getProjectId(),
modelId: param.modelId,
handlerClass: param.handlerClass,
elementIds: [],
reactionIds: []
};
for (var i = 0; i < param.bioEntities.length; i++) {
var ie = new IdentifiedElement(param.bioEntities[i]);
if (ie.getType() === "ALIAS") {
exportParams.elementIds.push(ie.getId());
} else if (ie.getType() === "REACTION") {
exportParams.reactionIds.push(ie.getId());
} else {
return Promise.reject(new Error("Unsupported bioentity type: " + ie.getType()));
}
if (ie.getModelId() !== param.modelId) {
return Promise.reject(new Error("Export of bioEntities from few maps is not supported. ModelId: " + param.modelId + "; element modelId: " + ie.getModelId()));
}
}
return options.map.getServerConnector().getPartOfModelInExportFormat(exportParams);
},
getAllBioEntities: function () {
var models = map.getProject().getModels();
var result = [];
......@@ -312,7 +344,7 @@ function createWrapperFunctionForDialogGuiUpdate(param) {
* @param {CustomMap} options.map
* @param {Plugin} options.plugin
* @param {string} options.pluginId
* @returns {{getVisibleDataOverlays: function(): (Promise<DataOverlay[]>|*), addListener: addListener, removeListener: removeListener, removeAllListeners: function(): Array, getHighlightedBioEntities: function(*=): *, showBioEntity: function(*=): *, hideBioEntity: function(*=): Promise<T>, setCenter: function(*): PromiseLike, getCenter: function(*): Point, getBounds: function(*): Bounds, fitBounds: function(*): void, setZoom: function(*): *, getZoom: function(*): number, openMap: function(*): PromiseLike}}
* @returns {{getVisibleDataOverlays: (function(): (Promise<DataOverlay[]>|*)), addListener: addListener, removeListener: removeListener, removeAllListeners: (function(): Array), getHighlightedBioEntities: (function(*=): Promise<Array | never>), showBioEntity: (function(*=): *), hideBioEntity: (function(*=): Promise<any | never>), setCenter: (function(*): PromiseLike), getCenter: (function(*): Point), getBounds: (function(*): Bounds), fitBounds: (function(*): void), setZoom: (function(*): *), getZoom: (function(*): number), openMap: (function(*): PromiseLike)}}
*/
function createProjectMap(options) {
var map = options.map;
......@@ -569,7 +601,7 @@ function createProjectMap(options) {
* @param {CustomMap} options.map
* @param {Plugin} options.plugin
* @param {string} options.pluginId
* @returns {{data: {getBioEntityById: function(*=): Promise<any>, getAllBioEntities: function(): *, getReactionsWithElement: function(*=): *, getProjectId: function(): string, getName: function(): string, getVersion: function(): string, getDisease: getDisease, getOrganism: getOrganism, getModels: function(): *[]}, map: {getVisibleDataOverlays: function(): (Promise<DataOverlay[]>|*), addListener: addListener, removeListener: removeListener, removeAllListeners: function(): Array, getHighlightedBioEntities: function(*=): *, showBioEntity: function(*=): *, hideBioEntity: function(*=): Promise<T>, setCenter: function(*): PromiseLike, getCenter: function(*): Point, getBounds: function(*): Bounds, fitBounds: function(*): void, setZoom: function(*): *, getZoom: function(*): number, openMap: function(*): PromiseLike}}}
* @returns {{data: {getBioEntityById: (function(*=): Promise<any>), getAllBioEntities: (function(): *), getReactionsWithElement: (function(*=): *), getProjectId: (function(): string), getName: (function(): string), getVersion: (function(): string), getDisease: getDisease, getOrganism: getOrganism, getModels: (function(): *[])}, map: {getVisibleDataOverlays: (function(): (Promise<DataOverlay[]>|*)), addListener: addListener, removeListener: removeListener, removeAllListeners: (function(): Array), getHighlightedBioEntities: (function(*=): Promise<Array|never>), showBioEntity: (function(*=): *), hideBioEntity: (function(*=): Promise<any|never>), setCenter: (function(*): PromiseLike), getCenter: (function(*): Point), getBounds: (function(*): Bounds), fitBounds: (function(*): void), setZoom: (function(*): *), getZoom: (function(*): number), openMap: (function(*): PromiseLike)}}}
*/
function createProject(options) {
return {
......@@ -635,17 +667,16 @@ function createPluginData(options) {
* @param {HTMLElement} options.element
* @param {Configuration} options.configuration
* @param {ServerConnector} options.serverConnector
* @returns {{pluginId: string|string, element: *, project: {data: {getBioEntityById: function(*=): Promise<any>, getAllBioEntities: function(): *, getReactionsWithElement: function(*=): *, getProjectId: function(): string, getName: function(): string, getVersion: function(): string, getDisease: getDisease, getOrganism: getOrganism, getModels: function(): *[]}, map: {getVisibleDataOverlays: function(): (Promise<DataOverlay[]>|*), addListener: addListener, removeListener: removeListener, removeAllListeners: function(): Array, getHighlightedBioEntities: function(*=): *, showBioEntity: function(*=): *, hideBioEntity: function(*=): Promise<T>, setCenter: function(*): PromiseLike, getCenter: function(*): Point, getBounds: function(*): Bounds, fitBounds: function(*): void, setZoom: function(*): *, getZoom: function(*): number, openMap: function(*): PromiseLike}}, configuration: {options: ConfigurationOption[], overlayTypes: string[], imageConverters: ImageConverter[], modelConverters: ModelConverter[], elementTypes: BioEntityType[], reactionTypes: BioEntityType[], miriamTypes: MiriamType[], mapTypes: MapType[], modificationStateTypes: ModificationStateType[], privilegeTypes: PrivilegeType[], annotators: Annotator[]}, pluginData: {setGlobalParam: function(*=, *=): *, getGlobalParam: function(*=): *, setUserParam: function(*=, *=): *, getUserParam: function(*=): *}}}
* @returns {{pluginId: (string|string), element: HTMLElement, project: {data: {getBioEntityById: (function(*=): Promise<any>), getAllBioEntities: (function(): *), getReactionsWithElement: (function(*=): *), getProjectId: (function(): string), getName: (function(): string), getVersion: (function(): string), getDisease: getDisease, getOrganism: getOrganism, getModels: (function(): *[])}, map: {getVisibleDataOverlays: (function(): (Promise<DataOverlay[]>|*)), addListener: addListener, removeListener: removeListener, removeAllListeners: (function(): Array), getHighlightedBioEntities: (function(*=): Promise<Array|never>), showBioEntity: (function(*=): *), hideBioEntity: (function(*=): Promise<any|never>), setCenter: (function(*): PromiseLike), getCenter: (function(*): Point), getBounds: (function(*): Bounds), fitBounds: (function(*): void), setZoom: (function(*): *), getZoom: (function(*): number), openMap: (function(*): PromiseLike)}}, configuration: {options: ConfigurationOption[], overlayTypes: string[], imageConverters: ImageConverter[], modelConverters: ModelConverter[], elementTypes: BioEntityType[], reactionTypes: BioEntityType[], miriamTypes: MiriamType[], mapTypes: MapType[], modificationStateTypes: ModificationStateType[], privilegeTypes: PrivilegeType[], annotators: Annotator[]}, pluginData: {setGlobalParam: (function(*=, *=): *), getGlobalParam: (function(*=): *), setUserParam: (function(*=, *=): *), getUserParam: (function(*=): *)}}}
* @constructor
*/
function MinervaPluginProxy(options) {
return {
pluginId: options.pluginId,
element: options.element,
project: createProject(options),
configuration: createConfiguration(options),
pluginData: createPluginData(options)
};
this.pluginId = options.pluginId;
this.element = options.element;
this.project = createProject(options);
this.configuration = createConfiguration(options);
this.pluginData = createPluginData(options);
}
module.exports = MinervaPluginProxy;
......@@ -181,10 +181,10 @@ describe('MinervaPluginProxy', function () {
describe("getBioEntityById", function () {
it("for alias", function () {
var map, proxy;
var map;
return ServerConnector.getProject().then(function (project) {
map = helper.createCustomMap(project);
proxy = createProxy(map);
var proxy = createProxy(map);
return proxy.project.data.getBioEntityById({
id: 329177,
modelId: 15781,
......@@ -198,10 +198,10 @@ describe('MinervaPluginProxy', function () {
});
it("for reaction", function () {
var map, proxy;
var map;
return ServerConnector.getProject().then(function (project) {
map = helper.createCustomMap(project);
proxy = createProxy(map);
var proxy = createProxy(map);
return proxy.project.data.getBioEntityById({
id: 153508,
modelId: 15781,
......@@ -216,6 +216,26 @@ describe('MinervaPluginProxy', function () {
});
});
describe("exportToMapFormat", function () {
it("for alias", function () {
var map;
return ServerConnector.getProject().then(function (project) {
map = helper.createCustomMap(project);
var proxy = createProxy(map);
return proxy.project.data.exportToMapFormat({
modelId: 15781,
bioEntities: [{id: 329177, modelId: 15781, type: "ALIAS"}],
handlerClass: helper.getConfiguration().getModelConverters()[0].handler
});
}).then(function (result) {
assert.ok(result);
}).then(function () {
map.destroy();
});
});
});
describe("showElement", function () {
it("alias", function () {
var elementToShow = {
......@@ -238,7 +258,8 @@ describe('MinervaPluginProxy', function () {
color: "#FF0000"
}
};
var map, proxy;
var map;
var proxy;
return ServerConnector.getProject().then(function (project) {
map = helper.createCustomMap(project);
proxy = createProxy(map);
......
<?xml version="1.0" encoding="UTF-8"?>
<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4">
<model metaid="untitled" id="untitled">
<listOfUnitDefinitions>
</listOfUnitDefinitions>
<listOfFunctionDefinitions>
</listOfFunctionDefinitions>
<annotation>
<celldesigner:extension>
<celldesigner:modelVersion>4.0</celldesigner:modelVersion>
<celldesigner:modelDisplay sizeX="1305" sizeY="473"/>
<celldesigner:listOfIncludedSpecies>
</celldesigner:listOfIncludedSpecies>
<celldesigner:listOfCompartmentAliases>
</celldesigner:listOfCompartmentAliases>
<celldesigner:listOfComplexSpeciesAliases>
</celldesigner:listOfComplexSpeciesAliases>
<celldesigner:listOfSpeciesAliases>
<celldesigner:speciesAlias id="sa10" species="s_id_sa10" >
<celldesigner:activity>inactive</celldesigner:activity>
<celldesigner:bounds x="0.0" y="186.0" w="80.0" h="30.0" />
<celldesigner:font size="12.0"/>
<celldesigner:view state="usual"/>
<celldesigner:usualView><celldesigner:innerPosition x="0.0" y="186.0"/><celldesigner:boxSize width="80.0" height="30.0"/><celldesigner:singleLine width="1.0"/><celldesigner:paint color="FFFF00FF" scheme="Color"/></celldesigner:usualView>
<celldesigner:briefView><celldesigner:innerPosition x="0.0" y="186.0"/><celldesigner:boxSize width="80.0" height="30.0"/><celldesigner:singleLine width="1.0"/><celldesigner:paint color="FFFF00FF" scheme="Color"/></celldesigner:briefView>
</celldesigner:speciesAlias>
</celldesigner:listOfSpeciesAliases>
<celldesigner:listOfProteins></celldesigner:listOfProteins>
<celldesigner:listOfGenes></celldesigner:listOfGenes>
<celldesigner:listOfRNAs></celldesigner:listOfRNAs>
<celldesigner:listOfAntisenseRNAs></celldesigner:listOfAntisenseRNAs>
<celldesigner:listOfLayers></celldesigner:listOfLayers>
</celldesigner:extension>
</annotation>
<listOfCompartments>
<compartment metaid="default" id="default" name="" size="1" units="volume" >
<annotation>
<celldesigner:extension>
<celldesigner:name></celldesigner:name>
</celldesigner:extension>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/">
<rdf:Description rdf:about="#">
</rdf:Description>
</rdf:RDF>
</annotation>
<notes><html xmlns="http://www.w3.org/1999/xhtml"><head><title/></head><body>
</body></html></notes>
</compartment>
</listOfCompartments>
<listOfSpecies><species name="s10" id="s_id_sa10" metaid="s_id_sa10" initialAmount="0.0" compartment="default"><annotation><celldesigner:extension><celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment><celldesigner:speciesIdentity><celldesigner:class>DRUG</celldesigner:class>
<celldesigner:name>s10</celldesigner:name>
</celldesigner:speciesIdentity>
</celldesigner:extension>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:vCard="http://www.w3.org/2001/vcard-rdf/3.0#" xmlns:bqbiol="http://biomodels.net/biology-qualifiers/" xmlns:bqmodel="http://biomodels.net/model-qualifiers/">
<rdf:Description rdf:about="#">
</rdf:Description>
</rdf:RDF>
</annotation>
</species>
</listOfSpecies>
<listOfReactions>
</listOfReactions>
<notes></notes></model></sbml>
\ No newline at end of file
......@@ -6,14 +6,15 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import lcsb.mapviewer.model.map.layout.graphics.Layer;
import lcsb.mapviewer.model.map.layout.graphics.LayerText;
import lcsb.mapviewer.model.map.model.Model;
import lcsb.mapviewer.model.map.reaction.AbstractNode;
import lcsb.mapviewer.model.map.reaction.Reaction;
import lcsb.mapviewer.model.map.reaction.ReactionNode;
import lcsb.mapviewer.model.map.species.Element;
import lcsb.mapviewer.model.map.species.Complex;
import lcsb.mapviewer.model.map.species.Element;
import lcsb.mapviewer.model.map.species.Species;
/**
......@@ -24,118 +25,160 @@ import lcsb.mapviewer.model.map.species.Species;
*
*/
public class SubModelCommand extends NewModelCommand {
/**
* Polygon that limits the area for the new model.
*
*/
private Path2D polygon;
/**
* Default constructor.
*
* @param model
* original {@link NewModelCommand#model}
* @param polygon
* #polygon that limits the area for the new model
*/
public SubModelCommand(Model model, Path2D polygon) {
super(model);
this.polygon = polygon;
}
@Override
public Model execute() {
CopyCommand copy = new CopyCommand(getModel());
Model result = copy.execute();
Set<Element> aliasNotToRemove = new HashSet<Element>();
for (Element alias : result.getElements()) {
if (polygon.intersects(alias.getBorder())) {
aliasNotToRemove.add(alias);
}
}
boolean added = false;
do {
Set<Element> iterativeAliasNotToRemove = new HashSet<>();
for (Element alias : aliasNotToRemove) {
Element parent = alias.getCompartment();
if (parent != null) {
if (!aliasNotToRemove.contains(parent)) {
iterativeAliasNotToRemove.add(parent);
}
}
if (alias instanceof Species) {
parent = ((Species) alias).getComplex();
if (parent != null) {
if (!aliasNotToRemove.contains(parent)) {
iterativeAliasNotToRemove.add(parent);
}
}
}
}
added = iterativeAliasNotToRemove.size() != 0;
aliasNotToRemove.addAll(iterativeAliasNotToRemove);
} while (added);
List<Element> aliasToRemove = new ArrayList<Element>();
for (Element alias : result.getElements()) {
if (!(polygon.intersects(alias.getBorder()))) {
boolean remove = true;
if (alias instanceof Species) {
remove = ((Species) alias).getComplex() == null;
}
if (aliasNotToRemove.contains(alias)) {
remove = false;
}
if (remove) {
aliasToRemove.add(alias);
if (alias instanceof Complex) {
List<Species> aliases = ((Complex) alias).getAllChildren();
aliasToRemove.addAll(aliases);
}
}
}
}
for (Element alias : aliasToRemove) {
result.removeElement(alias);
}
List<Reaction> reactionsToRemove = new ArrayList<Reaction>();
for (Reaction reaction : result.getReactions()) {
boolean remove = false;
for (AbstractNode node : reaction.getNodes()) {
if (node instanceof ReactionNode) {
if (!result.getElements().contains(((ReactionNode) node).getElement())) {
remove = true;
break;
}
}
}
if (remove) {
reactionsToRemove.add(reaction);
}
}
for (Reaction reaction : reactionsToRemove) {
result.removeReaction(reaction);
}
for (Layer layer : result.getLayers()) {
List<LayerText> textToRemove = new ArrayList<LayerText>();
for (LayerText text : layer.getTexts()) {
if (!(polygon.intersects(text.getBorder()))) {
textToRemove.add(text);
}
}
for (LayerText text : textToRemove) {
layer.removeLayerText(text);
}
}
return result;
}
Logger logger = Logger.getLogger(SubModelCommand.class);
/**
* Polygon that limits the area for the new model.
*
*/
private Path2D polygon;
private Set<Integer> elementIds;
private Set<Integer> reactionIds;
/**
* Default constructor.
*
* @param model
* original {@link NewModelCommand#model}
* @param polygon
* #polygon that limits the area for the new model
*/
public SubModelCommand(Model model, Path2D polygon) {
this(model, polygon, new HashSet<>(), new HashSet<>());
}
/**
* Default constructor.
*
* @param model
* original {@link NewModelCommand#model}
* @param polygon
* #polygon that limits the area for the new model
*/
public SubModelCommand(Model model, Path2D polygon, Set<Integer> elementIds, Set<Integer> reactionIds) {
super(model);
this.polygon = polygon;
this.elementIds = elementIds;
this.reactionIds = reactionIds;
}
@Override
public Model execute() {
CopyCommand copy = new CopyCommand(getModel());
Model result = copy.execute();
Set<Element> inputElements = new HashSet<>();
if (elementIds.size() == 0) {
inputElements.addAll(result.getElements());
} else {
for (Element element : getModel().getElements()) {
if (elementIds.contains(element.getId())) {
inputElements.add(result.getElementByElementId(element.getElementId()));
}
}
}
Set<Element> aliasNotToRemove = new HashSet<>();
for (Element alias : result.getElements()) {
if (polygon.intersects(alias.getBorder())) {
aliasNotToRemove.add(alias);
}
}
aliasNotToRemove.retainAll(inputElements);
boolean added = false;
do {
Set<Element> iterativeAliasNotToRemove = new HashSet<>();
for (Element alias : aliasNotToRemove) {
Element parent = alias.getCompartment();
if (parent != null) {
if (!aliasNotToRemove.contains(parent)) {
iterativeAliasNotToRemove.add(parent);
}
}
if (alias instanceof Species) {
parent = ((Species) alias).getComplex();
if (parent != null) {
if (!aliasNotToRemove.contains(parent)) {
iterativeAliasNotToRemove.add(parent);
}
}
}
}
added = iterativeAliasNotToRemove.size() != 0;
aliasNotToRemove.addAll(iterativeAliasNotToRemove);
} while (added);
List<Element> aliasToRemove = new ArrayList<>();
for (Element element : result.getElements()) {
if (!(polygon.intersects(element.getBorder())) || !inputElements.contains(element)) {
boolean remove = true;
if (element instanceof Species) {
remove = ((Species) element).getComplex() == null;
}
if (aliasNotToRemove.contains(element)) {
remove = false;
}
if (remove) {
aliasToRemove.add(element);
if (element instanceof Complex) {
List<Species> aliases = ((Complex) element).getAllChildren();
aliasToRemove.addAll(aliases);
}
}
}
}
for (Element alias : aliasToRemove) {
result.removeElement(alias);
}
Set<String> reactionStringIds = new HashSet<>();
for (Reaction reaction : getModel().getReactions()) {
if (reactionIds.size() == 0 || reactionIds.contains(reaction.getId())) {
reactionStringIds.add(reaction.getElementId());
}
}
List<Reaction> reactionsToRemove = new ArrayList<>();
for (Reaction reaction : result.getReactions()) {
boolean remove = false;
if (!reactionStringIds.contains(reaction.getElementId())) {
remove = true;
} else {
for (ReactionNode node : reaction.getReactionNodes()) {
if (!result.getElements().contains(node.getElement())) {
remove = true;
break;
}
}
}
if (remove) {
reactionsToRemove.add(reaction);
}
}
for (Reaction reaction : reactionsToRemove) {
result.removeReaction(reaction);
}
for (Layer layer : result.getLayers()) {
List<LayerText> textToRemove = new ArrayList<>();
for (LayerText text : layer.getTexts()) {