blob: 7ea699dd35926fac9bd366fc7f384dce633f3a06 [file] [log] [blame]
/**
*
* Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
*
*
* This copyright notice shows up in the generated Java code
*
*/
package org.eclipse.osbp.xtext.chart.jvmmodel
import com.vaadin.data.Property.ValueChangeListener
import com.vaadin.server.Page
import com.vaadin.server.Page.Styles
import com.vaadin.server.StreamResource
import com.vaadin.ui.HorizontalLayout
import com.vaadin.ui.JavaScriptFunction
import com.vaadin.ui.Label
import com.vaadin.ui.Panel
import com.vaadin.ui.TabSheet
import com.vaadin.ui.UI
import elemental.json.JsonArray
import elemental.json.JsonException
import elemental.json.JsonObject
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.util.ArrayList
import java.util.Collection
import java.util.Date
import java.util.HashMap
import java.util.List
import java.util.Locale
import java.util.Map
import java.util.ResourceBundle
import java.util.UUID
import java.util.concurrent.Executors
import javax.imageio.ImageIO
import javax.inject.Inject
import mondrian.olap.Member.MemberType
import org.dussan.vaadin.dcharts.DCharts
import org.dussan.vaadin.dcharts.DownloadButtonLocation
import org.dussan.vaadin.dcharts.base.elements.Trendline
import org.dussan.vaadin.dcharts.base.elements.XYaxis
import org.dussan.vaadin.dcharts.base.elements.XYseries
import org.dussan.vaadin.dcharts.data.DataSeries
import org.dussan.vaadin.dcharts.data.Ticks
import org.dussan.vaadin.dcharts.metadata.LegendPlacements
import org.dussan.vaadin.dcharts.metadata.PyramidSides
import org.dussan.vaadin.dcharts.metadata.SeriesToggles
import org.dussan.vaadin.dcharts.metadata.TooltipAxes
import org.dussan.vaadin.dcharts.metadata.XYaxes
import org.dussan.vaadin.dcharts.metadata.Xaxes
import org.dussan.vaadin.dcharts.metadata.Yaxes
import org.dussan.vaadin.dcharts.metadata.directions.BarDirections
import org.dussan.vaadin.dcharts.metadata.locations.TooltipLocations
import org.dussan.vaadin.dcharts.metadata.renderers.AxisRenderers
import org.dussan.vaadin.dcharts.metadata.renderers.SeriesRenderers
import org.dussan.vaadin.dcharts.options.Axes
import org.dussan.vaadin.dcharts.options.AxesDefaults
import org.dussan.vaadin.dcharts.options.Cursor
import org.dussan.vaadin.dcharts.options.Highlighter
import org.dussan.vaadin.dcharts.options.Legend
import org.dussan.vaadin.dcharts.options.Options
import org.dussan.vaadin.dcharts.options.Series
import org.dussan.vaadin.dcharts.options.SeriesDefaults
import org.dussan.vaadin.dcharts.options.Title
import org.dussan.vaadin.dcharts.renderers.axis.LinearAxisRenderer
import org.dussan.vaadin.dcharts.renderers.legend.EnhancedLegendRenderer
import org.dussan.vaadin.dcharts.renderers.series.BarRenderer
import org.dussan.vaadin.dcharts.renderers.series.BubbleRenderer
import org.dussan.vaadin.dcharts.renderers.series.DonutRenderer
import org.dussan.vaadin.dcharts.renderers.series.MeterGaugeRenderer
import org.dussan.vaadin.dcharts.renderers.series.PieRenderer
import org.dussan.vaadin.dcharts.renderers.series.PyramidRenderer
import org.dussan.vaadin.dcharts.renderers.tick.AxisTickRenderer
import org.dussan.vaadin.dcharts.renderers.tick.CanvasAxisTickRenderer
import org.eclipse.e4.core.di.extensions.EventUtils
import org.eclipse.e4.ui.model.application.ui.MUIElement
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective
import org.eclipse.e4.ui.model.application.ui.basic.MPartStack
import org.eclipse.e4.ui.model.application.ui.impl.UIElementImpl
import org.eclipse.e4.ui.model.application.ui.impl.UiPackageImpl
import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement
import org.eclipse.emf.common.notify.Notification
import org.eclipse.emf.ecore.EObject
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.osbp.eventbroker.EventBrokerMsg
import org.eclipse.osbp.runtime.common.event.EventDispatcherEvent
import org.eclipse.osbp.ui.api.datamart.DatamartFilter
import org.eclipse.osbp.ui.api.datamart.IDatamartFilterGenerator
import org.eclipse.osbp.utils.vaadin.ViewLayoutManager
import org.eclipse.osbp.xtext.action.ChartActionEnum
import org.eclipse.osbp.xtext.basic.generator.BasicDslGeneratorUtils
import org.eclipse.osbp.xtext.chart.Chart
import org.eclipse.osbp.xtext.chart.ChartModel
import org.eclipse.osbp.xtext.chart.ChartTree
import org.eclipse.osbp.xtext.datamart.common.DatamartFilterGenerator
import org.eclipse.osbp.xtext.datamart.common.olap.CellSetToD3JsonConverter
import org.eclipse.osbp.xtext.datamart.common.olap.DerivedAxis
import org.eclipse.osbp.xtext.datamart.common.olap.DerivedCell
import org.eclipse.osbp.xtext.datamart.common.olap.DerivedHierarchy
import org.eclipse.osbp.xtext.datamart.common.olap.DerivedLevel
import org.eclipse.osbp.xtext.datamart.common.olap.DerivedMember
import org.eclipse.osbp.xtext.datamart.common.olap.DerivedPosition
import org.eclipse.osbp.xtext.i18n.I18NModelGenerator
import org.eclipse.xtext.generator.IFileSystemAccess
import org.eclipse.xtext.naming.IQualifiedNameProvider
import org.eclipse.xtext.xbase.compiler.GeneratorConfig
import org.eclipse.xtext.xbase.compiler.ImportManager
import org.osgi.service.event.Event
import org.osgi.service.event.EventHandler
import com.vaadin.ui.Button
import com.vaadin.server.FileDownloader
import com.vaadin.server.StreamResource.StreamSource
import java.io.InputStream
class ChartModelGenerator extends I18NModelGenerator {
@Inject extension IQualifiedNameProvider
@Inject extension D3JsJavaUtil
@Inject extension BasicDslGeneratorUtils
override createAppendable(EObject context, ImportManager importManager, GeneratorConfig config) {
// required to initialize the needed builder to avoid deprecated methods
builder = context.eResource
// ---------
importManager.addImportFor(_typeReferenceBuilder.typeRef(HashMap, _typeReferenceBuilder.typeRef(String), _typeReferenceBuilder.typeRef(String)).type)
importManager.addImportFor(_typeReferenceBuilder.typeRef(Map, _typeReferenceBuilder.typeRef(String), _typeReferenceBuilder.typeRef(String)).type)
importManager.addImportFor(_typeReferenceBuilder.typeRef(Collection, _typeReferenceBuilder.typeRef(String)).type)
addImportFor(importManager, _typeReferenceBuilder
, ValueChangeListener
, DCharts
, Label
, List
, ArrayList
, Page
, Styles
, DerivedAxis
, DerivedCell
, DerivedPosition
, DerivedMember
, HorizontalLayout
, TabSheet
, Series
, XYseries
, Ticks
, DataSeries
, SeriesDefaults
, SeriesRenderers
, CanvasAxisTickRenderer
, DonutRenderer
, PieRenderer
, BubbleRenderer
, BarRenderer
, BarDirections
, MeterGaugeRenderer
, PyramidRenderer
, PyramidSides
, Trendline
, Cursor
, Legend
, LegendPlacements
, EnhancedLegendRenderer
, SeriesToggles
, Highlighter
, Title
, TooltipLocations
, TooltipAxes
, Axes
, XYaxes
, XYaxis
, Xaxes
, Yaxes
, AxisTickRenderer
, AxisRenderers
, LinearAxisRenderer
, AxesDefaults
, DownloadButtonLocation
, Options
, DerivedHierarchy
, DerivedLevel
, CellSetToD3JsonConverter
, Date
, JavaScriptFunction
, JsonArray
, JsonObject
, JsonException
, EventHandler
, Event
, EventUtils
, EventBrokerMsg
, Executors
, Notification
, EObject
, UIElementImpl
, UiPackageImpl
, MUIElement
, MPartStack
, UI
, ResourceBundle
, Locale
, DatamartFilterGenerator
, ViewLayoutManager
, IDatamartFilterGenerator.FilterChangeListener
, EventDispatcherEvent
, EventDispatcherEvent.EventDispatcherDataTag
, EventDispatcherEvent.EventDispatcherCommand
, DatamartFilter
, MemberType
, Panel
, MPerspective
, ChartActionEnum
, UUID
, StreamResource
, MToolBarElement
, Button
, FileDownloader
, StreamSource
, ByteArrayOutputStream
, ImageIO
, ByteArrayInputStream
, InputStream
)
super.createAppendable(context, importManager, config)
}
override void doGenerate(Resource input, IFileSystemAccess fsa) {
super.addTranslatables("download")
super.doGenerate(input, fsa )
for (obj : input.contents) {
obj.internalDoGenerate(fsa)
}
}
def dispatch void internalDoGenerate(ChartModel chartModel, IFileSystemAccess fsa) {
for (pkg : chartModel.packages) {
for (chart : pkg.charts) {
if ((chart.charttype instanceof ChartTree)) {
var pckgName = pkg.fullyQualifiedName.toString
// println(pckgName)
var strBuilder = new StringBuilder
var pckgNamePath = pckgName.replaceAll("\\.","/")
// var propOutputFile = '''«pckgNamePath»/«chart.createChartJsFilename(chartTree)»'''
var propOutputFile = '''«pckgNamePath»/«chart.createChartJsFilename»'''
// println("********************* Property-Output *********************")
chart.generateJsFile(strBuilder)
if (strBuilder.length > 0){
fsa.generateFile(propOutputFile, strBuilder)
// println(strBuilder.toString)
}
}
}
}
}
def void generateJsFile(Chart chart,StringBuilder strBuilder){
var chartFilePath = chart.createfullyQualifiedChartFilename.replaceAll("\\.","_")
if (chart.charttype instanceof ChartTree){
var chartTree = chart.charttype as ChartTree
if (chartTree.map){
strBuilder.generateTreeMapJsFile(chartFilePath)
} else if (chartTree.collapsible) {
strBuilder.generateCollTreeJsFile(chartFilePath)
}
}
}
def void generateTreeMapJsFile(StringBuilder strBuilder, String chartJavaFileName){
strBuilder.append('''«chartJavaFileName» = function() {
var margin = {
top: 40,
right: 10,
bottom: 10,
left: 10
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var color = d3.scale.category20c();
function position() {
this.style("left", function (d) {
return d.x + "px";
})
.style("top", function (d) {
return d.y + "px";
})
.style("width", function (d) {
return Math.max(0, d.dx - 1) + "px";
})
.style("height", function (d) {
return Math.max(0, d.dy - 1) + "px";
});
}
var cxD3TreeMapJsHTMLRootComponent = this.getElement();
var cxD3TreeMapJsComponentHtmlTagId = this.getState().htmlTagId;
var checked = "";
var connector = this;
var dataColumn = "";
var preValueLabel = "";
for (var i=0;i < this.getState().dataColumnList.length;i++) {
if (i == 0){
checked = " checked";
preValueLabel = this.getState().dataColumnList[0];
} else {
checked = "";
}
dataColumn = dataColumn + "\t<label><input id=\""+this.getState().htmlTagId+"_input\" type=\"radio\" name=\"mode\" value=\""+ this.getState().dataColumnList[i] + "\"" + checked + "> "+ this.getState().dataColumnList[i] + "</label>\n";
}
var treemap = d3.layout.treemap()
.size([width, height])
.sticky(true)
.value(function (d) {
return eval("d." + preValueLabel);
});
// alert("dataColumn: " + dataColumn);
cxD3TreeMapJsHTMLRootComponent.innerHTML = "<form>\n" +
dataColumn +
"</form>\n" +
"<div id=\""+this.getState().htmlTagId+"_div\">" + "</div>";
var cxD3TreeMapJsHTMLRootComponentSelection = d3.select(cxD3TreeMapJsHTMLRootComponent).select("#"+this.getState().htmlTagId+"_div");
// alert("selection: " + selection);
var cxD3TreeMapJsHTMLRootComponentDiv = cxD3TreeMapJsHTMLRootComponentSelection.append("div")
.style("position", "relative")
.style("width", (width + margin.left + margin.right) + "px")
.style("height", (height + margin.top + margin.bottom) + "px")
.style("left", margin.left + "px")
.style("top", margin.top + "px");
jsonTreeMapFunction = function(jsonObj) {
var node = cxD3TreeMapJsHTMLRootComponentDiv.datum(jsonObj).selectAll(".node")
.data(treemap.nodes)
.enter().append("div")
.attr("class", "node")
.attr("title", function(d) { return d.children ? "" : d.tooltipName + "\n" + preValueLabel + ": " + eval("d." + preValueLabel); })
.call(position)
.style("background", function(d) { return d.children ? color(d.name) : null; })
// .style("background", function(d) { return d.children ? d3.rgb("red") : null; })
.text(function(d) { return d.children ? null : d.name; });
d3.select(cxD3TreeMapJsHTMLRootComponent).selectAll("#"+cxD3TreeMapJsComponentHtmlTagId+"_input").on("change", function change() {
var valueLabel = this.value;
// alert("valueOut: " + valueOut);
var value = this.value === "count"
? function() { return 1; }
: function (d) { return eval("d." + valueLabel); };
// : function (d) { return d.size; };
node.data(treemap.value(value).nodes)
.attr("title", function(d) { return d.children ? "" : d.tooltipName + "\n" + valueLabel + ": " + eval("d." + valueLabel); })
.transition()
.duration(1500)
.call(position);
});
}
var jsonString = this.getState().jsonData;
jsonTreeMapFunction(JSON.parse(jsonString));
}
''')
}
def void generateCollTreeJsFile(StringBuilder strBuilder, String chartJavaFileName){
strBuilder.append('''«chartJavaFileName» = function() {
var margin = {top: 20, right: 120, bottom: 20, left: 120},
width = 1460 - margin.right - margin.left,
height = 1000 - margin.top - margin.bottom;
var i = 0,
duration = 750,
cxD3TreeJsComponent_jsonRoot;
var tree = d3.layout.tree()
.size([height, width]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var cxD3TreeJsHTMLRootComponent = this.getElement();
cxD3TreeJsHTMLRootComponent.innerHTML =
"<label><input id=\""+this.getState().htmlTagId+"_input\" type=\"radio\" name=\"mode\" value=\"expand\">Expand</label>\n" +
"<label><input id=\""+this.getState().htmlTagId+"_input\" type=\"radio\" name=\"mode\" value=\"collapse\" checked>Collapse</label>\n" +
"<div id=\""+this.getState().htmlTagId+"_div\">" + "</div>";
var cxD3TreeJsHTMLRootComponentSelection = d3.select(cxD3TreeJsHTMLRootComponent).select("#"+this.getState().htmlTagId+"_div");
var cxD3TreeJsHTMLRootComponentSvg = cxD3TreeJsHTMLRootComponentSelection.append("svg")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
function expand(d) {
if (d._children) {
d.children = d._children;
d.children.forEach(expand);
d._children = null;
}
}
jsonTreeFunction = function(jsonData) {
cxD3TreeJsComponent_jsonRoot = jsonData;
cxD3TreeJsComponent_jsonRoot.x0 = height / 2;
cxD3TreeJsComponent_jsonRoot.y0 = 0;
cxD3TreeJsComponent_jsonRoot.children.forEach(collapse);
update(cxD3TreeJsComponent_jsonRoot);
}
jsonTreeFunction(JSON.parse(this.getState().jsonData));
d3.select(cxD3TreeJsHTMLRootComponent).select(self.frameElement).style("height", "800px");
d3.select(cxD3TreeJsHTMLRootComponent).selectAll("#"+this.getState().htmlTagId+"_input").on("change", function change() {
// alert("this.value = " + this.value);
if (this.value === "expand"){
cxD3TreeJsComponent_jsonRoot.children.forEach(expand);
} else {
cxD3TreeJsComponent_jsonRoot.children.forEach(collapse);
}
update(cxD3TreeJsComponent_jsonRoot);
});
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(cxD3TreeJsComponent_jsonRoot).reverse(),
links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });
// Update the nodes€¦
var node = cxD3TreeJsHTMLRootComponentSvg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", click);
nodeEnter.append("circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeEnter.append("text")
.attr("x", function(d) { return d.children || d._children ? -10 : 10; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links€¦
var link = cxD3TreeJsHTMLRootComponentSvg.selectAll("path.link")
.data(links, function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
}
''')
}
}