From: Lukas P. <pe...@us...> - 2002-07-15 11:16:33
|
Update of /cvsroot/javaprofiler/module/net/sourceforge/javaprofiler/module/views In directory usw-pr-cvs1:/tmp/cvs-serv10532 Added Files: TimeSeriesGraph.java TimeSeriesModel.java Log Message: Graphical component --- NEW FILE: TimeSeriesGraph.java --- package net.sourceforge.javaprofiler.module.views; import javax.swing.*; import java.awt.*; import javax.swing.event.ChangeListener; import javax.swing.event.ChangeEvent; /** Draws values of a time series in a bar graph. * @author Lukas Petru */ public class TimeSeriesGraph extends JComponent implements ChangeListener { /** The model that holds time series data. */ private TimeSeriesModel model; /** This JLabel shows the maximum value of the graph. */ private JLabel maximum; /** This is the maximum value of the graph. */ private int maxValue; /** This JLabel shows the last value of the graph. */ private JLabel current; /** This is the last value shown in the graph. */ private int curValue; /** Constructs graph with default model. */ public TimeSeriesGraph() { setPreferredSize(new Dimension(40,40)); setOpaque(true); setModel(new TimeSeriesModel()); maximum=new JLabel("00"); add(maximum); maximum.setBackground(null); maximum.setOpaque(true); current=new JLabel("00"); add(current); current.setBackground(null); current.setOpaque(true); } /** Sets a new model. */ public void setModel(TimeSeriesModel seriesModel) { if (seriesModel==null) throw new RuntimeException("TimeSeriesModel must not be null"); TimeSeriesModel oldModel = getModel(); if (oldModel != null) { oldModel.removeChangeListener(this); } model=seriesModel; model.addChangeListener(this); } /** Returns current model. */ public TimeSeriesModel getModel() { return model; } /** Used for notification of a model data change. Internal function, not to be called by end users. */ public void stateChanged(ChangeEvent e) { repaint(); } /** Revalidates Label position. Called in case of size change, border change or label text change. */ private void revalidateLabel() { Insets insets = getInsets(); int mw=getWidth() - insets.left - insets.right; int mh=getHeight() - insets.top - insets.bottom; // maximum Dimension size=maximum.getPreferredSize(); int w=size.width; int h=size.height; if (w>mw) w=mw; if (h>mh) h=mh; maximum.setBounds(insets.left, insets.top, w, h); // current size=current.getPreferredSize(); w=size.width; h=size.height; if (w>mw) w=mw; if (h>mh) h=mh; current.setBounds(getWidth()-insets.right-w, insets.top, w, h); } /* Provides hook for revalidateLabel. */ public void revalidate() { revalidateLabel(); super.revalidate(); } /* Provides hook for revalidateLabel. */ public void setBounds(int x, int y, int width, int height) { Rectangle old=getBounds(); super.setBounds(x, y, width, height); if (! getBounds().equals(old)) revalidateLabel(); } /** Paints a bar graph. */ protected void paintComponent(Graphics g) { // draw background (component is always opaque) super.paintComponent(g); g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); // compute usable area Insets insets = getInsets(); int currentWidth = getWidth() - insets.left - insets.right; int currentHeight = getHeight() - insets.top - insets.bottom; currentHeight -= current.getHeight(); int top=insets.top; int left=insets.left; // draw horizontal line g.setColor(getForeground()); int y1=insets.top + current.getHeight(); g.drawLine(insets.left, y1, currentWidth, y1); // retrieve data int[] data=model.getData(); // find largest value int max=1; for (int i=0; i<data.length; i++) { if (data[i] > max) max=data[i]; if (data[i] < 0) throw new RuntimeException("Illegal value in TimeSeriesModel"); } max=fineScale(max); if (maxValue != max) { maxValue=max; maximum.setText(String.valueOf(max)); revalidateLabel(); } int last=data[data.length-1]; if (curValue != last) { curValue=last; current.setText(String.valueOf(last)); revalidateLabel(); } final int sCnt=data.length; if (sCnt==0) throw new RuntimeException( "Array has zero length in TimeSeriesModel."); // draw final int advance=(currentWidth+1) / sCnt; int columnW=advance-1; if (columnW<1) columnW=1; int columnH; int x=getWidth() - insets.right - sCnt*advance + 1; final int y=getHeight() - insets.bottom; for (int i=0; i<sCnt; i++) { columnH=data[i]*currentHeight/max; g.fillRect(x, y-columnH, columnW, columnH); x+=advance; } } /** Returns round number greater or equal to argument. */ private int fineScale (int x) { int d=1; int i=x; while (i>=10) { i/=10; d*=10; } return (x+d-1)/d*d; } } --- NEW FILE: TimeSeriesModel.java --- package net.sourceforge.javaprofiler.module.views; import javax.swing.event.EventListenerList; import javax.swing.event.ChangeListener; import javax.swing.event.ChangeEvent; /** Holds data of a time series. Data are stored in an <code>int</code> array. * @author Lukas Petru */ public class TimeSeriesModel { /** Holds time series values. */ private int[] data; private transient ChangeEvent changeEvent = null; private EventListenerList listenerList = new EventListenerList(); public TimeSeriesModel() { // test data data=new int[20]; for (int i=0; i<10; i++) data[i]=i; for (int i=10; i<20; i++) data[i]=20-i; } /** Sets new time series values. */ public void setData(int[] series) { if (series==null) throw new IllegalArgumentException("null"); data=series; fireStateChanged(); } /** Returns current time series values. You must not modify the returned value. Returned value is not null. */ public int[] getData() { return data; } /** Returns a copy of time series values. You can freely modify returned value. */ public int[] copyData() { int[] r=new int[data.length]; System.arraycopy(data, 0, r, 0, data.length); return r; } // event firing /** * Adds a <code>ChangeListener</code> to the TimeSeriesModel. * * @param l the listener to add */ public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); } /** * Removes a <code>ChangeListener</code> from the TimeSeriesModel. * * @param l the listener to remove */ public void removeChangeListener(ChangeListener l) { listenerList.remove(ChangeListener.class, l); } /** * Returns an array of all the change listeners * registered on this <code>TimeSeriesModel</code>. * * @return all of this model's <code>ChangeListener</code>s * or an empty * array if no change listeners are currently registered */ public ChangeListener[] getChangeListeners() { return (ChangeListener[])listenerList.getListeners( ChangeListener.class); } /** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is created lazily. * * @see EventListenerList */ protected void fireStateChanged() { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==ChangeListener.class) { // Lazily create the event: if (changeEvent == null) changeEvent = new ChangeEvent(this); ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); } } } } |