Project

General

Profile

Revision 311

GUI battery meter added

View differences:

trunk/code/projects/colonet/ColonetGUI/Colonet.java
3 3
//
4 4

  
5 5
import javax.swing.*;
6
import javax.swing.event.*;
7
import javax.imageio.*;
8 6
import java.awt.*;
9 7
import java.awt.image.*;
10 8
import java.awt.event.*;
......
13 11
import java.util.Random;
14 12
import java.applet.*;
15 13

  
16
/**
17
*	The Colonet Graphical User Interface Applet for use locally and over an internet connection.
18
*	@author Gregory Tress
19
*	
20
*
21
*/
22
public class Colonet extends JApplet implements ActionListener, MouseInputListener, KeyListener, Runnable {
14
public class Colonet extends JApplet implements ActionListener, MouseListener, Runnable {
23 15

  
24
	final int CANVAS_SIZE = 500;  //the applet may be slow if the canvas gets too large
16
	final int CANVAS_SIZE = 500;  //don't make this too large, or the applet will be slow.
25 17
	final int BUFFER = 50;
26 18
	final int RADIUS = 30;
27 19

  
......
31 23
	JButton btnConnect;	
32 24
	JButton btnGraph;
33 25
	JLabel lblConnectionStatus;
34
	JTextArea txtMatrix;
26
	JTextArea txtInput;
35 27
	JTextArea txtInfo; 
36 28
	JPanel panelConnect;
37 29
	JPanel panelServerInterface;
38 30
	
31
	// Stats
32
	JLabel lblBattery;
33
	JLabel lblTokenPasses;
34
	JLabel lblHastToken;
35
	JPanel panelStats;
36
	JPanel panelBattery;
37
	
39 38
	// South
40 39
	JPanel panelSouth;
41 40
	JTextArea log;
......
46 45
	JTabbedPane tabPaneControl;
47 46
	JPanel panelRobotControl;
48 47
	JPanel panelRobotDirection;
49
	JPanel panelRobotDirectionButtons;
50 48
	JPanel panelRobotCommands;
51 49
	JButton btnF, btnB, btnL, btnR, btnActivate;
52
	JComboBox cmbRobotNum;
53
	JLabel lblBattery;
54
	VectorController vectorController;
55
	BufferedImage imageVectorControl;
56
	JButton btnCommand_StopTask;
57
	JButton btnCommand_ResumeTask;
58
	JButton btnCommand_ChargeNow;
59
	JButton btnCommand_StopCharging;
60 50
	
61 51
	// Task Manager
62 52
	JPanel panelTaskManager;
......
69 59
	JButton btnRemoveTask;
70 60
	JButton btnMoveTaskUp;
71 61
	JButton btnMoveTaskDown;
72
	JButton btnUpdateTasks;
73
	TaskAddWindow taskAddWindow;
74 62
	
75
	//Webcam and Graph
76
	WebcamPanel panelWebcam;
77
	GraphicsPanel panelGraph;
63
	// Graphics
64
	JPanel panel;
78 65
	GraphicsConfiguration gc;
79 66
	volatile BufferedImage image;
80 67
	volatile Graphics2D canvas;
81 68
	int cx, cy;
82
	JTabbedPane tabPaneMain;
83 69
	
84
	
85 70
	Socket socket;					
86
	OutputStreamWriter out;
87
	DataUpdater dataUpdater;  
71
	OutputStreamWriter out;			//TODO: add a BufferedWriter
72
	DataListener datalistener;  
88 73
	
89 74
	Font botFont;
90 75
	Random random = new Random();
......
92 77
	volatile int numBots;
93 78
	volatile int selectedBot;  //the user has selected this bot
94 79
	volatile Rectangle[] botRect;  //contains boundary shapes around bots for click detection
95
	volatile int[] xbeeID;
96 80
	
97 81
	Thread drawThread;
98
	Simulator simulator;
99 82
	SelectionIndicator indicator;
100
	WebcamLoader webcamLoader;
83
	PacketMonitor packetMonitor;
101 84
	ColonetServerInterface csi;
102 85

  
103 86
	
104 87
	public void init () {
105
		// set the default look and feel - choose one
106
        //String laf = UIManager.getSystemLookAndFeelClassName();
107
		String laf = UIManager.getCrossPlatformLookAndFeelClassName();
108
		//String laf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
88
		// set the default look and feel
89
        String laf = UIManager.getSystemLookAndFeelClassName();
109 90
        try {
110 91
            UIManager.setLookAndFeel(laf);
111 92
        } catch (UnsupportedLookAndFeelException exc) {
......
123 104
			SwingUtilities.invokeAndWait(r);
124 105
		} catch (InterruptedException e) {
125 106
			//Not really sure why we would be in this situation
126
			System.out.println("InterruptedException in init: " + e);
107
			System.out.println(e);
127 108
		} catch (java.lang.reflect.InvocationTargetException e) {
128
			//This could happen for various reasons if there is a problem in createAndShowGUI
129
			e.printStackTrace();
109
			//This should never happen. Seriously.
110
			System.out.println(e);
130 111
		}
131 112
	}
132 113
	
133 114
	public void destroy () {
134 115
		try { drawThread.interrupt(); } catch (Exception e) { }
135 116
		try { indicator.interrupt(); } catch (Exception e) { }
117
		try { packetMonitor.interrupt(); } catch (Exception e) { }
136 118
	}
137 119

  
138 120
	private synchronized void createAndShowGUI () {
139 121
		// init graphical elements
140
		// Get the graphics configuration of the screen to create a buffer
141
		gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
142
			.getDefaultScreenDevice().getDefaultConfiguration();
143
		image = gc.createCompatibleImage(CANVAS_SIZE,CANVAS_SIZE);
144
		canvas = image.createGraphics();
145
		canvas.setStroke(new BasicStroke(2));  //set pen width
146
		panelGraph = new GraphicsPanel(false, image);  //set automatic double-buffering to false. we are doing it manually.
147
		panelWebcam = new WebcamPanel();
148
		tabPaneMain = new JTabbedPane();
149
		tabPaneMain.add(panelWebcam, "Webcam");
150
		tabPaneMain.add(panelGraph, "Graph");
122
		panel = new JPanel(false);  //set automatic double-buffering to false. we are doing it manually.
151 123
		
152
		// Calculate center of canvas
153
		cx = image.getWidth() / 2;
154
		cy = image.getHeight() / 2;
155
		
156
		botFont = new Font("Arial", Font.PLAIN, 14);
157
		tokenLoc = 0;
158
		numBots = 0;
159
		selectedBot = 0;
160
		
161 124
		// Connection area
162
		txtMatrix = new JTextArea();
163
		txtMatrix.setBorder(BorderFactory.createTitledBorder("Input Matrix"));
125
		txtInput = new JTextArea("- 9 3 - 1\n- - - 5 -\n4 - - - 2\n- - - - -\n1 - - 3 -");
126
		txtInput.setBorder(BorderFactory.createTitledBorder("Input Matrix"));
164 127
		txtInfo = new JTextArea();
165 128
		txtInfo.setBorder(BorderFactory.createTitledBorder("Info"));
166 129
		txtInfo.setEditable(false);
167 130
		btnGraph = new JButton("Run");
168
		txtHost = new JTextField("roboclub9.frc.ri.cmu.edu");
131
		txtHost = new JTextField("roboclub1.frc.ri.cmu.edu");
169 132
		txtHost.setBorder(BorderFactory.createTitledBorder("Host"));
170 133
		txtPort = new JTextField("10123");
171 134
		txtPort.setBorder(BorderFactory.createTitledBorder("Port"));
......
177 140
		panelConnect.add(txtHost);
178 141
		panelConnect.add(txtPort);
179 142
		panelConnect.add(btnConnect);
180
		//panelConnect.add(btnGraph);
143
		panelConnect.add(txtInfo);
144
		panelConnect.add(btnGraph);
181 145
		panelServerInterface = new JPanel();
182 146
		panelServerInterface.setLayout(new GridLayout(2,1));
183 147
		panelServerInterface.add(panelConnect);
184
		panelServerInterface.add(txtMatrix);
185
	
148
		panelServerInterface.add(txtInput);
149
				
150
		// Status Elements
151
		lblTokenPasses = new JLabel();
152
		lblBattery = new JLabel(new BatteryIcon(75, 100, 100));
153
		panelStats = new JPanel();
154
		panelStats.setLayout(new GridLayout(4,2));
155
		panelStats.add(new JLabel("Token Passes / sec          "));
156
		panelStats.add(lblTokenPasses);
157
		panelStats.add(new JLabel("Battery     "));
158
		panelStats.add(lblBattery);
159
		panelStats.add(new JLabel("Token Passes / sec     "));
160
		panelStats.add(lblTokenPasses);
161
		
162
		//TODO: add panelStats somewhere!
163

  
186 164
		// Robot direction panel
187 165
		panelRobotDirection = new JPanel();
188
		panelRobotDirectionButtons = new JPanel();
189 166
		btnF = new JButton("^");
190 167
		btnB = new JButton("v");
191 168
		btnL = new JButton("<");
192 169
		btnR = new JButton(">");
193 170
		btnActivate = new JButton("o");
194
		panelRobotDirectionButtons.setLayout(new GridLayout(1,5));
195
		panelRobotDirectionButtons.add(btnActivate);
196
		panelRobotDirectionButtons.add(btnF);
197
		panelRobotDirectionButtons.add(btnB);
198
		panelRobotDirectionButtons.add(btnL);
199
		panelRobotDirectionButtons.add(btnR);
171
		panelRobotDirection = new JPanel();
172
		panelRobotDirection.setLayout(new GridLayout(3,3));
173
		panelRobotDirection.add(new JLabel(""));
174
		panelRobotDirection.add(btnF);
175
		panelRobotDirection.add(new JLabel(""));
176
		panelRobotDirection.add(btnL);
177
		panelRobotDirection.add(btnActivate);
178
		panelRobotDirection.add(btnR);
179
		panelRobotDirection.add(new JLabel(""));
180
		panelRobotDirection.add(btnB);
181
		panelRobotDirection.add(new JLabel(""));
200 182
		
201
		imageVectorControl = gc.createCompatibleImage(395, 220);
202
		vectorController = new VectorController(imageVectorControl);
203
		panelRobotDirection.setLayout(new BorderLayout());
204
		panelRobotDirection.add(vectorController, BorderLayout.CENTER);
205
		panelRobotDirection.add(panelRobotDirectionButtons, BorderLayout.SOUTH);
206
		
207 183
		// Robot Control and Commands
208 184
		panelRobotCommands = new JPanel();
209
		panelRobotCommands.setLayout(new GridLayout(5,2));
210
		cmbRobotNum = new JComboBox();
211
		lblBattery = new JLabel("Unknown");
212
		btnCommand_StopTask = new JButton("Stop Current Task");
213
		btnCommand_ResumeTask = new JButton("Resume Current Task");
214
		btnCommand_ChargeNow = new JButton("Recharge Now");
215
		btnCommand_StopCharging = new JButton("Stop Recharging");
216
		panelRobotCommands.add(new JLabel("Select Robot to Control: "));
217
		panelRobotCommands.add(cmbRobotNum);
218
		panelRobotCommands.add(new JLabel("Battery Level: "));
219
		panelRobotCommands.add(lblBattery);
220
		panelRobotCommands.add(btnCommand_StopTask);
221
		panelRobotCommands.add(btnCommand_ResumeTask);
222
		panelRobotCommands.add(btnCommand_ChargeNow);
223
		panelRobotCommands.add(btnCommand_StopCharging);
185
		panelRobotCommands.setLayout(new FlowLayout());
186
		panelRobotCommands.add(new JLabel("Commands go here"));
224 187
		panelRobotControl = new JPanel();
225 188
		panelRobotControl.setLayout(new GridLayout(2,1));
226 189
		panelRobotControl.add(panelRobotDirection);
......
230 193
		panelTaskManager = new JPanel();
231 194
		panelTaskManager.setLayout(new BorderLayout());
232 195
		taskListModel = new DefaultListModel();
196
		taskListModel.addElement("Map the Environment");
197
		taskListModel.addElement("Clean Up Chemical Spill");
198
		taskListModel.addElement("Grow Plants");
199
		taskListModel.addElement("Save the Cheerleader");
200
		taskListModel.addElement("Save the World");
233 201
		taskList = new JList(taskListModel);
234 202
		taskList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
235 203
		taskList.setSelectedIndex(0);
236 204
		spTaskManager = new JScrollPane(taskList);
237 205
		panelTaskManagerControls = new JPanel();
238
		panelTaskManagerControls.setLayout(new GridLayout(1,4));
206
		panelTaskManagerControls.setLayout(new GridLayout(1,3));
239 207
		panelTaskManagerControlsPriority = new JPanel();
240 208
		panelTaskManagerControlsPriority.setLayout(new GridLayout(1,2));
241 209
		btnAddTask = new JButton("Add...");
242 210
		btnRemoveTask = new JButton("Remove");
243 211
		btnMoveTaskUp = new JButton("^");
244 212
		btnMoveTaskDown = new JButton("v");
245
		btnUpdateTasks = new JButton("Update");
246 213
		panelTaskManagerControlsPriority.add(btnMoveTaskUp);
247 214
		panelTaskManagerControlsPriority.add(btnMoveTaskDown);
248 215
		panelTaskManagerControls.add(btnAddTask);
249 216
		panelTaskManagerControls.add(btnRemoveTask);
250
		panelTaskManagerControls.add(btnUpdateTasks);
251 217
		panelTaskManagerControls.add(panelTaskManagerControlsPriority);
252 218
		panelTaskManager.add(spTaskManager, BorderLayout.CENTER);
253 219
		panelTaskManager.add(panelTaskManagerControls, BorderLayout.SOUTH);
254 220
		panelTaskManager.add(new JLabel("Current Task Queue"), BorderLayout.NORTH);
255
		taskAddWindow = new TaskAddWindow();
256 221
		
257 222
		// Message log
258 223
		log = new JTextArea();
......
260 225
			ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, 
261 226
			ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
262 227
		spLog.setBorder(BorderFactory.createTitledBorder("Log"));
263
		spLog.setPreferredSize(new Dimension(0, 120));
228
		spLog.setPreferredSize(new Dimension(0, 150));
264 229
		log.setEditable(false);
265 230
		
266 231
		// Main control mechanism
267 232
		panelControl = new JPanel();
268 233
		panelControl.setLayout(new GridLayout(1,1));
269 234
		tabPaneControl = new JTabbedPane(JTabbedPane.TOP);
270
		tabPaneControl.setPreferredSize(new Dimension(330, 0));
235
		tabPaneControl.setPreferredSize(new Dimension(300, 0));
271 236
		tabPaneControl.addTab("Connection", panelServerInterface);
272 237
		tabPaneControl.addTab("Robots", panelRobotControl);
273 238
		tabPaneControl.addTab("Tasks", panelTaskManager);
239
		tabPaneControl.addTab("Stats", panelStats);
274 240
		panelControl.add(tabPaneControl);
275 241
		
276 242
		// Set up elements in the south
277 243
		panelSouth = new JPanel();
278 244
		panelSouth.setLayout(new GridLayout(1,2));
279
		//panelSouth.add(spLog);
245
		panelSouth.add(spLog);
280 246

  
281
		// Put all elements in the ContentPane
282 247
		this.getContentPane().setLayout(new BorderLayout());
283
		this.getContentPane().add(tabPaneMain, BorderLayout.CENTER);
248
		this.getContentPane().add(panel, BorderLayout.CENTER);
284 249
		this.getContentPane().add(panelSouth, BorderLayout.SOUTH);
285 250
		this.getContentPane().add(panelControl, BorderLayout.EAST);
286 251
		this.setVisible(true);
287 252
		
288
		/* Add all listeners here */
289
		// Task Management
290 253
		btnAddTask.addActionListener(this);
291 254
		btnRemoveTask.addActionListener(this);
292 255
		btnMoveTaskUp.addActionListener(this);
293 256
		btnMoveTaskDown.addActionListener(this);
294
		btnUpdateTasks.addActionListener(this);
295
		// Robot Control
296
		btnF.addActionListener(this);
297
		btnB.addActionListener(this);
298
		btnL.addActionListener(this);
299
		btnR.addActionListener(this);
300
		btnF.addKeyListener(this);
301
		btnB.addKeyListener(this);
302
		btnL.addKeyListener(this);
303
		btnR.addKeyListener(this);
304
		btnActivate.addActionListener(this);
305
		btnActivate.addKeyListener(this);
306
		cmbRobotNum.addKeyListener(this);
307
		vectorController.addMouseMotionListener(this);
308
		vectorController.addMouseListener(this);
309
		btnCommand_StopTask.addActionListener(this);
310
		btnCommand_ResumeTask.addActionListener(this);
311
		btnCommand_ChargeNow.addActionListener(this);
312
		btnCommand_StopCharging.addActionListener(this);
313
		// Other
314 257
		btnGraph.addActionListener(this);
315 258
		btnConnect.addActionListener(this);
316
		panelGraph.addMouseListener(this);
317
		this.addMouseMotionListener(this);	
259
		panel.addMouseListener(this);
318 260
		
319
				
261
		
262
		// Get the graphics configuration of the screen to create a buffer
263
		gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
264
			.getDefaultScreenDevice().getDefaultConfiguration();
265
		image = gc.createCompatibleImage(CANVAS_SIZE,CANVAS_SIZE);
266
		canvas = image.createGraphics();
267
		canvas.setStroke(new BasicStroke(2));  //set pen width
268
		
269
		// Calculate center of canvas
270
		cx = image.getWidth() / 2;
271
		cy = image.getHeight() / 2;
272
		
273
		botFont = new Font("Arial", Font.PLAIN, 30);
274
		tokenLoc = 0;
275
		numBots = 0;
276
		selectedBot = 0;
277
		
320 278
		// Set up dependent threads
321 279
		indicator = new SelectionIndicator(canvas);
322 280
		indicator.setRadius(RADIUS+3, 15);  //a tad more than the bot radius
323
		simulator = new Simulator();
324
		webcamLoader = new WebcamLoader(this);
325
		dataUpdater = new DataUpdater();
326
		csi = new ColonetServerInterface(this);
281
		packetMonitor = new PacketMonitor();
282
		datalistener = new DataListener();
283
		
284
		csi = new ColonetServerInterface(log);
327 285
	
328 286
	}
329 287
	
330 288
	public synchronized void paint (Graphics g) {
331
		/*	Redraw the graphical components in the applet. 
289
		/*	First, redraw the graphical components in the applet. 
332 290
			This paint method overrides the built-in paint of the 
333 291
			JApplet, and we don't want to deal with redrawing the
334 292
			components manually. Fuck that shit. */
335
		step();
336 293
		super.paint(g);
294
		
295
		// Place the buffered image on the screen, inside the panel
296
		panel.getGraphics().drawImage(image, 0, 0, Color.WHITE, this);
297
		
337 298
	}
338 299
	
339 300
	public synchronized void update (Graphics g) {
340 301
		paint(g);
341 302
	}
342 303
	
304
	public void actionPerformed (ActionEvent e) {
305
		Object source = e.getSource();
306
		if (source == btnGraph) {
307
			btnGraph.setEnabled(false);
308
			lblConnectionStatus.setText("Simulating");
309
			
310
			//Start dependent threads
311
			drawThread = new Thread(this, "drawThread");
312
			drawThread.start();
313
			indicator.start();
314
			packetMonitor.start();
315
		} else if (source == btnConnect) {
316
			doSocket();
317
		} else if (source == btnRemoveTask) {
318
			try {
319
				taskListModel.remove(taskList.getSelectedIndex());
320
			} catch (ArrayIndexOutOfBoundsException ex) {
321
			}
322
		}
323
	}
324
	
343 325
	private void randomize () {
344 326
		Random r = new Random();
345 327
		StringBuilder s = new StringBuilder();
......
357 339
			if (i != count-1) s.append("\n");
358 340
		}
359 341
		
360
		txtMatrix.setText(s.toString());
342
		txtInput.setText(s.toString());
361 343
	}
362 344
	
345
	private void doSocket () {
346
		csi.connect(txtHost.getText(), txtPort.getText());
347
	}
348
	
363 349
	public void drawRobot (int id, int x, int y) {
364 350
		//save the bot in memory, so we can tell if we click on it later
365 351
		botRect[id] = new Rectangle(x-RADIUS, y-RADIUS, 2*RADIUS, 2*RADIUS);
......
370 356
		
371 357
		//draw the label
372 358
		canvas.setFont(botFont);
373
		try {
374
			canvas.drawString("" + xbeeID[id], x-20, y+2);
375
		} catch (Exception e) {
376
			canvas.drawString("???", x-22, y+2);
377
		}
359
		canvas.drawString("" + id, x-10, y+10);
378 360
	}
379 361
	
380 362
	public void drawConnection (int start, int end, int radius, Color color) {
......
421 403
	
422 404
	public void run () {
423 405
		while (true) {
406
			step();
424 407
			repaint();
425 408
			try { 
426 409
				Thread.sleep(90);
......
441 424
		canvas.fillRect(0, 0, image.getWidth(), image.getHeight());
442 425
		
443 426
		// parse the matrix, to see what robots exist
444
		String [] rows = txtMatrix.getText().split("\n");
427
		String [] rows = txtInput.getText().split("\n");
445 428
		numBots = rows.length;
446 429
		String [][] entries = new String[numBots][numBots];
447 430
		valid = true;
......
491 474
			// draw the selection indicator
492 475
			indicator.draw();
493 476
			
494
		} else {  // if matrix is not valid
477
		} else {// if matrix is not valid
495 478
			this.showStatus("Error: Invalid matrix");
496 479
		}
497 480
	
498 481
	}
499 482
	
500
	public JTextArea getLog () {
501
		return log;
502
	}
503
	
504
	public JTextArea getMatrixInput () {
505
		return txtMatrix;
506
	}
507
	
508
	public void parseMatrix (String line) {
509
		txtMatrix.setText("");
510
		String [] str = line.split(" ");
511
		int num = Integer.parseInt(str[2]);
512
		for (int i = 0; i < num; i++) {
513
			for (int j = 0; j < num; j++) {
514
				String next = str[3 + i*num + j];
515
				if (next.equals("-1"))
516
					txtMatrix.append("-");
517
				else 
518
					txtMatrix.append(next);
519
				if (j < num - 1) 
520
					txtMatrix.append(" ");
521
			}
522
			if (i < num - 1) 
523
				txtMatrix.append("\n");
483
	/*	At this point, moveToken is only called by the simulator.
484
	*	In the future, it can be rewritten to account for non-standard
485
	*	token passing or deleted if the information can be retrieved
486
	*	directly from the Colonet server instead.
487
	*/
488
	public void moveToken () {
489
		try {
490
			tokenLoc = (tokenLoc+1)%numBots;
491
		} catch (ArithmeticException e) {  // in case numRobots is zero
524 492
		}
525 493
		
494
		packetMonitor.addTokenPass();
526 495
	}
527 496
	
528
	public void parseQueue (String line) {
529
		log.append("Got queue update\n");
530
	}
531
	
532
	public void parseXBeeIDs (String line) {
533
		String [] str = line.split(" ");
534
		int num = Integer.parseInt(str[2]);
535
		xbeeID = new int[num];
536
		for (int i = 0; i < num; i++)
537
			xbeeID[i] = Integer.parseInt(str[i+3]);
538
		
539
		//update the list of robots to control
540
		//but save the old value first
541
		Object oldSelection = cmbRobotNum.getSelectedItem();
542
		cmbRobotNum.removeAllItems();
543
		cmbRobotNum.addItem(new String("   All   "));
544
		for (int i = 0; i < num; i++)
545
			cmbRobotNum.addItem(new String("" + xbeeID[i]));
546
		cmbRobotNum.setSelectedItem(oldSelection);
547
	}
548
	
549
	public void parseBattery (String line) {
550
		String [] str = line.split(" ");
551
		int botNum = Integer.parseInt(str[2]);
552
		int batteryVal = Integer.parseInt(str[3]);
553
		if (cmbRobotNum != null && cmbRobotNum.getSelectedIndex()-1 == botNum)
554
			lblBattery.setText("" + batteryVal);
555
	}
556
	
557 497
	//
558
	// MouseListener methods
498
	// MouseEvent methods
559 499
	//
560
	public void mouseExited(MouseEvent e) {
561
	}
562
	public void mouseEntered(MouseEvent e) {
563
	}
564
	public void mouseReleased(MouseEvent e) {
565
		vectorController.notifyMouseEvent(e, true);
566
	}
567
	public void mouseClicked(MouseEvent e) {
568
		vectorController.notifyMouseEvent(e, false);
569
	}
500
	public void mouseExited(MouseEvent e) {}
501
	public void mouseEntered(MouseEvent e) {}
502
	public void mouseReleased(MouseEvent e) {}
503
	public void mouseClicked(MouseEvent e) {}
570 504
	public void mousePressed(MouseEvent e) {
571 505
		try {
572 506
			for (int i = 0; i < numBots; i++) {
573
				if (botRect[i].contains(e.getPoint())) {
507
				if (botRect[i].contains(e.getPoint()))
574 508
					selectedBot = i;
575
					cmbRobotNum.setSelectedIndex(i+1);
576
				}
577 509
			}
578 510
		} catch (Exception ex) {
511
			System.out.println(e);
579 512
		}
580
	}
581
	public void mouseDragged(MouseEvent e) {
582
		vectorController.notifyMouseEvent(e, false);
583
	}
584
	public void mouseMoved(MouseEvent e) {
585
	}
586 513
	
587
	//
588
	// KeyListener methods
589
	//
590
	public void keyPressed (KeyEvent e) {
591
		int code = e.getKeyCode();
592
		if (code == KeyEvent.VK_UP) {
593
			vectorController.setMaxForward();
594
			vectorController.sendToServer();
595
		} else if (code == KeyEvent.VK_DOWN) {
596
			vectorController.setMaxReverse();
597
			vectorController.sendToServer();
598
		} else if (code == KeyEvent.VK_LEFT) {
599
			vectorController.setMaxLeft();
600
			vectorController.sendToServer();
601
		} else if (code == KeyEvent.VK_RIGHT) {
602
			vectorController.setMaxRight();
603
			vectorController.sendToServer();
604
		} else if (code == KeyEvent.VK_S) {
605
			vectorController.setZero();
606
			vectorController.sendToServer();
607
		}
608 514
	}
609
	public void keyReleased (KeyEvent e) {
610
	}
611
	public void keyTyped (KeyEvent e) {
612
	}
613 515
	
614
	
615
	//
616
	// ActionListener method
617
	//
618
	public void actionPerformed (ActionEvent e) {
619
		Object source = e.getSource();
620
		if (source == btnGraph) {
621
			btnGraph.setEnabled(false);
622
			//Start dependent threads
623
			drawThread = new Thread(this, "drawThread");
624
			drawThread.start();
625
			indicator.start();
626
			simulator.start();
627
			webcamLoader.start();
628
		} else if (source == btnConnect) {
629
			csi.connect(txtHost.getText(), txtPort.getText());
630
			dataUpdater.start();
631
			drawThread = new Thread(this, "drawThread");
632
			drawThread.start();
633
			indicator.start();
634
			simulator.start();
635
			webcamLoader.start();
636
		}
637
		// Robot Movement Controls
638
		else if (source == btnF) {
639
			vectorController.setMaxForward();
640
			vectorController.sendToServer();
641
		} else if (source == btnB) {
642
			vectorController.setMaxReverse();
643
			vectorController.sendToServer();
644
		} else if (source == btnL) {
645
			vectorController.setMaxLeft();
646
			vectorController.sendToServer();
647
		} else if (source == btnR) {
648
			vectorController.setMaxRight();
649
			vectorController.sendToServer();
650
		} else if (source == btnActivate) {
651
			vectorController.setZero();
652
			vectorController.sendToServer();
653
		}
654
		// Robot Commands (non-movement)
655
		else if (source == btnCommand_StopTask) {
656
		
657
		} else if (source == btnCommand_ResumeTask) {
658
		
659
		} else if (source == btnCommand_ChargeNow) {
660
		
661
		} else if (source == btnCommand_StopCharging) {
662
		
663
		}
664
			
665
		// Queue Management
666
		else if (source == btnAddTask) {
667
			taskAddWindow.prompt();
668
		} else if (source == btnRemoveTask) {
669
			if (taskList.getSelectedIndex() >= 0);
670
				csi.sendQueueRemove(taskList.getSelectedIndex());
671
			csi.sendQueueUpdate();
672
		} else if (source == btnMoveTaskUp) {
673
			csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() - 1);
674
			csi.sendQueueUpdate();
675
		} else if (source == btnMoveTaskDown) {
676
			csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() + 1);
677
			csi.sendQueueUpdate();
678
		} else if (source == btnUpdateTasks) {
679
			csi.sendQueueUpdate();
680
		}
681
	}
682
	
683 516
	/*
684 517
	*	SelectionIndicator thread.
685 518
	*	Graphical representation of the selection marker
......
691 524
	*/
692 525
	private class SelectionIndicator extends Thread {
693 526
	
694
		final int INDICATOR_DELAY = 180;
695
		final double DTHETA = 0.4;    //larger values make the marker rotate faster
527
		final int INDICATOR_DELAY = 100;
528
		final double DTHETA = 0.3;    //larger values make the marker rotate faster
696 529
		Graphics2D g;   //canvas to draw on
697 530
		boolean running;
698 531
		
......
772 605
			//recalculate radius, if it will look cool, lolz
773 606
			int newr = r;
774 607
			if (steps < 100)
775
			newr = (int)( r + 200/(steps+1) );
608
        newr = (int)( r + 200/(steps+1) );
776 609
			
777 610
			//precompute values for dx and dy
778 611
			int dx_inner = (int)(newr * Math.cos(theta));
......
865 698
		}
866 699
		
867 700
		private void step () {
868
			// don't do anything! the colonet should work on its own!
701
			// simulate passing the token
702
			moveToken();
869 703
		}
870 704
	
871 705
	}
872 706
	
873 707
	/*
874
	*	DataUpdater thread.
875
	*   The purpose of this thread is to request data from the server at regular intervals.
708
	*	PacketMonitor thread.
876 709
	*
710
	*	Currently, this counts the rate of token passes but will eventually 
711
	*	be modified to keep more important statistics.
877 712
	*/
878
	class DataUpdater extends Thread {
879
		final int DATAUPDATER_DELAY = 4000;
880
		
881
		public DataUpdater () {
882
			super("Colonet DataUpdater");
883
		}
884
		
885
		public void run () {
886
			String line;
887
			while (true) {
888
				try {
889
					//request more data
890
					if (csi != null && csi.isReady()) {
891
						csi.sendSensorDataRequest();
892
						csi.sendXBeeIDRequest();
893
						if (cmbRobotNum.getSelectedIndex() > 0)
894
							csi.sendBatteryRequest(cmbRobotNum.getSelectedIndex()-1);
895
					}
896
					Thread.sleep(DATAUPDATER_DELAY);
897
				} catch (InterruptedException e) {
898
					return;
899
				} 
900
			}
901
		}
902

  
903
	}
713
	private class PacketMonitor extends Thread {
714
		final int PACKETMONITOR_DELAY = 1000;
904 715
	
905
	/*
906
	*	GraphicsPanel class
907
	*	Enables more efficient image handling in a component-controlled environment
908
	*/
909
	class GraphicsPanel extends JPanel {
910
		protected Image img;
716
		boolean running;
717
		int tokenPasses;
911 718
	
912
		public GraphicsPanel (Image img) {
913
			super();
914
			this.img = img;
719
		public PacketMonitor () {
720
			super("PacketMonitor");
721
			running = false;
722
			tokenPasses = 0;
915 723
		}
916 724
		
917
		public GraphicsPanel (boolean isDoubleBuffered, Image img) {
918
			super(isDoubleBuffered);
919
			this.img = img;
920
		}
921
		
922
		public void paint (Graphics g) {
923
			// Place the buffered image on the screen, inside the panel
924
			g.drawImage(img, 0, 0, Color.WHITE, this);
925
		}
926
	
927
	}
928
	
929
	/*
930
	*	WebcamPanel class
931
	*	Enables more efficient image handling in a component-controlled environment
932
	*/
933
	class WebcamPanel extends JPanel {
934
		int BORDER = 16;  // this is arbitrary. it makes the image look nice inside a border.
935
		int BOT_RADIUS = 40;
936
		volatile BufferedImage img;
937
		volatile Point [] points;
938
	
939
		public WebcamPanel () {
940
			super();
941
		}
942
		
943
		public synchronized void setImage (BufferedImage newimg) {
944
			if (img != null) {
945
				img.flush();
946
				img = null;
947
				img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
725
		public void run () {
726
			running = true;
727
			while (running) {
728
				displayTokenPasses();
729
				try { 
730
					Thread.sleep(PACKETMONITOR_DELAY);
731
				} catch (InterruptedException e) { 
732
					running = false;
733
					return; 
734
				}
948 735
			}
949
			System.gc();
950
			img = newimg;
951 736
		}
952 737
		
953
		public synchronized void setPoints (Point [] newpoints) {
954
			this.points = newpoints;
738
		public synchronized void addTokenPass () {
739
			tokenPasses++;
955 740
		}
956 741
		
957
		public synchronized void paint (Graphics g) {
958
			
959
			if (img == null)
960
				return;
961
			// Place the image on the screen, inside the panel
962
			g.drawImage(img, 
963
						BORDER,	//dx1 - the x coordinate of the first corner of the destination rectangle.
964
						BORDER,	//dy1 - the y coordinate of the first corner of the destination rectangle.
965
						this.getWidth() - BORDER, 	//dx2 - the x coordinate of the second corner of the destination rectangle.
966
						this.getHeight() - BORDER,	//dy2 - the y coordinate of the second corner of the destination rectangle.
967
						0,	//sx1 - the x coordinate of the first corner of the source rectangle.
968
						0,	//sy1 - the y coordinate of the first corner of the source rectangle.
969
						image.getWidth(),	//sx2 - the x coordinate of the second corner of the source rectangle.
970
						image.getHeight(),	//sy2 - the y coordinate of the second corner of the source rectangle.
971
						null	//observer - object to be notified as more of the image is scaled and converted.
972
						);
973
						
974
			// Draw Identifiers
975
			if (points == null)
976
				return;
977
			g.setColor(Color.RED);
978
			((Graphics2D)g).setStroke(new BasicStroke(2));
979
			for (int i = 0; i < points.length; i++) {
980
				g.drawOval(points[i].x - BOT_RADIUS, points[i].y - BOT_RADIUS, 2*BOT_RADIUS, 2*BOT_RADIUS);
981
			}
982
			
742
		public synchronized void displayTokenPasses () {
743
			lblTokenPasses.setText("" + tokenPasses);
744
			tokenPasses = 0;
983 745
		}
984 746
	
985 747
	}
986 748
	
987 749
	/*
988
	*	WebcamLoader class
989
	*	Handles the loading of the webcam image.
750
	*	DataListener thread.
751
	*
990 752
	*/
991
	class WebcamLoader extends Thread 
992
	{
993
		final int WEBCAMLOADER_DELAY = 1000;
994
		final String IMAGE_PATH = "http://roboclub9.frc.ri.cmu.edu/colonet.jpg";
995
		final String LOCATIONS_PATH = "http://roboclub9.frc.ri.cmu.edu/colonet/locations.txt";
753
	class DataListener extends Thread {
754
		final int DATALISTENER_DELAY = 666;
755
		BufferedReader reader;
996 756
		
997
		URL imagePath;
998
		URI locationsPath;
999
		
1000
		MediaTracker mt;
1001
		BufferedImage image;
1002
		
1003
		public WebcamLoader (JApplet applet)
1004
		{
1005
			super("ColonetWebcamLoader");
1006
			mt = new MediaTracker(applet);
1007
			ImageIO.setUseCache(false);
1008
			try {
1009
				imagePath = new URL(IMAGE_PATH);
1010
			} catch (MalformedURLException e) {
1011
				System.out.println("Malformed URL: could not form URL from: [" + IMAGE_PATH + "]\n");
1012
			}
1013
			try {
1014
				locationsPath = new URI(LOCATIONS_PATH);
1015
			} catch (URISyntaxException x) {
1016
				System.out.println("Malformed URI: could not form URI from: [" + LOCATIONS_PATH + "]\n");
1017
			}
1018
			
757
		public DataListener () {
758
			super("Colonet DataListener");
1019 759
		}
1020 760
		
1021
		public synchronized void run ()
1022
		{
761
		public void run () {
762
			String line;
1023 763
			while (true) {
1024 764
				try {
1025
					Thread.sleep(WEBCAMLOADER_DELAY);
1026
					if (image != null) 
1027
						image.flush();
1028
					System.gc();
1029
					image = ImageIO.read(imagePath);
1030
					// The MediaTracker waitForID pauses the thread until the image is loaded.
1031
					// We don't want to display a half-downloaded image.
1032
					mt.addImage(image, 1);
1033
					mt.waitForID(1);
1034
					mt.removeImage(image);
1035
					// Save
1036
					panelWebcam.setImage(image);
1037
					parseLocations(locationsPath.toURL());
765
					if (csi == null) return;
766
					line = csi.getLine();
767
					if (line != null) {
768
						csi.msg("Incoming data: [" + line + "]");
769
						//TODO: parse incoming data here
770
					}
771
					Thread.sleep(DATALISTENER_DELAY);
1038 772
				} catch (InterruptedException e) {
1039 773
					return;
1040
				} catch (java.security.AccessControlException e) {
1041
					csi.warn("java.security.AccessControlException in WebcamLoader.\n" + 
1042
						"The image cannot be loaded from the specified location.\n" + 
1043
						"Make sure you are accessing this applet from the correct server.");
1044
					return;
1045
				} catch (IOException e) {
1046
					log.append("IOException while trying to load image.");
1047
				}
774
				} 
1048 775
			}
1049 776
		}
1050
		
1051
		private void parseLocations (URL url) {
1052
			URLConnection conn = null;
1053
			DataInputStream data = null;
1054
			String line;
1055
			String [] lines = new String[30];
1056
			StringBuffer buf = new StringBuffer();
1057
			int i = 0;
1058
		
1059
			try {
1060
				conn = url.openConnection();
1061
				conn.connect();
1062
				data = new DataInputStream(new BufferedInputStream(conn.getInputStream()));
1063
				while ((line = data.readLine()) != null) {
1064
					buf.append(line + ";");
1065
					lines[i] = line;
1066
					i++;
1067
				}
1068
				data.close();
1069
			} catch (IOException e) {
1070
				System.out.println("IOException:" + e.getMessage());
1071
			}
1072
			//log.append("Got robot locations: " + buf + "\n");
1073
			
1074
			// Get Point values from strings
1075
			Point [] points = new Point[i];
1076
			for (int j = 0; j < i; j++) {
1077
				String [] parts = lines[j].split(",");
1078
				int xval = Integer.parseInt(parts[0]);
1079
				int yval = Integer.parseInt(parts[1]);
1080
				Point p = new Point(xval, yval);
1081
				points[j] = p;
1082
			}
1083
			if (points.length != 0)
1084
				panelWebcam.setPoints(points);
1085
			
1086
		}
777

  
1087 778
	}
1088 779

  
1089
	
1090
	/*
1091
	*	VectorController class
1092
	*	Manages robot motion control graphically
1093
	*/
1094
	class VectorController extends GraphicsPanel {
1095
		int x, y, cx, cy;
1096
		int width, height;
1097
		int side;
1098
		
1099
		public VectorController (Image img) {
1100
			super (img);
1101
			width = img.getWidth(null);
1102
			height = img.getHeight(null);
1103
			cx = img.getWidth(null)/2;
1104
			cy = img.getHeight(null)/2;
1105
			x = cx;
1106
			y = cy;
1107
			if (width < height)
1108
				side = width;
1109
			else
1110
				side = height;
1111
		}
1112
		
1113
		public void setPoint (int x, int y) {
1114
			if (!isValidPoint(x, y))
1115
				return;
1116
			this.x = x;
1117
			this.y = y;
1118
			repaint();
1119
		}
1120
		
1121
		public boolean isValidPoint (int x, int y) {
1122
			double xterm = Math.pow(1.0*(x - cx)/(side/2), 2);
1123
			double yterm = Math.pow(1.0*(y - cy)/(side/2), 2);
1124
			return (xterm + yterm <= 1);
1125
		}
1126
		
1127
		public void notifyMouseEvent (MouseEvent e, boolean send) {
1128
			if (!isValidPoint(e.getX(), e.getY()))
1129
				return;
1130
			vectorController.setPoint(e.getX(), e.getY());
1131
			vectorController.repaint();
1132
			if (send)
1133
				vectorController.sendToServer();
1134
		}
1135
		
1136
		public int getSpeed () {
1137
			int dx = x - cx;
1138
			int dy = y - cy;
1139
			int v = (int) Math.sqrt( Math.pow(dx, 2) + Math.pow(dy, 2) );
1140
			return v;
1141
		}
1142
		
1143
		public int getAngle () {
1144
			int dx = x - cx;
1145
			int dy = cy - y;
1146
			double theta = Math.atan2(Math.abs(dx), Math.abs(dy));
1147
			theta = (int) (1.0 * theta * 180 / Math.PI);  //transform to degrees
1148
			if (dy < 0)
1149
				theta = 180 - theta;
1150
			theta *= Math.signum(dx);
1151
			return (int) theta;
1152
		}
1153
		
1154
		public void paint (Graphics g) {
1155
			g.setColor(Color.BLACK);
1156
			g.fillRect(0, 0, width, height);
1157
			((Graphics2D)g).setStroke(new BasicStroke(1));
1158
			g.setColor(Color.RED);
1159
			g.drawOval(cx-side/2, cy-side/2, side, side);
1160
			((Graphics2D)g).setStroke(new BasicStroke(2));
1161
			g.setColor(Color.GREEN);
1162
			g.drawLine(cx, cy, x, y);
1163
			g.fillOval(x-3, y-3, 6, 6);
1164
		}
1165
		
1166
		public void setMaxForward () {
1167
			setPoint(cx, cy - (side/2) + 1);
1168
		}
1169
		
1170
		public void setMaxReverse () {
1171
			setPoint(cx, cy + (side/2) - 1);
1172
		}
1173
		
1174
		public void setMaxLeft () {
1175
			setPoint(cx - (side/2) + 1, cy);
1176
		}
1177
		
1178
		public void setMaxRight () {
1179
			setPoint(cx + (side/2) - 1, cy);
1180
		}
1181
		
1182
		public void setZero () {
1183
			setPoint(cx, cy);
1184
		}
1185
		
1186
		public void sendToServer () {
1187
			//log.append("Attempitng to send angle = " + vectorController.getAngle() + ", velocity = " + vectorController.getVelocity() + "\n");
1188
			String dest = ColonetServerInterface.GLOBAL_DEST;
1189
			if (cmbRobotNum != null && cmbRobotNum.getSelectedIndex() > 0)
1190
				dest = "" + (cmbRobotNum.getSelectedIndex()-1);
1191
			
1192
			if (csi != null) {
1193
				if (cx == 0 && cy == 0) {
1194
					csi.sendData(ColonetServerInterface.MOTORS_OFF, dest);
1195
				} else {
1196
					//Directional commands
1197
					/*
1198
					if (x > cx && y == cy) {  //move right
1199
						csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", dest);
1200
						csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", dest);
1201
					} else if (x < cx && y == cy) {  //move left
1202
						csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", dest);
1203
						csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", dest);
1204
					} else if (x == cx && y > cy) {  //move forward
1205
						csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 225", dest);
1206
						csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 225", dest);
1207
					} else if (x == cx && y < cy) {  //move backward
1208
						csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 225", dest);
1209
						csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 225", dest);
1210
					} else if (x == cx && y == cy) {  //stop!
1211
						csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 0", dest);
1212
						csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 0", dest);
1213
					}
1214
					*/
1215
					
1216
				}
1217
			}
1218
				
1219
			//The move command doesn't really work...or does it?
1220
			csi.sendData(ColonetServerInterface.MOVE + " " + 
1221
				vectorController.getSpeed() + " " + 
1222
				vectorController.getAngle(), dest);
1223
				
1224
			
1225
		}
1226
	
780
	class BatteryIcon implements Icon{
781
		private int width;
782
	    private int height;
783
	    private int level;
784
	    
785
	    public BatteryIcon(){
786
	    	width = 100;
787
	    	height =100;
788
	    	level = 100;
789
	    }
790
	    
791
	    public BatteryIcon(int startLevel){
792
	    	width = 50;
793
	    	height = 50;
794
	    	level = startLevel;
795
	    }
796
	    
797
	    public BatteryIcon(int startLevel, int w, int h){
798
	    	level = startLevel;
799
	    	width = w;
800
	    	height = h;
801
	    }
802
	    
803
	    public void paintIcon(Component c, Graphics g, int x, int y) {
804
	        Graphics2D g2d = (Graphics2D) g.create();
805
	        //background
806
	        g2d.setColor(Color.WHITE);
807
	        g2d.fillRect(x +1 ,y + 1,width-2,height-2);
808
	        //outline
809
	        g2d.setColor(Color.BLACK);
810
	        g2d.drawRect((int)(x + width*.3) ,y + 2,(int)(width*.4),height -4);
811
	        //battery life rectangle
812
	        g2d.setColor(Color.GREEN);
813
	        int greenX = (int)(x + 1 + width*.3);
814
	        int greenY = (int)((y+3) + Math.abs(level-100.0)*(height-6)/(100));
815
	        int greenWidth = (int)(width*.4 - 2)+1;
816
	        int greenHeight = 1+(int)(level-0.0)*(height-6)/(100);
817
	        g2d.fillRect(greenX, greenY, greenWidth, greenHeight);
818
	        //text
819
	        g2d.setColor(Color.BLACK);
820
	        g2d.drawString(level + "%", greenX + greenWidth/2 - 10, greenY + greenHeight/2 + 5);
821
	        
822
	        g2d.dispose();
823
	    }
824
	    
825
	    public void setLevel(int newLevel){
826
	    	level = newLevel;
827
	    }
828
	    
829
	    public int getIconWidth() {
830
	        return width;
831
	    }
832
	    
833
	    public int getIconHeight() {
834
	        return height;
835
	    }
1227 836
	}
1228 837
	
1229
	/*
1230
	*	TaskAddWindow class
1231
	*	makes it easy to add tasks to the queue
1232
	*/
1233
	class TaskAddWindow extends JFrame implements ActionListener, ListSelectionListener {
1234
		JPanel panelButtons;
1235
		JPanel panelParameters;
1236
		JPanel panelSouth;
1237
		JPanel panelSelection;
1238
		JButton btnSubmit;
1239
		JButton btnCancel;
1240
		DefaultListModel availableListModel;
1241
		JList availableList;
1242
		JScrollPane spAvailableTasks;
1243
		JTextArea txtDescription;
1244
		JTextField txtParameters;
1245
		MouseListener mouseListener;
1246
		
1247
		public TaskAddWindow () {
1248
			super("Add a Task");
1249
			super.setSize(500,500);
1250
			super.setLayout(new BorderLayout());
1251
			
1252
			// set up buttons
1253
			btnSubmit = new JButton("Submit");
1254
			btnCancel = new JButton("Cancel");
1255
			panelButtons = new JPanel();
1256
			panelButtons.setLayout(new FlowLayout());
1257
			panelButtons.add(btnSubmit);
1258
			panelButtons.add(btnCancel);
1259
			this.getRootPane().setDefaultButton(btnSubmit);
1260
			
1261
			// set up task list
1262
			availableListModel = new DefaultListModel();
1263
			availableListModel.addElement("Map the Environment");
1264
			availableListModel.addElement("Clean Up Chemical Spill");
1265
			availableListModel.addElement("Grow Plants");
1266
			availableListModel.addElement("Save the Cheerleader");
1267
			availableListModel.addElement("Save the World");
1268
			availableList = new JList(availableListModel);
1269
			availableList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
1270
			availableList.setSelectedIndex(-1);
1271
			spAvailableTasks = new JScrollPane(availableList);
1272
			spAvailableTasks.setBorder(BorderFactory.createTitledBorder("Select A Task"));
1273
			txtDescription = new JTextArea();
1274
			txtDescription.setEditable(false);
1275
			txtDescription.setLineWrap(true);
1276
			txtDescription.setWrapStyleWord(true);
1277
			txtDescription.setBorder(BorderFactory.createTitledBorder("Description"));
1278
			
1279
			//set up parameter area
1280
			panelParameters = new JPanel();
1281
			panelParameters.setLayout(new BorderLayout());
1282
			txtParameters = new JTextField();
1283
			panelParameters.add(new JLabel("Optional parameters for this task: "), BorderLayout.WEST);
1284
			panelParameters.add(txtParameters);
1285
			
1286
			// assemble objects
1287
			panelSelection = new JPanel();
1288
			panelSelection.setLayout(new GridLayout(1,2));
1289
			panelSelection.add(spAvailableTasks);
1290
			panelSelection.add(txtDescription);
1291
			
1292
			panelSouth = new JPanel();
1293
			panelSouth.setLayout(new GridLayout(2,1));
1294
			panelSouth.add(panelParameters);
1295
			panelSouth.add(panelButtons);
1296
			
1297
			this.getContentPane().add(panelSouth, BorderLayout.SOUTH);
1298
			this.getContentPane().add(panelSelection, BorderLayout.CENTER);
1299
			this.setLocationRelativeTo(null);
1300
			
1301
			// add listeners here
1302
			availableList.addListSelectionListener(this);
1303
			btnSubmit.addActionListener(this);
1304
			btnCancel.addActionListener(this);
1305
		}
1306
		
1307
		public void prompt () {
1308
			this.setVisible(true);
1309
		}
1310
		
1311
		private String getDescription (int index) {
1312
			if (index < 0)
1313
				return "";
1314
			switch (index) {
1315
				case 0: return "SLAM and junk";
1316
				case 1: return "I'm not sure this works";
1317
				case 2: return "Push them into the light";
1318
				case 3: return "Watch out for clock repair guys";
1319
				case 4: return "But make sure he's dead, geez, why would you let him get away? I mean come on, "
1320
					+"he's just lying there and everyone's too busy looking at people flying through the sky to "
1321
					+"notice? Oh yeah, that's a good transition to a new season, let's make the audience think "
1322
					+"he's dead and then pull a fast one on them, they'll never see that coming.";
1323
			
1324
				default: return "Task not recognized";
1325
			}
1326
		}
1327
		
1328
		public void actionPerformed (ActionEvent e) {
1329
			Object source = e.getSource();
1330
			if (source == btnSubmit) {
1331
				txtParameters.setText(txtParameters.getText().trim());
1332
				
1333
				
1334
				this.setVisible(false);
1335
			} else if (source == btnCancel) {
1336
				this.setVisible(false);
1337
			}
1338
		}
1339
		
1340
		public void valueChanged (ListSelectionEvent e) {
1341
			int index = availableList.getSelectedIndex();
1342
			if (index >= 0)
1343
				txtDescription.setText(getDescription(index));
1344
		}
1345
	
1346
	}
1347 838

  
1348 839
}

Also available in: Unified diff