Project

General

Profile

Revision 407

Added by Greg Tress over 16 years ago

cleaned up old files; fixed thread bug when connecting to colonet server

View differences:

trunk/code/projects/colonet/ColonetGUI/index_simple.html
1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3

  
4
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
5
<head>
6
	<title>Colony Control Applet - Carnegie Mellon Robotics Club</title>
7
	<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
8
	<link rel="stylesheet" type="text/css" href="colonetstyle.css" />
9
</head>
10

  
11
<body>
12

  
13
<div class="top">
14
	<h1>Colonet</h1>
15
	<p>Carnegie Mellon Robotics Club: Colony Project</p>
16
	<img src="http://roboclub8.frc.ri.cmu.edu/mainwiki/roboclublogo.png" height="125px" width="110px" />
17
</div>
18

  
19
<div class="app">
20
	<p>
21
	<object
22
		classid = "java:SimpleColonet.class"
23
		type = "application/x-java-applet"
24
		width = "900"
25
		height = "600"
26
		align = "bottom"
27
		codebase = "http://roboclub1.frc.ri.cmu.edu/gui/" 
28
		name = "SimpleColonet"
29
		title = "SimpleColonet" >
30
		<param name = "code" value = "SimpleColonet.class" />
31
	</object>
32
	<br />
33
	</p>
34
</div>
35

  
36
<div class="bottom">
37
	<p><b>Colony Project Home page:</b><br />
38
	<a href="http://www.robotcolony.org/">www.robotcolony.org</a></p>
39
	
40
	<p><b>Colonet Developers:</b><br />
41
	Gregory Tress, Eugene Edward Marinelli III, Jason Knichel, Suresh Nidhiry</p>
42
	
43
	<p><b>Validator:</b><br />
44
	<a href="http://validator.w3.org/check?uri=referer">
45
	<img src="http://www.w3.org/Icons/valid-xhtml10-blue"
46
		 alt="Valid XHTML 1.0 Transitional"
47
		 height="31"
48
		 width="88" 
49
		 border="0"
50
		 />
51
	</a>
52
	<a href="http://jigsaw.w3.org/css-validator/validator?uri=http://roboclub1.frc.ri.cmu.edu/ColonetGUI/colonetstyle.css">
53
  	<img style="border:0;width:88px;height:31px"
54
       src="http://www.w3.org/Icons/valid-css-blue" 
55
       alt="Valid CSS!" />
56
	</a><br />
57
	</p>
58
	
59
</div>
60

  
61

  
62

  
63
</body>
64
</html>
trunk/code/projects/colonet/ColonetGUI/BotGraph.java
1
/* 
2
	BotGraph.java
3
	Colony Project
4
	Gregory Tress 
5
*/
6

  
7
import javax.swing.*;
8
import java.awt.*;
9
import java.awt.image.*;
10
import java.awt.event.*;
11
import java.net.*;
12
import java.io.*;
13
import java.util.Random;
14

  
15
public class BotGraph extends JApplet implements ActionListener, MouseListener, Runnable
16
{
17

  
18
	final int CANVAS_SIZE = 550;  //don't make this too large, or the applet will be slow.
19
	final int BUFFER = 50;
20
	final int RADIUS = 30;
21

  
22
	JTextField txtHost;				
23
	JTextField txtPort;				
24
	JButton btnConnect;	
25
	JButton btnGraph;
26
	JButton btnRandomize;
27
	JLabel lblNumRobots;
28
	JLabel lblHasToken;
29
	JLabel lblTokenPasses;
30
	JLabel lblConnectionStatus;
31
	JTextArea txtInput;  //sample matrix is entered in this area
32
	JTextArea txtInfo; 
33
	JPanel panel;
34
	JPanel panelConnect;
35
	JPanel panelControl;
36
	JPanel panelStats;
37
	
38
	GraphicsConfiguration gc;
39
	volatile BufferedImage image;
40
	volatile Graphics2D canvas;
41
	int cx, cy;
42
	
43
	Socket socket;					
44
	OutputStreamWriter out;			//TODO: add a BufferedWriter
45
	DataListener datalistener;  
46
	
47
	Font botFont;
48
	Random random = new Random();
49
	volatile int tokenLoc;  //the token is currently here
50
	volatile int numBots;
51
	volatile int selectedBot;  //the user has selected this bot
52
	volatile Rectangle[] botRect;  //contains boundary shapes around bots for click detection
53
	
54
	Thread drawThread;
55
	SelectionIndicator indicator;
56
	Simulator simulator;
57
	PacketMonitor packetMonitor;
58
	
59
	public void init ()
60
	{
61
		// We should invoke and wait to avoid browser display difficulties
62
		Runnable r = new Runnable() {
63
			public void run() {
64
				createAndShowGUI();
65
			}
66
		};
67
		try {
68
			SwingUtilities.invokeAndWait(r);
69
		} catch (InterruptedException e) {
70
			//Not really sure why we would be in this situation
71
			System.out.println(e);
72
		} catch (java.lang.reflect.InvocationTargetException e) {
73
			//This should never happen. Seriously.
74
			System.out.println(e);
75
		}
76
	}
77
	
78
	public void destroy ()
79
	{
80
		drawThread.interrupt();
81
		indicator.interrupt();
82
		simulator.interrupt();
83
		packetMonitor.interrupt();
84
	}
85

  
86
	private synchronized void createAndShowGUI ()
87
	{
88
		// init graphical elements
89
		panel = new JPanel(false);  //set automatic double-buffering to false. we are doing it manually.
90
		
91
		// Set up connection area
92
		txtHost = new JTextField("roboclub1.frc.ri.cmu.edu");
93
		txtPort = new JTextField("10123");
94
		btnConnect = new JButton("Connect");
95
		lblConnectionStatus = new JLabel("Status: Offline");
96
		panelConnect = new JPanel();
97
		panelConnect.setLayout(new GridLayout(2,3));
98
		panelConnect.add(new JLabel("Host"));
99
		panelConnect.add(new JLabel("Port"));
100
		panelConnect.add(lblConnectionStatus);
101
		panelConnect.add(txtHost);
102
		panelConnect.add(txtPort);
103
		panelConnect.add(btnConnect);
104
		panelConnect.setBorder(BorderFactory.createTitledBorder("Connection"));
105
		
106
		// Set up elements in the east
107
		panelControl = new JPanel();
108
		panelControl.setLayout(new GridLayout(5,1));
109
		lblNumRobots = new JLabel();
110
		lblHasToken = new JLabel();
111
		lblTokenPasses = new JLabel();
112
		panelStats = new JPanel();
113
		panelStats.setLayout(new GridLayout(3,2));
114
		panelStats.add(new JLabel("Number of Bots  "));
115
		panelStats.add(lblNumRobots);
116
		panelStats.add(new JLabel("Token At  "));
117
		panelStats.add(lblHasToken);
118
		panelStats.add(new JLabel("Token Passes / sec     "));
119
		panelStats.add(lblTokenPasses);
120
		txtInput = new JTextArea("- 9 3 - 1\n- - - 5 -\n4 - - - 2\n- - - - -\n1 - - 3 -");
121
		txtInput.setBorder(BorderFactory.createTitledBorder("Input Matrix"));
122
		txtInfo = new JTextArea();
123
		txtInfo.setBorder(BorderFactory.createTitledBorder("Info"));
124
		txtInfo.setEditable(false);
125
		btnGraph = new JButton("Run");
126
		btnRandomize = new JButton("Randomize");
127
		panelControl.add(panelStats);
128
		panelControl.add(txtInput);
129
		panelControl.add(txtInfo);
130
		panelControl.add(btnRandomize);
131
		panelControl.add(btnGraph);
132
		
133
		
134
		this.getContentPane().setLayout(new BorderLayout());
135
		this.getContentPane().add(panelConnect, BorderLayout.NORTH);
136
		this.getContentPane().add(panelControl, BorderLayout.EAST);
137
		this.getContentPane().add(panel, BorderLayout.CENTER);
138
		this.setVisible(true);
139
		
140
		btnGraph.addActionListener(this);
141
		btnRandomize.addActionListener(this);
142
		btnConnect.addActionListener(this);
143
		panel.addMouseListener(this);
144
		
145
		
146
		// Get the graphics configuration of the screen to create a buffer
147
		gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
148
			.getDefaultScreenDevice().getDefaultConfiguration();
149
		image = gc.createCompatibleImage(CANVAS_SIZE,CANVAS_SIZE);
150
		canvas = image.createGraphics();
151
		canvas.setStroke(new BasicStroke(2));  //set pen width
152
		
153
		// Calculate center of canvas
154
		cx = image.getWidth() / 2;
155
		cy = image.getHeight() / 2;
156
		
157
		botFont = new Font("Arial", Font.PLAIN, 30);
158
		tokenLoc = 0;
159
		numBots = 0;
160
		selectedBot = 0;
161
		
162
		// Set up dependent threads
163
		indicator = new SelectionIndicator(canvas);
164
		indicator.setRadius(RADIUS+3, 15);  //a tad more than the bot radius
165
		simulator = new Simulator();
166
		packetMonitor = new PacketMonitor();
167
		datalistener = new DataListener();
168
	
169
	}
170
	
171
	public synchronized void paint (Graphics g)
172
	{
173
		/*	First, redraw the graphical components in the applet. 
174
			This paint method overrides the built-in paint of the 
175
			JApplet, and we don't want to deal with redrawing the
176
			components manually. Fuck that shit. */
177
		super.paint(g);
178
		
179
		// Place the buffered image on the screen, inside the panel
180
		panel.getGraphics().drawImage(image, 0, 0, Color.WHITE, this);
181
		
182
	}
183
	
184
	public synchronized void update (Graphics g)
185
	{
186
		paint(g);
187
	}
188
	
189
	public void actionPerformed (ActionEvent e)
190
	{
191
		Object source = e.getSource();
192
		if (source == btnGraph)
193
		{
194
			btnGraph.setEnabled(false);
195
			lblConnectionStatus.setText("Status: Simulation mode => running");
196
			
197
			//Start dependent threads
198
			drawThread = new Thread(this, "drawThread");
199
			drawThread.start();
200
			indicator.start();
201
			simulator.start();
202
			packetMonitor.start();
203
		}
204
		else if (source == btnConnect)
205
		{
206
			doSocket();
207
		}
208
		else if (source == btnRandomize)
209
		{
210
			randomize();
211
		}
212
	}
213
	
214
	private void randomize ()
215
	{
216
		Random r = new Random();
217
		StringBuilder s = new StringBuilder();
218
		
219
		int count = r.nextInt(8) + 1;
220
		for (int i = 0; i < count; i++)
221
		{
222
			for (int j = 0; j < count; j++)
223
			{
224
				if (r.nextBoolean())	
225
					s.append("" + (r.nextInt(16) + 1));
226
				else 
227
					s.append("-");
228
				if (j != count-1)
229
					s.append(" ");
230
			}
231
			if (i != count-1) s.append("\n");
232
		}
233
		
234
		txtInput.setText(s.toString());
235
	}
236
	
237
	private void doSocket ()
238
	{
239
		//make sure hostname and port are valid
240
		if (txtHost.getText().equals("") || txtPort.getText().equals("")) {
241
			err("Please enter a hostname and port.");
242
			return;
243
		}
244
		int port = 0;
245
		try {
246
			port = Integer.parseInt(txtPort.getText());
247
		} catch (Exception e) {
248
			err("Invalid port");
249
			return;
250
		}
251
		
252
		//make sure we aren't already connected. if so, disconnect first.
253
		if (socket != null && socket.isConnected()) {
254
			try {
255
				out.close();
256
				socket.close();
257
			} catch (IOException e) {}
258
		}
259
		
260
		try {
261
			socket = new Socket(txtHost.getText(), port);
262
		} catch (UnknownHostException e) {
263
			err("Unknown Host Exception");
264
			return;
265
		} catch (IOException e) {
266
			err("IO Exception\n\n" + e);
267
			return;
268
		} catch (java.security.AccessControlException e) {
269
			err("Permission denied by java.security.AccessControlException.\n\nYou may only connect to the server from which this applet was loaded.");
270
			return;
271
		}
272
		if (socket == null || !socket.isConnected()) {
273
			err("Connection failed. Try connecting again.");
274
			return;
275
		}
276
		msg("Connected to " + txtHost.getText() + " on port " + port + "\n");
277
		lblConnectionStatus.setText("Status: ONLINE");
278
		try {
279
			out = new OutputStreamWriter(socket.getOutputStream());
280
		} catch (IOException e) {
281
			warn("Could not get OutputStream from socket connection.");
282
		}
283
	
284
	}
285
	
286
	public void drawRobot (int id, int x, int y) 
287
	{
288
		//save the bot in memory, so we can tell if we click on it later
289
		botRect[id] = new Rectangle(x-RADIUS, y-RADIUS, 2*RADIUS, 2*RADIUS);
290
	
291
		//draw the bot on the canvas
292
		canvas.setColor(Color.BLACK);
293
		canvas.drawOval(x-RADIUS, y-RADIUS, RADIUS*2, RADIUS*2);
294
		
295
		//draw the label
296
		canvas.setFont(botFont);
297
		canvas.drawString("" + id, x-10, y+10);
298
	}
299
	
300
	public void drawConnection (int start, int end, int radius, Color color)
301
	{
302
		final int ARROW_LENGTH = 18;
303
	
304
		double angle = 2.0 * Math.PI / numBots;
305
		int startx, starty, endx, endy;
306
		startx = cx - (int)(radius * Math.cos(start * angle));
307
		starty = cy - (int)(radius * Math.sin(start * angle));
308
		endx = cx - (int)(radius * Math.cos(end * angle));
309
		endy = cy - (int)(radius * Math.sin(end * angle));
310
		canvas.setColor(color);
311
		canvas.drawLine(startx, starty, endx, endy);
312
		
313
		//create arrow
314
		if (color.equals(Color.BLACK)) return;
315
		int big_dy = starty - endy;
316
		int big_dx = endx - startx;
317
		double theta = 0;
318
		if (big_dx == 0 && starty > endy) //pointing up
319
			theta = Math.PI/2;
320
		else if (big_dx == 0 && starty < endy) //pointing down 
321
			theta = 3*Math.PI/2;
322
		else if (big_dy == 0 && startx > endx) //pointing left
323
			theta = Math.PI;
324
		else if (big_dy == 0 && startx < endx) //pointing right
325
			theta = 0;
326
		else
327
			theta = Math.atan(1.0 * big_dy / big_dx);
328
		
329
		//create ploygon
330
		Polygon poly = new Polygon();
331
		int dx_arrow = Math.abs((int)(ARROW_LENGTH * Math.cos(theta)));
332
		int dy_arrow = Math.abs((int)(ARROW_LENGTH * Math.sin(theta)));
333
		int dy_half = (int)(ARROW_LENGTH/2 * Math.cos(theta));
334
		int dx_half = (int)(ARROW_LENGTH/2 * Math.sin(theta));
335
		int rx = (big_dx > 0) ? endx - dx_arrow : endx + dx_arrow;
336
		int ry = (big_dy > 0) ? endy + dy_arrow : endy - dy_arrow;
337
		//System.out.println("" + start + "->" + end + " : dx=" + big_dx + ",dy=" + big_dy + ",dy_arrow=" + dy_arrow + ",dx_arrow=" + dx_arrow + ",theta=" + theta + ",endx=" + endx + ",endy=" + endy + ",rx=" + rx + ",ry=" + ry);
338
		poly.addPoint(endx, endy);
339
		poly.addPoint(rx - dx_half, ry - dy_half);
340
		poly.addPoint(rx + dx_half, ry + dy_half);
341
		canvas.fillPolygon(poly);
342
	}
343
	
344
	public void run ()
345
	{
346
		while (true)
347
		{
348
			step();
349
			repaint();
350
			try { Thread.sleep(90); }
351
				catch (InterruptedException e) { return; }
352
		}
353
	}
354
	
355
	public void step () 
356
	{
357
		final int DIAMETER = image.getWidth() - 2*BUFFER;
358
		final int BIGRADIUS = DIAMETER / 2;
359
		final int TOKENRADIUS = 40;
360
		boolean valid;
361
	
362
		// clear image
363
		canvas.setColor(Color.WHITE);
364
		canvas.fillRect(0, 0, image.getWidth(), image.getHeight());
365
		
366
		// parse the matrix, to see what robots exist
367
		String [] rows = txtInput.getText().split("\n");
368
		numBots = rows.length;
369
		String [][] entries = new String[numBots][numBots];
370
		valid = true;
371
		for (int i = 0; i < numBots; i++) 
372
		{
373
			entries[i] = rows[i].split(" ");
374
			if (entries[i].length != rows.length) valid = false;
375
		}
376
		
377
		if (valid)
378
		{
379
			lblNumRobots.setText("" + numBots);
380
			lblHasToken.setText("" + tokenLoc);
381
			this.showStatus("Matrix OK");
382
			
383
			// draw outer ring
384
			//canvas.setColor(Color.GREEN);
385
			//canvas.drawOval(BUFFER, BUFFER, DIAMETER, DIAMETER);
386
			
387
			// draw robots and find which one is seleced
388
			double angle = 2.0 * Math.PI / numBots;
389
			canvas.setColor(Color.BLACK);
390
			botRect = new Rectangle[numBots];
391
			int x, y;
392
			if (selectedBot >= numBots) selectedBot = 0;
393
			for (int i = 0; i < numBots; i++)
394
			{
395
				x = cx - (int)(BIGRADIUS * Math.cos(i * angle));
396
				y = cy - (int)(BIGRADIUS * Math.sin(i * angle));
397
				drawRobot(i, x, y);
398
				if (i == selectedBot) indicator.setCenter(x, y);
399
			}
400
			
401
			// draw token marker
402
			int tokenx, tokeny;
403
			int tokenNum = tokenLoc;
404
			tokenx = cx - (int)(BIGRADIUS * Math.cos(tokenNum * angle));
405
			tokeny = cy - (int)(BIGRADIUS * Math.sin(tokenNum * angle));
406
			canvas.setColor(Color.RED);
407
			canvas.drawOval(tokenx-TOKENRADIUS, tokeny-TOKENRADIUS, 2*TOKENRADIUS, 2*TOKENRADIUS);
408
			
409
			// create an inner circle along which the connections are made.
410
			// let the diameter of this circle be 2*RADIUS less than the outerDiameter.
411
			// see what connections exist
412
			for (int row = 0; row < numBots; row++)
413
			{
414
				for(int col = 0; col < numBots; col++)
415
				{
416
					if (! entries[row][col].equals("-") && entries[col][row].equals("-") && row != col) //one-way
417
					{
418
						//drawConnection(row, col, BIGRADIUS-RADIUS, Color.GRAY);
419
						drawConnection(row, col, BIGRADIUS-RADIUS, new Color(200,200,200));
420
					}
421
					else if (! entries[row][col].equals("-") && ! entries[col][row].equals("-") && row != col) //two-way
422
					{
423
						drawConnection(row, col, BIGRADIUS-RADIUS, Color.BLACK);
424
					}
425
				}
426
			}
427
			
428
			// draw the selection indicator
429
			indicator.draw();
430
			txtInfo.setText("Bot " + selectedBot + " is selected.\n");
431
			txtInfo.append("Battery: ???\n");
432
			txtInfo.append("Packet statistics: ???");
433
			
434
		}
435
		else // if matrix is not valid
436
		{
437
			this.showStatus("Error: Invalid matrix");
438
		}
439
	
440
	}
441
	
442
	/*	At this point, moveToken is only called by the simulator.
443
	*	In the future, it can be rewritten to account for non-standard
444
	*	token passing or deleted if the information can be retrieved
445
	*	directly from the Colonet server instead.
446
	*/
447
	public void moveToken ()
448
	{
449
		try { tokenLoc = (tokenLoc+1)%numBots; }
450
			catch (ArithmeticException e) { }  // in case numRobots is zero
451
		
452
		packetMonitor.addTokenPass();
453
	}
454
	
455
	//
456
	// MouseEvent methods
457
	//
458
	public void mouseExited(MouseEvent e) {}
459
	public void mouseEntered(MouseEvent e) {}
460
	public void mouseReleased(MouseEvent e) {}
461
	public void mouseClicked(MouseEvent e) {}
462
	public void mousePressed(MouseEvent e)
463
	{
464
		try {
465
			for (int i = 0; i < numBots; i++)
466
			{
467
				if (botRect[i].contains(e.getPoint()))
468
					selectedBot = i;
469
			}
470
		} catch (Exception ex) {
471
			System.out.println(e);
472
		}
473
	
474
	}
475
	
476
	private void msg (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.INFORMATION_MESSAGE);}
