/******************************************************************************* * Copyright (c) 2012-2015 INRIA. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Damien Dosimont <damien.dosimont@imag.fr> * Youenn Corre <youenn.corret@inria.fr> ******************************************************************************/ package fr.inria.soctrace.tools.ocelotl.ui.views; import java.lang.reflect.InvocationTargetException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.draw2d.ColorConstants; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.LightweightSystem; import org.eclipse.draw2d.OrderedLayout; import org.eclipse.draw2d.RectangleFigure; import org.eclipse.draw2d.ToolbarLayout; import org.eclipse.draw2d.XYLayout; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.wb.swt.SWTResourceManager; import org.osgi.framework.Bundle; import fr.inria.soctrace.framesoc.core.bus.FramesocBusTopic; import fr.inria.soctrace.framesoc.core.bus.FramesocBusTopicList; import fr.inria.soctrace.framesoc.core.bus.IFramesocBusListener; import fr.inria.soctrace.lib.model.utils.SoCTraceException; import fr.inria.soctrace.tools.ocelotl.core.dataaggregmanager.IDataAggregManager; import fr.inria.soctrace.tools.ocelotl.core.exceptions.OcelotlException; import fr.inria.soctrace.tools.ocelotl.core.idataaggregop.IDataAggregationOperator; import fr.inria.soctrace.tools.ocelotl.core.ivisuop.IVisuOperator; import fr.inria.soctrace.tools.ocelotl.core.microdesc.MicroscopicDescription; import fr.inria.soctrace.tools.ocelotl.core.parameters.OcelotlParameters; import fr.inria.soctrace.tools.ocelotl.core.timeregion.TimeRegion; import fr.inria.soctrace.tools.ocelotl.ui.views.timelineview.AggregatedView; import fr.inria.soctrace.tools.ocelotl.ui.views.timelineview.IAggregatedView; public class Overview implements IFramesocBusListener { private OcelotlView ocelotlView; private MicroscopicDescription microModel; private IDataAggregationOperator aggregOperator; private IDataAggregManager aggregManager; private IVisuOperator visuOperator; private String visuOperatorName = ""; private OcelotlParameters overviewParameters; private Figure root; private Canvas canvas; private AggregatedView timeLineView; private boolean redrawOverview; private double parameter = 0.0; private int timeSlice; private TimeRegion displayedTimeRegion; private TimeRegion zoomedTimeRegion; private TimeRegion selectedTimeRegion; private Color displayFGColor = ColorConstants.black; private Color displayBGColor = ColorConstants.red; private int displayAlphaValue = 110; private Color selectFGColor = ColorConstants.white; private Color selectBGColor = ColorConstants.black; private int selectAlphaValue = 110; // Show the currently displayed zone private SelectFigure displayedZone; // Show the currently selected zone private SelectFigure selectedZone; private int Border = 3; private OverviewThread overviewThread = null; // Used to control the overview computing thread NullProgressMonitor monitor; /** * Followed topics */ protected FramesocBusTopicList topics = null; public Overview(OcelotlView aView) { super(); ocelotlView = aView; redrawOverview = true; displayedTimeRegion = null; // Set colors according to the settings displayFGColor = ocelotlView.getOcelotlParameters().getOcelotlSettings().getOverviewDisplayFgColor(); displayBGColor = ocelotlView.getOcelotlParameters().getOcelotlSettings().getOverviewDisplayBgColor(); displayAlphaValue = ocelotlView.getOcelotlParameters().getOcelotlSettings().getOverviewDisplayAlphaValue(); selectFGColor = ocelotlView.getOcelotlParameters().getOcelotlSettings().getOverviewSelectionFgColor(); selectBGColor = ocelotlView.getOcelotlParameters().getOcelotlSettings().getOverviewSelectionBgColor(); selectAlphaValue = ocelotlView.getOcelotlParameters().getOcelotlSettings().getOverviewSelectionAlphaValue(); // Register update to synchronize traces topics = new FramesocBusTopicList(this); topics.addTopic(FramesocBusTopic.TOPIC_UI_COLORS_CHANGED); topics.registerAll(); initSelectionFigure(); } // When receiving a notification, redraw the overview with the new color @Override public void handle(FramesocBusTopic topic, Object data) { if (topic.equals(FramesocBusTopic.TOPIC_UI_COLORS_CHANGED) && aggregManager != null) { createDiagram(); displayedZone.draw(zoomedTimeRegion, true); } } /** * Initialize the canvas * * @param parent * @return */ public Canvas init(final Composite parent) { root = new Figure(); root.setFont(parent.getFont()); final XYLayout layout = new XYLayout(); root.setLayoutManager(layout); canvas = new Canvas(parent, SWT.DOUBLE_BUFFERED); canvas.setSize(parent.getSize()); final LightweightSystem lws = new LightweightSystem(canvas); lws.setContents(root); lws.setControl(canvas); canvas.addControlListener(new ControlListener() { @Override public void controlMoved(final ControlEvent arg0) { canvas.redraw(); root.repaint(); resizeDiagram(); } @Override public void controlResized(final ControlEvent arg0) { canvas.redraw(); root.repaint(); resizeDiagram(); } }); root.setFont(SWTResourceManager.getFont("Cantarell", 24, SWT.NORMAL)); root.setSize(parent.getSize().x, parent.getSize().y); return canvas; } /** * Draw the diagram * * @param time */ public void createDiagram() { displayedTimeRegion = new TimeRegion(overviewParameters.getTimeRegion()); timeLineView.setBorder(Border); timeLineView.createDiagram(aggregManager, displayedTimeRegion, visuOperator); } /** * Redraw the diagram to adapt to the new size of the display */ public void resizeDiagram() { root.removeAll(); canvas.update(); if (aggregManager != null && displayedTimeRegion != null) { createDiagram(); displayedZone.draw(zoomedTimeRegion, true); drawSelection(); } } /** * Update the overview (the selection, and the drawing) * * @param time * @throws OcelotlException */ public void updateDiagram(TimeRegion time) throws OcelotlException { if(overviewThread != null && overviewThread.isAlive()) return; zoomedTimeRegion = new TimeRegion(time); // Is it necessary to change completely the computed model if (redrawOverview) { overviewThread = new OverviewThread(time); return; } displayedZone.draw(time, true); deleteSelection(); } /** * Update the selected region with the displayed region * * @param time * the new selected time region */ public void updateSelection(TimeRegion time) { selectedTimeRegion = time; drawSelection(); } /** * Draw the selection */ protected void drawSelection() { if(selectedTimeRegion != null && displayedTimeRegion != null && aggregOperator != null) selectedZone.draw(selectedTimeRegion, false); } /** * Don't the show the selection anymore */ public void deleteSelection() { selectedZone.delete(); // Avoid further redraw selectedTimeRegion = displayedTimeRegion; } public IAggregatedView getTimeLineView() { return timeLineView; } public void setTimeLineView(AggregatedView timeLineView) { this.timeLineView = timeLineView; } public boolean isRedrawOverview() { return redrawOverview; } public void setRedrawOverview(boolean redrawOverview) { this.redrawOverview = redrawOverview; } public SelectFigure getSelectedZone() { return selectedZone; } public void setSelectedZone(SelectFigure selectedZone) { this.selectedZone = selectedZone; } public OverviewThread getOverviewThread() { return overviewThread; } public void setOverviewThread(OverviewThread overviewThread) { this.overviewThread = overviewThread; } public IVisuOperator getVisuOperator() { return visuOperator; } public void setVisuOperator(IVisuOperator visuOperator) { this.visuOperator = visuOperator; } public String getVisuOperatorName() { return visuOperatorName; } public void setVisuOperatorName(String visuOperatorName) { this.visuOperatorName = visuOperatorName; } public Color getDisplayFGColor() { return displayFGColor; } public void setDisplayFGColor(Color displayFGColor) { this.displayFGColor = displayFGColor; if (displayedZone != null) { displayedZone.setForegroundColor(displayFGColor); if(zoomedTimeRegion != null) displayedZone.draw(zoomedTimeRegion, true); } } public Color getDisplayBGColor() { return displayBGColor; } public void setDisplayBGColor(Color displayBGColor) { this.displayBGColor = displayBGColor; if (displayedZone != null) { displayedZone.setBackgroundColor(displayBGColor); if(zoomedTimeRegion != null) displayedZone.draw(zoomedTimeRegion, true); } } public Color getSelectFGColor() { return selectFGColor; } public void setSelectFGColor(Color selectFGColor) { this.selectFGColor = selectFGColor; if (selectedZone != null) { selectedZone.setForegroundColor(selectFGColor); drawSelection(); } } public Color getSelectBGColor() { return selectBGColor; } public void setSelectBGColor(Color selectBGColor) { this.selectBGColor = selectBGColor; if (selectedZone != null) { selectedZone.setBackgroundColor(selectBGColor); drawSelection(); } } public int getDisplayAlphaValue() { return displayAlphaValue; } public void setDisplayAlphaValue(int displayAlphaValue) { this.displayAlphaValue = displayAlphaValue; if (displayedZone != null) { displayedZone.setAlpha(displayAlphaValue); if (zoomedTimeRegion != null) displayedZone.draw(zoomedTimeRegion, true); } } public int getSelectAlphaValue() { return selectAlphaValue; } public void setSelectAlphaValue(int selectAlphaValue) { this.selectAlphaValue = selectAlphaValue; if (selectedZone != null) { selectedZone.setAlpha(selectAlphaValue); drawSelection(); } } /** * Initialize the visualization operator and perform additional init * operation * * @param name * the name of the visualization operator */ public void initVisuOperator(String name) { // Instantiate the chosen visu operator visuOperator = ocelotlView.getCore().getVisuOperators().instantiateOperator(name); visuOperatorName = name; final Bundle mybundle = Platform.getBundle(ocelotlView.getCore().getVisuOperators().getOperatorResource(name).getBundle()); // Instantiate the actual view try { this.timeLineView = (AggregatedView) mybundle.loadClass(ocelotlView.getCore().getVisuOperators().getOperatorResource(name).getVisualization()).getDeclaredConstructor(OcelotlView.class).newInstance(ocelotlView); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } root.removeAll(); canvas.update(); // Init the view timeLineView.setRoot(root); timeLineView.setCanvas(canvas); redrawOverview = true; aggregManager = null; // Init other stuff displayedTimeRegion = new TimeRegion(ocelotlView.getTimeRegion()); initSelectionFigure(); parameter = 0.0; } /** * Set the overview parameters with a set of ocelotlParameters * * @param ocelotlParameters * the parameters used to perform the update */ public void updateOverviewParameters(OcelotlParameters ocelotlParameters) { // Copy the given parameters overviewParameters = new OcelotlParameters(ocelotlView.getOcelotlParameters()); // Set the time slice number at the current value for overview overviewParameters.setTimeSlicesNumber(timeSlice); // Set the time region at global TimeRegion overviewTimeRegion = new TimeRegion(overviewParameters.getTrace().getMinTimestamp(), overviewParameters.getTrace().getMaxTimestamp()); overviewParameters.setTimeRegion(overviewTimeRegion); // Set the pre-aggregation to true overviewParameters.setAggregatedLeaveEnable(overviewParameters.getOcelotlSettings().isOverviewAggregateLeaves()); overviewParameters.setMaxNumberOfLeaves(overviewParameters.getOcelotlSettings().getOverviewMaxNumberOfLeaves()); } public void initSelectionFigure() { selectedZone = new SelectFigure(selectFGColor, selectBGColor, selectAlphaValue); displayedZone = new SelectFigure(displayFGColor, displayBGColor, displayAlphaValue); } public void reset() { if (overviewThread != null && overviewThread.isAlive()) { monitor.setCanceled(true); } overviewThread = null; aggregManager = null; displayedTimeRegion = null; zoomedTimeRegion = null; selectedTimeRegion = null; } /** * Look for the next smaller parameter value */ public void modifyParameterDown() { if (aggregManager != null) { for (final double aParam : aggregManager.getParameters()) { if (aParam > parameter) { parameter = aParam; changeParameter(); break; } } } } /** * Look for the next greater parameter value */ public void modifyParameterUp() { if (aggregManager != null) { for (int aParam = aggregManager.getParameters().size() - 1; aParam >= 0; aParam--) { if (aggregManager.getParameters().get(aParam) < parameter) { parameter = aggregManager.getParameters().get(aParam); changeParameter(); break; } } } } /** * If the parameter value has changed then recompute parts and redraw */ public void changeParameter() { // Recompute the parts aggregManager.computeParts(parameter); // Idem in the view visuOperator.initManager(ocelotlView.getCore(), aggregManager); // Redraw createDiagram(); displayedZone.draw(zoomedTimeRegion, true); drawSelection(); } /** * Class for describing and displaying selected zones */ private class SelectFigure extends RectangleFigure { private Color foreground; private Color background; // Init with a given color set public SelectFigure(Color foreGround, Color backGround, int alphaValue) { super(); final ToolbarLayout layout = new ToolbarLayout(); layout.setMinorAlignment(OrderedLayout.ALIGN_CENTER); setLayoutManager(layout); this.foreground = foreGround; this.background = backGround; setForegroundColor(this.foreground); setBackgroundColor(this.background); setAlpha(alphaValue); } /** * Draw the actual selected time region * * @param timeRegion * the time region (time boundaries of the region) * @param displayed * flag to distinguish between the display and the selection * figure */ public void draw(final TimeRegion timeRegion, boolean displayed) { // If there is no zoom, don't show indicator if (timeRegion.compareTimeRegion(displayedTimeRegion)) { delete(); return; } if (getParent() != root) root.add(this); // Use to embed the selection figure within the display figure int delta = 0; if (!displayed) { delta = 2; } root.setConstraint(this, new Rectangle(new Point((int) ((timeRegion.getTimeStampStart() - displayedTimeRegion.getTimeStampStart()) * (root.getSize().width - 2 * Border) / displayedTimeRegion.getTimeDuration() + Border), root.getSize().height - delta), new Point((int) ((timeRegion.getTimeStampEnd() - displayedTimeRegion.getTimeStampStart()) * (root.getSize().width - 2 * Border) / displayedTimeRegion.getTimeDuration() + Border), delta))); } /** * Remove the selection from display */ public void delete() { if (getParent() != null) root.remove(this); } } /** * Thread use to compute the display of an overview */ class OverviewThread extends Thread { TimeRegion time; public OverviewThread(TimeRegion time) { super(); this.time = time; } @Override public void run() { try { // Get the number of time slice for the current overview aggregation operator timeSlice = ocelotlView.getCore().getAggregOperators().getOperatorResource(ocelotlView.getOcelotlParameters().getOcelotlSettings().getOverviewAggregOperator()).getTs(); //Set the overview parameters with the current ocelotlParameters updateOverviewParameters(ocelotlView.getOcelotlParameters()); monitor = new NullProgressMonitor(); // Get a new micro model microModel = ocelotlView.getCore().getMicromodelTypes().instantiateMicroModel(overviewParameters.getMicroModelType()); // Build the microscopic description microModel.setOcelotlParameters(overviewParameters, monitor); if (monitor.isCanceled()) return; // Init the aggregation operator aggregOperator = ocelotlView.getCore().getAggregOperators().instantiateOperator(ocelotlView.getOcelotlParameters().getOcelotlSettings().getOverviewAggregOperator()); aggregManager = aggregOperator.createManager(microModel, monitor); aggregManager.computeQualities(); if (monitor.isCanceled()) return; aggregManager.computeDichotomy(); if (monitor.isCanceled()) return; parameter = ocelotlView.getParameterPPolicy().computeInitialParameter(aggregManager, ocelotlView.getOcelotlParameters().getParameterPPolicy()); // Compute the view according to the new parameter value aggregManager.computeParts(parameter); if (monitor.isCanceled()) return; visuOperator.initManager(ocelotlView.getCore(), aggregManager); if (monitor.isCanceled()) return; Display.getDefault().syncExec(new Runnable() { @Override public void run() { createDiagram(); displayedZone.draw(time, true); } }); if (monitor.isCanceled()) return; redrawOverview = false; } catch (OcelotlException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SoCTraceException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }