2-APL UPC project.
1package blockworld;
2
3import java.awt.BorderLayout;
4import java.awt.Dimension;
5import java.awt.Point;
6import java.awt.event.ActionEvent;
7import java.awt.event.ActionListener;
8import java.io.File;
9import java.io.FileInputStream;
10import java.io.FileOutputStream;
11import java.util.Observable;
12import java.util.Observer;
13import java.util.StringTokenizer;
14import java.util.Vector;
15
16import javax.swing.JComponent;
17import javax.swing.JFileChooser;
18import javax.swing.JFrame;
19import javax.swing.JMenu;
20import javax.swing.JMenuBar;
21import javax.swing.JMenuItem;
22import javax.swing.JOptionPane;
23import javax.swing.JScrollPane;
24import javax.swing.JSplitPane;
25import javax.swing.JTable;
26import javax.swing.table.AbstractTableModel;
27
28import javax.swing.ImageIcon;
29import javax.swing.JButton;
30import javax.swing.JToggleButton;
31import javax.swing.JToolBar;
32import java.util.ArrayList;
33
34import blockworld.lib.Signal;
35
36/// statistics view
37class Statistics extends AbstractTableModel implements Observer {
38
39 private static final long serialVersionUID = 5372407086612717903L;
40
41 protected EnvView _view = null;
42
43 protected Vector _signals = new Vector();
44
45
46 public int getColumnCount() {
47 return 2;
48 }
49
50 public int getRowCount() {
51 return _signals.size();
52 }
53
54 public Object getValueAt( int row, int col ) {
55 // get requested row
56 final Signal signal = (Signal) _signals.get( row );
57
58 // name column requested
59 if( col == 0 )
60 return signal.getName();
61
62 // count column requested
63 return new Integer( (int) signal.getEmitCount() );
64 }
65
66 public String getColumnName( int i ) {
67 if( i == 0 )
68 return "Signal Description";
69 return "Total Emitted Events";
70 }
71
72 public Statistics( EnvView view ) {
73 setEnvView( view );
74 }
75
76 // \todo throw illegal argument exception is view == null
77 public void setEnvView( EnvView view ) {
78 // remove old listener
79 if( _view != null )
80 _view.signalSelectionChanged.deleteObserver( this );
81
82 _view = view;
83 _view.signalSelectionChanged.addObserver( this );
84
85
86 // Changed SA: On a screen refresh of the environment update yourself (call the update( Observable o, Object arg ))
87 // _view.signalRefresh.addObserver(this);
88 // agent/env changed
89 update();
90 }
91
92 public void update( Observable o, Object arg ) {
93 // agent/env changed
94 update();
95 }
96
97 // \todo het is netter als ipv tableStructureChanged, rowsInserted
98 // en rowsDeleted wordt gesignaled
99 public void update() {
100 // empty list
101 _signals.clear();
102
103 final Env env = _view.getEnv();
104 final Agent agent = _view.getSelectedAgent();
105
106 // add events
107 _signals.add( env.signalBombTrapped );
108 if( agent != null ) {
109 _signals.add( agent.signalDropBomb );
110 _signals.add( agent.signalDropBombSucces );
111 _signals.add( agent.signalMove );
112 _signals.add( agent.signalMoveSucces );
113 _signals.add( agent.signalPickupBomb );
114 _signals.add( agent.signalPickupBombSucces );
115 }
116
117 // notify observers
118 // fireTableRowsUpdated(0, _signals.size() - 1);
119
120 // Changed SA: This is better, this will not change the layout of the complete table!
121 fireTableDataChanged();
122 }
123
124}
125
126// / Window with EnvView and buttons for loading/saving
127// / \todo implement step blocking function and gray done button
128// / when step is not possible
129public class Window extends JFrame{
130
131 private static final long serialVersionUID = -462965463955994316L;
132
133 protected boolean _done = false;
134
135 protected boolean _init = false;
136
137 protected File _lastFile = null;
138
139 private JToolBar m_tbToolbar = null;
140 private ArrayList<JToggleButton> m_aEditOptions = new ArrayList<JToggleButton>();
141
142
143 public Window( final Env env ){
144 super( "Blockworld" );
145
146 // create clear menuitem + action
147 JMenuItem clear = new JMenuItem( "Clear environment" );
148 clear.addActionListener( new ActionListener() {
149 public void actionPerformed( ActionEvent e ) {
150 // popup confirmation dialog
151 final int rv = JOptionPane.showConfirmDialog( Window.this,
152 "Are you sure you want to clear the environment",
153 "Confirm clear", JOptionPane.YES_NO_OPTION );
154
155 // abort unless YES is pressed
156 if( rv != JOptionPane.YES_OPTION )
157 return;
158
159 env.clear();
160 }
161 } );
162
163 // create revert menuitem + action
164 JMenuItem revert = new JMenuItem( "Revert to saved" );
165 revert.addActionListener( new ActionListener() {
166 public void actionPerformed( ActionEvent e ) {
167 // see if we can revert at all
168 if( _lastFile == null ) {
169 JOptionPane
170 .showMessageDialog(
171 Window.this,
172 "You did not load or save this environment yet.\nPlease load or save first",
173 "Nothing to revert to",
174 JOptionPane.ERROR_MESSAGE );
175 return;
176 }
177
178 // popup confirmation dialog
179 final int rv = JOptionPane.showConfirmDialog( Window.this,
180 "Are you sure you want revert to "
181 + _lastFile.getPath(),
182 "Confirm revert to saved", JOptionPane.YES_NO_OPTION );
183
184 // abort unless YES is pressed
185 if( rv != JOptionPane.YES_OPTION )
186 return;
187
188 try {
189 env.clear();
190 final FileInputStream stream = new FileInputStream(
191 _lastFile );
192 env.load( stream );
193 }
194 catch( Exception ex ) {
195 System.out.println( "Loading failed! " + ex );
196 }
197 }
198 } );
199
200 // create 'load' button + action
201 JMenuItem load = new JMenuItem( "Load from File" );
202 load.addActionListener( new ActionListener() {
203 public void actionPerformed( ActionEvent e ) {
204 try {
205 final File cwd = new File( "." );
206 final JFileChooser fc = new JFileChooser( cwd );
207 final int rv = fc.showOpenDialog( Window.this );
208
209 // cancel pressed
210 if( rv != JFileChooser.APPROVE_OPTION )
211 return;
212
213 final File file = fc.getSelectedFile();
214 final FileInputStream stream = new FileInputStream( file );
215 env.load( stream );
216 _lastFile = file;
217 }
218 catch( Exception ex ) {
219 System.out.println( "Loading failed! " + ex );
220 }
221 }
222 } );
223
224 JMenuItem save = new JMenuItem( "Save to File" );
225 save.addActionListener( new ActionListener() {
226 public void actionPerformed( ActionEvent e ) {
227 try {
228 final File cwd = new File( "." );
229 final JFileChooser fc = new JFileChooser( cwd );
230 final int rv = fc.showSaveDialog( Window.this );
231
232 // cancel pressed
233 if( rv != JFileChooser.APPROVE_OPTION )
234 return;
235
236 final File file = fc.getSelectedFile();
237 final FileOutputStream stream = new FileOutputStream( file );
238 env.save( stream );
239 _lastFile = file;
240 }
241 catch( Exception ex ) {
242 System.out.println( "Saving failed! " + ex );
243 }
244 }
245 } );
246
247 JMenuItem resize = new JMenuItem( "Environment Size" );
248 resize.addActionListener( new ActionListener() {
249 public void actionPerformed( ActionEvent e ) {
250 // show dialog
251 String size = (String) JOptionPane.showInputDialog(
252 Window.this,
253 "Resize environment (X * Y) (X, Y) (X x Y) (X Y)",
254 "Resize environment", JOptionPane.PLAIN_MESSAGE, null, null, env
255 .getWidth()
256 + " * " + env.getHeight() );
257
258 // if a string was returned, parse and set size
259 if( (size != null) && (size.length() > 0) ) {
260 StringTokenizer st = new StringTokenizer( size, "*x, " );
261
262 if( !st.hasMoreTokens() )
263 return;
264 String x = st.nextToken();
265
266 if( !st.hasMoreTokens() )
267 return;
268 String y = st.nextToken();
269
270 try {
271 Dimension d = new Dimension( Integer.parseInt( x ),
272 Integer.parseInt( y ) );
273
274 env.setSize( d );
275 }
276 catch( NumberFormatException e1 ) {
277 JOptionPane
278 .showMessageDialog(
279 Window.this,
280 "Invalid number format, it should be one of (X * Y) (X, Y) (X x Y) (X Y)",
281 "Error parsing size",
282 JOptionPane.ERROR_MESSAGE );
283 }
284 }
285 }
286 } );
287
288 JMenuItem setid = new JMenuItem( "Default APLIdentifier" );
289 setid.addActionListener( new ActionListener() {
290 public void actionPerformed( ActionEvent e ) {
291 // show dialog
292 String objType = ((String) JOptionPane.showInputDialog(
293 Window.this,
294 "Enter default identifier for new bombs/traps (all char, first char in lowercase)",
295 "Set Default Object APLIdentifier", JOptionPane.PLAIN_MESSAGE, null, null, env.getObjType() ));
296 // -- validate objType --
297 if(objType == null) return;
298 boolean invalid = false;
299 for(int i = 0; i < objType.length(); i++) {
300 char ichar = objType.charAt(i);
301 if(!Character.isLetter(ichar) || (i ==0 && !Character.isLowerCase(ichar))) {
302 invalid = true;
303 break;
304 }
305 }
306
307 if(objType.length() == 0 || invalid) {
308 JOptionPane.showMessageDialog(Window.this,
309 "The object type identifier must be an all-character string with the first character in lowercase",
310 "Invalid object type",
311 JOptionPane.ERROR_MESSAGE );
312 return;
313 }
314
315 env.setObjType(objType);
316 }
317 } );
318
319 JMenuItem senserange = new JMenuItem( "Sensor Range" );
320 senserange.addActionListener( new ActionListener() {
321 public void actionPerformed( ActionEvent e ) {
322 String range = (String) JOptionPane.showInputDialog(
323 Window.this, "Set agent sensor range in cells",
324 "Set Sensor Range in Cells", JOptionPane.PLAIN_MESSAGE, null, null,
325 Integer.toString( env.getSenseRange() ) );
326
327 // If a string was returned, parse and set range
328 if( (range != null) && (range.length() > 0) )
329 env.setSenseRange( Integer.parseInt( range ) );
330 }
331 } );
332
333 JMenuItem about = new JMenuItem( "About BlockWorld" );
334 about.addActionListener( new ActionListener() {
335 public void actionPerformed( ActionEvent e ) {
336 // show dialog
337 JOptionPane.showMessageDialog(Window.this,
338 "BlockWorld for 2APL\n\n"+
339 "http://www.cs.uu.nl/2apl/\n\n"+
340 "Developed by\n"+
341 " The 2APL development group\n"+
342 " Utrecht University, the Netherlands",
343 "About BlockWorld",
344 JOptionPane.INFORMATION_MESSAGE );
345 }
346 } );
347
348 JMenu world = new JMenu( "World" );
349 world.add( load );
350 world.add( save );
351 world.add( revert );
352 world.add( clear );
353
354 JMenu properties = new JMenu( "Properties" );
355 properties.add( resize );
356 properties.add( senserange );
357 properties.add( setid );
358
359 JMenu help = new JMenu( "Help" );
360 help.add( about );
361
362 JMenuBar menubar = new JMenuBar();
363 menubar.add( world );
364 menubar.add( properties );
365 menubar.add( help );
366
367 // create window
368 getContentPane().setLayout( new BorderLayout() );
369
370 final EnvView envView = new EnvView( env );
371 final Statistics stats = new Statistics( envView );
372 final JComponent statsView = new JScrollPane( new JTable( stats ) );
373
374 final JSplitPane sp = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT,
375 envView, statsView );
376 sp.setOneTouchExpandable( true );
377 sp.setDividerLocation( 230 );
378 sp.setResizeWeight(1);
379 getContentPane().add( sp, BorderLayout.CENTER );
380 setJMenuBar( menubar );
381
382 // The toolbar
383 m_tbToolbar = new JToolBar();
384 m_tbToolbar.setFloatable(false);
385 addButton("info.gif", "Select agent", envView.tool.STATE_SELECT, envView.tool).setSelected(true);
386 addButton("bomb.gif", "Place bombs", envView.tool.STATE_ADDBOMB, envView.tool);
387 addButton("stone.gif", "Place walls", envView.tool.STATE_ADDWALL, envView.tool);
388 addButton("trap.gif", "Place traps", envView.tool.STATE_ADDTRAP, envView.tool);
389 addButton("eraser.gif", "Erase objects", envView.tool.STATE_REMOVE, envView.tool);
390 getContentPane().add(m_tbToolbar, BorderLayout.NORTH);
391
392
393 // pack();
394 setSize( 400, 250 );
395 setVisible( true );
396 }
397
398 // / the first call to this method will display the
399 // / edit window and block until user has finished editing
400 public synchronized void init() {
401 if( _init )
402 return;
403
404 while( !_done ) {
405 try {
406 wait();
407 } catch( InterruptedException e ) {
408 }
409 }
410
411 _init = true;
412 }
413
414 // / call this method to end the editing session. This function
415 // / is called from a JButton.
416 protected synchronized void done() {
417 _done = true;
418 notifyAll();
419 }
420
421
422 public JToggleButton addButton(String sImage, String tooltip, final int nState, final EnvView.MouseTool tool)
423 {
424 final JToggleButton button = new JToggleButton(makeIcon(sImage));
425 button.addActionListener(new ActionListener()
426 {
427 public void actionPerformed(ActionEvent e)
428 {
429 tool._state = nState;
430
431 for (JToggleButton cmdButton : m_aEditOptions)
432 {
433 if (button != cmdButton)
434 {
435 cmdButton.setSelected(false);
436 }
437 }
438 }
439 });
440 button.setToolTipText(tooltip);
441 m_tbToolbar.add(button);
442 m_aEditOptions.add(button);
443
444 return button;
445 }
446
447 private ImageIcon makeIcon(String sImage)
448 {
449 sImage = "images/toolbar/"+sImage;
450 return new ImageIcon(this.getClass().getResource(sImage));
451 }
452}