477
	private void warn (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.WARNING_MESSAGE);}
478
	private void err (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.ERROR_MESSAGE);}
479
	
480
	
481
	/*
482
	*	SelectionIndicator thread.
483
	*	Graphical representation of the selection marker
484
	*
485
	*	step() and draw() are synchronized methods. step() is private and 
486
	*	used to update the position of the crosshairs. draw() is called 
487
	*	externally and should only run if all calculations in step() have
488
	*	been completed.
489
	*/
490
	private class SelectionIndicator extends Thread
491
	{
492
	
493
		final int INDICATOR_DELAY = 100;
494
		final double DTHETA = 0.3;    //larger values make the marker rotate faster
495
		Graphics2D g;   //canvas to draw on
496
		boolean running;
497
		
498
		int sx, sy;		//center
499
		int r, dr;		//radius and width of marker
500
		double theta;   //current angle
501
		
502
		volatile Polygon poly1, poly2, poly3, poly4;
503
		
504
		int px1, py1;
505
		int rx1, ry1;
506
		int px2, py2;
507
		int rx2, ry2;
508
		int px3, py3;
509
		int rx3, ry3;
510
		int px4, py4;
511
		int rx4, ry4;
512
		
513
		int steps;
514
	
515
		public SelectionIndicator (Graphics2D g)
516
		{
517
			super("SelectionIndicator");
518
			this.g = g;
519
			running = false;
520
			steps = 0;
521
			
522
			theta = 0;
523
			rx1 = 0; ry1 = 0;
524
			px1 = 0; py1 = 0;
525
			rx2 = 0; ry2 = 0;
526
			px2 = 0; py2 = 0;
527
			rx3 = 0; ry3 = 0;
528
			px3 = 0; py3 = 0;
529
			rx4 = 0; ry4 = 0;
530
			px4 = 0; py4 = 0;
531
		}
532
		
533
		public synchronized void setCenter (int sx, int sy)
534
		{
535
			if (sx == this.sx && sy == this.sy) return;
536
			this.sx = sx;
537
			this.sy = sy;
538
			steps = 0;
539
		}
540
		
541
		public synchronized void setRadius (int r, int dr)
542
		{
543
			this.r = r;
544
			this.dr = dr;
545
			steps = 0;
546
		}
547
		
548
		public void run ()
549
		{
550
			running = true;
551
			while (running)
552
			{
553
				step();
554
				try { Thread.sleep(INDICATOR_DELAY); }
555
					catch (InterruptedException e) {  running = false; return; }
556
			}
557
		}
558
		
559
		private synchronized void step ()
560
		{
561
			Polygon poly1_new = new Polygon();
562
			Polygon poly2_new = new Polygon();
563
			Polygon poly3_new = new Polygon();
564
			Polygon poly4_new = new Polygon();
565
		
566
			//the step
567
			theta = (theta + DTHETA/Math.PI) % (Math.PI);
568
			
569
			//the calculation
570
			//let p be the point of the pointy thing toward the center
571
			//let r be the point at the opposite side
572
			
573
			//recalculate radius, if it will look cool, lolz
574
			int newr = r;
575
			if (steps < 100) newr = (int)( r + 200/(steps+1) );
576
			
577
			//precompute values for dx and dy
578
			int dx_inner = (int)(newr * Math.cos(theta));
579
			int dy_inner = (int)(newr * Math.sin(theta));
580
			int dx_outer = (int)((newr+dr) * Math.cos(theta));
581
			int dy_outer = (int)((newr+dr) * Math.sin(theta));
582
			
583
			//calculate polygon constants
584
			int dy_poly = (int)(dr/2 * Math.cos(theta));
585
			int dx_poly = (int)(dr/2 * Math.sin(theta));
586
			
587
			//determine critical points
588
			px1 = sx + dx_inner;
589
			py1 = sy - dy_inner;
590
			rx1 = sx + dx_outer;
591
			ry1 = sy - dy_outer;
592
			px2 = sx - dx_inner;
593
			py2 = sy + dy_inner;
594
			rx2 = sx - dx_outer;
595
			ry2 = sy + dy_outer;
596
			px3 = sx - dy_inner;
597
			py3 = sy - dx_inner;
598
			rx3 = sx - dy_outer;
599
			ry3 = sy - dx_outer;
600
			px4 = sx + dy_inner;
601
			py4 = sy + dx_inner;
602
			rx4 = sx + dy_outer;
603
			ry4 = sy + dx_outer;
604
			
605
			//create polygons
606
			poly1_new.addPoint(px1, py1);
607
			poly1_new.addPoint(rx1+dx_poly, ry1+dy_poly);
608
			poly1_new.addPoint(rx1-dx_poly, ry1-dy_poly);
609
			poly2_new.addPoint(px2, py2);
610
			poly2_new.addPoint(rx2+dx_poly, ry2+dy_poly);
611
			poly2_new.addPoint(rx2-dx_poly, ry2-dy_poly);
612
			poly3_new.addPoint(px3, py3);
613
			poly3_new.addPoint(rx3-dy_poly, ry3+dx_poly);
614
			poly3_new.addPoint(rx3+dy_poly, ry3-dx_poly);
615
			poly4_new.addPoint(px4, py4);
616
			poly4_new.addPoint(rx4-dy_poly, ry4+dx_poly);
617
			poly4_new.addPoint(rx4+dy_poly, ry4-dx_poly);
618
			
619
			//reassign updated polygons
620
			poly1 = poly1_new;
621
			poly2 = poly2_new;
622
			poly3 = poly3_new;
623
			poly4 = poly4_new;
624
		
625
			if (steps < 300) steps++;
626
		}
627
		
628
		public synchronized void draw ()
629
		{
630
			if (!running) return;
631
			g.setColor(Color.GRAY);
632
			//draw polygons
633
			g.fillPolygon(poly1);
634
			g.fillPolygon(poly2);
635
			g.fillPolygon(poly3);
636
			g.fillPolygon(poly4);
637
		}
638
	
639
	
640
	}
