001: package tide.threadanalysis;
002:
003: import snow.utils.gui.*;
004: import java.awt.FlowLayout;
005: import java.awt.event.*;
006: import java.awt.EventQueue;
007: import java.awt.Color;
008: import java.awt.Dimension;
009: import java.util.*;
010: import java.awt.BorderLayout;
011: import java.awt.Graphics2D;
012: import java.awt.Graphics;
013: import javax.swing.*;
014:
015: public final class SequencerViewer extends JPanel {
016: final ThreadSequencer seq;
017: final TimePanel timePanel;
018:
019: // nanos
020: private long viewTime1 = 0, viewTime2 = -1; // -1 => all
021:
022: JButton play = new JButton(new Icons.StartIcon(14, 14, true));
023: JButton stop = new JButton(new Icons.StopIcon(14, 14, true));
024: JButton pause = new JButton(new Icons.PauseIcon(14, 14, true));
025: JLabel state = new JLabel("running...");
026:
027: private final JTextPane detailsPane = new JTextPane();
028:
029: public SequencerViewer(final ThreadSequencer seq) {
030: super (new BorderLayout());
031: this .seq = seq;
032: timePanel = new TimePanel();
033: add(new JScrollPane(timePanel), BorderLayout.CENTER);
034:
035: JPanel cp = new JPanel(new BorderLayout());
036: JPanel bpc = new JPanel();
037: bpc.setLayout(new BoxLayout(bpc, BoxLayout.Y_AXIS));
038: cp.add(bpc, BorderLayout.NORTH);
039:
040: JPanel bp = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
041:
042: bpc.add(bp);
043: bpc.add(state);
044:
045: bp.add(play);
046: play.addActionListener(new ActionListener() {
047: public void actionPerformed(ActionEvent ae) {
048: seq.resumeSequencer();
049: pause.setEnabled(true);
050: state.setText("running...");
051: }
052: });
053: play.setEnabled(false);
054:
055: bp.add(pause);
056: pause.addActionListener(new ActionListener() {
057: public void actionPerformed(ActionEvent ae) {
058: seq.pauseSequencer();
059: play.setEnabled(true);
060: state.setText("paused...");
061: }
062: });
063:
064: bp.add(stop);
065: stop.addActionListener(new ActionListener() {
066: public void actionPerformed(ActionEvent ae) {
067: seq.stopSequencer();
068: play.setEnabled(false);
069: pause.setEnabled(false);
070: stop.setEnabled(false);
071: state.setText("stopped");
072: }
073: });
074:
075: add(cp, BorderLayout.WEST);
076:
077: add(new JScrollPane(detailsPane), BorderLayout.SOUTH);
078: }
079:
080: public static void view(ThreadSequencer seq) {
081: SequencerViewer sv = new SequencerViewer(seq);
082: JFrame f = new JFrame("Thread Sequencer Viewer");
083: f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
084: f.add(sv, BorderLayout.CENTER);
085: f.setSize(600, 500);
086: f.setVisible(true);
087: }
088:
089: class TimePanel extends JPanel {
090: int n = 0;
091: int dh = 30; // height for a thread
092:
093: public TimePanel() {
094: }
095:
096: @Override
097: public void paintComponent(Graphics g) {
098: // background
099: super .paintComponents(g);
100:
101: int w = this .getWidth();
102: int h = this .getHeight();
103: if (w == 0 || h == 0)
104: return;
105:
106: long t1 = viewTime1;
107: long t2 = viewTime2 > 0 ? viewTime2 : seq.getTEnd()
108: - seq.getT0();
109:
110: final Map<Thread, ThreadHistory> href = seq
111: .getHistoriesREF();
112: if (href.size() == 0)
113: return;
114:
115: if (n != href.size()) {
116: // adapt height (causes also vertical scrollbar to resize)
117: n = href.size();
118: EventQueue.invokeLater(new Runnable() {
119: public void run() {
120: setPreferredSize(new Dimension(getWidth(), n
121: * dh));
122: }
123: });
124:
125: }
126:
127: final List<Thread> lt = new ArrayList<Thread>(href.keySet());
128: Collections.sort(lt, new Comparator<Thread>() {
129: public int compare(Thread t1, Thread t2) {
130: return t1.getName().compareTo(t2.getName());
131: }
132: });
133:
134: //double dh = h/n;
135:
136: for (int i = 0; i < lt.size(); i++) {
137: Thread ti = lt.get(i);
138: final ThreadHistory ths = href.get(ti);
139: final List<StackItem> hist = ths.getHist();
140:
141: //System.out.println("" + ti.getName());
142: int posy = dh / 2 + dh * i;
143: g.setColor(Color.darkGray);
144: g.drawString("" + (i + 1) + ": " + ti.getName() + " ("
145: + hist.size() + ")", 0, posy - 2);
146: g.drawRect(0, posy, w, dh / 2);
147:
148: for (int j = 0; j < hist.size(); j++) {
149: final StackItem si = hist.get(j);
150:
151: switch (si.getState()) {
152: case RUNNABLE:
153: g.setColor(Color.green);
154: break;
155: case WAITING:
156: g.setColor(Color.darkGray);
157: break;
158: case TIMED_WAITING:
159: g.setColor(Color.lightGray);
160: break;
161: default: // New, Blocked, Terminated
162: g.setColor(Color.red);
163: break;
164: }
165:
166: long ts = si.getCreated();
167: long te = si.getEnd();
168: if (ts - te == 0) {
169: if (j + 1 < hist.size()) {
170: final StackItem sip1 = hist.get(j + 1);
171: te = sip1.getCreated();
172: }
173:
174: }
175:
176: int ps = (int) (w * (ts - t1) / (t2 - t1));
177: int pe = (int) (w * (te - t1) / (t2 - t1));
178:
179: // give at least a pixel !
180: if (ps == pe)
181: pe = ps + 1;
182:
183: g.fillRect(ps, posy, pe - ps, dh / 2);
184:
185: }
186:
187: }
188: //
189:
190: }
191: }
192:
193: // TEST
194: public static void main(String[] args) throws Exception {
195: ThreadSequencer.main(args);
196: }
197:
198: }
|