root / trunk / code / projects / colonet / ColonetGUI / Colonet.java @ 168
History | View | Annotate | Download (31.3 KB)
1 | 32 | gtress | //
|
---|---|---|---|
2 | // Colonet.java
|
||
3 | //
|
||
4 | |||
5 | import javax.swing.*; |
||
6 | 136 | gtress | import javax.swing.event.*; |
7 | 32 | gtress | import java.awt.*; |
8 | import java.awt.image.*; |
||
9 | import java.awt.event.*; |
||
10 | import java.net.*; |
||
11 | import java.io.*; |
||
12 | import java.util.Random; |
||
13 | import java.applet.*; |
||
14 | |||
15 | 136 | gtress | public class Colonet extends JApplet implements ActionListener, MouseInputListener, Runnable { |
16 | 32 | gtress | |
17 | 155 | gtress | final int CANVAS_SIZE = 500; //the applet may be slow if the canvas gets too large |
18 | 32 | gtress | final int BUFFER = 50; |
19 | final int RADIUS = 30; |
||
20 | |||
21 | // Connection
|
||
22 | JTextField txtHost;
|
||
23 | JTextField txtPort;
|
||
24 | JButton btnConnect;
|
||
25 | JButton btnGraph;
|
||
26 | JLabel lblConnectionStatus;
|
||
27 | 76 | gtress | JTextArea txtMatrix;
|
28 | 32 | gtress | JTextArea txtInfo;
|
29 | JPanel panelConnect;
|
||
30 | JPanel panelServerInterface;
|
||
31 | |||
32 | // Stats
|
||
33 | JLabel lblBattery;
|
||
34 | JLabel lblTokenPasses;
|
||
35 | JLabel lblHastToken;
|
||
36 | JPanel panelStats;
|
||
37 | |||
38 | // South
|
||
39 | JPanel panelSouth;
|
||
40 | JTextArea log;
|
||
41 | JScrollPane spLog;
|
||
42 | |||
43 | // Control
|
||
44 | JPanel panelControl;
|
||
45 | JTabbedPane tabPaneControl;
|
||
46 | JPanel panelRobotControl;
|
||
47 | JPanel panelRobotDirection;
|
||
48 | 136 | gtress | JPanel panelRobotDirectionButtons;
|
49 | 32 | gtress | JPanel panelRobotCommands;
|
50 | JButton btnF, btnB, btnL, btnR, btnActivate;
|
||
51 | 67 | gtress | JComboBox cmbRobotNum;
|
52 | 136 | gtress | VectorController vectorController; |
53 | BufferedImage imageVectorControl;
|
||
54 | 168 | gtress | JButton btnCommand_StopTask;
|
55 | JButton btnCommand_ResumeTask;
|
||
56 | 32 | gtress | |
57 | // Task Manager
|
||
58 | JPanel panelTaskManager;
|
||
59 | JScrollPane spTaskManager;
|
||
60 | JPanel panelTaskManagerControls;
|
||
61 | JPanel panelTaskManagerControlsPriority;
|
||
62 | DefaultListModel taskListModel;
|
||
63 | JList taskList;
|
||
64 | JButton btnAddTask;
|
||
65 | JButton btnRemoveTask;
|
||
66 | JButton btnMoveTaskUp;
|
||
67 | JButton btnMoveTaskDown;
|
||
68 | 136 | gtress | JButton btnUpdateTasks;
|
69 | TaskAddWindow taskAddWindow; |
||
70 | 32 | gtress | |
71 | // Graphics
|
||
72 | 136 | gtress | ImagePanel panel; |
73 | 32 | gtress | GraphicsConfiguration gc;
|
74 | volatile BufferedImage image; |
||
75 | volatile Graphics2D canvas; |
||
76 | int cx, cy;
|
||
77 | |||
78 | Socket socket;
|
||
79 | 136 | gtress | OutputStreamWriter out;
|
80 | 76 | gtress | DataUpdater dataUpdater; |
81 | 32 | gtress | |
82 | Font botFont;
|
||
83 | Random random = new Random(); |
||
84 | volatile int tokenLoc; //the token is currently here |
||
85 | volatile int numBots; |
||
86 | volatile int selectedBot; //the user has selected this bot |
||
87 | volatile Rectangle[] botRect; //contains boundary shapes around bots for click detection |
||
88 | 136 | gtress | volatile int[] xbeeID; |
89 | 32 | gtress | |
90 | Thread drawThread;
|
||
91 | 76 | gtress | Simulator simulator; |
92 | 32 | gtress | SelectionIndicator indicator; |
93 | PacketMonitor packetMonitor; |
||
94 | 35 | gtress | ColonetServerInterface csi; |
95 | 32 | gtress | |
96 | |||
97 | public void init () { |
||
98 | 136 | gtress | // set the default look and feel - choose one
|
99 | //String laf = UIManager.getSystemLookAndFeelClassName();
|
||
100 | 155 | gtress | String laf = UIManager.getCrossPlatformLookAndFeelClassName(); |
101 | //String laf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
|
||
102 | 32 | gtress | try {
|
103 | UIManager.setLookAndFeel(laf);
|
||
104 | } catch (UnsupportedLookAndFeelException exc) { |
||
105 | System.err.println ("Warning: UnsupportedLookAndFeel: " + laf); |
||
106 | } catch (Exception exc) { |
||
107 | System.err.println ("Error loading " + laf + ": " + exc); |
||
108 | } |
||
109 | // We should invoke and wait to avoid browser display difficulties
|
||
110 | Runnable r = new Runnable() { |
||
111 | public void run() { |
||
112 | createAndShowGUI(); |
||
113 | } |
||
114 | }; |
||
115 | try {
|
||
116 | SwingUtilities.invokeAndWait(r);
|
||
117 | } catch (InterruptedException e) { |
||
118 | //Not really sure why we would be in this situation
|
||
119 | System.out.println(e);
|
||
120 | } catch (java.lang.reflect.InvocationTargetException e) {
|
||
121 | 136 | gtress | //This could happen for various reasons if there is a problem in createAndShowGUI
|
122 | e.printStackTrace(); |
||
123 | 32 | gtress | } |
124 | } |
||
125 | |||
126 | public void destroy () { |
||
127 | try { drawThread.interrupt(); } catch (Exception e) { } |
||
128 | try { indicator.interrupt(); } catch (Exception e) { } |
||
129 | try { packetMonitor.interrupt(); } catch (Exception e) { } |
||
130 | } |
||
131 | |||
132 | private synchronized void createAndShowGUI () { |
||
133 | // init graphical elements
|
||
134 | 136 | gtress | // Get the graphics configuration of the screen to create a buffer
|
135 | gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
|
||
136 | .getDefaultScreenDevice().getDefaultConfiguration(); |
||
137 | image = gc.createCompatibleImage(CANVAS_SIZE,CANVAS_SIZE); |
||
138 | canvas = image.createGraphics(); |
||
139 | canvas.setStroke(new BasicStroke(2)); //set pen width |
||
140 | panel = new ImagePanel(false, image); //set automatic double-buffering to false. we are doing it manually. |
||
141 | 32 | gtress | |
142 | 136 | gtress | // Calculate center of canvas
|
143 | cx = image.getWidth() / 2;
|
||
144 | cy = image.getHeight() / 2;
|
||
145 | |||
146 | botFont = new Font("Arial", Font.PLAIN, 14); |
||
147 | tokenLoc = 0;
|
||
148 | numBots = 0;
|
||
149 | selectedBot = 0;
|
||
150 | |||
151 | 32 | gtress | // Connection area
|
152 | 136 | gtress | txtMatrix = new JTextArea(); |
153 | 76 | gtress | txtMatrix.setBorder(BorderFactory.createTitledBorder("Input Matrix")); |
154 | 32 | gtress | txtInfo = new JTextArea(); |
155 | txtInfo.setBorder(BorderFactory.createTitledBorder("Info")); |
||
156 | txtInfo.setEditable(false);
|
||
157 | btnGraph = new JButton("Run"); |
||
158 | 155 | gtress | txtHost = new JTextField("roboclub9.frc.ri.cmu.edu"); |
159 | 32 | gtress | txtHost.setBorder(BorderFactory.createTitledBorder("Host")); |
160 | txtPort = new JTextField("10123"); |
||
161 | txtPort.setBorder(BorderFactory.createTitledBorder("Port")); |
||
162 | btnConnect = new JButton("Connect"); |
||
163 | lblConnectionStatus = new JLabel("Status: Offline"); |
||
164 | panelConnect = new JPanel(); |
||
165 | panelConnect.setLayout(new GridLayout(6,1)); |
||
166 | panelConnect.add(lblConnectionStatus); |
||
167 | panelConnect.add(txtHost); |
||
168 | panelConnect.add(txtPort); |
||
169 | panelConnect.add(btnConnect); |
||
170 | panelConnect.add(txtInfo); |
||
171 | panelConnect.add(btnGraph); |
||
172 | panelServerInterface = new JPanel(); |
||
173 | panelServerInterface.setLayout(new GridLayout(2,1)); |
||
174 | panelServerInterface.add(panelConnect); |
||
175 | 76 | gtress | panelServerInterface.add(txtMatrix); |
176 | 32 | gtress | |
177 | // Status Elements
|
||
178 | lblTokenPasses = new JLabel(); |
||
179 | lblBattery = new JLabel("???"); |
||
180 | panelStats = new JPanel(); |
||
181 | panelStats.setLayout(new GridLayout(4,2)); |
||
182 | panelStats.add(new JLabel("Token Passes / sec ")); |
||
183 | panelStats.add(lblTokenPasses); |
||
184 | panelStats.add(new JLabel("Battery ")); |
||
185 | panelStats.add(lblBattery); |
||
186 | panelStats.add(new JLabel("Token Passes / sec ")); |
||
187 | panelStats.add(lblTokenPasses); |
||
188 | |||
189 | 72 | gtress | //TODO: add panelStats somewhere?
|
190 | 32 | gtress | |
191 | // Robot direction panel
|
||
192 | panelRobotDirection = new JPanel(); |
||
193 | 136 | gtress | panelRobotDirectionButtons = new JPanel(); |
194 | 32 | gtress | btnF = new JButton("^"); |
195 | btnB = new JButton("v"); |
||
196 | btnL = new JButton("<"); |
||
197 | btnR = new JButton(">"); |
||
198 | btnActivate = new JButton("o"); |
||
199 | 136 | gtress | panelRobotDirectionButtons.setLayout(new GridLayout(1,5)); |
200 | panelRobotDirectionButtons.add(btnActivate); |
||
201 | panelRobotDirectionButtons.add(btnF); |
||
202 | panelRobotDirectionButtons.add(btnB); |
||
203 | panelRobotDirectionButtons.add(btnL); |
||
204 | panelRobotDirectionButtons.add(btnR); |
||
205 | 32 | gtress | |
206 | 136 | gtress | imageVectorControl = gc.createCompatibleImage(380, 210); |
207 | vectorController = new VectorController(imageVectorControl);
|
||
208 | panelRobotDirection.setLayout(new BorderLayout()); |
||
209 | panelRobotDirection.add(vectorController, BorderLayout.CENTER);
|
||
210 | panelRobotDirection.add(panelRobotDirectionButtons, BorderLayout.SOUTH);
|
||
211 | |||
212 | 32 | gtress | // Robot Control and Commands
|
213 | panelRobotCommands = new JPanel(); |
||
214 | panelRobotCommands.setLayout(new FlowLayout()); |
||
215 | 67 | gtress | cmbRobotNum = new JComboBox(); |
216 | panelRobotCommands.add(cmbRobotNum); |
||
217 | 32 | gtress | panelRobotCommands.add(new JLabel("Commands go here")); |
218 | panelRobotControl = new JPanel(); |
||
219 | panelRobotControl.setLayout(new GridLayout(2,1)); |
||
220 | panelRobotControl.add(panelRobotDirection); |
||
221 | panelRobotControl.add(panelRobotCommands); |
||
222 | |||
223 | // Task Manager
|
||
224 | panelTaskManager = new JPanel(); |
||
225 | panelTaskManager.setLayout(new BorderLayout()); |
||
226 | taskListModel = new DefaultListModel(); |
||
227 | taskList = new JList(taskListModel); |
||
228 | taskList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||
229 | taskList.setSelectedIndex(0);
|
||
230 | spTaskManager = new JScrollPane(taskList); |
||
231 | panelTaskManagerControls = new JPanel(); |
||
232 | 136 | gtress | panelTaskManagerControls.setLayout(new GridLayout(1,4)); |
233 | 32 | gtress | panelTaskManagerControlsPriority = new JPanel(); |
234 | panelTaskManagerControlsPriority.setLayout(new GridLayout(1,2)); |
||
235 | btnAddTask = new JButton("Add..."); |
||
236 | btnRemoveTask = new JButton("Remove"); |
||
237 | btnMoveTaskUp = new JButton("^"); |
||
238 | btnMoveTaskDown = new JButton("v"); |
||
239 | 136 | gtress | btnUpdateTasks = new JButton("Update"); |
240 | 32 | gtress | panelTaskManagerControlsPriority.add(btnMoveTaskUp); |
241 | panelTaskManagerControlsPriority.add(btnMoveTaskDown); |
||
242 | panelTaskManagerControls.add(btnAddTask); |
||
243 | panelTaskManagerControls.add(btnRemoveTask); |
||
244 | 136 | gtress | panelTaskManagerControls.add(btnUpdateTasks); |
245 | 32 | gtress | panelTaskManagerControls.add(panelTaskManagerControlsPriority); |
246 | panelTaskManager.add(spTaskManager, BorderLayout.CENTER);
|
||
247 | panelTaskManager.add(panelTaskManagerControls, BorderLayout.SOUTH);
|
||
248 | panelTaskManager.add(new JLabel("Current Task Queue"), BorderLayout.NORTH); |
||
249 | |||
250 | 136 | gtress | // Task Manager Add Window
|
251 | taskAddWindow = new TaskAddWindow();
|
||
252 | |||
253 | 32 | gtress | // Message log
|
254 | log = new JTextArea(); |
||
255 | spLog = new JScrollPane(log, |
||
256 | ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
|
||
257 | ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||
258 | spLog.setBorder(BorderFactory.createTitledBorder("Log")); |
||
259 | spLog.setPreferredSize(new Dimension(0, 150)); |
||
260 | log.setEditable(false);
|
||
261 | |||
262 | // Main control mechanism
|
||
263 | panelControl = new JPanel(); |
||
264 | panelControl.setLayout(new GridLayout(1,1)); |
||
265 | tabPaneControl = new JTabbedPane(JTabbedPane.TOP); |
||
266 | 136 | gtress | tabPaneControl.setPreferredSize(new Dimension(400, 0)); |
267 | 32 | gtress | tabPaneControl.addTab("Connection", panelServerInterface);
|
268 | tabPaneControl.addTab("Robots", panelRobotControl);
|
||
269 | tabPaneControl.addTab("Tasks", panelTaskManager);
|
||
270 | panelControl.add(tabPaneControl); |
||
271 | |||
272 | // Set up elements in the south
|
||
273 | panelSouth = new JPanel(); |
||
274 | panelSouth.setLayout(new GridLayout(1,2)); |
||
275 | panelSouth.add(spLog); |
||
276 | |||
277 | this.getContentPane().setLayout(new BorderLayout()); |
||
278 | this.getContentPane().add(panel, BorderLayout.CENTER); |
||
279 | this.getContentPane().add(panelSouth, BorderLayout.SOUTH); |
||
280 | this.getContentPane().add(panelControl, BorderLayout.EAST); |
||
281 | this.setVisible(true); |
||
282 | |||
283 | 72 | gtress | /* Add all listeners here */
|
284 | // Task Management
|
||
285 | 32 | gtress | btnAddTask.addActionListener(this);
|
286 | btnRemoveTask.addActionListener(this);
|
||
287 | btnMoveTaskUp.addActionListener(this);
|
||
288 | btnMoveTaskDown.addActionListener(this);
|
||
289 | 136 | gtress | btnUpdateTasks.addActionListener(this);
|
290 | 72 | gtress | // Robot Control
|
291 | btnF.addActionListener(this);
|
||
292 | btnB.addActionListener(this);
|
||
293 | btnL.addActionListener(this);
|
||
294 | btnR.addActionListener(this);
|
||
295 | btnActivate.addActionListener(this);
|
||
296 | 136 | gtress | vectorController.addMouseMotionListener(this);
|
297 | vectorController.addMouseListener(this);
|
||
298 | 72 | gtress | // Other
|
299 | 32 | gtress | btnGraph.addActionListener(this);
|
300 | btnConnect.addActionListener(this);
|
||
301 | panel.addMouseListener(this);
|
||
302 | 136 | gtress | this.addMouseMotionListener(this); |
303 | 32 | gtress | |
304 | 136 | gtress | |
305 | 32 | gtress | // Set up dependent threads
|
306 | indicator = new SelectionIndicator(canvas);
|
||
307 | indicator.setRadius(RADIUS+3, 15); //a tad more than the bot radius |
||
308 | packetMonitor = new PacketMonitor();
|
||
309 | 76 | gtress | simulator = new Simulator();
|
310 | 35 | gtress | |
311 | 136 | gtress | csi = new ColonetServerInterface(this); |
312 | 32 | gtress | |
313 | } |
||
314 | |||
315 | 35 | gtress | public synchronized void paint (Graphics g) { |
316 | 136 | gtress | /* Redraw the graphical components in the applet.
|
317 | 32 | gtress | This paint method overrides the built-in paint of the
|
318 | JApplet, and we don't want to deal with redrawing the
|
||
319 | components manually. Fuck that shit. */
|
||
320 | 136 | gtress | step(); |
321 | 32 | gtress | super.paint(g);
|
322 | } |
||
323 | |||
324 | 35 | gtress | public synchronized void update (Graphics g) { |
325 | 32 | gtress | paint(g); |
326 | } |
||
327 | |||
328 | 35 | gtress | public void actionPerformed (ActionEvent e) { |
329 | 32 | gtress | Object source = e.getSource();
|
330 | if (source == btnGraph) {
|
||
331 | btnGraph.setEnabled(false);
|
||
332 | //Start dependent threads
|
||
333 | drawThread = new Thread(this, "drawThread"); |
||
334 | drawThread.start(); |
||
335 | indicator.start(); |
||
336 | packetMonitor.start(); |
||
337 | 76 | gtress | simulator.start(); |
338 | 32 | gtress | } else if (source == btnConnect) { |
339 | 155 | gtress | csi.connect(txtHost.getText(), txtPort.getText()); |
340 | 76 | gtress | dataUpdater = new DataUpdater();
|
341 | dataUpdater.start(); |
||
342 | 136 | gtress | } |
343 | // Robot Movement Controls
|
||
344 | else if (source == btnF) { |
||
345 | vectorController.setMaxForward(); |
||
346 | vectorController.sendToServer(); |
||
347 | 72 | gtress | } else if (source == btnB) { |
348 | 136 | gtress | vectorController.setMaxReverse(); |
349 | vectorController.sendToServer(); |
||
350 | 72 | gtress | } else if (source == btnL) { |
351 | 136 | gtress | vectorController.setMaxLeft(); |
352 | vectorController.sendToServer(); |
||
353 | 72 | gtress | } else if (source == btnR) { |
354 | 136 | gtress | vectorController.setMaxRight(); |
355 | vectorController.sendToServer(); |
||
356 | 72 | gtress | } else if (source == btnActivate) { |
357 | 136 | gtress | vectorController.setZero(); |
358 | vectorController.sendToServer(); |
||
359 | } |
||
360 | 107 | gtress | |
361 | // Queue Management
|
||
362 | 136 | gtress | else if (source == btnAddTask) { |
363 | taskAddWindow.prompt(); |
||
364 | 107 | gtress | } else if (source == btnRemoveTask) { |
365 | 136 | gtress | if (taskList.getSelectedIndex() >= 0); |
366 | csi.sendQueueRemove(taskList.getSelectedIndex()); |
||
367 | csi.sendQueueUpdate(); |
||
368 | 107 | gtress | } else if (source == btnMoveTaskUp) { |
369 | 136 | gtress | csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() - 1);
|
370 | csi.sendQueueUpdate(); |
||
371 | 107 | gtress | } else if (source == btnMoveTaskDown) { |
372 | 136 | gtress | csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() + 1);
|
373 | csi.sendQueueUpdate(); |
||
374 | } else if (source == btnUpdateTasks) { |
||
375 | csi.sendQueueUpdate(); |
||
376 | 32 | gtress | } |
377 | } |
||
378 | |||
379 | 35 | gtress | private void randomize () { |
380 | 32 | gtress | Random r = new Random(); |
381 | StringBuilder s = new StringBuilder(); |
||
382 | |||
383 | int count = r.nextInt(8) + 1; |
||
384 | 35 | gtress | for (int i = 0; i < count; i++) { |
385 | for (int j = 0; j < count; j++) { |
||
386 | 32 | gtress | if (r.nextBoolean())
|
387 | s.append("" + (r.nextInt(16) + 1)); |
||
388 | else
|
||
389 | s.append("-");
|
||
390 | if (j != count-1) |
||
391 | s.append(" ");
|
||
392 | } |
||
393 | if (i != count-1) s.append("\n"); |
||
394 | } |
||
395 | |||
396 | 76 | gtress | txtMatrix.setText(s.toString()); |
397 | 32 | gtress | } |
398 | |||
399 | 35 | gtress | public void drawRobot (int id, int x, int y) { |
400 | 32 | gtress | //save the bot in memory, so we can tell if we click on it later
|
401 | botRect[id] = new Rectangle(x-RADIUS, y-RADIUS, 2*RADIUS, 2*RADIUS); |
||
402 | |||
403 | //draw the bot on the canvas
|
||
404 | canvas.setColor(Color.BLACK);
|
||
405 | canvas.drawOval(x-RADIUS, y-RADIUS, RADIUS*2, RADIUS*2); |
||
406 | |||
407 | //draw the label
|
||
408 | canvas.setFont(botFont); |
||
409 | 136 | gtress | try {
|
410 | canvas.drawString("" + xbeeID[id], x-20, y+2); |
||
411 | } catch (Exception e) { |
||
412 | canvas.drawString("???", x-22, y+2); |
||
413 | } |
||
414 | 32 | gtress | } |
415 | |||
416 | 35 | gtress | public void drawConnection (int start, int end, int radius, Color color) { |
417 | 32 | gtress | final int ARROW_LENGTH = 18; |
418 | |||
419 | double angle = 2.0 * Math.PI / numBots; |
||
420 | int startx, starty, endx, endy;
|
||
421 | startx = cx - (int)(radius * Math.cos(start * angle)); |
||
422 | starty = cy - (int)(radius * Math.sin(start * angle)); |
||
423 | endx = cx - (int)(radius * Math.cos(end * angle)); |
||
424 | endy = cy - (int)(radius * Math.sin(end * angle)); |
||
425 | canvas.setColor(color); |
||
426 | canvas.drawLine(startx, starty, endx, endy); |
||
427 | |||
428 | //create arrow
|
||
429 | if (color.equals(Color.BLACK)) return; |
||
430 | int big_dy = starty - endy;
|
||
431 | int big_dx = endx - startx;
|
||
432 | double theta = 0; |
||
433 | if (big_dx == 0 && starty > endy) //pointing up |
||
434 | theta = Math.PI/2; |
||
435 | else if (big_dx == 0 && starty < endy) //pointing down |
||
436 | theta = 3*Math.PI/2; |
||
437 | else if (big_dy == 0 && startx > endx) //pointing left |
||
438 | theta = Math.PI;
|
||
439 | else if (big_dy == 0 && startx < endx) //pointing right |
||
440 | theta = 0;
|
||
441 | else
|
||
442 | theta = Math.atan(1.0 * big_dy / big_dx); |
||
443 | |||
444 | //create ploygon
|
||
445 | Polygon poly = new Polygon(); |
||
446 | int dx_arrow = Math.abs((int)(ARROW_LENGTH * Math.cos(theta))); |
||
447 | int dy_arrow = Math.abs((int)(ARROW_LENGTH * Math.sin(theta))); |
||
448 | int dy_half = (int)(ARROW_LENGTH/2 * Math.cos(theta)); |
||
449 | int dx_half = (int)(ARROW_LENGTH/2 * Math.sin(theta)); |
||
450 | int rx = (big_dx > 0) ? endx - dx_arrow : endx + dx_arrow; |
||
451 | int ry = (big_dy > 0) ? endy + dy_arrow : endy - dy_arrow; |
||
452 | poly.addPoint(endx, endy); |
||
453 | poly.addPoint(rx - dx_half, ry - dy_half); |
||
454 | poly.addPoint(rx + dx_half, ry + dy_half); |
||
455 | canvas.fillPolygon(poly); |
||
456 | } |
||
457 | |||
458 | 35 | gtress | public void run () { |
459 | while (true) { |
||
460 | 32 | gtress | repaint(); |
461 | 35 | gtress | try {
|
462 | Thread.sleep(90); |
||
463 | } catch (InterruptedException e) { |
||
464 | return;
|
||
465 | } |
||
466 | 32 | gtress | } |
467 | } |
||
468 | |||
469 | 35 | gtress | public void step () { |
470 | 32 | gtress | final int DIAMETER = image.getWidth() - 2*BUFFER; |
471 | final int BIGRADIUS = DIAMETER / 2; |
||
472 | final int TOKENRADIUS = 40; |
||
473 | boolean valid;
|
||
474 | |||
475 | // clear image
|
||
476 | canvas.setColor(Color.WHITE);
|
||
477 | canvas.fillRect(0, 0, image.getWidth(), image.getHeight()); |
||
478 | |||
479 | // parse the matrix, to see what robots exist
|
||
480 | 76 | gtress | String [] rows = txtMatrix.getText().split("\n"); |
481 | 32 | gtress | numBots = rows.length; |
482 | String [][] entries = new String[numBots][numBots]; |
||
483 | valid = true;
|
||
484 | 35 | gtress | for (int i = 0; i < numBots; i++) { |
485 | 32 | gtress | entries[i] = rows[i].split(" ");
|
486 | if (entries[i].length != rows.length) valid = false; |
||
487 | } |
||
488 | |||
489 | 35 | gtress | if (valid) {
|
490 | 38 | gtress | this.showStatus("Running"); |
491 | 32 | gtress | |
492 | // draw robots and find which one is seleced
|
||
493 | double angle = 2.0 * Math.PI / numBots; |
||
494 | canvas.setColor(Color.BLACK);
|
||
495 | botRect = new Rectangle[numBots]; |
||
496 | int x, y;
|
||
497 | if (selectedBot >= numBots) selectedBot = 0; |
||
498 | 35 | gtress | for (int i = 0; i < numBots; i++) { |
499 | 32 | gtress | x = cx - (int)(BIGRADIUS * Math.cos(i * angle)); |
500 | y = cy - (int)(BIGRADIUS * Math.sin(i * angle)); |
||
501 | drawRobot(i, x, y); |
||
502 | if (i == selectedBot) indicator.setCenter(x, y);
|
||
503 | } |
||
504 | |||
505 | // draw token marker
|
||
506 | int tokenx, tokeny;
|
||
507 | int tokenNum = tokenLoc;
|
||
508 | tokenx = cx - (int)(BIGRADIUS * Math.cos(tokenNum * angle)); |
||
509 | tokeny = cy - (int)(BIGRADIUS * Math.sin(tokenNum * angle)); |
||
510 | canvas.setColor(Color.RED);
|
||
511 | canvas.drawOval(tokenx-TOKENRADIUS, tokeny-TOKENRADIUS, 2*TOKENRADIUS, 2*TOKENRADIUS); |
||
512 | |||
513 | // create an inner circle along which the connections are made.
|
||
514 | // let the diameter of this circle be 2*RADIUS less than the outerDiameter.
|
||
515 | // see what connections exist
|
||
516 | 35 | gtress | for (int row = 0; row < numBots; row++) { |
517 | for(int col = 0; col < numBots; col++) { |
||
518 | if (!entries[row][col].equals("-") && entries[col][row].equals("-") && row != col) { |
||
519 | //TODO: Make a standard gray
|
||
520 | 32 | gtress | drawConnection(row, col, BIGRADIUS-RADIUS, new Color(200,200,200)); |
521 | 38 | gtress | } else if (!entries[row][col].equals("-") && ! entries[col][row].equals("-") && row != col) { |
522 | 32 | gtress | drawConnection(row, col, BIGRADIUS-RADIUS, Color.BLACK);
|
523 | } |
||
524 | } |
||
525 | } |
||
526 | |||
527 | // draw the selection indicator
|
||
528 | indicator.draw(); |
||
529 | |||
530 | 35 | gtress | } else {// if matrix is not valid |
531 | 32 | gtress | this.showStatus("Error: Invalid matrix"); |
532 | } |
||
533 | |||
534 | } |
||
535 | |||
536 | /* At this point, moveToken is only called by the simulator.
|
||
537 | * In the future, it can be rewritten to account for non-standard
|
||
538 | * token passing or deleted if the information can be retrieved
|
||
539 | * directly from the Colonet server instead.
|
||
540 | */
|
||
541 | 35 | gtress | public void moveToken () { |
542 | try {
|
||
543 | tokenLoc = (tokenLoc+1)%numBots;
|
||
544 | } catch (ArithmeticException e) { // in case numRobots is zero |
||
545 | } |
||
546 | 32 | gtress | |
547 | packetMonitor.addTokenPass(); |
||
548 | } |
||
549 | |||
550 | 136 | gtress | public JTextArea getLog () { |
551 | return log;
|
||
552 | } |
||
553 | |||
554 | public JTextArea getMatrixInput () { |
||
555 | return txtMatrix;
|
||
556 | } |
||
557 | |||
558 | public void parseMatrix (String line) { |
||
559 | txtMatrix.setText("");
|
||
560 | String [] str = line.split(" "); |
||
561 | int num = Integer.parseInt(str[2]); |
||
562 | for (int i = 0; i < num; i++) { |
||
563 | for (int j = 0; j < num; j++) { |
||
564 | String next = str[3 + i*num + j]; |
||
565 | if (next.equals("-1")) |
||
566 | txtMatrix.append("-");
|
||
567 | else
|
||
568 | txtMatrix.append(next); |
||
569 | if (j < num - 1) |
||
570 | txtMatrix.append(" ");
|
||
571 | } |
||
572 | if (i < num - 1) |
||
573 | txtMatrix.append("\n");
|
||
574 | } |
||
575 | |||
576 | } |
||
577 | |||
578 | public void parseQueue (String line) { |
||
579 | log.append("Got queue update\n");
|
||
580 | |||
581 | } |
||
582 | |||
583 | public void parseXBeeIDs (String line) { |
||
584 | String [] str = line.split(" "); |
||
585 | int num = Integer.parseInt(str[2]); |
||
586 | xbeeID = new int[num]; |
||
587 | for (int i = 0; i < num; i++) |
||
588 | xbeeID[i] = Integer.parseInt(str[i+3]); |
||
589 | |||
590 | //update the list of robots to control
|
||
591 | cmbRobotNum.removeAllItems(); |
||
592 | cmbRobotNum.addItem(new String(" All ")); |
||
593 | for (int i = 0; i < num; i++) |
||
594 | cmbRobotNum.addItem(new String("" + xbeeID[i])); |
||
595 | } |
||
596 | |||
597 | 32 | gtress | //
|
598 | // MouseEvent methods
|
||
599 | //
|
||
600 | 155 | gtress | public void mouseExited(MouseEvent e) { |
601 | } |
||
602 | public void mouseEntered(MouseEvent e) { |
||
603 | } |
||
604 | 136 | gtress | public void mouseReleased(MouseEvent e) { |
605 | vectorController.sendToServer(); |
||
606 | } |
||
607 | public void mouseClicked(MouseEvent e) { |
||
608 | mouseDragged(e); |
||
609 | } |
||
610 | 35 | gtress | public void mousePressed(MouseEvent e) { |
611 | 32 | gtress | try {
|
612 | 35 | gtress | for (int i = 0; i < numBots; i++) { |
613 | 32 | gtress | if (botRect[i].contains(e.getPoint()))
|
614 | selectedBot = i; |
||
615 | } |
||
616 | } catch (Exception ex) { |
||
617 | System.out.println(e);
|
||
618 | } |
||
619 | |||
620 | } |
||
621 | 136 | gtress | public void mouseDragged(MouseEvent e) { |
622 | vectorController.setPoint(e.getX(), e.getY()); |
||
623 | vectorController.repaint(); |
||
624 | } |
||
625 | 155 | gtress | public void mouseMoved(MouseEvent e) { |
626 | } |
||
627 | 32 | gtress | |
628 | 136 | gtress | |
629 | 32 | gtress | /*
|
630 | * SelectionIndicator thread.
|
||
631 | * Graphical representation of the selection marker
|
||
632 | *
|
||
633 | * step() and draw() are synchronized methods. step() is private and
|
||
634 | * used to update the position of the crosshairs. draw() is called
|
||
635 | * externally and should only run if all calculations in step() have
|
||
636 | * been completed.
|
||
637 | */
|
||
638 | 35 | gtress | private class SelectionIndicator extends Thread { |
639 | 32 | gtress | |
640 | final int INDICATOR_DELAY = 100; |
||
641 | 155 | gtress | final double DTHETA = 0.4; //larger values make the marker rotate faster |
642 | 32 | gtress | Graphics2D g; //canvas to draw on |
643 | boolean running;
|
||
644 | |||
645 | int sx, sy; //center |
||
646 | int r, dr; //radius and width of marker |
||
647 | double theta; //current angle |
||
648 | |||
649 | volatile Polygon poly1, poly2, poly3, poly4; |
||
650 | |||
651 | int px1, py1;
|
||
652 | int rx1, ry1;
|
||
653 | int px2, py2;
|
||
654 | int rx2, ry2;
|
||
655 | int px3, py3;
|
||
656 | int rx3, ry3;
|
||
657 | int px4, py4;
|
||
658 | int rx4, ry4;
|
||
659 | |||
660 | int steps;
|
||
661 | |||
662 | 35 | gtress | public SelectionIndicator (Graphics2D g) { |
663 | 32 | gtress | super("SelectionIndicator"); |
664 | this.g = g;
|
||
665 | running = false;
|
||
666 | steps = 0;
|
||
667 | |||
668 | theta = 0;
|
||
669 | rx1 = 0; ry1 = 0; |
||
670 | px1 = 0; py1 = 0; |
||
671 | rx2 = 0; ry2 = 0; |
||
672 | px2 = 0; py2 = 0; |
||
673 | rx3 = 0; ry3 = 0; |
||
674 | px3 = 0; py3 = 0; |
||
675 | rx4 = 0; ry4 = 0; |
||
676 | px4 = 0; py4 = 0; |
||
677 | } |
||
678 | |||
679 | 35 | gtress | public synchronized void setCenter (int sx, int sy) { |
680 | 32 | gtress | if (sx == this.sx && sy == this.sy) return; |
681 | this.sx = sx;
|
||
682 | this.sy = sy;
|
||
683 | steps = 0;
|
||
684 | } |
||
685 | |||
686 | 35 | gtress | public synchronized void setRadius (int r, int dr) { |
687 | 32 | gtress | this.r = r;
|
688 | this.dr = dr;
|
||
689 | steps = 0;
|
||
690 | } |
||
691 | |||
692 | 35 | gtress | public void run () { |
693 | 32 | gtress | running = true;
|
694 | 35 | gtress | while (running) {
|
695 | 32 | gtress | step(); |
696 | 35 | gtress | try {
|
697 | Thread.sleep(INDICATOR_DELAY);
|
||
698 | } catch (InterruptedException e) { |
||
699 | running = false;
|
||
700 | return;
|
||
701 | } |
||
702 | 32 | gtress | } |
703 | } |
||
704 | |||
705 | 35 | gtress | private synchronized void step () { |
706 | 32 | gtress | Polygon poly1_new = new Polygon(); |
707 | Polygon poly2_new = new Polygon(); |
||
708 | Polygon poly3_new = new Polygon(); |
||
709 | Polygon poly4_new = new Polygon(); |
||
710 | |||
711 | //the step
|
||
712 | theta = (theta + DTHETA/Math.PI) % (Math.PI); |
||
713 | |||
714 | //the calculation
|
||
715 | //let p be the point of the pointy thing toward the center
|
||
716 | //let r be the point at the opposite side
|
||
717 | |||
718 | //recalculate radius, if it will look cool, lolz
|
||
719 | int newr = r;
|
||
720 | 38 | gtress | if (steps < 100) |
721 | 107 | gtress | newr = (int)( r + 200/(steps+1) ); |
722 | 32 | gtress | |
723 | //precompute values for dx and dy
|
||
724 | int dx_inner = (int)(newr * Math.cos(theta)); |
||
725 | int dy_inner = (int)(newr * Math.sin(theta)); |
||
726 | int dx_outer = (int)((newr+dr) * Math.cos(theta)); |
||
727 | int dy_outer = (int)((newr+dr) * Math.sin(theta)); |
||
728 | |||
729 | //calculate polygon constants
|
||
730 | int dy_poly = (int)(dr/2 * Math.cos(theta)); |
||
731 | int dx_poly = (int)(dr/2 * Math.sin(theta)); |
||
732 | |||
733 | //determine critical points
|
||
734 | 35 | gtress | //kansas city shuffle!
|
735 | 32 | gtress | px1 = sx + dx_inner; |
736 | py1 = sy - dy_inner; |
||
737 | rx1 = sx + dx_outer; |
||
738 | ry1 = sy - dy_outer; |
||
739 | px2 = sx - dx_inner; |
||
740 | py2 = sy + dy_inner; |
||
741 | rx2 = sx - dx_outer; |
||
742 | ry2 = sy + dy_outer; |
||
743 | px3 = sx - dy_inner; |
||
744 | py3 = sy - dx_inner; |
||
745 | rx3 = sx - dy_outer; |
||
746 | ry3 = sy - dx_outer; |
||
747 | px4 = sx + dy_inner; |
||
748 | py4 = sy + dx_inner; |
||
749 | rx4 = sx + dy_outer; |
||
750 | ry4 = sy + dx_outer; |
||
751 | |||
752 | //create polygons
|
||
753 | poly1_new.addPoint(px1, py1); |
||
754 | poly1_new.addPoint(rx1+dx_poly, ry1+dy_poly); |
||
755 | poly1_new.addPoint(rx1-dx_poly, ry1-dy_poly); |
||
756 | poly2_new.addPoint(px2, py2); |
||
757 | poly2_new.addPoint(rx2+dx_poly, ry2+dy_poly); |
||
758 | poly2_new.addPoint(rx2-dx_poly, ry2-dy_poly); |
||
759 | poly3_new.addPoint(px3, py3); |
||
760 | poly3_new.addPoint(rx3-dy_poly, ry3+dx_poly); |
||
761 | poly3_new.addPoint(rx3+dy_poly, ry3-dx_poly); |
||
762 | poly4_new.addPoint(px4, py4); |
||
763 | poly4_new.addPoint(rx4-dy_poly, ry4+dx_poly); |
||
764 | poly4_new.addPoint(rx4+dy_poly, ry4-dx_poly); |
||
765 | |||
766 | //reassign updated polygons
|
||
767 | poly1 = poly1_new; |
||
768 | poly2 = poly2_new; |
||
769 | poly3 = poly3_new; |
||
770 | poly4 = poly4_new; |
||
771 | |||
772 | if (steps < 300) steps++; |
||
773 | } |
||
774 | |||
775 | 35 | gtress | public synchronized void draw () { |
776 | 32 | gtress | if (!running) return; |
777 | g.setColor(Color.GRAY);
|
||
778 | //draw polygons
|
||
779 | g.fillPolygon(poly1); |
||
780 | g.fillPolygon(poly2); |
||
781 | g.fillPolygon(poly3); |
||
782 | g.fillPolygon(poly4); |
||
783 | } |
||
784 | |||
785 | } |
||
786 | |||
787 | /*
|
||
788 | * Simulator thread.
|
||
789 | *
|
||
790 | */
|
||
791 | 35 | gtress | private class Simulator extends Thread { |
792 | 32 | gtress | final int SIMULATOR_DELAY = 300; |
793 | boolean running;
|
||
794 | |||
795 | 35 | gtress | public Simulator () {
|
796 | 32 | gtress | super("Simulator"); |
797 | running = false;
|
||
798 | } |
||
799 | |||
800 | 35 | gtress | public void run () { |
801 | 32 | gtress | running = true;
|
802 | 35 | gtress | while (running) {
|
803 | 32 | gtress | step(); |
804 | 35 | gtress | try {
|
805 | Thread.sleep(SIMULATOR_DELAY);
|
||
806 | } catch (InterruptedException e) { |
||
807 | running = false;
|
||
808 | return;
|
||
809 | } |
||
810 | 32 | gtress | } |
811 | } |
||
812 | |||
813 | 35 | gtress | private void step () { |
814 | 155 | gtress | // don't do anything! the colonet should work on its own!
|
815 | 32 | gtress | } |
816 | |||
817 | } |
||
818 | |||
819 | /*
|
||
820 | * PacketMonitor thread.
|
||
821 | *
|
||
822 | * Currently, this counts the rate of token passes but will eventually
|
||
823 | * be modified to keep more important statistics.
|
||
824 | */
|
||
825 | 35 | gtress | private class PacketMonitor extends Thread { |
826 | 32 | gtress | final int PACKETMONITOR_DELAY = 1000; |
827 | |||
828 | boolean running;
|
||
829 | int tokenPasses;
|
||
830 | |||
831 | 35 | gtress | public PacketMonitor () {
|
832 | 32 | gtress | super("PacketMonitor"); |
833 | running = false;
|
||
834 | tokenPasses = 0;
|
||
835 | } |
||
836 | |||
837 | 35 | gtress | public void run () { |
838 | 32 | gtress | running = true;
|
839 | 35 | gtress | while (running) {
|
840 | 32 | gtress | displayTokenPasses(); |
841 | 35 | gtress | try {
|
842 | Thread.sleep(PACKETMONITOR_DELAY);
|
||
843 | } catch (InterruptedException e) { |
||
844 | running = false;
|
||
845 | return;
|
||
846 | } |
||
847 | 32 | gtress | } |
848 | } |
||
849 | |||
850 | 35 | gtress | public synchronized void addTokenPass () { |
851 | 32 | gtress | tokenPasses++; |
852 | } |
||
853 | |||
854 | 35 | gtress | public synchronized void displayTokenPasses () { |
855 | 32 | gtress | lblTokenPasses.setText("" + tokenPasses);
|
856 | tokenPasses = 0;
|
||
857 | } |
||
858 | |||
859 | } |
||
860 | |||
861 | /*
|
||
862 | 67 | gtress | * DataUpdater thread.
|
863 | 76 | gtress | * The purpose of this thread is to request data from the server at regular intervals.
|
864 | 32 | gtress | *
|
865 | */
|
||
866 | 67 | gtress | class DataUpdater extends Thread { |
867 | 155 | gtress | final int DATAUPDATER_DELAY = 5000; |
868 | 32 | gtress | |
869 | 67 | gtress | public DataUpdater () {
|
870 | super("Colonet DataUpdater"); |
||
871 | 32 | gtress | } |
872 | |||
873 | 35 | gtress | public void run () { |
874 | 32 | gtress | String line;
|
875 | 35 | gtress | while (true) { |
876 | 32 | gtress | try {
|
877 | 76 | gtress | //request more data
|
878 | 136 | gtress | if (csi.isReady()) {
|
879 | 107 | gtress | csi.sendSensorDataRequest(); |
880 | 136 | gtress | csi.sendXBeeIDRequest(); |
881 | } |
||
882 | 67 | gtress | Thread.sleep(DATAUPDATER_DELAY);
|
883 | 32 | gtress | } catch (InterruptedException e) { |
884 | return;
|
||
885 | 39 | gtress | } |
886 | 32 | gtress | } |
887 | } |
||
888 | |||
889 | } |
||
890 | 136 | gtress | |
891 | /*
|
||
892 | * ImagePanel class
|
||
893 | * Enables more efficient image handling in a component-controlled environment
|
||
894 | */
|
||
895 | class ImagePanel extends JPanel { |
||
896 | protected Image img; |
||
897 | |||
898 | public ImagePanel (Image img) { |
||
899 | super();
|
||
900 | this.img = img;
|
||
901 | } |
||
902 | |||
903 | public ImagePanel (boolean isDoubleBuffered, Image img) { |
||
904 | super(isDoubleBuffered);
|
||
905 | this.img = img;
|
||
906 | } |
||
907 | |||
908 | public void paint (Graphics g) { |
||
909 | // Place the buffered image on the screen, inside the panel
|
||
910 | g.drawImage(img, 0, 0, Color.WHITE, this); |
||
911 | } |
||
912 | |||
913 | } |
||
914 | |||
915 | /*
|
||
916 | * VectorController class
|
||
917 | * Manages robot motion control graphically
|
||
918 | */
|
||
919 | class VectorController extends ImagePanel { |
||
920 | int x, y, cx, cy;
|
||
921 | int width, height;
|
||
922 | int side;
|
||
923 | |||
924 | public VectorController (Image img) { |
||
925 | super (img);
|
||
926 | width = img.getWidth(null);
|
||
927 | height = img.getHeight(null);
|
||
928 | cx = img.getWidth(null)/2; |
||
929 | cy = img.getHeight(null)/2; |
||
930 | x = cx; |
||
931 | y = cy; |
||
932 | if (width < height)
|
||
933 | side = width; |
||
934 | else
|
||
935 | side = height; |
||
936 | } |
||
937 | |||
938 | public void setPoint (int x, int y) { |
||
939 | if (!isValidPoint(x, y))
|
||
940 | return;
|
||
941 | this.x = x;
|
||
942 | this.y = y;
|
||
943 | repaint(); |
||
944 | } |
||
945 | |||
946 | public boolean isValidPoint (int x, int y) { |
||
947 | double xterm = Math.pow(1.0*(x - cx)/(side/2), 2); |
||
948 | double yterm = Math.pow(1.0*(y - cy)/(side/2), 2); |
||
949 | return (xterm + yterm <= 1); |
||
950 | } |
||
951 | |||
952 | public int getVelocity () { |
||
953 | int dx = x - cx;
|
||
954 | int dy = y - cy;
|
||
955 | int v = (int) Math.sqrt( Math.pow(dx, 2) + Math.pow(dy, 2) ); |
||
956 | return v;
|
||
957 | } |
||
958 | |||
959 | 155 | gtress | public int getAngle () { |
960 | 136 | gtress | int dx = x - cx;
|
961 | int dy = cy - y;
|
||
962 | double theta = Math.atan2(Math.abs(dx), Math.abs(dy)); |
||
963 | theta = (int) (1.0 * theta * 180 / Math.PI); //transform to degrees |
||
964 | if (dy < 0) |
||
965 | theta = 180 - theta;
|
||
966 | theta *= Math.signum(dx);
|
||
967 | 155 | gtress | return (int) theta; |
968 | 136 | gtress | } |
969 | |||
970 | public void paint (Graphics g) { |
||
971 | g.setColor(Color.BLACK);
|
||
972 | g.fillRect(0, 0, width, height); |
||
973 | ((Graphics2D)g).setStroke(new BasicStroke(1)); |
||
974 | g.setColor(Color.RED);
|
||
975 | g.drawOval(cx-side/2, cy-side/2, side, side); |
||
976 | ((Graphics2D)g).setStroke(new BasicStroke(2)); |
||
977 | g.setColor(Color.GREEN);
|
||
978 | g.drawLine(cx, cy, x, y); |
||
979 | g.fillOval(x-3, y-3, 6, 6); |
||
980 | } |
||
981 | |||
982 | public void setMaxForward () { |
||
983 | setPoint(cx, cy - (side/2) + 1); |
||
984 | } |
||
985 | |||
986 | public void setMaxReverse () { |
||
987 | setPoint(cx, cy + (side/2) - 1); |
||
988 | } |
||
989 | |||
990 | public void setMaxLeft () { |
||
991 | setPoint(cx - (side/2) + 1, cy); |
||
992 | } |
||
993 | |||
994 | public void setMaxRight () { |
||
995 | setPoint(cx + (side/2) - 1, cy); |
||
996 | } |
||
997 | |||
998 | public void setZero () { |
||
999 | setPoint(cx, cy); |
||
1000 | } |
||
1001 | |||
1002 | public void sendToServer () { |
||
1003 | if (csi != null) |
||
1004 | csi.sendData(ColonetServerInterface.MOVE + " " +
|
||
1005 | vectorController.getAngle() + " " +
|
||
1006 | vectorController.getVelocity(), ColonetServerInterface.GLOBAL_DEST); |
||
1007 | } |
||
1008 | |||
1009 | } |
||
1010 | |||
1011 | /*
|
||
1012 | * TaskAddWindow class
|
||
1013 | * makes it easy to add tasks to the queue
|
||
1014 | */
|
||
1015 | class TaskAddWindow extends JFrame implements ActionListener, ListSelectionListener { |
||
1016 | JPanel panelButtons;
|
||
1017 | JPanel panelParameters;
|
||
1018 | JPanel panelSouth;
|
||
1019 | JPanel panelSelection;
|
||
1020 | JButton btnSubmit;
|
||
1021 | JButton btnCancel;
|
||
1022 | DefaultListModel availableListModel;
|
||
1023 | JList availableList;
|
||
1024 | JScrollPane spAvailableTasks;
|
||
1025 | JTextArea txtDescription;
|
||
1026 | JTextField txtParameters;
|
||
1027 | MouseListener mouseListener;
|
||
1028 | |||
1029 | public TaskAddWindow () {
|
||
1030 | super("Add a Task ... if you dare!"); |
||
1031 | super.setSize(500,500); |
||
1032 | super.setLayout(new BorderLayout()); |
||
1033 | |||
1034 | // set up buttons
|
||
1035 | btnSubmit = new JButton("Submit"); |
||
1036 | btnCancel = new JButton("Cancel"); |
||
1037 | panelButtons = new JPanel(); |
||
1038 | panelButtons.setLayout(new FlowLayout()); |
||
1039 | panelButtons.add(btnSubmit); |
||
1040 | panelButtons.add(btnCancel); |
||
1041 | this.getRootPane().setDefaultButton(btnSubmit);
|
||
1042 | |||
1043 | // set up task list
|
||
1044 | availableListModel = new DefaultListModel(); |
||
1045 | availableListModel.addElement("Map the Environment");
|
||
1046 | availableListModel.addElement("Clean Up Chemical Spill");
|
||
1047 | availableListModel.addElement("Grow Plants");
|
||
1048 | availableListModel.addElement("Save the Cheerleader");
|
||
1049 | availableListModel.addElement("Save the World");
|
||
1050 | availableList = new JList(availableListModel); |
||
1051 | availableList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||
1052 | availableList.setSelectedIndex(-1);
|
||
1053 | spAvailableTasks = new JScrollPane(availableList); |
||
1054 | spAvailableTasks.setBorder(BorderFactory.createTitledBorder("Select A Task")); |
||
1055 | txtDescription = new JTextArea(); |
||
1056 | txtDescription.setEditable(false);
|
||
1057 | txtDescription.setLineWrap(true);
|
||
1058 | txtDescription.setWrapStyleWord(true);
|
||
1059 | txtDescription.setBorder(BorderFactory.createTitledBorder("Description")); |
||
1060 | |||
1061 | //set up parameter area
|
||
1062 | panelParameters = new JPanel(); |
||
1063 | panelParameters.setLayout(new BorderLayout()); |
||
1064 | txtParameters = new JTextField(); |
||
1065 | panelParameters.add(new JLabel("Optional parameters for this task: "), BorderLayout.WEST); |
||
1066 | panelParameters.add(txtParameters); |
||
1067 | |||
1068 | // assemble objects
|
||
1069 | panelSelection = new JPanel(); |
||
1070 | panelSelection.setLayout(new GridLayout(1,2)); |
||
1071 | panelSelection.add(spAvailableTasks); |
||
1072 | panelSelection.add(txtDescription); |
||
1073 | |||
1074 | panelSouth = new JPanel(); |
||
1075 | panelSouth.setLayout(new GridLayout(2,1)); |
||
1076 | panelSouth.add(panelParameters); |
||
1077 | panelSouth.add(panelButtons); |
||
1078 | |||
1079 | this.getContentPane().add(panelSouth, BorderLayout.SOUTH); |
||
1080 | this.getContentPane().add(panelSelection, BorderLayout.CENTER); |
||
1081 | this.setLocationRelativeTo(null); |
||
1082 | |||
1083 | // add listeners here
|
||
1084 | availableList.addListSelectionListener(this);
|
||
1085 | btnSubmit.addActionListener(this);
|
||
1086 | btnCancel.addActionListener(this);
|
||
1087 | } |
||
1088 | |||
1089 | public void prompt () { |
||
1090 | this.setVisible(true); |
||
1091 | } |
||
1092 | |||
1093 | private String getDescription (int index) { |
||
1094 | if (index < 0) |
||
1095 | return ""; |
||
1096 | switch (index) {
|
||
1097 | case 0: return "SLAM and junk"; |
||
1098 | case 1: return "I'm not sure this works"; |
||
1099 | case 2: return "Push them into the light"; |
||
1100 | case 3: return "Watch out for clock repair guys"; |
||
1101 | case 4: return "But make sure he's dead, geez, why would you let him get away? I mean come on, " |
||
1102 | +"he's just lying there and everyone's too busy looking at people flying through the sky to "
|
||
1103 | +"notice? Oh yeah, that's a good transition to a new season, let's make the audience think "
|
||
1104 | +"he's dead and then pull a fast one on them, they'll never see that coming.";
|
||
1105 | |||
1106 | default: return "Task not recognized"; |
||
1107 | } |
||
1108 | } |
||
1109 | |||
1110 | public void actionPerformed (ActionEvent e) { |
||
1111 | Object source = e.getSource();
|
||
1112 | if (source == btnSubmit) {
|
||
1113 | txtParameters.setText(txtParameters.getText().trim()); |
||
1114 | |||
1115 | |||
1116 | this.setVisible(false); |
||
1117 | } else if (source == btnCancel) { |
||
1118 | this.setVisible(false); |
||
1119 | } |
||
1120 | } |
||
1121 | |||
1122 | public void valueChanged (ListSelectionEvent e) { |
||
1123 | int index = availableList.getSelectedIndex();
|
||
1124 | if (index >= 0) |
||
1125 | txtDescription.setText(getDescription(index)); |
||
1126 | } |
||
1127 | |||
1128 | } |
||
1129 | 32 | gtress | |
1130 | } |