641
	
642
	/*
643
	*	Simulator thread.
644
	*
645
	*/
646
	private class Simulator extends Thread
647
	{
648
		final int SIMULATOR_DELAY = 300;
649
	
650
		boolean running;
651
	
652
		public Simulator ()
653
		{
654
			super("Simulator");
655
			running = false;
656
		}
657
		
658
		public void run ()
659
		{
660
			running = true;
661
			while (running)
662
			{
663
				step();
664
				try { Thread.sleep(SIMULATOR_DELAY); }
665
					catch (InterruptedException e) { running = false; return; }
666
			}
667
		}
668
		
669
		private void step ()
670
		{
671
			// simulate passing the token
672
			moveToken();
673
		
674
		}
675
	
676
	}
677
	
678
	/*
679
	*	PacketMonitor thread.
680
	*
681
	*	Currently, this counts the rate of token passes but will eventually 
682
	*	be modified to keep more important statistics.
683
	*/
684
	private class PacketMonitor extends Thread
685
	{
686
		final int PACKETMONITOR_DELAY = 1000;
687
	
688
		boolean running;
689
		int tokenPasses;
690
	
691
		public PacketMonitor ()
692
		{
693
			super("PacketMonitor");
694
			running = false;
695
			tokenPasses = 0;
696
		}
697
		
698
		public void run ()
699
		{
700
			running = true;
701
			while (running)
702
			{
703
				displayTokenPasses();
704
				try { Thread.sleep(PACKETMONITOR_DELAY); }
705
					catch (InterruptedException e) { running = false; return; }
706
			}
707
		}
708
		
709
		public synchronized void addTokenPass ()
710
		{
711
			tokenPasses++;
712
		}
713
		
714
		public synchronized void displayTokenPasses ()
715
		{
716
			lblTokenPasses.setText("" + tokenPasses);
717
			tokenPasses = 0;
718
		}
719
	
720
	}
