001: /*
002: * soapUI, copyright (C) 2004-2007 eviware.com
003: *
004: * soapUI is free software; you can redistribute it and/or modify it under the
005: * terms of version 2.1 of the GNU Lesser General Public License as published by
006: * the Free Software Foundation.
007: *
008: * soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009: * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: * See the GNU Lesser General Public License for more details at gnu.org.
011: */
012:
013: package com.eviware.soapui.impl.wsdl.panels.loadtest;
014:
015: import java.awt.Color;
016: import java.awt.Dimension;
017: import java.awt.Graphics;
018: import java.awt.Rectangle;
019: import java.awt.event.ComponentAdapter;
020: import java.awt.event.ComponentEvent;
021: import java.awt.event.MouseEvent;
022: import java.awt.event.MouseMotionListener;
023: import java.awt.image.BufferedImage;
024:
025: import javax.swing.BorderFactory;
026: import javax.swing.Icon;
027: import javax.swing.ImageIcon;
028: import javax.swing.JComponent;
029: import javax.swing.JLabel;
030: import javax.swing.Scrollable;
031: import javax.swing.event.TableModelEvent;
032: import javax.swing.event.TableModelListener;
033: import javax.swing.table.TableModel;
034:
035: import com.eviware.soapui.impl.wsdl.loadtest.WsdlLoadTest;
036: import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics;
037: import com.eviware.soapui.impl.wsdl.loadtest.data.LoadTestStatistics.Statistic;
038: import com.eviware.soapui.impl.wsdl.loadtest.data.StatisticsHistory.StatisticsHistoryModel;
039: import com.eviware.soapui.model.testsuite.TestStep;
040: import com.jgoodies.forms.builder.ButtonBarBuilder;
041:
042: /**
043: * Graphical representation of testschedule statistics
044: *
045: * @author Ole.Matzura
046: */
047:
048: public class JStatisticsGraph extends JComponent implements Scrollable {
049: private static final Color THREADCOUNT_COLOR = Color.GREEN.darker();
050: private static final Color AVERAGE_COLOR = Color.BLUE;
051: private static final Color ERRORS_COLOR = Color.RED.darker();
052: private static final Color TPS_COLOR = Color.BLACK;
053: private static final Color BPS_COLOR = Color.ORANGE;
054: private static final Color LAST_COLOR = Color.MAGENTA.brighter();
055:
056: private static final int SCROLL_AHEAD = 50;
057:
058: @SuppressWarnings("unused")
059: private final WsdlLoadTest loadTest;
060: private final LoadTestStatistics statisticsModel;
061: private StatisticsHistoryModel data;
062: private JComponent legend;
063: private InternalTableModelListener tableModelListener = new InternalTableModelListener();
064: private long[] maxValues;
065: private float[] scales;
066:
067: public JStatisticsGraph(WsdlLoadTest loadTest) {
068: this .loadTest = loadTest;
069: this .statisticsModel = loadTest.getStatisticsModel();
070: this .data = statisticsModel.getHistory().getTestStepHistory(
071: LoadTestStatistics.TOTAL);
072:
073: setAutoscrolls(true);
074: addMouseMotionListener(new InternalMouseMotionListener());
075:
076: data.addTableModelListener(tableModelListener);
077:
078: initMaxValues();
079: initScales();
080:
081: setBackground(Color.WHITE);
082: setOpaque(true);
083:
084: addComponentListener(new ComponentAdapter() {
085:
086: public void componentResized(ComponentEvent e) {
087: initScales();
088: }
089: });
090: }
091:
092: public TableModel getModel() {
093: return data;
094: }
095:
096: public void release() {
097: data.removeTableModelListener(tableModelListener);
098: }
099:
100: public void setTestStep(TestStep testStep) {
101: if (data != null) {
102: data.removeTableModelListener(tableModelListener);
103: data.release();
104: }
105:
106: if (testStep == null) {
107: data = statisticsModel.getHistory().getTestStepHistory(
108: LoadTestStatistics.TOTAL);
109: } else {
110: data = statisticsModel.getHistory()
111: .getTestStepHistory(
112: testStep.getTestCase().getIndexOfTestStep(
113: testStep));
114: }
115:
116: initMaxValues();
117: initScales();
118:
119: data.addTableModelListener(tableModelListener);
120:
121: getParent().invalidate();
122: revalidate();
123: repaint();
124: }
125:
126: public long getResolution() {
127: return statisticsModel.getHistory().getResolution();
128: }
129:
130: public void setResolution(long resolution) {
131: statisticsModel.getHistory().setResolution(resolution);
132: }
133:
134: private void initMaxValues() {
135: maxValues = new long[data.getColumnCount()];
136:
137: for (int c = 0; c < data.getRowCount(); c++) {
138: for (int i = 0; i < data.getColumnCount(); i++) {
139: long value = (Long) data.getValueAt(c, i);
140: if (value > maxValues[i])
141: maxValues[i] = value;
142: }
143: }
144: }
145:
146: private void initScales() {
147: scales = new float[maxValues.length];
148:
149: for (int c = 0; c < maxValues.length; c++) {
150: recalcScale(c);
151: }
152: }
153:
154: private boolean recalcScale(int index) {
155: float scale = (index == 0 || maxValues[index] == 0) ? 1
156: : (float) (getHeight())
157: / (float) (maxValues[index] + 10);
158: if (scale > 1)
159: scale = 1;
160:
161: if (Float.compare(scale, scales[index]) == 0) {
162: return false;
163: }
164:
165: scales[index] = scale;
166: return true;
167: }
168:
169: public void paintComponent(Graphics g) {
170: g.setColor(getBackground());
171:
172: Rectangle clip = g.getClipBounds();
173: g.fillRect((int) clip.getX(), (int) clip.getY(), (int) clip
174: .getWidth(), (int) clip.getHeight());
175:
176: double right = clip.getX() + clip.getWidth();
177: int rowCount = data.getRowCount();
178: int height = getHeight();
179:
180: for (int c = (int) clip.getX(); c < rowCount && c < right; c++) {
181: for (int i = 0; i < data.getColumnCount(); i++) {
182: if (i == 0)
183: g.setColor(THREADCOUNT_COLOR);
184: else if (i == Statistic.AVERAGE.getIndex() + 1)
185: g.setColor(AVERAGE_COLOR);
186: else if (i == Statistic.ERRORS.getIndex() + 1)
187: g.setColor(ERRORS_COLOR);
188: else if (i == Statistic.TPS.getIndex() + 1)
189: g.setColor(TPS_COLOR);
190: else if (i == Statistic.LAST.getIndex() + 1)
191: g.setColor(LAST_COLOR);
192: else if (i == Statistic.BPS.getIndex() + 1)
193: g.setColor(BPS_COLOR);
194: else
195: continue;
196:
197: int yOffset = (int) ((float) ((Long) data.getValueAt(c,
198: i)) * scales[i]);
199:
200: if (clip.contains(c, height - yOffset - 1)) {
201: g.drawLine(c, height - yOffset - 1, c, height
202: - yOffset - 1);
203: }
204: }
205: }
206: }
207:
208: public JComponent getLegend() {
209: if (legend == null)
210: buildLegend();
211:
212: return legend;
213: }
214:
215: private void buildLegend() {
216: ButtonBarBuilder builder = new ButtonBarBuilder();
217:
218: builder.addFixed(new JLabel("ThreadCount",
219: createLegendIcon(THREADCOUNT_COLOR), JLabel.LEFT));
220: builder.addUnrelatedGap();
221: builder.addFixed(new JLabel("Average (ms)",
222: createLegendIcon(AVERAGE_COLOR), JLabel.LEFT));
223: builder.addUnrelatedGap();
224: builder.addFixed(new JLabel("ErrorCount",
225: createLegendIcon(ERRORS_COLOR), JLabel.LEFT));
226: builder.addUnrelatedGap();
227: builder.addFixed(new JLabel("Transaction/Sec",
228: createLegendIcon(TPS_COLOR), JLabel.LEFT));
229: builder.addUnrelatedGap();
230: builder.addFixed(new JLabel("Bytes/Sec",
231: createLegendIcon(BPS_COLOR), JLabel.LEFT));
232: builder.addUnrelatedGap();
233: builder.addFixed(new JLabel("Last (ms)",
234: createLegendIcon(LAST_COLOR), JLabel.LEFT));
235:
236: builder.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
237:
238: legend = builder.getPanel();
239: }
240:
241: private Icon createLegendIcon(Color color) {
242: BufferedImage image = new BufferedImage(10, 10,
243: BufferedImage.TYPE_3BYTE_BGR);
244: Graphics g = image.getGraphics();
245: g.setColor(color);
246: g.fillRect(1, 1, 8, 8);
247: g.setColor(Color.DARK_GRAY);
248: g.drawRect(0, 0, 10, 10);
249: return new ImageIcon(image);
250: }
251:
252: public Dimension getPreferredScrollableViewportSize() {
253: return getPreferredSize();
254: }
255:
256: public Dimension getPreferredSize() {
257: int height = getHeight();
258: int width = data.getRowCount() + SCROLL_AHEAD;
259: return new Dimension(width, height);
260: }
261:
262: public int getScrollableUnitIncrement(Rectangle visibleRect,
263: int orientation, int direction) {
264: return 1;
265: }
266:
267: public int getScrollableBlockIncrement(Rectangle visibleRect,
268: int orientation, int direction) {
269: return 10;
270: }
271:
272: public boolean getScrollableTracksViewportWidth() {
273: return false;
274: }
275:
276: public boolean getScrollableTracksViewportHeight() {
277: return true;
278: }
279:
280: private final class InternalTableModelListener implements
281: TableModelListener {
282: public synchronized void tableChanged(TableModelEvent e) {
283: boolean repaint = false;
284:
285: if (e.getType() == TableModelEvent.INSERT) {
286: int firstRow = e.getFirstRow();
287: int lastRow = e.getLastRow();
288: int height = getHeight();
289:
290: for (int c = firstRow; c <= lastRow; c++) {
291: for (int i = 0; i < data.getColumnCount(); i++) {
292: long value = (Long) data.getValueAt(c, i);
293:
294: if (value > maxValues[i]) {
295: maxValues[i] = value;
296: repaint = recalcScale(i);
297: }
298: }
299: }
300:
301: if (!repaint) {
302: Rectangle rect = new Rectangle(firstRow, 0,
303: (lastRow - firstRow) + 1, height);
304: repaint(rect);
305: }
306:
307: Dimension size = getSize();
308: Rectangle r = getVisibleRect();
309:
310: double x2 = r.getX() + r.getWidth();
311: if (x2 >= data.getRowCount()
312: && x2 < data.getRowCount() + SCROLL_AHEAD) {
313: scrollRectToVisible(new Rectangle(firstRow
314: + SCROLL_AHEAD / 2, 0,
315: (lastRow - firstRow) + 1, height));
316: }
317:
318: if (!repaint
319: && size.getWidth() < data.getRowCount()
320: + SCROLL_AHEAD) {
321: revalidate();
322: }
323: } else if (e.getType() == TableModelEvent.UPDATE) {
324: initMaxValues();
325: initScales();
326:
327: repaint = true;
328: }
329:
330: if (repaint) {
331: getParent().invalidate();
332: revalidate();
333: repaint();
334: }
335: }
336: }
337:
338: private class InternalMouseMotionListener implements
339: MouseMotionListener {
340: public void mouseDragged(MouseEvent e) {
341: Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
342: scrollRectToVisible(r);
343: }
344:
345: public void mouseMoved(MouseEvent e) {
346: }
347: }
348: }
|