1 /*******************************************************************************
2 * Copyright (c) 2010, 2011 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation
11 * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code
12 * Bernd Hufmann - Adapted to new model-view-controller design, display improvements
13 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.internal
.lttng
.ui
.views
.latency
.listeners
;
16 import java
.text
.DecimalFormat
;
17 import java
.util
.Collections
;
18 import java
.util
.Vector
;
20 import org
.eclipse
.linuxtools
.internal
.lttng
.ui
.views
.latency
.AbstractViewer
;
21 import org
.eclipse
.linuxtools
.internal
.lttng
.ui
.views
.latency
.HistogramViewer
;
22 import org
.eclipse
.linuxtools
.internal
.lttng
.ui
.views
.latency
.Messages
;
23 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.histogram
.HistogramScaledData
;
24 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.histogram
.HistogramUtils
;
25 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.histogram
.IHistogramDataModel
;
26 import org
.eclipse
.swt
.graphics
.Image
;
27 import org
.eclipse
.swt
.graphics
.Point
;
28 import org
.eclipse
.swt
.widgets
.Display
;
29 import org
.eclipse
.ui
.plugin
.AbstractUIPlugin
;
32 * <b><u>HistogramPaintListener</u></b>
34 * Histogram paint listener.
36 * @author Philippe Sawicki
38 public class HistogramPaintListener
extends AbstractPaintListener
{
40 // ------------------------------------------------------------------------
42 // ------------------------------------------------------------------------
45 * Is a histogram bar so high that it is clipped from the draw area ?
47 private boolean fBarIsClipped
= false;
50 * Scaled data from data model
52 protected HistogramScaledData fScaledData
;
57 protected Image fWarningImage
;
59 // ------------------------------------------------------------------------
61 // ------------------------------------------------------------------------
66 * A reference to the listener's viewer.
68 public HistogramPaintListener(AbstractViewer viewer
) {
70 fWarningImage
= AbstractUIPlugin
.imageDescriptorFromPlugin(Messages
.LatencyView_tmf_UI
, "icons/elcl16/warning.gif").createImage(Display
.getCurrent()); //$NON-NLS-1$
73 // ------------------------------------------------------------------------
75 // ------------------------------------------------------------------------
78 * Returns the histogram's bar Width.
79 * @return The histogram's bar Width.
81 public int getBarWidth() {
85 // ------------------------------------------------------------------------
87 // ------------------------------------------------------------------------
91 * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#dispose()
94 public void dispose() {
95 fWarningImage
.dispose();
101 * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#scale()
104 public void scale() {
105 // width of the plot area
106 double width
= getWidth();
107 // height of the plot area
108 double height
= getHeight();
110 int barWidth
= getBarWidth();
112 IHistogramDataModel model
= ((HistogramViewer
)fViewer
).getModel();
113 fScaledData
= model
.scaleTo((int)width
, (int)height
, barWidth
);
116 fYMax
= fScaledData
.fMaxValue
;
118 fXMin
= fScaledData
.getFirstBucketTime();
119 fXMin
= fXMin
> 0 ? fXMin
: 0;
120 fXMax
= fScaledData
.getBucketEndTime(fScaledData
.fLastBucket
- 1);
122 // No data to display - set end time to 0
130 * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintVerticalTicks(int)
133 public void paintVerticalTicks(int x
) {
134 // done in method paintVerticalAxisValues()
139 * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintVerticalAxisValues(int)
142 public void paintVerticalAxisValues(int x
) {
145 zoomFactor
= fViewer
.getZoomFactor();
147 if (fYMin
>= 0L && fYMax
!= 0L) {
148 fAxisImage
.setForeground(fTextColor
);
149 fAxisImage
.setBackground(fBackgroundColor
);
151 // Apply the zoom to the max value of the graph for the next calculations
152 long yMax
= fYMax
/ zoomFactor
;
154 int nbTicks
= ((int)getHeight()) / MAX_HEIGHT_BETWEEN_TICKS
+ 1;
156 Vector
<Integer
> values
= new Vector
<Integer
>();
157 boolean multipleSameValues
= true;
158 while (multipleSameValues
) {
159 double valueStep
= (double) (yMax
- fYMin
) / (double) (nbTicks
);
161 for (int i
= 0; i
< nbTicks
; i
++) {
162 double currentValue
= (double) (fYMin
+ i
* valueStep
) / (Math
.pow(10, fDelta
));
164 values
.add((int) currentValue
);
167 Collections
.sort(values
);
168 boolean hasRepetition
= false;
169 for (int i
= 1; i
< values
.size(); i
++) {
170 if (values
.get(i
) == values
.get(i
- 1)) {
171 hasRepetition
= true;
180 multipleSameValues
= false;
182 // Draw rectangle over the old values
183 int height
= fViewer
.getBounds().height
- 2 * fPadding
- fPaddingTop
- fHorizontalAxisYOffset
;
184 fAxisImage
.fillRectangle(0, fPadding
+ fPaddingTop
, fPadding
+ fVerticalAxisOffset
, height
);
186 double pixelStep
= (getHeight()) / values
.size() + 1;
188 for (int i
= 0; i
< values
.size(); i
++) {
189 double currentValue
= values
.get(i
);
191 int y
= (int) (fClientArea
.height
- fPadding
- fHorizontalAxisYOffset
- i
* pixelStep
);
192 String currentLabel
= formatStringForVerticalAxis((long) currentValue
);
194 fAxisImage
.setFont(fValuesFont
);
196 Point textDimensions
= fAxisImage
.stringExtent(currentLabel
);
197 fAxisImage
.drawText(currentLabel
, x
- textDimensions
.x
- 5, y
- textDimensions
.y
/ 2);
198 fAxisImage
.drawLine(x
- 3, y
, x
, y
);
207 * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintContent()
210 public void paintContent() {
211 double zoomFactor
= fViewer
.getZoomFactor();
213 // Calculate the vertical axis factor and see if it has changed
214 double tmpDelta
= fDelta
;
216 if (Long
.toString(fYMax
/ (long) zoomFactor
).length() > MAX_CHAR_VERTICAL_DISPLAY
) {
217 fDelta
= Long
.toString(fYMax
/ (long) zoomFactor
).length() - MAX_CHAR_VERTICAL_DISPLAY
;
219 if (tmpDelta
!= fDelta
) {
220 fViewer
.clearBackground();
225 paintHorizontalAxis();
227 fAxisImage
.setForeground(fDataColor
);
228 fAxisImage
.setBackground(fDataColor
);
230 // height of the plot area
231 double height
= getHeight();
233 int barWidth
= getBarWidth();
235 // axisImage_.setBackground(backgroundColor_);
236 // 1.a Iterate over the points, from 0 to nbPoints
237 // 1.b Find the max counter value
238 // 2. Assign the max value to the "yMax_" class attribute
239 // 3. Draw the histogram bars using "axisImage_.fillRectangle(...)"
240 boolean oneBarIsClipped
= false;
242 for (int i
= 0; i
< fScaledData
.fData
.length
; i
++) {
243 double pointY
= fScaledData
.fData
[i
];
246 double x
= fPadding
+ i
* barWidth
+ fVerticalAxisOffset
+ 1;
248 if (i
== fScaledData
.fData
.length
- 1)
250 double barHeight
= zoomFactor
* ((double)(pointY
- fYMin
) / (double)(fYMax
- fYMin
)) * height
;
252 if (barHeight
> height
+ 1) {
254 oneBarIsClipped
= true;
256 fAxisImage
.drawImage(fWarningImage
, 5, 3);
259 // Only draw the bars that have a barHeight of more than 1 pixel
261 double y
= fPadding
+ fPaddingTop
+ height
- barHeight
;
262 fAxisImage
.setBackground(fDataColor
);
264 if (barHeight
> height
- 1) {
265 fAxisImage
.fillRectangle((int) x
, (int) y
, (int) barWidth
, (int) (barHeight
+ 1));
267 fAxisImage
.fillRectangle((int) x
, (int) y
, (int) barWidth
, (int) (barHeight
+ 2));
273 fBarIsClipped
= true;
275 fBarIsClipped
= false;
279 * Paints the histogram horizontal axis values in engineering notation in which the exponent is a multiple of three.
281 * The numeric value to convert to engineering notation.
282 * @return The given value formatted according to the engineering notation.
285 public String
formatStringForHorizontalAxis(long value
) {
286 DecimalFormat formatter
= new DecimalFormat("##0.#E0"); //$NON-NLS-1$
287 return formatter
.format(value
);
291 * Sets the bar width.
295 public void setBarWidth(int barWidth
) {
300 * Returns "true" if a histogram bar is so high that it cannot be drawn in the draw area, "false" otherwise.
301 * @return "true" if a histogram bar is so high that it cannot be drawn in the draw area, "false" otherwise.
303 public boolean barIsClipped() {
304 return fBarIsClipped
;
309 * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatToolTipLabel(int, int)
312 public String
formatToolTipLabel(int x
, int y
) {
313 if (fScaledData
!= null) {
315 double barWidth
= getBarWidth();
316 double height
= getHeight(); // height of the plot area
318 double zoomFactor
= fViewer
.getZoomFactor();
320 int index
= (int) ((x
- fPadding
- fVerticalAxisOffset
- 1) / barWidth
);
322 double barHeight
= 0.0;
323 if (index
>= 0 && index
<= fScaledData
.fLastBucket
) {
324 barHeight
= (zoomFactor
* height
* (fScaledData
.fData
[index
] - fYMin
) / (fYMax
- fYMin
));
327 long fMouseY
= (long) (height
- (y
- fPadding
- fPaddingTop
));
329 // Verifying mouse pointer is over histogram bar
330 if (index
>= 0 && fScaledData
.fLastBucket
>= index
&& fMouseY
>= 0 && fMouseY
< barHeight
&& fMouseY
< height
&& x
>= (fVerticalAxisOffset
+ fPadding
)) {
332 fScaledData
.fCurrentBucket
= index
;
334 long startTime
= fScaledData
.getBucketStartTime(index
);
335 // negative values are possible if time values came into the model in decreasing order
339 long endTime
= fScaledData
.getBucketEndTime(index
);
340 int nbEvents
= fScaledData
.fData
[index
];
342 StringBuffer buffer
= new StringBuffer();
343 buffer
.append("Latency Range in s = ["); //$NON-NLS-1$
344 buffer
.append(HistogramUtils
.nanosecondsToString(startTime
));
345 buffer
.append(","); //$NON-NLS-1$
346 buffer
.append(HistogramUtils
.nanosecondsToString(endTime
));
347 buffer
.append("]\n"); //$NON-NLS-1$
348 buffer
.append("Latency count = "); //$NON-NLS-1$
349 buffer
.append(nbEvents
);
350 return buffer
.toString();
353 return ""; //$NON-NLS-1$