721
	
722
	/*
723
	*	DataListener thread.
724
	*
725
	*/
726
	class DataListener extends Thread
727
	{
728
		final int DATALISTENER_DELAY = 1000;
729
		BufferedReader reader;
730
		
731
		public DataListener ()
732
		{
733
			super("Colonet DataListener");
734
		}
735
		
736
		public void run ()
737
		{
738
			String line;
739
			try {
740
				reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
741
			} catch (IOException e) {
742
				warn("Could not open input stream from socket.\nTry relooding the applet.");
743
			}
744
			while (true)
745
			{
746
				try {
747
					if (reader.ready())
748
					{
749
						line = reader.readLine();
750
						if (line != null)
751
						{
752
							msg("Incoming data: [" + line + "]");
753
						}
754
					}
755
					Thread.sleep(DATALISTENER_DELAY);
756
				} catch (InterruptedException e) {
757
					return;
758
				} catch (IOException e) {
759
					warn("IOException while reading incoming data.");
760
				}
761
			}
762
		}
763

  
764
	}
765

  
766
	
767
	/*
768
	*	Matrix class
769
	*	holds current sensor matrix data
770
	*/
771
	
772
	/*
773
	private class Matrix
774
	{
775
		int [][] grid;
776
	
777
		public Matrix ()
778
		{
779
			grid = new int[1][1];
780
		}
781
		
782
		public String toString ()
783
		{
784
			StringBuilder s = new StringBuilder();
785
			for (int j = 0; j < grid.length; j++)
786
			{
787
				for (int i = 0; i < grid[0].length; i++)
788
					s.append(grid[i][j]);
789
				if (j < grid.length-1) s.append("\n");
790
			}
791
			return s.toString();
792
		}
793
	
794
	}
795
	*/
796
	
797
	
798
	
799
}
800

  
trunk/code/projects/colonet/ColonetGUI/SimpleColonet.java
1

  
2
import java.awt.*;
3
import java.awt.event.*;
4
import java.applet.*;
5
import javax.swing.*;
6
import javax.swing.event.*;
7
import java.net.*;
8
import java.io.*;
9

  
10
/**
11
 *		Colonet: The Colony Control Applet.
12
 *		This applet provides a graphical control mechanism for the robot colony designed
13
 *		for web deployment.
14
 *
15
 *		@author Gregory Tress
16
 *		@version 0.1
17
 *
18
 */
19
public class SimpleColonet extends JApplet implements ActionListener, KeyListener, ChangeListener
20
{
21

  
22
	/*
23
	*   Graphical Applet Elements
24
	*/
25

  
26
	ColonetServerInterface csi;
27
	DataListener datalistener;      
28
	
29
	// panelTop contains stuff on top
30
	JPanel panelTop;				
31
	JPanel panelConnect;			
32
	JTextField txtHost;				
33
	JTextField txtPort;				
34
	JButton btnConnect;				
35
	
36
	// panelMove contains directional buttons for controlling the robot
37
	JPanel panelMove;
38
	JButton btnF, btnB, btnL, btnR, btnActivate;
39
	boolean isMoving;
40
	
41
	// panelCommands contains 
42
	JPanel panelCommands;
43
	JButton btnClearLog;
44
	JButton btnBuzzerOn;
45
	JButton btnBuzzerOff;
46
	JButton btnRequestBattery;
47
	JButton btnChangeOrbColor;
48
	JButton btnGetSensorData;
49
	JComboBox cmbRobotNumber;
50
	String robotNumber;
51
	
52
	JColorChooser chooser;
53
	JPanel panelChooser;
54
	
55
	JPanel panelBottom;
56
	JTextArea log;
57
	JScrollPane spLog;
58
	
59
	JPanel panelWebcam;
60
	WebcamLoader webcamLoader;
61
	boolean destroyed = false;
62
	
63
	/**
64
	 * Sets up user control elements.
65
	 * Specifies layout for all GUI elements,
66
	 * attaches all ActionListeners, KeyListeners, and ChangeListeners, and
67
	 * creates threads for loading webcam image and listening for incoming data.
68
	 *
69
	 */
70
	public void init () {
71
		Container content = getContentPane();
72
		content.setLayout(new GridLayout(2,1));
73
		
74
		txtHost = new JTextField();
75
		txtPort = new JTextField();
76
		btnConnect = new JButton("Connect");
77
		panelConnect = new JPanel();
78
		panelConnect.setLayout(new GridLayout(2,3));
79
		panelConnect.add(new JLabel("Host"));
80
		panelConnect.add(new JLabel("Port"));
81
		panelConnect.add(new JLabel(" "));
82
		panelConnect.add(txtHost);
83
		panelConnect.add(txtPort);
84
		panelConnect.add(btnConnect);
85
		panelConnect.setBorder(BorderFactory.createTitledBorder("Connection"));
86
		
87
		btnF = new JButton("Forward");
88
		btnB = new JButton("Back");
89
		btnL = new JButton("Left");
90
		btnR = new JButton("Right");
91
		btnActivate = new JButton("On/Stop");
92
		panelMove = new JPanel();
93
		panelMove.setLayout(new GridLayout(3,3));
94
		panelMove.add(new JLabel(""));
95
		panelMove.add(btnF);
96
		panelMove.add(new JLabel(""));
97
		panelMove.add(btnL);
98
		panelMove.add(btnActivate);
99
		panelMove.add(btnR);
100
		panelMove.add(new JLabel(""));
101
		panelMove.add(btnB);
102
		panelMove.add(new JLabel(""));
103
		panelMove.setBorder(BorderFactory.createTitledBorder("Movement Control"));
104
		
105
		btnClearLog = new JButton("Clear Log");
106
		btnBuzzerOn = new JButton("Buzzer On");
107
		btnBuzzerOff = new JButton("Buzzer Off");
108
		btnRequestBattery = new JButton("Request Battery");
109
		btnChangeOrbColor = new JButton("Change Orb Color");
110
		btnGetSensorData = new JButton("Get Sensor Data");
111
		String [] robotList = {"All   ", "0", "1", "2", "3", "4", "5"};
112
		cmbRobotNumber = new JComboBox(robotList);
113
		panelCommands = new JPanel();
114
		panelCommands.setLayout(new FlowLayout());
115
		panelCommands.add(btnBuzzerOn);
116
		panelCommands.add(btnBuzzerOff);
117
		panelCommands.add(btnClearLog);
118
		panelCommands.add(btnRequestBattery);
119
		//panelCommands.add(btnChangeOrbColor);
120
		panelCommands.add(btnGetSensorData);
121
		panelCommands.add(new JLabel("Robot # to control"));
122
		panelCommands.add(cmbRobotNumber);
123
		panelCommands.setBorder(BorderFactory.createTitledBorder("Commands"));
124
		
125
		chooser = new JColorChooser();
126
		chooser.setPreviewPanel(new JPanel());
127
		panelChooser = new JPanel();
128
		panelChooser.setLayout(new BorderLayout());
129
		panelChooser.add(chooser, BorderLayout.CENTER);
130
		panelChooser.setBorder(BorderFactory.createTitledBorder("Orb"));
131
		
132
		panelTop = new JPanel();
133
		panelTop.setLayout(new BorderLayout());
134
		panelTop.add(panelConnect, BorderLayout.NORTH);
135
		panelTop.add(panelMove, BorderLayout.WEST);
136
		panelTop.add(panelCommands, BorderLayout.CENTER);
137
		panelTop.add(panelChooser, BorderLayout.EAST);
138
		
139
		log = new JTextArea();
140
		spLog = new JScrollPane(log, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
141
		spLog.setBorder(BorderFactory.createTitledBorder("Log"));
142
		log.setEditable(false);
143
		
144
		panelWebcam = new JPanel();
145
		panelWebcam.setBorder(BorderFactory.createTitledBorder("Webcam"));
146
		
147
		panelBottom = new JPanel();
148
		panelBottom.setLayout(new GridLayout(1,2));
149
		panelBottom.add(spLog);
150
		panelBottom.add(panelWebcam);
151
		
152
		content.add(panelTop);
153
		content.add(panelBottom);
154
		
155
		txtHost.setText("roboclub1.frc.ri.cmu.edu");
156
		txtPort.setText("10123");
157
		isMoving = false;
158
		
159
		btnConnect.addActionListener(this);
160
		btnClearLog.addActionListener(this);
161
		btnBuzzerOn.addActionListener(this);
162
		btnBuzzerOff.addActionListener(this);
163
		btnRequestBattery.addActionListener(this);
164
		btnChangeOrbColor.addActionListener(this);
165
		btnGetSensorData.addActionListener(this);
166
		
167
		btnActivate.addActionListener(this);
168
		btnActivate.addKeyListener(this);
169
		btnF.addActionListener(this);
170
		btnF.addKeyListener(this);
171
		btnB.addActionListener(this);
172
		btnB.addKeyListener(this);
173
		btnL.addActionListener(this);
174
		btnL.addKeyListener(this);
175
		btnR.addActionListener(this);
176
		btnR.addKeyListener(this);
177
		
178
		chooser.getSelectionModel().addChangeListener(this);
179
		
180
		csi = new ColonetServerInterface(log);
181
		webcamLoader = new WebcamLoader(this);
182
		datalistener = new DataListener(log);
183
	}
184
	
185
	/**
186
	 * Attempt to shut down the applet cleanly. 
187
	 * Clean up leftover tasks when destroyed,
188
	 * i.e., browser window is closed or appletviewer is stopped. 
189
	 * This method attempts to pause the destruction of the applet for 1000ms.
190
	 * If successful, other threads will have the chance to receive the shutdown
191
	 * signal and stop. Otherwise catches an exception.
192
	 */
193
	public void destroy ()
194
	{
195
		try {
196
			destroyed = true;
197
			//Wait for a second to give other threads a chance to be interrupted and return.
198
			//This may not be necessary but it seems to prevent some browser crashes. 
199
			Thread.sleep(1000);
200
		} catch (InterruptedException e) {
201
			err("Interrupted exception in destroy()");
202
		}
203
	}
204
	
205
	public void actionPerformed (ActionEvent event) {
206
		Object source = event.getSource();
207
		
208
		if (source == btnConnect)
209
		{
210
			csi.connect(txtHost.getText(), txtPort.getText());
211
			webcamLoader.start();
212
			datalistener.start();
213
		}
214
		else if (source == btnClearLog)
215
			log.setText("");
216
		else if (source == btnBuzzerOn)
217
		{
218
			csi.sendData(ColonetServerInterface.BUZZER_SET_FREQ + " 254", ColonetServerInterface.GLOBAL_DEST);
219
		}
220
		else if (source == btnBuzzerOff)
221
		{
222
			csi.sendData(ColonetServerInterface.BUZZER_OFF, ColonetServerInterface.GLOBAL_DEST);
223
		}
224
		else if (source == btnRequestBattery)
225
		{
226
			csi.sendRequest(ColonetServerInterface.BATTERY, ColonetServerInterface.GLOBAL_DEST);
227
		}
228
		else if (source == btnGetSensorData)
229
		{
230
			SensorDataWindow sd = new SensorDataWindow(this);
231
			Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
232
			sd.setBounds(screenDim.width/4, screenDim.height/4, screenDim.width/2, screenDim.height/2);
233
			sd.setVisible(true);
234
		}
235
		else if (source == btnActivate)
236
		{
237
			isMoving = false;
238
			csi.sendData(ColonetServerInterface.MOTORS_INIT, ColonetServerInterface.GLOBAL_DEST);
239
			csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 0", ColonetServerInterface.GLOBAL_DEST);
240
			csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 0", ColonetServerInterface.GLOBAL_DEST);
241
		}
242
		else if (source == btnF)
243
		{
244
			isMoving = true;
245
			csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
246
			csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
247
		}
248
		else if (source == btnB)
249
		{
250
			isMoving = true;
251
			csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
252
			csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
253
		}
254
		else if (source == btnL)
255
		{
256
			isMoving = true;
257
			csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
258
			csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
259
		}
260
		else if (source == btnR)
261
		{
262
			isMoving = true;
263
			csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
264
			csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
265
		}
266
	
267
	}
268
	
269
	public void stateChanged (ChangeEvent e) 
270
	{
271
		//Update the orb color
272
		int red = chooser.getColor().getRed();
273
		int green = chooser.getColor().getGreen();
274
		int blue = chooser.getColor().getBlue();
275
		csi.sendData(ColonetServerInterface.ORB_SET + " " + red + " " + green + " " + blue, ColonetServerInterface.GLOBAL_DEST);
276
	}
277
	
278
	
279
	/**
280
	 * Display informational message box on the screen. Used for casual communicaton to the user.
281
	 * @param text Text to display
282
	 */
283
	private void msg (String text) {
284
		JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.INFORMATION_MESSAGE);
285
	}
286
	
287
	/**
288
	 * Display warning message box on the screen. Used for minor alerts or exceptions.
289
	 * @param text Text to display
290
	 */
291
	private void warn (String text) {
292
		JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.WARNING_MESSAGE);
293
	}
