Skip to content
Snippets Groups Projects
Commit 4ef727a3 authored by Simon Barner's avatar Simon Barner
Browse files

Merge branch '4310' into 'master'

Setting up Metric extraction plugin for AF3 :  Issue 4310

See merge request !210
parents b41ae985 105a0ee4
No related branches found
No related tags found
1 merge request!210Setting up Metric extraction plugin for AF3 : Issue 4310
Showing
with 874 additions and 1 deletion
......@@ -5,4 +5,4 @@
/target/
*.rej
.DS_Store
._.DS_Store
._.DS_Store
......@@ -34,6 +34,12 @@
[submodule "org.fortiss.variability/.settings"]
path = org.fortiss.variability/.settings
url = https://git.fortiss.org/af3/plugin-settings.git
[submodule "org.fortiss.tooling.ext.quality/.settings"]
path = org.fortiss.tooling.ext.quality/.settings
url = https://git.fortiss.org/af3/plugin-settings.git
[submodule "org.fortiss.tooling.ext.quality.ui/.settings"]
path = org.fortiss.tooling.ext.quality.ui/.settings
url = https://git.fortiss.org/af3/plugin-settings.git
[submodule "org.fortiss.tooling.ext.reuse/.settings"]
path = org.fortiss.tooling.ext.reuse/.settings
url = https://git.fortiss.org/af3/plugin-settings.git
......
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="res"/>
<classpathentry kind="output" path="build"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.fortiss.tooling.ext.quality.ui</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.systemfocus.tooling.emfgeneration.git.EcoreBuilderGIT</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.systemfocus.tooling.codereview.builder.CodeReviewBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.systemfocus.tooling.codereview.builder.RemoveWarningsBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.systemfocus.tooling.codereview.builder.GuidelinesCheckBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.systemfocus.tooling.codereview.nature.CodeReviewNature</nature>
</natures>
</projectDescription>
Subproject commit 310d1c04f28f6252d5a02dd8fde1b76ae4a4da51
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Model Quality UI
Bundle-SymbolicName: org.fortiss.tooling.ext.quality.ui;singleton:=true
Bundle-Version: 2.23.0.qualifier
Automatic-Module-Name: org.fortiss.tooling.ext.quality.ui
Bundle-RequiredExecutionEnvironment: JavaSE-11
Require-Bundle: org.fortiss.tooling.base.ui;visibility:=reexport,
org.fortiss.tooling.ext.quality;visibility:=reexport,
org.fortiss.tooling.spiderchart.ui;visibility:=reexport
Export-Package: org.fortiss.tooling.ext.quality.ui.view.fx
Bundle-Activator: org.fortiss.tooling.ext.quality.ui.ModelQualityUIActivator
Bundle-ActivationPolicy: lazy
Bundle-Vendor: fortiss GmbH
# (c) 2023 fortiss GmbH
bin.includes = .,\
META-INF/,\
plugin.xml,\
icons/
source.. = src/,\
res/
output.. = build/
src.includes = icons/
documentation.html aaa534ab30ef337c5e7bc75d37490eb6a5a4edd1 GREEN
<html><body>
<h1>Developer Documentation for <i>AF3 Model Quality</i> (org.fortiss.tooling.ext.quality.ui)</h1>
<h2>Plugin description</h2>
<p>This is the user interface part of the tooling.ext.quality plugin. It provides a simple view to display collected metrics</p>
<h2>Package description</h2>
<ul>
<li><tt>quality.ui</tt>: main package with the UI plugin activator.</li>
<li><tt>quality.ui.view.fx</tt>: implementation of quality library view (FX-based).</li>
</ul>
</body></html>
org.fortiss.tooling.ext.quality.ui/icons/metric.png

826 B

