1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.panels.loadtest;
14
15 import java.awt.Color;
16 import java.awt.Dimension;
17 import java.awt.Graphics;
18 import java.awt.Rectangle;
19 import java.awt.event.ComponentAdapter;
20 import java.awt.event.ComponentEvent;
21 import java.awt.event.MouseEvent;
22 import java.awt.event.MouseMotionListener;
23 import java.awt.image.BufferedImage;
24
25 import javax.swing.BorderFactory;
26 import javax.swing.Icon;
27 import javax.swing.ImageIcon;
28 import javax.swing.JComponent;
29 import javax.swing.JLabel;
30 import javax.swing.Scrollable;
31 import javax.swing.event.TableModelEvent;
32 import javax.swing.event.TableModelListener;
33 import javax.swing.table.TableModel;
34
35 import com.eviware.soapui.impl.wsdl.loadtest.ColorPalette;
36 import com.eviware.soapui.impl.wsdl.loadtest.WsdlLoadTest;
37 import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics;
38 import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics.Statistic;
39 import com.eviware.soapui.impl.wsdl.loadtest.data.StatisticsHistory.StatisticsHistoryModel;
40 import com.jgoodies.forms.builder.ButtonBarBuilder;
41
42 /***
43 * Graphical representation of testschedule statistics
44 *
45 * @author Ole.Matzura
46 */
47
48 public class JStatisticsHistoryGraph extends JComponent implements Scrollable
49 {
50 private static final Color THREADCOUNT_COLOR = Color.GREEN.darker();
51 private static final int SCROLL_AHEAD = 50;
52 private static final Color TOTAL_COLOR = Color.BLACK;
53
54 private final WsdlLoadTest loadTest;
55 private final LoadTestStatistics statisticsModel;
56 private StatisticsHistoryModel data;
57 private JComponent legend;
58 private InternalTableModelListener tableModelListener = new InternalTableModelListener();
59 private long[] maxValues;
60 private float [] scales;
61
62 public JStatisticsHistoryGraph(WsdlLoadTest loadTest)
63 {
64 this.loadTest = loadTest;
65 this.statisticsModel = loadTest.getStatisticsModel();
66 this.data = statisticsModel.getHistory().getStatisticsValueHistory( Statistic.AVERAGE );
67
68 setAutoscrolls(true);
69 addMouseMotionListener(new InternalMouseMotionListener());
70
71 data.addTableModelListener(tableModelListener);
72
73 initMaxValues();
74 initScales();
75
76 setBackground( Color.WHITE );
77 setOpaque( true );
78
79 addComponentListener( new ComponentAdapter() {
80
81 public void componentResized(ComponentEvent e)
82 {
83 initScales();
84 }
85 } );
86 }
87
88 public long getResolution()
89 {
90 return statisticsModel.getHistory().getResolution();
91 }
92
93 public void setResolution( long resolution )
94 {
95 statisticsModel.getHistory().setResolution( resolution );
96 }
97
98 public TableModel getModel()
99 {
100 return data;
101 }
102
103 public void release()
104 {
105 data.removeTableModelListener( tableModelListener );
106 }
107
108 public void setStatistic( Statistic statistic )
109 {
110 if (data != null)
111 {
112 data.removeTableModelListener(tableModelListener);
113 data.release();
114 }
115
116 data = statisticsModel.getHistory().getStatisticsValueHistory( statistic );
117
118 initMaxValues();
119 initScales();
120
121 data.addTableModelListener(tableModelListener);
122
123 getParent().invalidate();
124 revalidate();
125 repaint();
126 }
127
128 private void initMaxValues()
129 {
130 maxValues = new long[data.getColumnCount()];
131
132 for( int c = 0; c < data.getRowCount(); c++ )
133 {
134 for( int i = 0; i < data.getColumnCount(); i++ )
135 {
136 long value = (Long)data.getValueAt( c, i );
137 if( value > maxValues[i] )
138 maxValues[i] = value;
139 }
140 }
141 }
142
143 private void initScales()
144 {
145 scales = new float[maxValues.length];
146
147 for( int c = 0; c < maxValues.length; c++ )
148 {
149 recalcScale( c );
150 }
151 }
152
153 private boolean recalcScale( int index)
154 {
155 float scale = (index == 0 || maxValues[index] == 0) ? 1 : (float)(getHeight())/(float)(maxValues[index]+10);
156 if( scale > 1 ) scale = 1;
157
158 if( Float.compare( scale, scales[index] ) == 0 )
159 {
160 return false;
161 }
162
163 scales[index] = scale;
164 return true;
165 }
166
167 public void paintComponent(Graphics g)
168 {
169 g.setColor( getBackground() );
170
171 Rectangle clip = g.getClipBounds();
172 g.fillRect( (int)clip.getX(), (int)clip.getY(), (int)clip.getWidth(), (int)clip.getHeight() );
173
174 double right = clip.getX() + clip.getWidth();
175 int height = getHeight();
176
177 for( int c = (int) clip.getX(); c < data.getRowCount() && c < right; c++ )
178 {
179 for (int i = 0; i < data.getColumnCount(); i++)
180 {
181 if( i == 0 )
182 g.setColor( THREADCOUNT_COLOR );
183 else if( i == data.getColumnCount()-1 )
184 g.setColor( TOTAL_COLOR );
185 else
186 g.setColor( ColorPalette.getColor( loadTest.getTestCase().getTestStepAt( i-1 )) );
187
188 int yOffset = (int) ((float) ((Long) data.getValueAt(c, i)) * scales[i]);
189
190 if( clip.contains( c, height - yOffset - 1 ))
191 {
192 g.drawLine(c, height - yOffset - 1, c, height - yOffset -1);
193 }
194 }
195 }
196 }
197
198 public JComponent getLegend()
199 {
200 if (legend == null)
201 buildLegend();
202
203 return legend;
204 }
205
206 private void buildLegend()
207 {
208 ButtonBarBuilder builder = new ButtonBarBuilder();
209
210 builder.addFixed( new JLabel( "ThreadCount", createLegendIcon( THREADCOUNT_COLOR ), JLabel.LEFT ));
211 builder.addUnrelatedGap();
212 builder.addFixed( new JLabel( "Total", createLegendIcon( TOTAL_COLOR ), JLabel.LEFT ));
213 builder.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ));
214
215 legend = builder.getPanel();
216 }
217
218 private Icon createLegendIcon(Color color)
219 {
220 BufferedImage image = new BufferedImage( 10, 10, BufferedImage.TYPE_3BYTE_BGR );
221 Graphics g = image.getGraphics();
222 g.setColor( color );
223 g.fillRect( 1, 1, 8, 8 );
224 g.setColor( Color.DARK_GRAY );
225 g.drawRect( 0, 0, 10, 10 );
226 return new ImageIcon( image );
227 }
228
229 public Dimension getPreferredScrollableViewportSize()
230 {
231 return getPreferredSize();
232 }
233
234 public Dimension getPreferredSize()
235 {
236 int height = getHeight();
237 int width = data.getRowCount() + SCROLL_AHEAD;
238 return new Dimension( width, height);
239 }
240
241 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
242 {
243 return 1;
244 }
245
246 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
247 {
248 return 10;
249 }
250
251 public boolean getScrollableTracksViewportWidth()
252 {
253 return false;
254 }
255
256 public boolean getScrollableTracksViewportHeight()
257 {
258 return true;
259 }
260
261 private final class InternalTableModelListener implements TableModelListener
262 {
263 public synchronized void tableChanged(TableModelEvent e)
264 {
265 boolean repaint = false;
266
267 if( e.getType() == TableModelEvent.INSERT )
268 {
269 int firstRow = e.getFirstRow();
270 int lastRow = e.getLastRow();
271 int height = getHeight();
272
273 for( int c = firstRow; c <= lastRow; c++ )
274 {
275 for( int i = 0; i < data.getColumnCount(); i++ )
276 {
277 long value = (Long)data.getValueAt( c, i );
278
279 if( value > maxValues[i] )
280 {
281 maxValues[i] = value;
282 repaint = recalcScale( i );
283 }
284 }
285 }
286
287 if( !repaint )
288 {
289 Rectangle rect = new Rectangle(firstRow, 0, (lastRow-firstRow)+1, height );
290 repaint( rect );
291 }
292
293 Dimension size = getSize();
294 Rectangle r = getVisibleRect();
295
296 double x2 = r.getX() + r.getWidth();
297 if( x2 >= data.getRowCount() && x2 < data.getRowCount()+SCROLL_AHEAD)
298 {
299 scrollRectToVisible( new Rectangle(firstRow + SCROLL_AHEAD/2, 0, (lastRow-firstRow)+1, height ) );
300 }
301
302 if( !repaint && size.getWidth() < data.getRowCount() + SCROLL_AHEAD )
303 {
304 revalidate();
305 }
306 }
307 else if( e.getType() == TableModelEvent.UPDATE )
308 {
309 initMaxValues();
310 initScales();
311
312 repaint = true;
313 }
314
315 if( repaint )
316 {
317 getParent().invalidate();
318 revalidate();
319 repaint();
320 }
321 }
322 }
323
324 private class InternalMouseMotionListener implements MouseMotionListener
325 {
326 public void mouseDragged(MouseEvent e)
327 {
328 Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
329 scrollRectToVisible(r);
330 }
331
332 public void mouseMoved(MouseEvent e)
333 {
334 }
335 }
336 }