294
	
295
	/**
296
	 * Display error message box on the screen. Used for major errors or exceptions in the program.
297
	 * @param text Text to display
298
	 */
299
	private void err (String text) {
300
		JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.ERROR_MESSAGE);
301
	}
302
	
303
	public void keyPressed (KeyEvent e) {
304
		if (isMoving) return;
305
		try {
306
			if (e.getKeyCode() == KeyEvent.VK_UP) {
307
				log.append("Key: Up\n");
308
				isMoving = true;
309

  
310
        csi.sendData(ColonetServerInterface.MOVE_AVOID + " 200 0 0", ColonetServerInterface.GLOBAL_DEST);
311

  
312
				//sendData(MOTOR1_SET + " 1 200");
313
				//sendData(MOTOR2_SET + " 1 200");
314
			}
315
			else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
316
				log.append("Key: Down\n");
317
				isMoving = true;
318
				csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
319
				csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
320
			}
321
			else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
322
				log.append("Key: Left\n");
323
				isMoving = true;
324
				csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
325
				csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
326
			}
327
			else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
328
				log.append("Key: Right\n");
329
				isMoving = true;
330
				csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
331
				csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
332
			}
333
			
334
		} catch (Exception ex) {
335
			log.append("Error sending command.\n");
336
		}
337
	}
338
	
339
	public void keyReleased (KeyEvent e) {
340
		if (!isMoving) return;
341
		// if we are no longer pressing a direction key, stop the robot
342
		if (e.getKeyCode() == KeyEvent.VK_UP ||
343
			e.getKeyCode() == KeyEvent.VK_DOWN ||
344
			e.getKeyCode() == KeyEvent.VK_LEFT ||
345
			e.getKeyCode() == KeyEvent.VK_RIGHT)
346
			log.append("Stopping robot\n");
347
			isMoving = false;
348
			csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 0", ColonetServerInterface.GLOBAL_DEST);
349
			csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 0", ColonetServerInterface.GLOBAL_DEST);
350
	}
351
	public void keyTyped (KeyEvent e) {
352
		
353
	}
354
	
355
	/**
356
	 * Listens for incoming data from the colonet server. 
357
	 * This includes responses to requests for robot data.
358
	 */
359
	class DataListener extends Thread
360
	{
361

  
362
		JTextArea log;
363
		BufferedReader reader;
364

  
365
		/**
366
		 * Create a new DataListener that listens for incoming data on the specified socket.
367
		 * @param log TextArea to which incoming messages should be printed.
368
		 * @param socket Socket on which to listen for data.
369
		 */
370
		public DataListener (JTextArea log)
371
		{
372
			super("Colonet DataListener");
373
			this.log = log;
374
		}
375
		
376
		public void run ()
377
		{
378
			String line;
379
			log.append("Started listener for responses\n");
380
			while (!destroyed)
381
			{
382
				try {
383
					if (csi.isReady())
384
					{
385
						line = csi.getBufferedReader().readLine();
386
						if (line != null) log.append("Message from server: " + line + "\n");
387
					}
388
					Thread.sleep(500);
389
				} catch (Exception e) {
390
					warn("Error: " + e);
391
				}
392
			}
393
		}
394

  
395
	}
396

  
397

  
398
	class WebcamLoader extends Thread 