<!-- (c) 2023 fortiss GmbH -->
pluginName = Model Quality UI
providerName = fortiss GmbH
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<!-- (c) 2021 fortiss GmbH -->
<plugin>
<extension point="org.fortiss.tooling.kernel.ui.contextMenuContribution">
<contextMenuContribution
contributor="org.fortiss.tooling.ext.quality.ui.ModelQualityExtractionMenu">
</contextMenuContribution>
</extension>
<extension point="org.eclipse.ui.views">
<view
class="org.fortiss.tooling.ext.quality.ui.view.fx.ModelQualityFXViewPart"
icon="icons/metric.png"
id="org.fortiss.tooling.ext.quality.ui.metricsView"
name="Metrics"
restorable="true"
allowMultiple="false">
</view>
</extension>
</plugin>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.chart.BarChart?>
<?import javafx.scene.chart.CategoryAxis?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.chart.PieChart?>
<?import javafx.scene.chart.ScatterChart?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.text.Text?>
<SplitPane fx:id="metricsSplitPane" dividerPositions="0.5" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" orientation="VERTICAL" prefHeight="400.0" prefWidth="1035.0" xmlns="http://javafx.com/javafx/13.0.2" xmlns:fx="http://javafx.com/fxml/1">
<items>
<TabPane prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE">
<tabs>
<Tab text="Pie and Spider">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<SplitPane dividerPositions="0.5" layoutX="56.0" layoutY="-19.0" prefHeight="134.0" prefWidth="1033.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<BorderPane prefHeight="200.0" prefWidth="200.0">
<center>
<PieChart fx:id="pieChart" prefHeight="184.0" prefWidth="1033.0" BorderPane.alignment="CENTER" />
</center>
<top>
<ChoiceBox fx:id="childMetricChoiceBox" onAction="#onChildMetricChoiceBoxChange" prefHeight="24.0" prefWidth="270.0" BorderPane.alignment="CENTER" />
</top>
</BorderPane>
<BorderPane fx:id="borderPane" prefHeight="158.0" prefWidth="81.0" />
</items>
</SplitPane>
</children>
</AnchorPane>
</content>
</Tab>
<Tab text="Scatter and Bar">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<SplitPane dividerPositions="0.5" prefHeight="336.0" prefWidth="1033.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<BorderPane prefHeight="200.0" prefWidth="200.0">
<center>
<ScatterChart fx:id="scatterChart" prefHeight="322.0" prefWidth="540.0" BorderPane.alignment="CENTER">
<xAxis>
<NumberAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</ScatterChart>
</center>
<top>
<HBox BorderPane.alignment="CENTER">
<children>
<ChoiceBox fx:id="yScatterMetricChoiceBox" onAction="#onScatterMetricChoiceBoxChange" prefHeight="24.0" prefWidth="270.0" />
<ChoiceBox fx:id="xScatterMetricChoiceBox" onAction="#onScatterMetricChoiceBoxChange" prefHeight="24.0" prefWidth="270.0" />
</children>
</HBox>
</top>
</BorderPane>
<BarChart fx:id="barChart">
<xAxis>
<CategoryAxis side="BOTTOM" />
</xAxis>
<yAxis>
<NumberAxis side="LEFT" />
</yAxis>
</BarChart>
</items>
</SplitPane>
</children>
</AnchorPane>
</content>
</Tab>
</tabs>
</TabPane>
<Text fx:id="bottomText" strokeType="OUTSIDE" strokeWidth="0.0" text="Save model to refresh" />
</items>
</SplitPane>
ModelQualityExtractionMenu.java d9282c7df44aa9461ec662beb557e74589f6b05f GREEN
ModelQualityUIActivator.java 2f47db82bc088072dbfe53f82d3ed417d77fd23c GREEN
/*-------------------------------------------------------------------------+
| Copyright 2023 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.ext.quality.ui;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.fortiss.tooling.kernel.ui.service.IContextMenuService.BOTTOM_MOST_MENU_SECTION_ID;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.resource.ImageDescriptor;
import org.fortiss.tooling.ext.quality.service.IModelQualityService;
import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
import org.fortiss.tooling.kernel.service.IPersistencyService;
import org.fortiss.tooling.kernel.ui.extension.IContextMenuContributor;
import org.fortiss.tooling.kernel.ui.extension.data.ContextMenuContextProvider;
/**
* Creates a context menu entry to extract metrics for the selected model.
*
* @author groh
*/
public class ModelQualityExtractionMenu implements IContextMenuContributor {
/** String appearing in the context menu. */
private static final String MENU_NAME = "Extract metrics";
/** {@inheritDoc} */
@Override
public List<IContributionItem> getContributedItems(EObject selection,
ContextMenuContextProvider contextProvider) {
if(!(selection.eContainer() != null)) {
return emptyList();
}
// A null eContainer indicates the model root
return asList(new IContributionItem[] {
new ActionContributionItem(new MetricExtractionAction(selection))});
}
/** {@inheritDoc} */
@Override
public String getMenuSectionID() {
return BOTTOM_MOST_MENU_SECTION_ID;
}
/** Returns the icon that is visible in the context menu for this entry. */
protected ImageDescriptor getActionIcon() {
return ModelQualityUIActivator.getImageDescriptor("icons/metric.png");
}
/** Action for generating the set of . */
protected class MetricExtractionAction extends Action {
/** Model on which the action will be triggered. */
private final EObject model;
/** Constructor. */
public MetricExtractionAction(EObject model) {
super(MENU_NAME, getActionIcon());
this.model = model;
}
/** {@inheritDoc} */
@Override
public void run() {
ITopLevelElement top =
IPersistencyService.getInstance().getTopLevelElementFor(this.model);
IModelQualityService.getInstance().scheduleMetricCollection(top);
}
}
}
/*-------------------------------------------------------------------------+
| Copyright 2023 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.ext.quality.ui;
import static org.eclipse.jface.resource.ResourceLocator.imageDescriptorFromBundle;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.jface.resource.ImageDescriptor;
import org.fortiss.tooling.ext.quality.service.IModelQualityService;
import org.fortiss.tooling.ext.quality.ui.view.fx.ModelQualityFXViewPart;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle.
*
* @author blaschke
*/
public class ModelQualityUIActivator extends Plugin {
/** The plug-in ID. */
public static final String PLUGIN_ID = ModelQualityUIActivator.class.getPackage().getName(); // $NON-NLS-1$
/** The shared instance. */
private static ModelQualityUIActivator plugin;
/** {@inheritDoc} */
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
IModelQualityService.getInstance()
.registerMetricUpdateListener(ModelQualityFXViewPart.getMetricsFXController());
System.out.println("[Plugin] " + PLUGIN_ID + " started.");
}
/** {@inheritDoc} */
@Override
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance.
*
* @return The shared instance of {@link ModelQualityUIActivator}
*/
public static ModelQualityUIActivator getDefault() {
return plugin;
}
/**
* Returns the image descriptor for the given icon file.
*
* @param path
* The path to the icon file of the image descriptor
* @return The image descriptor
*/
public static ImageDescriptor getImageDescriptor(String path) {
return imageDescriptorFromBundle(PLUGIN_ID, path).orElse(null);
}
}
IModelQualityViewPart.java 708f8089645df12098ea67190805cce343045d2e GREEN
ModelQualityFXController.java c5577d2762eb916835386de5987109fc7899f1bc GREEN
ModelQualityFXViewPart.java 9cfc7f60a86ea5b915c726b16712f8be7dec2c5f GREEN
/*-------------------------------------------------------------------------+
| Copyright 2023 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.ext.quality.ui.view.fx;
/**
* Interface for views displaying the Metrics view.
*
* @author groh
*/
public interface IModelQualityViewPart {
/** View ID for model quality views. */
// Keep in sync with plugin.xml
public static String MODEL_QUALITY_VIEW_ID = "org.fortiss.tooling.ext.quality.ui.metricsView";
}
/*-------------------------------------------------------------------------+
| Copyright 2023 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.tooling.ext.quality.ui.view.fx;
import static java.util.stream.Collectors.toList;
import static javafx.scene.paint.Color.BLUE;
import static javafx.scene.paint.Color.DARKGRAY;
import static javafx.scene.paint.Color.LIGHTGRAY;
import static org.fortiss.tooling.common.ui.javafx.style.FontStyle.BLACK_VERDANA_10PT;
import static org.fortiss.tooling.common.ui.javafx.style.FontStyle.BLACK_VERDANA_12PT;
import static org.fortiss.tooling.common.ui.javafx.style.FontStyle.BLACK_VERDANA_14PT;
import static org.fortiss.tooling.common.ui.javafx.style.FontStyle.BLACK_VERDANA_8PT;
import static org.fortiss.tooling.common.ui.javafx.style.LineStyle.SOLID_BLACK_1PT;
import static org.fortiss.tooling.kernel.ui.util.SelectionUtils.checkAndPickFirst;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.getFirstParentWithType;
import java.text.DecimalFormat;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.fortiss.tooling.common.ui.javafx.layout.CompositeFXControllerBase;
import org.fortiss.tooling.common.ui.javafx.style.FillStyle;
import org.fortiss.tooling.common.ui.javafx.style.FontStyle;
import org.fortiss.tooling.common.ui.javafx.style.LineStyle;
import org.fortiss.tooling.ext.quality.IMetricUpdateListener;
import org.fortiss.tooling.ext.quality.data.MetricData;
import org.fortiss.tooling.ext.quality.data.MetricKey;
import org.fortiss.tooling.ext.quality.data.MetricTreeNode;
import org.fortiss.tooling.ext.quality.service.IModelQualityService;
import org.fortiss.tooling.kernel.model.IProjectRootElement;
import org.fortiss.tooling.spiderchart.control.SpiderChartViewer;
import org.fortiss.tooling.spiderchart.model.DataSeries;
import org.fortiss.tooling.spiderchart.model.DoubleAxis;
import org.fortiss.tooling.spiderchart.model.SpiderChart;
import org.fortiss.tooling.spiderchart.style.AxisStyle;
import org.fortiss.tooling.spiderchart.style.ChartStyle;
import org.fortiss.tooling.spiderchart.style.DataSeriesStyle;
import org.fortiss.tooling.spiderchart.style.LegendStyle;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.ScatterChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.util.Pair;
/**
* FX Controller for the Metrics view.
*
* @author groh
*/
@SuppressWarnings("unchecked")
public class ModelQualityFXController extends CompositeFXControllerBase<SplitPane, Node>
implements ISelectionListener, IMetricUpdateListener {
/**
* Selection of colors for the overlays in the spider chart. The length of this array also
* limits the depth of the {@link ModelQualityFXController#lastViewedElements} list.
*/
private static Color[] SPIDER_CHART_OVERLAY_COLORS = {Color.GREEN, Color.BLUE, Color.RED};
/** {@link ChoiceBox} for selecting the metric which shall be displayed. */
@FXML
private ChoiceBox<MetricKey> childMetricChoiceBox;
/** {@link PieChart} displaying the metrics. */
@FXML
private PieChart pieChart;
/** The bottom {@link BorderPane} for the spider chart. */
@FXML
private BorderPane borderPane;
/** {@link ChoiceBox} for selecting the metric displayed on the x axis of the scatter chart. */
@FXML
private ChoiceBox<MetricKey> xScatterMetricChoiceBox;
/** {@link ChoiceBox} for selecting the metric displayed on the y axis of the scatter chart. */
@FXML
private ChoiceBox<MetricKey> yScatterMetricChoiceBox;
/** A {@link ScatterChart} for displaying metrics. */
@FXML
private ScatterChart<Number, Number> scatterChart;
/** A {@link BarChart} for displaying metrics. */
@FXML
private BarChart<String, Number> barChart;
/** {@link Text} at the bottom of the view. */
@FXML
private Text bottomText;
/** Time format when displaying updating time. */
private final DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("HH:mm:ss");
/**
* The last {@link EObject} which the user has clicked. Might be null when no or an invalid
* object is selected.
*/
private EObject lastSelectedElement;
/** List of elements for which metrics were displayed. */
private List<Pair<MetricTreeNode, Set<MetricKey>>> lastViewedElements = new ArrayList<>();
/** {@inheritDoc} */
@Override
public String getFXMLLocation() {
return "MetricsViewFx.fxml";
}
/** {@inheritDoc} */
@Override
public void initialize() {
// TODO (#4335)
childMetricChoiceBox.getItems().addAll(MetricKey.values());
xScatterMetricChoiceBox.getItems().addAll(MetricKey.values());
yScatterMetricChoiceBox.getItems().addAll(MetricKey.values());
}
/** {@inheritDoc} */
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
// Invalidate last selection, so if no new selection is found the charts are cleared
lastSelectedElement = null;
EObject selected = checkAndPickFirst(selection, EObject.class);
if(selected == null) {
updateCharts("Nothing selected.");
return;
}
IProjectRootElement currentRootElement =
selected instanceof IProjectRootElement ? (IProjectRootElement)selected
: getFirstParentWithType(selected, IProjectRootElement.class);
if(currentRootElement == null) {
updateCharts("Selection does not have a project root element.");
return;
}
MetricData metricData = IModelQualityService.getInstance().getMetricData();
var rootDataElement = metricData.getDataRootElementMap().get(currentRootElement);
if(rootDataElement == null) {
bottomText.setText(
"Save model or select \"Export Metrics\" in project options to generate metrics.");
updateCharts("No metrics available");
return;
}
bottomText.setText("Metrics last updated: " +
timeFormat.format(rootDataElement.getLastRefresh()) + ". Save model to refresh.");
lastSelectedElement = selected;
updateCharts("Selection does not have metric information.");
}
/** Triggered when the choice box changes. */
public void onChoiceBoxChange() {
updateCharts("Invalid selection or metrics not available.");
}
/** Triggered when the child metric choice box changes. */
public void onChildMetricChoiceBoxChange() {
updateCharts("Invalid selection or metrics not available.");
}
/** Triggered when one of the scatter choice boxes changes. */
public void onScatterMetricChoiceBoxChange() {
updateCharts("Invalid selection or metrics not available.");
}
/**
* Updates the chart in the metric view.
*
* @param message
* to display if metric is not available
*/
private void updateCharts(String message) {
if(lastSelectedElement != null) {
MetricData metricData = IModelQualityService.getInstance().getMetricData();
MetricTreeNode node = metricData.getTreeNodeLookupTable().get(lastSelectedElement);
if(node != null) {
if(!node.getChildren().isEmpty()) {
updatePieChart(node);
updateScatterChart(node);
updateBarChart(node);
updateLastViewedElements(node);
SpiderChartViewer viewer = buildSpiderChart();
borderPane.setCenter(viewer.getViewerPane());
// Return, otherwise the data will be cleared
return;
}
message = "Selection does not have contained elements.";
} else {
message = "Selection does not have metric information.";
}
} else {
// Nothing selected, so remove the bottom text
bottomText.setText("");
}
borderPane.setCenter(new Label(message));
pieChart.getData().clear();
}
/**
* Updates the {@link #pieChart} with data from the provided {@link MetricTreeNode}.
*
* @param node
* which provides the data for this chart
*/
private void updatePieChart(MetricTreeNode node) {
MetricKey selectedMetric = childMetricChoiceBox.getValue();
if(selectedMetric != null) {
// Create PieChart and add data
pieChart.getData().clear();
pieChart.setLegendVisible(false);
pieChart.setTitle("");
DecimalFormat format = new DecimalFormat("0.#");
for(var child : node.getChildren()) {
Double value = child.getValueAsDouble(selectedMetric);
if(value != null) {
PieChart.Data slice =
new PieChart.Data(child.getName() + ": " + format.format(value), value);
pieChart.getData().add(slice);
}
}
}
}
/**
* Updates the {@link #scatterChart} with data from the provided {@link MetricTreeNode}.
*
* @param node
* which provides the data for this chart
*/
private void updateScatterChart(MetricTreeNode node) {
MetricKey xScatterKey = xScatterMetricChoiceBox.getValue();
MetricKey yScatterKey = yScatterMetricChoiceBox.getValue();
if(xScatterKey != null && yScatterKey != null) {
scatterChart.getXAxis().setLabel(xScatterKey.toString());
scatterChart.getYAxis().setLabel(yScatterKey.toString());
scatterChart.getData().clear();
for(var child : node.getChildren()) {
Double xValue = child.getValueAsDouble(xScatterKey);
Double yValue = child.getValueAsDouble(yScatterKey);
if(xValue != null && yValue != null) {
// Add data to the chart
XYChart.Series<Number, Number> dataSeries = new XYChart.Series<>();
dataSeries.setName(child.getName());
dataSeries.getData().add(new XYChart.Data<>(xValue, yValue));
scatterChart.getData().add(dataSeries);
}
}
}
}
/**
* Updates the {@link #barChart} with data from the provided {@link MetricTreeNode}.
*
* @param node
* which provides the data for this chart
*/
private void updateBarChart(MetricTreeNode node) {
MetricKey yScatterKey = yScatterMetricChoiceBox.getValue();
if(yScatterKey != null) {
barChart.getYAxis().setLabel(yScatterKey.toString());
barChart.getData().clear();
for(var child : node.getChildren()) {
Double yValue = child.getValueAsDouble(yScatterKey);
if(yValue != null) {
// Add data to the chart
XYChart.Series<String, Number> dataSeries = new XYChart.Series<>();
dataSeries.setName(child.getName());
dataSeries.getData().add(new XYChart.Data<>(child.getName(), yValue));
barChart.getData().add(dataSeries);
}
}
}
}
/**
* Creates a SpiderChart using the elements in
* {@link ModelQualityFXController#lastViewedElements}. A set of keys which are present in all
* elements in the list is created, and then these elements are overlaid.
*/
private SpiderChartViewer buildSpiderChart() {
// Calculate the intersection of the keys, i.e. a set of keys which have a non-null value in
// all elements of the lastViewedElements list
// lastViewedElements is never empty due to the fact, that updateLastViewedElements() is
// always executed before in updateCharts(), which ensure that there is at least one element
Set<MetricKey> keysIntersection = lastViewedElements.get(0).getValue();
for(var p : lastViewedElements) {
keysIntersection.retainAll(p.getValue());
}
// Create DataSeries for all elements
List<Pair<MetricTreeNode, DataSeries>> dataSeriesList =
lastViewedElements.stream().map(pair -> {
MetricTreeNode key = pair.getKey();
String name = key.getName();
return new Pair<>(key, (name == null) ? new DataSeries("No name found")
: new DataSeries(name));
}).collect(toList());
// Create SpiderChart and set basic styling
SpiderChart spiderChart = new SpiderChart();
spiderChart.setLegendLabel("Legend");
ChartStyle chartStyle = new ChartStyle(true, true, true);
chartStyle.setUseIndividualAxisSegments(false);
chartStyle.setTitleStyle(new FontStyle("Verdana", 14, BLUE.brighter()));
// Iterate over all keys, and add data points
for(MetricKey key : keysIntersection) {
// Calculate maximumValue for the range of the axis
Double maxmiumValue = lastViewedElements.stream()
.mapToDouble(p -> p.getKey().getValueAsDouble(key)).max().getAsDouble();
if(maxmiumValue == 0.0) {
// Don't display metrics where all values are zero
continue;
}
// Create Axis and apply Styling
DoubleAxis doubleAxis = new DoubleAxis(key.toString(), 0.0, maxmiumValue);
AxisStyle aStyle3Segs = new AxisStyle(SOLID_BLACK_1PT, BLACK_VERDANA_14PT, 3,
BLACK_VERDANA_8PT, new DecimalFormat("#.##"));
chartStyle.setAxisStyle(doubleAxis, aStyle3Segs);
spiderChart.addAxis(doubleAxis);
// Add the data point for this axis to all elements
for(var pair : dataSeriesList) {
pair.getValue().setPoint(doubleAxis, pair.getKey().getValueAsDouble(key));
}
}
// Iterate over all dataSeries and add them to the spider chart
int i = 0;
for(var pair : dataSeriesList) {
spiderChart.addData(pair.getValue());
// Assign different colors to different data series
// updateLastViewedElements() ensures that the are are at most three elements in
// updateLastViewedElements, from which dataSeriesList is derived above.
Color color = SPIDER_CHART_OVERLAY_COLORS[i];
LineStyle olive1pt = new LineStyle(color);
FillStyle oliveFill = new FillStyle(color, 0.25);
DataSeriesStyle style = new DataSeriesStyle(olive1pt, oliveFill, true, true,
BLACK_VERDANA_10PT, 7, new DecimalFormat("#.#"));
chartStyle.setDataSeriesStyle(pair.getValue(), style);
i++;
}
// Configure legend
LegendStyle legendStyle = new LegendStyle(false, 5, BLACK_VERDANA_12PT);
chartStyle.setLegendStyle(legendStyle);
chartStyle.setAxisSegments(4);
chartStyle.setBackgroundFillStyle(new FillStyle(LIGHTGRAY));
chartStyle.setBackgroundLineStyle(new LineStyle(DARKGRAY));
SpiderChartViewer viewer = new SpiderChartViewer(spiderChart, chartStyle);
return viewer;
}
/** {@inheritDoc} */
@Override
public void metricUpdate(IProjectRootElement updatedElement) {
Platform.runLater(() -> {
if(lastSelectedElement == null) {
// If nothing is selected, there is nothing to update
return;
}
MetricData metricData = IModelQualityService.getInstance().getMetricData();
var rootDataElement = metricData.getDataRootElementMap().get(updatedElement);
if(rootDataElement != null) {
bottomText.setText("Metrics last updated: " +
timeFormat.format(rootDataElement.getLastRefresh()) +
". Save model to refresh.");
} else {
bottomText.setText(
"Save model or select \"Export Metrics\" in project options to generate metrics.");
}
updateCharts("Selection does not have metric information.");
});
}
/**
* Updates the {@link ModelQualityFXController#lastViewedElements} variable. It will add the
* provided {@link MetricTreeNode} in the back of the list, and if the list is too long it will
* remove the first element.
*
* @param node
* which was selected
*/
private void updateLastViewedElements(MetricTreeNode node) {
// Create set of keys which store values in the node
Set<MetricKey> keys = new HashSet<>();
keys.addAll(node.getDoubleMetrics().keySet());
keys.addAll(node.getIntegerMetrics().keySet());
// Check if the node is already part of the list, and skip adding it if it is
if(lastViewedElements.stream().allMatch(p -> p.getKey() != node)) {
lastViewedElements.add(new Pair<>(node, keys));
}
// Limit the amount of elements in the list to the amount of colors
if(lastViewedElements.size() > SPIDER_CHART_OVERLAY_COLORS.length) {
lastViewedElements.remove(0);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment