/* =====================================================================
* Ocelotl Visualization Tool
* =====================================================================
*
* Ocelotl is a Framesoc plug in that enables to visualize a trace
* overview by using aggregation techniques
*
* (C) Copyright 2013 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>
* Generoso Pagano <generoso.pagano@inria.fr>
*/
package fr.inria.soctrace.tools.ocelotl.visualizations.temporal.proportion.views;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.ImageFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.RectangleFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PrecisionPoint;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import fr.inria.soctrace.framesoc.ui.colors.FramesocColorManager;
import fr.inria.soctrace.tools.ocelotl.core.constants.OcelotlConstants;
import fr.inria.soctrace.tools.ocelotl.core.ivisuop.PartMap;
import fr.inria.soctrace.tools.ocelotl.ui.views.OcelotlView;
import fr.inria.soctrace.tools.ocelotl.ui.views.timelineview.TimeLineView;
import fr.inria.soctrace.tools.ocelotl.visualizations.temporal.proportion.TemporalProportion;
public class TemporalProportionView extends TimeLineView {
TemporalProportion distribution;
public class EventStack {
private int index;
//Minimal height for a rectangle to be displayed
private static final int MinHeight = 6;
//Minimal size of the icon to be displayed
private static final int IconMin = 6;
private static final int IconMax = 32;
private static final double DrawingMarginRatio = OcelotlConstants.TemporalProportionDrawingMarginRatio;
private int stackSpace = 2;
private IconManager iconManager;
//Minimum value to consider a color too light
private static final int Light = 225;
public EventStack(final int index, final int space) {
super();
setIndex(index);
this.stackSpace = space / 2;
this.iconManager = new IconManager();
}
public int getIndex() {
return index;
}
public boolean isTooLight(Color color) {
if (color.getGreen() > Light && color.getBlue() > Light
&& color.getRed() > Light)
return true;
return false;
}
// Draw the proportion visualization of the aggregates
public void init() {
DecimalFormat valueFormat = new DecimalFormat("0.00E0");
valueFormat.setMaximumIntegerDigits(3);
double total = 0;
// Height of the drawing area
final double y0 = root.getSize().height - aBorder;
final double y1 = DrawingMarginRatio * root.getSize().height - aBorder;
// Width of the drawing area
final double drawingAreaWidth = root.getSize().width - 2 * aBorder;
final double numberOfTimeSlice = distribution.getSliceNumber();
final double sliceWidth = drawingAreaWidth / numberOfTimeSlice;
// Highest value among the aggregates
final double maxValue = distribution.getMax();
double agg = 0;
final List<String> aggList = new ArrayList<String>();
final List<String> states = new ArrayList<String>();
states.addAll(distribution.getStates());
int startingX = (int) (distribution.getPart(index).getStartPart()
* sliceWidth + aBorder);
int endingX = (int) (distribution.getPart(index).getEndPart()
* sliceWidth - space + aBorder);
// Sort states alphabetically
Collections.sort(states, new Comparator<String>() {
@Override
public int compare(final String o1, final String o2) {
return o1.compareTo(o2);
}
});
for (final String state : states) {
final double value = ((PartMap) distribution.getPart(index)
.getData()).getElements().get(state);
if (value > 0) {
final RectangleFigure rect = new RectangleFigure();
rect.setBackgroundColor(FramesocColorManager.getInstance()
.getEventTypeColor(state).getSwtColor());
rect.setForegroundColor(ColorConstants.white);
rect.setLineWidth(1);
// If the color is too light, add a border
if (isTooLight(rect.getBackgroundColor())) {
rect.setForegroundColor(ColorConstants.black);
}
final Label label = new Label(" " + state + ": "
+ valueFormat.format(value) + " " + unit + " ");
rect.setToolTip(label);
// If the height of the state proportion is big enough
if (!ocelotlView.getOcelotlParameters().getOcelotlSettings().isUseVisualAggregate()
|| y1 * value / maxValue - stackSpace > MinHeight) {
// Draw a rectangle
if (isTooLight(rect.getBackgroundColor())) {
root.add(rect, new Rectangle(new Point(
startingX + 1, (int) (y0 - y1 * total
/ maxValue)), new Point(
endingX - 1, (int) (y0 + space - y1
* (total + value) / maxValue))));
} else {
root.add(rect, new Rectangle(new PrecisionPoint(
startingX, (int) (y0 - y1 * total
/ maxValue)), new PrecisionPoint(
endingX, (int) (y0 + stackSpace - y1
* (total + value) / maxValue))));
}
total += value;
} else { // else aggregates it
agg += value;
aggList.add(state + ": " + valueFormat.format(value));
}
label.getUpdateManager().performUpdate();
rect.getUpdateManager().performUpdate();
}
}
if (agg != 0) {
final ImageFigure icon = new ImageFigure();
final RectangleFigure rectangle = new RectangleFigure();
icon.setBackgroundColor(ColorConstants.black);
icon.setForegroundColor(ColorConstants.white);
rectangle.setBackgroundColor(ColorConstants.black);
rectangle.setForegroundColor(ColorConstants.white);
String aggString = " ";
for (int i = 0; i < aggList.size() - 1; i++)
aggString = aggString + aggList.get(i) + " \n ";
aggString = aggString + aggList.get(aggList.size() - 1) + " ";
final Label label = new Label(aggString);
icon.setToolTip(label);
rectangle.setToolTip(label);
final PolylineConnection lineDash = new PolylineConnection();
lineDash.setBackgroundColor(ColorConstants.black);
lineDash.setForegroundColor(ColorConstants.black);
lineDash.setLineWidth(2);
lineDash.setLineStyle(SWT.LINE_DASH);
lineDash.setToolTip(label);
// If the aggregated state proportion is high enough
if (y1 * agg / maxValue - stackSpace > MinHeight) {
// Display a rectangle
root.add(rectangle, new Rectangle(new Point(startingX,
(int) (y0 - y1 * total / maxValue)), new Point(
endingX, (int) (y0 + stackSpace - y1
* (total + agg) / maxValue))));
} else { // else display as a dash line and an icon
int size = (int) Math.min(IconMax,
Math.min(sliceWidth - 2 * stackSpace, (y0 - y1 * total / maxValue)));
if (size > IconMin) {
icon.setImage(iconManager.getImage(size));
lineDash.setEndpoints(new Point(startingX + 1,
(int) (y0 - y1 * total / maxValue)), new Point(
endingX, (int) (y0 - y1 * (total) / maxValue)));
root.add(lineDash);
root.add(icon, new Rectangle(
new Point(startingX, (int) (y0 - y1 * total
/ maxValue)
- stackSpace), new Point(endingX,
(int) (y0 - y1 * (total) / maxValue)
- size - stackSpace)));
} else {
lineDash.setEndpoints(new Point(startingX + 1,
(int) (y0 - y1 * total / maxValue)), new Point(
endingX, (int) (y0 - y1 * (total) / maxValue)));
root.add(lineDash);
}
}
label.getUpdateManager().performUpdate();
icon.getUpdateManager().performUpdate();
}
root.validate();
}
public void setIndex(final int index) {
this.index = index;
}
}
public TemporalProportionView(final OcelotlView ocelotlView) {
super(ocelotlView);
// TODO Auto-generated constructor stub
}
@Override
protected void computeDiagram() {
distribution = (TemporalProportion) ocelotlView.getCore()
.getVisuOperator();
for (int i = 0; i < distribution.getPartNumber(); i++) {
final EventStack part = new EventStack(i, space);
part.init();
}
}
}