399
	{
400

  
401
		URL path;
402
		Image image;
403
		MediaTracker mt;
404
		int BUFFER = 16;  // this is arbitrary. it makes the image look nice.
405
		
406
		public WebcamLoader (JApplet applet)
407
		{
408
			super("Colonet WebcamLoader");
409
			try {
410
				path = new URL("http://roboclub1.frc.ri.cmu.edu/ColonetGUI/webcam/colonet.jpg");
411
			} catch (MalformedURLException e) {
412
				err("MalformedURLException.\nCannot load webcam image.");
413
			}
414
			mt = new MediaTracker(applet);
415
		}
416
		
417
		public void run ()
418
		{
419
			while (!destroyed) {
420
				try {
421
					Thread.sleep(1000);
422
					if (destroyed) return;
423
					if (image != null) image.flush();
424
					image = getImage(path);
425
					mt.addImage(image, 1);
426
					mt.waitForID(1);
427
					panelWebcam.getGraphics().drawImage(image, 
428
						BUFFER,	//dx1 - the x coordinate of the first corner of the destination rectangle.
429
						BUFFER,	//dy1 - the y coordinate of the first corner of the destination rectangle.
430
						panelWebcam.getWidth() - BUFFER, 	//dx2 - the x coordinate of the second corner of the destination rectangle.
431
						panelWebcam.getHeight() - BUFFER,	//dy2 - the y coordinate of the second corner of the destination rectangle.
432
						0,	//sx1 - the x coordinate of the first corner of the source rectangle.
433
						0,	//sy1 - the y coordinate of the first corner of the source rectangle.
434
						image.getWidth(null),	//sx2 - the x coordinate of the second corner of the source rectangle.
435
						image.getHeight(null),	//sy2 - the y coordinate of the second corner of the source rectangle.
436
						null	//observer - object to be notified as more of the image is scaled and converted.
437
						);
438
						
439
				} catch (InterruptedException e) {
440
					//Closing the browser window will probably couse an InterruptedException.
441
					//I can't think of anything else to do than let it happen and then return.
442
					return;
443
				} catch (java.security.AccessControlException e) {
444
					warn("java.security.AccessControlException in WebcamLoader.\n" + 
445
						"The image cannot be loaded from the specified location.\n" + 
446
						"Make sure you are accessing this applet from the correct server.");
447
					destroyed = true;
448
				}
449
			}
450
		}
451
	}
452
	
453
	class SensorDataWindow extends JFrame implements ActionListener
454
	{
455
	
456
		JApplet applet;
457
		JTextArea log;
458
		JScrollPane spLog;
459
		JButton btnClose;
460
		JPanel panelButtons;
461
		SensorDataLoader sdl;
462
	
463
		public SensorDataWindow (JApplet applet)
464
		{
465
			super("Sensor Data");
466
			this.applet = applet;
467
			
468
			log = new JTextArea();
469
			log.setEditable(false);
470
			spLog = new JScrollPane(log, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
471
			spLog.setBorder(BorderFactory.createTitledBorder("Log"));
472
			
473
			Container content = this.getContentPane();
474
			content.setLayout(new BorderLayout());
475
			content.add(spLog, BorderLayout.CENTER);
476
			
477
			btnClose = new JButton("Close Window");
478
			btnClose.addActionListener(this);
479
			panelButtons = new JPanel();
480
			panelButtons.setLayout(new FlowLayout());
481
			panelButtons.add(btnClose);
482
			content.add(panelButtons, BorderLayout.SOUTH);
483
			
484
			//start thread to continuously update data
485
			sdl = new SensorDataLoader(this, this.applet);
486
			sdl.start();
487
			
488
			//if the window is closed,
489
			//make sure we stop the thread.
490
			this.addWindowListener(new SensorDataWindowListener());
491
			
492
		}
493
		
494
		public void actionPerformed (ActionEvent event)
495
		{
496
			Object source = event.getSource();
497
			if (source == btnClose)
498
			{
499
				this.setVisible(false);
500
				sdl.stopMe();
501
			}
502
		}
503
		
504
		class SensorDataWindowListener extends WindowAdapter
505
		{
506
			public SensorDataWindowListener ()
507
			{
508
				super();
509
			}
510
			public void windowClosing (WindowEvent e)
511
			{
512
				sdl.stopMe();
513
			}
514
		}
515
		
516
	}
517
	
518
	class SensorDataLoader extends Thread
519
	{
520
	
521
		SensorDataWindow window;
522
		JApplet applet;
523
		boolean running;
524
	
525
		public SensorDataLoader (SensorDataWindow window, JApplet applet)
526
		{
527
			this.window = window;
528
			this.applet = applet;
529
		}
530
		
531
		public void run ()
532
		{
533
			running = true;
534
			log.append("Sensor data loading started.\n");
535
			while (running)
536
			{
537
				try {
538
					Thread.sleep(2000);
539
				} catch (InterruptedException e) {
540
					err("InterruptedException in SensorDataLoader\n" + e);
541
				}
542
				log.append("<update data here ...>\n");
543
			}
544
			log.append("Sensor data loading stopped.\n");
545
		}
546
		
547
		public void stopMe ()
548
		{
549
			running = false;
550
		}
551
	
552
	}
553
	
554
}
trunk/code/projects/colonet/ColonetGUI/index_graph.html
1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3

  
4
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
5
<head>
6
	<title>Colony Control Applet - Carnegie Mellon Robotics Club</title>
7
	<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
8
	<link rel="stylesheet" type="text/css" href="colonetstyle.css" />
9
</head>
10

  
11
<body>
12

  
13
<div class="top">
14
	<h1>Colonet: Robot Graph</h1>
15
	<p>Carnegie Mellon Robotics Club: Colony Project</p>
16
	<img src="http://roboclub8.frc.ri.cmu.edu/mainwiki/roboclublogo.png" height="125px" width="110px" alt="RoboClub Logo" />
17
</div>
18

  
19
<div class="app">
20
	<p>
21
	<object
22
		classid = "java:BotGraph.class"
23
		type = "application/x-java-applet"
24
		width = "850"
25
		height = "650"
26
		align = "bottom"
27
		codebase = "http://roboclub1.frc.ri.cmu.edu/gui/" 
28
		name = "BotGraph"
29
		title = "BotGraph" >
30
		<param name = "code" value = "BotGraph.class" />
31
	</object>
32
	<br />
33
	Requires Java 5.
34
	<br />
35
	<a href="BotGraph.java">Source Code</a>
36
	<br />
37
	<br />
38
	</p>
39
</div>
40

  
41
<div class="bottom">
42
	<p><b>Colony Project Home page:</b><br />
43
	<a href="http://www.robotcolony.org/">www.robotcolony.org</a></p>
44
	
45
	<p><b>Validator:</b><br />
46
	<a href="http://validator.w3.org/check?uri=referer">
47
	<img src="http://www.w3.org/Icons/valid-xhtml10-blue"
48
		 alt="Valid XHTML 1.0 Transitional"
49
		 height="31"
50
		 width="88" 
51
		 border="0"
52
		 />
53
	</a>
54
	<a href="http://jigsaw.w3.org/css-validator/validator?uri=http://roboclub1.frc.ri.cmu.edu/ColonetGUI/colonetstyle.css">
55
  	<img style="border:0;width:88px;height:31px"
56
       src="http://www.w3.org/Icons/valid-css-blue" 
57
       alt="Valid CSS!" />
58
	</a><br />
59
	</p>
60
	
61
</div>
62

  
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff