From 407b70f095cb921ac722090fca10bab186337046 Mon Sep 17 00:00:00 2001 From: yblanken Date: Thu, 14 Dec 2023 08:51:30 +0100 Subject: [PATCH] Support categories in data analysis time-series viewer --- .../jfree/ExportImageAction.java | 2 +- .../jfree/ShowLegendAction.java | 72 ++++++++++ .../ui/SynchronizedTimingViewerPane.java | 65 +++------ .../nl.esi.pps.tmsc.analysis.ui/plugin.xml | 11 +- ...ityIsomorphismClassesContentProvider.xtend | 43 ++++++ ...tricActivityIsomorphismClassesHandler.java | 41 +----- ...tricActivityIsomorphismClassesHelper.xtend | 51 +++++++ ...vityIsomorphismClassesContentProvider.java | 69 ++++++++++ ...etricActivityIsomorphismClassesHelper.java | 126 +++++++++++++++++ .../IDataAnalysisItemContentProvider.java | 15 +++ .../DataAnalysisItemContentProvider.java | 10 ++ .../provider/ext/ui/DataAnalysisInput.java | 16 ++- .../provider/ext/ui/IDataAnalysisInput.java | 10 ++ .../dataanalysis/TmscDataAnalysisPage.java | 20 ++- .../dataanalysis/TmscTimeSeriesViewer.java | 127 +++++++++++++----- ...MetricDataAnalysisItemContentProvider.java | 2 +- 16 files changed, 556 insertions(+), 124 deletions(-) create mode 100644 plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/jfree/ShowLegendAction.java create mode 100644 plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/dataanalysis/MetricActivityIsomorphismClassesContentProvider.xtend create mode 100644 plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHelper.xtend create mode 100644 plugins/nl.esi.pps.tmsc.analysis.ui/xtend-gen/nl/esi/pps/tmsc/analysis/ui/dataanalysis/MetricActivityIsomorphismClassesContentProvider.java create mode 100644 plugins/nl.esi.pps.tmsc.analysis.ui/xtend-gen/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHelper.java diff --git a/plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/jfree/ExportImageAction.java b/plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/jfree/ExportImageAction.java index c2e321a..8509525 100644 --- a/plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/jfree/ExportImageAction.java +++ b/plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/jfree/ExportImageAction.java @@ -45,7 +45,7 @@ public ExportImageAction() { this(null, Activator.getDescriptor(Activator.IMAGE_EXPORT_IMAGE)); } - public ExportImageAction(ChartPanelComposite plotComposite) { + public ExportImageAction(@Nullable ChartPanelComposite plotComposite) { this(plotComposite, Activator.getDescriptor(Activator.IMAGE_EXPORT_IMAGE)); } diff --git a/plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/jfree/ShowLegendAction.java b/plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/jfree/ShowLegendAction.java new file mode 100644 index 0000000..f9252a5 --- /dev/null +++ b/plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/jfree/ShowLegendAction.java @@ -0,0 +1,72 @@ +package nl.esi.pps.common.emf.synchronizedtiming.jfree; + + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.trace4cps.common.jfreechart.ui.widgets.ChartPanelComposite; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.title.LegendTitle; +import org.jfree.chart.title.Title; + +import nl.esi.pps.common.emf.synchronizedtiming.ui.Activator; + +public class ShowLegendAction extends Action { + private @Nullable ChartPanelComposite chartPanelComposite; + + public ShowLegendAction() { + this(null, Activator.getDescriptor(Activator.IMAGE_LEGEND_ONOFF)); + } + + public ShowLegendAction(@Nullable ChartPanelComposite plotComposite) { + this(plotComposite, Activator.getDescriptor(Activator.IMAGE_LEGEND_ONOFF)); + } + + public ShowLegendAction(@Nullable ChartPanelComposite chartPanelComposite, @Nullable ImageDescriptor imageDescriptor) { + super("Show Legend", IAction.AS_CHECK_BOX); + setImageDescriptor(imageDescriptor); + setToolTipText("If checked, this chart will show a legend."); + setChartPanelComposite(chartPanelComposite); + } + + public void setChartPanelComposite(@Nullable ChartPanelComposite plotComposite) { + this.chartPanelComposite = plotComposite; + update(); + } + + protected @Nullable ChartPanelComposite getChartPanelComposite() { + return chartPanelComposite; + } + + public void update() { + if (chartPanelComposite != null) { + JFreeChart chart = chartPanelComposite.getChart(); + LegendTitle legend = chart == null ? null : chart.getLegend(); + if (legend != null) { + setEnabled(true); + setChecked(legend.isVisible()); + return; + } + } + setEnabled(false); + setChecked(false); + } + + @Override + public void run() { + if (chartPanelComposite != null) { + JFreeChart chart = chartPanelComposite.getChart(); + if (chart == null) { + return; + } + + for (int i = 0; i < chart.getSubtitleCount(); i++) { + Title subtitle = chart.getSubtitle(i); + if (subtitle instanceof LegendTitle) { + subtitle.setVisible(isChecked()); + } + } + } + } +} \ No newline at end of file diff --git a/plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/ui/SynchronizedTimingViewerPane.java b/plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/ui/SynchronizedTimingViewerPane.java index 6d94062..408cea9 100644 --- a/plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/ui/SynchronizedTimingViewerPane.java +++ b/plugins/nl.esi.pps.common.emf.synchronizedtiming.ui/src/nl/esi/pps/common/emf/synchronizedtiming/ui/SynchronizedTimingViewerPane.java @@ -10,9 +10,8 @@ package nl.esi.pps.common.emf.synchronizedtiming.ui; +import static java.lang.String.format; import static nl.esi.pps.common.emf.synchronizedtiming.ui.Activator.IMAGE_DATASET_VIEW; -import static nl.esi.pps.common.emf.synchronizedtiming.ui.Activator.IMAGE_EXPORT_IMAGE; -import static nl.esi.pps.common.emf.synchronizedtiming.ui.Activator.IMAGE_LEGEND_ONOFF; import static nl.esi.pps.common.emf.synchronizedtiming.ui.Activator.IMAGE_MARGIN_SYNC; import static nl.esi.pps.common.emf.synchronizedtiming.ui.Activator.IMAGE_MARGIN_SYNC_ENABLED; import static nl.esi.pps.common.emf.synchronizedtiming.ui.Activator.IMAGE_TIME_SYNC; @@ -20,7 +19,6 @@ import static nl.esi.pps.common.emf.synchronizedtiming.ui.Activator.IMAGE_ZOOM_OUT_HORIZONTAL; import static nl.esi.pps.common.emf.synchronizedtiming.ui.Activator.IMAGE_ZOOM_OUT_VERTICAL; import static nl.esi.pps.common.emf.synchronizedtiming.ui.Activator.IMAGE_ZOOM_VIEW; -import static java.lang.String.format; import java.awt.Rectangle; import java.util.Collection; @@ -58,12 +56,11 @@ import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.plot.Zoomable; -import org.jfree.chart.title.LegendTitle; -import org.jfree.chart.title.Title; import nl.esi.pps.common.emf.synchronizedtiming.TimeSyncSupport; import nl.esi.pps.common.emf.synchronizedtiming.TimeSyncSupportProvider; import nl.esi.pps.common.emf.synchronizedtiming.jfree.ExportImageAction; +import nl.esi.pps.common.emf.synchronizedtiming.jfree.ShowLegendAction; public abstract class SynchronizedTimingViewerPane extends ActionsViewerPane { protected static final String GROUP_VIEW = "view"; @@ -83,7 +80,7 @@ public abstract class SynchronizedTimingViewerPane extends ActionsViewerPane { protected final ZoomOutAction zoomOutAction = new ZoomOutAction(); protected final ZoomToSelectionXAction zoomToSelectionXAction = new ZoomToSelectionXAction(); protected final ZoomToSelectionYAction zoomToSelectionYAction = new ZoomToSelectionYAction(); - protected final ShowLegendAction showLegendAction = new ShowLegendAction(); + protected @Nullable ViewerShowLegendAction showLegendAction; // Initialized in 'createControl' method. protected @Nullable ViewerExportImageAction exportImageAction; // Initialized in 'createControl' method. public SynchronizedTimingViewerPane(IWorkbenchPage page, IWorkbenchPart part) { @@ -104,7 +101,7 @@ public SynchronizedTimingViewerPane(IWorkbenchPage page, IWorkbenchPart part) { return null; } - private @Nullable ChartPanelComposite getChartPanelComposite() { + @Nullable ChartPanelComposite getChartPanelComposite() { final ChartPanelViewer chartPanelViewer = getChartPanelViewer(); return chartPanelViewer == null ? null : chartPanelViewer.getChartPanelComposite(); } @@ -202,11 +199,10 @@ protected void addNavigationActions() { protected void addViewActions() { exportImageAction = new ViewerExportImageAction(getChartPanelComposite()); + showLegendAction = new ViewerShowLegendAction(getChartPanelComposite()); getMenuManager().appendToGroup(GROUP_VIEW, exportImageAction); getMenuManager().appendToGroup(GROUP_VIEW, showLegendAction); - - showLegendAction.update(); } protected class TimeSyncAction extends Action { @@ -437,7 +433,7 @@ public void run() { protected class ViewerExportImageAction extends ExportImageAction { public ViewerExportImageAction(@Nullable ChartPanelComposite chartPanelComposite) { - super(chartPanelComposite, Activator.getDescriptor(IMAGE_EXPORT_IMAGE)); + super(chartPanelComposite); } @Override @@ -462,48 +458,25 @@ public void run() { super.run(); } } - - protected class ShowLegendAction extends Action { - public ShowLegendAction() { - super("Show Legend", IAction.AS_CHECK_BOX); - setImageDescriptor(Activator.getDescriptor(IMAGE_LEGEND_ONOFF)); - setToolTipText("If checked, this chart will show a legend."); + + protected class ViewerShowLegendAction extends ShowLegendAction { + public ViewerShowLegendAction(@Nullable ChartPanelComposite plotComposite) { + super(plotComposite); } - public void update() { - ChartPanelComposite chartPanelComposite = getChartPanelComposite(); - JFreeChart chart = null == chartPanelComposite ? null : chartPanelComposite.getChart(); - LegendTitle legend = null == chart ? null : chart.getLegend(); - setVisible(null != legend); - setChecked(null != legend && legend.isVisible()); - } - - protected void setVisible(boolean visible) { + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + + // Also hide the action if disabled for (IContributionItem item : getToolBarManager().getItems()) { - if (item instanceof ActionContributionItem && ((ActionContributionItem)item).getAction() == ShowLegendAction.this) { - item.setVisible(visible); + if (item instanceof ActionContributionItem && ((ActionContributionItem)item).getAction() == ViewerShowLegendAction.this) { + item.setVisible(enabled); } } for (IContributionItem item : getMenuManager().getItems()) { - if (item instanceof ActionContributionItem && ((ActionContributionItem)item).getAction() == ShowLegendAction.this) { - item.setVisible(visible); - } - } - } - - @Override - public void run() { - ChartPanelComposite chartPanelComposite = getChartPanelComposite(); - if (null == chartPanelComposite) return; - ChartPanel chartPanel = chartPanelComposite.getChartPanel(); - if (null == chartPanel) return; - JFreeChart chart = chartPanel.getChart(); - if (null == chart) return; - - for (int i = 0; i < chart.getSubtitleCount(); i++) { - Title subtitle = chart.getSubtitle(i); - if (subtitle instanceof LegendTitle) { - subtitle.setVisible(isChecked()); + if (item instanceof ActionContributionItem && ((ActionContributionItem)item).getAction() == ViewerShowLegendAction.this) { + item.setVisible(enabled); } } } diff --git a/plugins/nl.esi.pps.tmsc.analysis.ui/plugin.xml b/plugins/nl.esi.pps.tmsc.analysis.ui/plugin.xml index 5beb7f5..8be1b67 100644 --- a/plugins/nl.esi.pps.tmsc.analysis.ui/plugin.xml +++ b/plugins/nl.esi.pps.tmsc.analysis.ui/plugin.xml @@ -17,7 +17,6 @@ id="nl.esi.pps.tmsc.analysis.ui.fragment" point="org.eclipse.e4.workbench.model"> @@ -45,6 +44,16 @@ eclass_uri="http://www.esi.nl/pps/tmsc#Dependency" id="nl.esi.pps.tmsc.analysis.ui.dataanalysis.TimeBoundOutlierDataAnalysisItemContentProvider"> + + + + diff --git a/plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/dataanalysis/MetricActivityIsomorphismClassesContentProvider.xtend b/plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/dataanalysis/MetricActivityIsomorphismClassesContentProvider.xtend new file mode 100644 index 0000000..a4fbad0 --- /dev/null +++ b/plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/dataanalysis/MetricActivityIsomorphismClassesContentProvider.xtend @@ -0,0 +1,43 @@ +package nl.esi.pps.tmsc.analysis.ui.dataanalysis + +import nl.esi.pps.tmsc.ScopedTMSC +import nl.esi.pps.tmsc.metric.MetricInstance +import nl.esi.pps.tmsc.metric.provider.dataanalysis.MetricDataAnalysisItemContentProvider + +import static extension nl.esi.pps.tmsc.analysis.ui.handlers.CreateMetricActivityIsomorphismClassesHelper.* + +class MetricActivityIsomorphismClassesContentProvider extends MetricDataAnalysisItemContentProvider { + override getConfigurations(Object object) { + return object.metric.instances.flatMap[scopes].map[configuration].filterNull.toSet + } + + override String getTitle(Object object, String configuration) { + return object.metric.name + ' - ' + configuration + } + + override isCategorized(Object object, String configuration) { + return true + } + + override getCategory(Object object, Object sibling, String configuration) { + if (sibling instanceof MetricInstance) { + val isomorphismClass = sibling.scopes.findFirst[s | s.configuration == configuration]?.isomorphismClass + if (isomorphismClass !== null) { + return 'Isomorphism class ' + isomorphismClass + } + } + return super.getCategory(object, sibling, configuration) + } + + protected def String getConfiguration(ScopedTMSC tmsc) { + val isomorphismStage = tmsc.isomorphismStage + if (isomorphismStage === null) { + return null + } + val isomorphismType = tmsc.isomorphismType + if (isomorphismType === null) { + return null + } + return isomorphismStage + ' ' + isomorphismType + } +} \ No newline at end of file diff --git a/plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHandler.java b/plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHandler.java index 413d491..ac6e9bd 100644 --- a/plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHandler.java +++ b/plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHandler.java @@ -10,12 +10,9 @@ package nl.esi.pps.tmsc.analysis.ui.handlers; -import static org.eclipse.lsat.common.queries.QueryableIterable.from; +import static nl.esi.pps.tmsc.analysis.ui.handlers.CreateMetricActivityIsomorphismClassesHelper.createIsomorphismClasses; -import java.text.DecimalFormat; import java.util.Collections; -import java.util.List; -import java.util.function.Function; import javax.inject.Named; @@ -43,19 +40,13 @@ import nl.esi.pps.preferences.PPSPreferences; import nl.esi.pps.tmsc.ScopedTMSC; -import nl.esi.pps.tmsc.TMSC; -import nl.esi.pps.tmsc.TmscFactory; import nl.esi.pps.tmsc.analysis.ui.commands.CreateScopedTMSCCommand; import nl.esi.pps.tmsc.compare.ArchitectureLifecycleStage; -import nl.esi.pps.tmsc.compare.TmscIsomorphismMatcher; import nl.esi.pps.tmsc.metric.Metric; import nl.esi.pps.tmsc.rendering.plot.ScopesRenderingStrategy; import nl.esi.pps.tmsc.util.TmscQueries; public class CreateMetricActivityIsomorphismClassesHandler extends CreateScopedTMSCCommandHandler { - private static final DecimalFormat INDEX_FORMAT = new DecimalFormat("000"); - private static final String INDEX_PROPERTY = "Isomorphism class"; - public CreateMetricActivityIsomorphismClassesHandler() { super("create isomorphism classes of TMSCs"); } @@ -107,45 +98,19 @@ protected boolean prepare() { } @Override - @SuppressWarnings("deprecation") protected ScopedTMSC createScopedTMSC(MultiStatus status, IProgressMonitor monitor) { ScopedTMSC tmsc = super.createScopedTMSC(status, monitor); // Apply some rendering hints such that this scope isn't grouped by the renderer ScopesRenderingStrategy.setGroupKey(tmsc, false); - List> isomorphismClasses = TmscIsomorphismMatcher.findIsomorphismClasses( - metric.getInstances().stream().map(strategy::createTMSC).iterator(), stage); - // Apply some rendering hints such that these scopes aren't grouped by the renderer - from(isomorphismClasses).collect(Function.identity()).closure(true, TMSC::getChildScopes) - .forEach(scope -> ScopesRenderingStrategy.setGroupKey(scope, false)); - - for (int index = 0; index < isomorphismClasses.size(); index++) { - List isomorphicTMSCs = isomorphismClasses.get(index); - ScopedTMSC isomorphismClassTMSC = TmscFactory.eINSTANCE.createScopedTMSC(); - isomorphismClassTMSC.setName(TmscQueries - .toEID(String.format("Isomorphism class %s %d %d", INDEX_FORMAT.format(index + 1), - isomorphicTMSCs.size(), isomorphicTMSCs.get(0).getDependencies().size()))); - isomorphismClassTMSC.getProperties().put(INDEX_PROPERTY, INDEX_FORMAT.format(index + 1)); - isomorphismClassTMSC.getChildScopes().addAll(isomorphicTMSCs); - - // All dependencies of a child scope should also be contained by its parent scope. - isomorphismClassTMSC.getChildScopes().forEach( - childScope -> isomorphismClassTMSC.getDependencies().addAll(childScope.getDependencies())); - - // IsomorphismClassTMSC itself is child-scope of tmsc - tmsc.getChildScopes().add(isomorphismClassTMSC); - tmsc.getDependencies().addAll(isomorphismClassTMSC.getDependencies()); + for (ScopedTMSC isomorphismClass : createIsomorphismClasses(metric, strategy, stage)) { + TmscQueries.addScopedTMSC(tmsc, isomorphismClass); } return tmsc; } } - @SuppressWarnings("deprecation") - public static String getIsomorphismClassIndex(TMSC tmsc) { - return (String) tmsc.getProperties().get(INDEX_PROPERTY); - } - private static class StrategyAndStageSelectionDialog extends CreateIntervalActivityStrategy.StrategySelectionDialog { private ArchitectureLifecycleStage stage = ArchitectureLifecycleStage.IMPLEMENTED; diff --git a/plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHelper.xtend b/plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHelper.xtend new file mode 100644 index 0000000..a3660df --- /dev/null +++ b/plugins/nl.esi.pps.tmsc.analysis.ui/src/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHelper.xtend @@ -0,0 +1,51 @@ +package nl.esi.pps.tmsc.analysis.ui.handlers + +import java.text.DecimalFormat +import nl.esi.emf.properties.xtend.PersistedProperty +import nl.esi.pps.tmsc.ScopedTMSC +import nl.esi.pps.tmsc.compare.ArchitectureLifecycleStage +import nl.esi.pps.tmsc.metric.Metric + +import static extension nl.esi.pps.tmsc.compare.TmscIsomorphismMatcher.* +import static extension nl.esi.pps.tmsc.rendering.plot.ScopesRenderingStrategy.* +import static extension nl.esi.pps.tmsc.util.TmscQueries.* + +class CreateMetricActivityIsomorphismClassesHelper { + static val CLASS_FORMAT = new DecimalFormat("000"); + + @PersistedProperty(ScopedTMSC) + public static var String isomorphismType + + @PersistedProperty(ScopedTMSC) + public static var String isomorphismStage + + @PersistedProperty(ScopedTMSC) + public static var String isomorphismClass + + static def Iterable createIsomorphismClasses(Metric metric, CreateIntervalActivityStrategy strategy, ArchitectureLifecycleStage stage) { + val metricInstanceTmscs = metric.instances.iterator.map[mi | + strategy.createTMSC(mi) => [ miTmsc | + mi.scopes += miTmsc + miTmsc.isomorphismType = strategy.label + miTmsc.isomorphismStage = stage.label + miTmsc.groupKey = false + ] + ] + + return metricInstanceTmscs.findIsomorphismClasses(stage).indexed.map [ + val isomorphismClass = CLASS_FORMAT.format(key + 1) + val isomorphicTmscs = value + val isomorphismClassName = '''Isomorphism class «isomorphismClass» «isomorphicTmscs.size» «isomorphicTmscs.head.dependencies.size»''' + + isomorphicTmscs.forEach[tmsc | tmsc.isomorphismClass = isomorphismClass] + + isomorphicTmscs.flatMap[dependencies].createScopedTMSC(isomorphismClassName) => [ groupTmsc | + groupTmsc.childScopes += isomorphicTmscs + groupTmsc.isomorphismType = strategy.label + groupTmsc.isomorphismStage = stage.label + groupTmsc.isomorphismClass = isomorphismClass + groupTmsc.groupKey = true + ] + ] + } +} \ No newline at end of file diff --git a/plugins/nl.esi.pps.tmsc.analysis.ui/xtend-gen/nl/esi/pps/tmsc/analysis/ui/dataanalysis/MetricActivityIsomorphismClassesContentProvider.java b/plugins/nl.esi.pps.tmsc.analysis.ui/xtend-gen/nl/esi/pps/tmsc/analysis/ui/dataanalysis/MetricActivityIsomorphismClassesContentProvider.java new file mode 100644 index 0000000..bf61f61 --- /dev/null +++ b/plugins/nl.esi.pps.tmsc.analysis.ui/xtend-gen/nl/esi/pps/tmsc/analysis/ui/dataanalysis/MetricActivityIsomorphismClassesContentProvider.java @@ -0,0 +1,69 @@ +package nl.esi.pps.tmsc.analysis.ui.dataanalysis; + +import com.google.common.base.Objects; +import java.util.Set; +import nl.esi.pps.tmsc.ScopedTMSC; +import nl.esi.pps.tmsc.analysis.ui.handlers.CreateMetricActivityIsomorphismClassesHelper; +import nl.esi.pps.tmsc.metric.MetricInstance; +import nl.esi.pps.tmsc.metric.provider.dataanalysis.MetricDataAnalysisItemContentProvider; +import org.eclipse.emf.common.util.EList; +import org.eclipse.xtext.xbase.lib.Functions.Function1; +import org.eclipse.xtext.xbase.lib.IterableExtensions; + +@SuppressWarnings("all") +public class MetricActivityIsomorphismClassesContentProvider extends MetricDataAnalysisItemContentProvider { + @Override + public Set getConfigurations(final Object object) { + final Function1> _function = (MetricInstance it) -> { + return it.getScopes(); + }; + final Function1 _function_1 = (ScopedTMSC it) -> { + return this.getConfiguration(it); + }; + return IterableExtensions.toSet(IterableExtensions.filterNull(IterableExtensions.map(IterableExtensions.flatMap(this.getMetric(object).getInstances(), _function), _function_1))); + } + + @Override + public String getTitle(final Object object, final String configuration) { + String _name = this.getMetric(object).getName(); + String _plus = (_name + " - "); + return (_plus + configuration); + } + + @Override + public boolean isCategorized(final Object object, final String configuration) { + return true; + } + + @Override + public String getCategory(final Object object, final Object sibling, final String configuration) { + if ((sibling instanceof MetricInstance)) { + final Function1 _function = (ScopedTMSC s) -> { + String _configuration = this.getConfiguration(s); + return Boolean.valueOf(Objects.equal(_configuration, configuration)); + }; + ScopedTMSC _findFirst = IterableExtensions.findFirst(((MetricInstance)sibling).getScopes(), _function); + String _isomorphismClass = null; + if (_findFirst!=null) { + _isomorphismClass=CreateMetricActivityIsomorphismClassesHelper.getIsomorphismClass(_findFirst); + } + final String isomorphismClass = _isomorphismClass; + if ((isomorphismClass != null)) { + return ("Isomorphism class " + isomorphismClass); + } + } + return super.getCategory(object, sibling, configuration); + } + + protected String getConfiguration(final ScopedTMSC tmsc) { + final String isomorphismStage = CreateMetricActivityIsomorphismClassesHelper.getIsomorphismStage(tmsc); + if ((isomorphismStage == null)) { + return null; + } + final String isomorphismType = CreateMetricActivityIsomorphismClassesHelper.getIsomorphismType(tmsc); + if ((isomorphismType == null)) { + return null; + } + return ((isomorphismStage + " ") + isomorphismType); + } +} diff --git a/plugins/nl.esi.pps.tmsc.analysis.ui/xtend-gen/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHelper.java b/plugins/nl.esi.pps.tmsc.analysis.ui/xtend-gen/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHelper.java new file mode 100644 index 0000000..a102df5 --- /dev/null +++ b/plugins/nl.esi.pps.tmsc.analysis.ui/xtend-gen/nl/esi/pps/tmsc/analysis/ui/handlers/CreateMetricActivityIsomorphismClassesHelper.java @@ -0,0 +1,126 @@ +package nl.esi.pps.tmsc.analysis.ui.handlers; + +import com.google.common.collect.Iterables; +import java.text.DecimalFormat; +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; +import nl.esi.pps.tmsc.Dependency; +import nl.esi.pps.tmsc.ScopedTMSC; +import nl.esi.pps.tmsc.compare.ArchitectureLifecycleStage; +import nl.esi.pps.tmsc.compare.TmscIsomorphismMatcher; +import nl.esi.pps.tmsc.metric.Metric; +import nl.esi.pps.tmsc.metric.MetricInstance; +import nl.esi.pps.tmsc.rendering.plot.ScopesRenderingStrategy; +import nl.esi.pps.tmsc.util.TmscQueries; +import org.eclipse.emf.common.util.EList; +import org.eclipse.xtend2.lib.StringConcatenation; +import org.eclipse.xtext.xbase.lib.Functions.Function1; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.IteratorExtensions; +import org.eclipse.xtext.xbase.lib.ObjectExtensions; +import org.eclipse.xtext.xbase.lib.Pair; +import org.eclipse.xtext.xbase.lib.Procedures.Procedure1; + +@SuppressWarnings("all") +public class CreateMetricActivityIsomorphismClassesHelper { + private static final DecimalFormat CLASS_FORMAT = new DecimalFormat("000"); + + public static Iterable createIsomorphismClasses(final Metric metric, final CreateIntervalActivityStrategy strategy, final ArchitectureLifecycleStage stage) { + final Function1 _function = (MetricInstance mi) -> { + ScopedTMSC _createTMSC = strategy.createTMSC(mi); + final Procedure1 _function_1 = (ScopedTMSC miTmsc) -> { + EList _scopes = mi.getScopes(); + _scopes.add(miTmsc); + CreateMetricActivityIsomorphismClassesHelper.setIsomorphismType(miTmsc, strategy.getLabel()); + CreateMetricActivityIsomorphismClassesHelper.setIsomorphismStage(miTmsc, stage.getLabel()); + ScopesRenderingStrategy.setGroupKey(miTmsc, false); + }; + return ObjectExtensions.operator_doubleArrow(_createTMSC, _function_1); + }; + final Iterator metricInstanceTmscs = IteratorExtensions.map(metric.getInstances().iterator(), _function); + final Function1>, ScopedTMSC> _function_1 = (Pair> it) -> { + ScopedTMSC _xblockexpression = null; + { + Integer _key = it.getKey(); + int _plus = ((_key).intValue() + 1); + final String isomorphismClass = CreateMetricActivityIsomorphismClassesHelper.CLASS_FORMAT.format(_plus); + final List isomorphicTmscs = it.getValue(); + StringConcatenation _builder = new StringConcatenation(); + _builder.append("Isomorphism class "); + _builder.append(isomorphismClass); + _builder.append(" "); + int _size = isomorphicTmscs.size(); + _builder.append(_size); + _builder.append(" "); + int _size_1 = IterableExtensions.head(isomorphicTmscs).getDependencies().size(); + _builder.append(_size_1); + final String isomorphismClassName = _builder.toString(); + final Consumer _function_2 = (ScopedTMSC tmsc) -> { + CreateMetricActivityIsomorphismClassesHelper.setIsomorphismClass(tmsc, isomorphismClass); + }; + isomorphicTmscs.forEach(_function_2); + final Function1> _function_3 = (ScopedTMSC it_1) -> { + return it_1.getDependencies(); + }; + ScopedTMSC _createScopedTMSC = TmscQueries.createScopedTMSC(IterableExtensions.flatMap(isomorphicTmscs, _function_3), isomorphismClassName); + final Procedure1 _function_4 = (ScopedTMSC groupTmsc) -> { + EList _childScopes = groupTmsc.getChildScopes(); + Iterables.addAll(_childScopes, isomorphicTmscs); + CreateMetricActivityIsomorphismClassesHelper.setIsomorphismType(groupTmsc, strategy.getLabel()); + CreateMetricActivityIsomorphismClassesHelper.setIsomorphismStage(groupTmsc, stage.getLabel()); + CreateMetricActivityIsomorphismClassesHelper.setIsomorphismClass(groupTmsc, isomorphismClass); + ScopesRenderingStrategy.setGroupKey(groupTmsc, true); + }; + _xblockexpression = ObjectExtensions.operator_doubleArrow(_createScopedTMSC, _function_4); + } + return _xblockexpression; + }; + return IterableExtensions.>, ScopedTMSC>map(IterableExtensions.>indexed(TmscIsomorphismMatcher.findIsomorphismClasses(metricInstanceTmscs, stage)), _function_1); + } + + public static String getIsomorphismType(final ScopedTMSC container) { + final String key = "isomorphismType"; + final Object value = container.getProperties().get(key); + return (String) value; + } + + public static void setIsomorphismType(final ScopedTMSC container, final String value) { + final String key = "isomorphismType"; + if (value == null) { + container.getProperties().remove(key); + } else { + container.getProperties().put(key, value); + } + } + + public static String getIsomorphismStage(final ScopedTMSC container) { + final String key = "isomorphismStage"; + final Object value = container.getProperties().get(key); + return (String) value; + } + + public static void setIsomorphismStage(final ScopedTMSC container, final String value) { + final String key = "isomorphismStage"; + if (value == null) { + container.getProperties().remove(key); + } else { + container.getProperties().put(key, value); + } + } + + public static String getIsomorphismClass(final ScopedTMSC container) { + final String key = "isomorphismClass"; + final Object value = container.getProperties().get(key); + return (String) value; + } + + public static void setIsomorphismClass(final ScopedTMSC container, final String value) { + final String key = "isomorphismClass"; + if (value == null) { + container.getProperties().remove(key); + } else { + container.getProperties().put(key, value); + } + } +} diff --git a/plugins/nl.esi.pps.tmsc.edit/src/nl/esi/pps/tmsc/provider/dataanalysis/IDataAnalysisItemContentProvider.java b/plugins/nl.esi.pps.tmsc.edit/src/nl/esi/pps/tmsc/provider/dataanalysis/IDataAnalysisItemContentProvider.java index d9af2b0..466f6c3 100644 --- a/plugins/nl.esi.pps.tmsc.edit/src/nl/esi/pps/tmsc/provider/dataanalysis/IDataAnalysisItemContentProvider.java +++ b/plugins/nl.esi.pps.tmsc.edit/src/nl/esi/pps/tmsc/provider/dataanalysis/IDataAnalysisItemContentProvider.java @@ -59,5 +59,20 @@ default Long getBudget(Object object, String configuration) { * {@code object} itself. */ Long getDuration(Object object, Object sibling, String configuration); + + /** + * @return (@code true} if the bars in the time-series viewer should be colored + * based on a {@link #getCategory(Object, Object, String) category}. + */ + default boolean isCategorized(Object object, String configuration) { + return false; + } + + /** + * @return the category for the {@code sibling} in the time-series viewer. + */ + default String getCategory(Object object, Object sibling, String configuration) { + return DEFAULT_CONFIGURATION; + } } // end::developer-guide[] diff --git a/plugins/nl.esi.pps.tmsc.edit/src/nl/esi/pps/tmsc/provider/dataanalysis/internal/DataAnalysisItemContentProvider.java b/plugins/nl.esi.pps.tmsc.edit/src/nl/esi/pps/tmsc/provider/dataanalysis/internal/DataAnalysisItemContentProvider.java index 0a82007..bfdf68c 100644 --- a/plugins/nl.esi.pps.tmsc.edit/src/nl/esi/pps/tmsc/provider/dataanalysis/internal/DataAnalysisItemContentProvider.java +++ b/plugins/nl.esi.pps.tmsc.edit/src/nl/esi/pps/tmsc/provider/dataanalysis/internal/DataAnalysisItemContentProvider.java @@ -56,6 +56,16 @@ public Long getDuration(Object object, Object sibling, String configuration) { return getRegisteredContentProviders(object).get(configuration).getDuration(object, sibling, configuration); } + @Override + public boolean isCategorized(Object object, String configuration) { + return getRegisteredContentProviders(object).get(configuration).isCategorized(object, configuration); + } + + @Override + public String getCategory(Object object, Object sibling, String configuration) { + return getRegisteredContentProviders(object).get(configuration).getCategory(object, sibling, configuration); + } + private Map getRegisteredContentProviders(Object object) { if (object instanceof EObject) { EClass eClass = ((EObject) object).eClass(); diff --git a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/provider/ext/ui/DataAnalysisInput.java b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/provider/ext/ui/DataAnalysisInput.java index 5a994ed..d454cac 100644 --- a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/provider/ext/ui/DataAnalysisInput.java +++ b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/provider/ext/ui/DataAnalysisInput.java @@ -27,17 +27,17 @@ class DataAnalysisInput implements IDataAnalysisInput { public Object getInput() { return input; } - + @Override public Set getConfigurations() { return contentProvider.getConfigurations(input); } - + @Override public String getTitle(String configuration) { return contentProvider.getTitle(input, configuration); } - + @Override public Long getBudget(String configuration) { return contentProvider.getBudget(input, configuration); @@ -52,4 +52,14 @@ public Iterable getSiblings(String configuration) { public Long getDuration(Object sibling, String configuration) { return contentProvider.getDuration(input, sibling, configuration); } + + @Override + public boolean isCategorized(String configuration) { + return contentProvider.isCategorized(input, configuration); + } + + @Override + public String getCategory(Object sibling, String configuration) { + return contentProvider.getCategory(input, sibling, configuration); + } } diff --git a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/provider/ext/ui/IDataAnalysisInput.java b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/provider/ext/ui/IDataAnalysisInput.java index 0554116..f4af60b 100644 --- a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/provider/ext/ui/IDataAnalysisInput.java +++ b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/provider/ext/ui/IDataAnalysisInput.java @@ -62,4 +62,14 @@ public interface IDataAnalysisInput { * @see IDataAnalysisItemContentProvider#getDuration(Object, Object, String) */ Long getDuration(Object sibling, String configuration); + + /** + * @see IDataAnalysisItemContentProvider#isCategorized(Object, String) + */ + boolean isCategorized(String configuration); + + /** + * @see IDataAnalysisItemContentProvider#getCategory(Object, Object, String) + */ + String getCategory(Object sibling, String configuration); } diff --git a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/dataanalysis/TmscDataAnalysisPage.java b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/dataanalysis/TmscDataAnalysisPage.java index 08de6a5..1cbefdb 100644 --- a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/dataanalysis/TmscDataAnalysisPage.java +++ b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/dataanalysis/TmscDataAnalysisPage.java @@ -32,14 +32,15 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Label; import org.eclipse.trace4cps.common.jfreechart.ui.viewers.ChartPanelContentViewer; +import org.eclipse.trace4cps.common.jfreechart.ui.widgets.ChartPanelComposite; import org.eclipse.ui.part.IPageSite; import nl.esi.pps.common.emf.synchronizedtiming.jfree.ExportImageAction; +import nl.esi.pps.common.emf.synchronizedtiming.jfree.ShowLegendAction; import nl.esi.pps.common.emf.ui.views.dataanalysis.DataAnalysisMultiViewerPage; import nl.esi.pps.common.ide.ui.action.DropDownMenuAction; import nl.esi.pps.common.ide.ui.action.DropDownMenuAction.DropDownAction; import nl.esi.pps.common.ide.ui.views.dataanalysis.DataAnalysisView; - import nl.esi.pps.tmsc.presentation.TmscEditor; import nl.esi.pps.tmsc.presentation.TmscEditorPlugin; import nl.esi.pps.tmsc.provider.ext.ui.AdapterFactoryDataAnalysisContentProvider; @@ -51,6 +52,7 @@ public abstract class TmscDataAnalysisPage extends DataAnalysisMultiViewerPage private static final String DATA_ANALYSIS_NOT_AVAILABLE = "Not available"; private final ExportImageAction exportImageAction = new ExportImageAction(); + private final ShowLegendAction showLegendAction = new ShowLegendAction(); private final DurationFilterAction durationFilterAction = new DurationFilterAction(() -> getSite().getShell()); private final ArrayList selectionChangedListeners = new ArrayList<>(); @@ -90,6 +92,7 @@ public void makeContributions(IMenuManager menuManager, IToolBarManager toolBarM toolBarManager.insertBefore(DataAnalysisView.GROUP_VIEW_END, durationFilterAction); menuManager.insertBefore(DataAnalysisView.GROUP_VIEW_END, exportImageAction); + menuManager.insertBefore(DataAnalysisView.GROUP_VIEW_END, showLegendAction); DataAnalysisViewerType[] viewerTypes = DataAnalysisViewerType.values(); DropDownAction[] viewerTypeActions = new DropDownAction[viewerTypes.length]; @@ -105,6 +108,7 @@ public void makeContributions(IMenuManager menuManager, IToolBarManager toolBarM public void dispose() { // Workaround for memory leak in menu manager due to Eclipse bug 543827 exportImageAction.setChartPanelComposite(null); + showLegendAction.setChartPanelComposite(null); super.dispose(); } @@ -197,9 +201,17 @@ private void addTmscDataAnalysisViewer(String configuration) { @Override protected void viewerChanged(Viewer oldViewer, Viewer newViewer) { super.viewerChanged(oldViewer, newViewer); - exportImageAction.setChartPanelComposite(newViewer instanceof ChartPanelContentViewer - ? ((ChartPanelContentViewer) newViewer).getChartPanelComposite() - : null); + + ChartPanelComposite chartPanelComposite = getChartPanelComposite(newViewer); + exportImageAction.setChartPanelComposite(chartPanelComposite); + showLegendAction.setChartPanelComposite(chartPanelComposite); + } + + private ChartPanelComposite getChartPanelComposite(Viewer newViewer) { + if (newViewer instanceof ChartPanelContentViewer) { + return ((ChartPanelContentViewer) newViewer).getChartPanelComposite(); + } + return null; } @Override diff --git a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/dataanalysis/TmscTimeSeriesViewer.java b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/dataanalysis/TmscTimeSeriesViewer.java index ce495d5..89a1075 100644 --- a/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/dataanalysis/TmscTimeSeriesViewer.java +++ b/plugins/nl.esi.pps.tmsc.editor/src/nl/esi/pps/tmsc/viewers/dataanalysis/TmscTimeSeriesViewer.java @@ -12,7 +12,10 @@ import static org.eclipse.lsat.common.queries.QueryableIterable.from; +import java.awt.Color; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import org.eclipse.emf.ecore.EObject; import org.eclipse.jface.viewers.StructuredSelection; @@ -25,8 +28,12 @@ import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.plot.SeriesRenderingOrder; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYBarRenderer; +import org.jfree.chart.title.LegendTitle; +import org.jfree.chart.ui.RectangleEdge; +import org.jfree.chart.ui.RectangleInsets; import org.jfree.data.xy.XYDataItem; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; @@ -45,6 +52,7 @@ public TmscTimeSeriesViewer(Composite parent, DurationFilter durationFilter, Str protected void configureChartPanel() { super.configureChartPanel(); final XYPlot xyPlot = getXYPlot(); + xyPlot.setSeriesRenderingOrder(SeriesRenderingOrder.FORWARD); IntervalRangeValueCrosshair.connectTo(getChartPanel(), v -> String.format(" %s ", EDurationFormat.eINSTANCE.format(v))); @@ -61,14 +69,18 @@ protected void configureChartPanel() { XYBarRenderer renderer = (XYBarRenderer) xyPlot.getRenderer(); renderer.setDefaultToolTipGenerator(labelGenerator); - renderer.setAutoPopulateSeriesPaint(false); - renderer.setAutoPopulateSeriesOutlinePaint(false); - renderer.setSeriesPaint(0, RenderingPaint.BLUE.getPaint()); - renderer.setSeriesOutlinePaint(0, RenderingPaint.BLUE.getOutlinePaint()); - renderer.setSeriesPaint(1, RenderingPaint.RED.getPaint()); - renderer.setSeriesOutlinePaint(1, RenderingPaint.RED.getOutlinePaint()); - - ChartFactory.getChartTheme().apply(getChart()); + + // Add a legend, but don't show it by default + JFreeChart chart = getChart(); + LegendTitle legend = new LegendTitle(xyPlot); + legend.setMargin(new RectangleInsets(1.0, 1.0, 1.0, 1.0)); + legend.setBackgroundPaint(Color.WHITE); + legend.setPosition(RectangleEdge.BOTTOM); + legend.setVisible(false); + chart.addSubtitle(legend); + legend.addChangeListener(chart); + + ChartFactory.getChartTheme().apply(chart); } @Override @@ -81,39 +93,94 @@ protected void inputChanged(Object input, Object oldInput) { @Override protected void refreshChart() { final JFreeChart chart = getChart(); - final XYSeries series0_Duration = new XYSeries("Duration"); - final XYSeries series1_ExceedsBudget = new XYSeries("Exceeds budget"); + XYSeriesCollection xyCollection; + + final XYBarRenderer renderer = (XYBarRenderer) getXYPlot().getRenderer(); + renderer.clearSeriesPaints(false); + renderer.clearSeriesOutlinePaints(false); IDataAnalysisInput input = getContentProvider().getDataAnalysisInput(getInput()); if (input == null) { chart.setTitle("Data analysis is not available for current selection."); + xyCollection = new XYSeriesCollection(); } else { - List> siblings = getSiblingsWithDuration(input); - Long budget = input.getBudget(getConfiguration()); - Integer index = 1; - for (Pair sibling : siblings) { - XYDataItem dataItem; - if (sibling.getKey() instanceof EObject) { - dataItem = new XYBackreferenceDataItem<>(index++, sibling.getValue(), sibling.getKey()); - } else { - dataItem = new XYDataItem(index++, sibling.getValue()); - } - if (budget != null && sibling.getValue() > budget) { - series1_ExceedsBudget.add(dataItem, false); - } else { - series0_Duration.add(dataItem, false); - } - } chart.setTitle(input.getTitle(getConfiguration())); + if (input.isCategorized(getConfiguration())) { + xyCollection = refreshCategoryChart(input, renderer); + } else { + xyCollection = refreshBudgetChart(input, renderer); + } } - - XYSeriesCollection xyCollection = new XYSeriesCollection(); - xyCollection.addSeries(series0_Duration); - xyCollection.addSeries(series1_ExceedsBudget); chart.getXYPlot().setDataset(xyCollection); + // Hide empty series in legend + for (int series = 0; series < xyCollection.getSeriesCount(); series++) { + if (xyCollection.getItemCount(series) == 0) { + renderer.setSeriesVisibleInLegend(series, false, false); + } + } + Number[] yValues = from(XYDataItemResolver.DEFAULT.resolveAllDataItems(xyCollection)) .objectsOfKind(XYDataItem.class).collectOne(XYDataItem::getY).toArray(Number.class); subTitle.setText(calculateStatistics(yValues)); } + + protected XYSeriesCollection refreshBudgetChart(IDataAnalysisInput input, XYBarRenderer renderer) { + renderer.setAutoPopulateSeriesPaint(false); + renderer.setAutoPopulateSeriesOutlinePaint(false); + renderer.setSeriesPaint(0, RenderingPaint.BLUE.getPaint()); + renderer.setSeriesOutlinePaint(0, RenderingPaint.BLUE.getOutlinePaint()); + renderer.setSeriesPaint(1, RenderingPaint.RED.getPaint()); + renderer.setSeriesOutlinePaint(1, RenderingPaint.RED.getOutlinePaint()); + + final XYSeries series0_Duration = new XYSeries("Normal"); + final XYSeries series1_ExceedsBudget = new XYSeries("Exceeds budget"); + + List> siblings = getSiblingsWithDuration(input); + Long budget = input.getBudget(getConfiguration()); + Integer index = 1; + for (Pair sibling : siblings) { + XYDataItem dataItem; + if (sibling.getKey() instanceof EObject) { + dataItem = new XYBackreferenceDataItem<>(index++, sibling.getValue(), sibling.getKey()); + } else { + dataItem = new XYDataItem(index++, sibling.getValue()); + } + if (budget != null && sibling.getValue() > budget) { + series1_ExceedsBudget.add(dataItem, false); + } else { + series0_Duration.add(dataItem, false); + } + } + + XYSeriesCollection xyCollection = new XYSeriesCollection(); + xyCollection.addSeries(series0_Duration); + xyCollection.addSeries(series1_ExceedsBudget); + return xyCollection; + } + + protected XYSeriesCollection refreshCategoryChart(IDataAnalysisInput input, XYBarRenderer renderer) { + renderer.setAutoPopulateSeriesPaint(true); + renderer.setAutoPopulateSeriesOutlinePaint(true); + ChartFactory.getChartTheme().apply(getChart()); + + Map series = new LinkedHashMap<>(); + List> siblings = getSiblingsWithDuration(input); + Integer index = 1; + for (Pair sibling : siblings) { + XYDataItem dataItem; + if (sibling.getKey() instanceof EObject) { + dataItem = new XYBackreferenceDataItem<>(index++, sibling.getValue(), sibling.getKey()); + } else { + dataItem = new XYDataItem(index++, sibling.getValue()); + } + XYSeries categorySeries = series.computeIfAbsent( + input.getCategory(sibling.getKey(), getConfiguration()), XYSeries::new); + categorySeries.add(dataItem, false); + } + + XYSeriesCollection xyCollection = new XYSeriesCollection(); + series.values().forEach(xyCollection::addSeries); + return xyCollection; + } } diff --git a/plugins/nl.esi.pps.tmsc.metric.edit/src/nl/esi/pps/tmsc/metric/provider/dataanalysis/MetricDataAnalysisItemContentProvider.java b/plugins/nl.esi.pps.tmsc.metric.edit/src/nl/esi/pps/tmsc/metric/provider/dataanalysis/MetricDataAnalysisItemContentProvider.java index c4cac9b..8854c58 100644 --- a/plugins/nl.esi.pps.tmsc.metric.edit/src/nl/esi/pps/tmsc/metric/provider/dataanalysis/MetricDataAnalysisItemContentProvider.java +++ b/plugins/nl.esi.pps.tmsc.metric.edit/src/nl/esi/pps/tmsc/metric/provider/dataanalysis/MetricDataAnalysisItemContentProvider.java @@ -50,7 +50,7 @@ public Long getDuration(Object object, Object sibling, String configuration) { return null; } - private Metric getMetric(Object object) { + protected Metric getMetric(Object object) { if (object instanceof MetricInstance) { return ((MetricInstance) object).getMetric(); }