001
002 package gui;
003
004 import java.awt.Color;
005 import java.awt.Font;
006 import java.awt.Graphics;
007 import java.awt.Graphics2D;
008 import java.awt.Dimension;
009 import java.awt.event.KeyListener;
010 import java.awt.event.WindowListener;
011 import java.awt.event.ActionListener;
012 import java.awt.event.KeyEvent;
013
014 import java.awt.BorderLayout;
015 import javax.swing.BoxLayout;
016
017 import javax.swing.event.ChangeListener;
018 import javax.swing.JFrame;
019 //import javax.swing.JCheckBox;
020 import javax.swing.JCheckBoxMenuItem;
021 import javax.swing.JOptionPane;
022 import javax.swing.JDialog;
023 import javax.swing.JPanel;
024 import javax.swing.JComponent;
025 import javax.swing.JLabel;
026 import javax.swing.JTextField;
027 import javax.swing.JTextArea;
028 import javax.swing.JScrollPane;
029 import javax.swing.JMenu;
030 import javax.swing.JMenuBar;
031 import javax.swing.JMenuItem;
032 import javax.swing.BorderFactory;
033 //import javax.swing.JSpinner;
034 //import javax.swing.SpinnerNumberModel;
035
036 import algo.Path;
037 import algo.PathByteArray;
038 import algo.Point;
039
040 /**
041 * Main class to setup the GUI and the controls.
042 * @author Heinz Kredel.
043 */
044 public class TSPguiMain extends JFrame implements TSPguiUpdate {
045
046 static Color background = new Color(0xFF,0xFF,0xF5);
047 static Color text = new Color(0xCC,0,0);
048 static Color text2 = Color.black;
049 static Font schrift = new Font("SansSerif", Font.PLAIN, 18);
050 static Font schrift2 = new Font("SansSerif", Font.PLAIN, 14);
051 static Font schrift3 = new Font("SansSerif", Font.PLAIN, 10);
052
053 TSPguiModel model;
054 KeyListener keyControl;
055 WindowListener windowControl;
056 ActionListener actionControl;
057 ChangeListener changeControl;
058
059 private JPanel graphPanel = null;
060 private JTextField statusLabel = null;
061 private JTextArea statusArea = null;
062 private JTextField algorithmText = null;
063
064 /**
065 * @param model the TSPguiMode.
066 * @param keyControl the KeyListener.
067 * @param windowControl the WindowListener.
068 * @param actionControl the ActionListener.
069 * @param changeControl the ChangeListener.
070 */
071 public TSPguiMain(TSPguiModel model,
072 KeyListener keyControl,
073 WindowListener windowControl,
074 ActionListener actionControl,
075 ChangeListener changeControl) {
076 super("Graphical user interface for TSP");
077 this.model = model;
078 this.keyControl = keyControl;
079 this.windowControl = windowControl;
080 this.actionControl = actionControl;
081 this.changeControl = changeControl;
082
083 addKeyListener(keyControl);
084 addWindowListener(windowControl);
085
086 setContentPane( makeGraphPane() );
087 setJMenuBar( makeTopMenu() );
088
089 setLocation(200,100);
090 pack();
091 setSize(950,650);
092
093 setVisible(true);
094 model.setUpdater(this);
095 }
096
097 /* never use this in swing
098 public void paint(Graphics g) {
099 super.paint( g );
100 g.drawString("Welcome at TSPgui",10,50);
101 g.drawString("Algorithm = "+model.algorithm,10,100);
102 }
103 */
104
105 /**
106 * @return top menue bar.
107 */
108 protected JMenuBar makeTopMenu() {
109 JMenuBar topMenu = new JMenuBar();
110 topMenu.setBackground( background );
111 topMenu.setForeground( text );
112 topMenu.add( makeFileMenu() );
113 topMenu.add( makeAlgoMenu() );
114 topMenu.add( makeProblemMenu() );
115 topMenu.add( makeHelpMenu() );
116 return topMenu;
117 }
118
119 /**
120 * @return file selection menue item.
121 */
122 protected JMenu makeFileMenu() {
123 JMenu file = new JMenu("File");
124 file.setMnemonic(KeyEvent.VK_F);
125 file.setBackground( background );
126 file.setForeground( text );
127 JCheckBoxMenuItem standAlone = new JCheckBoxMenuItem("Standalone",model.getStandAlone());
128 standAlone.setMnemonic(KeyEvent.VK_A);
129 standAlone.setBackground( background );
130 standAlone.setForeground( text );
131 standAlone.setActionCommand("standAlone");
132 standAlone.addActionListener(actionControl);
133 file.add(standAlone);
134 JMenuItem exit = new JMenuItem("Exit");
135 exit.setMnemonic(KeyEvent.VK_E);
136 exit.setBackground( background );
137 exit.setForeground( text );
138 exit.setActionCommand("exit");
139 exit.addActionListener(actionControl);
140 file.add(exit);
141 return file;
142 }
143
144 /**
145 * @return algorithm selection menue item.
146 */
147 protected JMenu makeAlgoMenu() {
148 JMenu algo = new JMenu("Algorithms");
149 algo.setMnemonic(KeyEvent.VK_A);
150 algo.setBackground( background );
151 algo.setForeground( text );
152 JMenuItem seq = new JMenuItem("Sequential");
153 seq.setMnemonic(KeyEvent.VK_S);
154 seq.setBackground( background );
155 seq.setForeground( text );
156 seq.setActionCommand("sequential");
157 seq.addActionListener(actionControl);
158 algo.add(seq);
159 JMenuItem para = new JMenuItem("Parallel");
160 para.setMnemonic(KeyEvent.VK_P);
161 para.setBackground( background );
162 para.setForeground( text );
163 para.setActionCommand("parallel");
164 para.addActionListener(actionControl);
165 algo.add(para);
166 JMenuItem dist = new JMenuItem("Distributed");
167 dist.setMnemonic(KeyEvent.VK_D);
168 dist.setBackground( background );
169 dist.setForeground( text );
170 dist.setActionCommand("distributed");
171 dist.addActionListener(actionControl);
172 algo.add(dist);
173 return algo;
174 }
175
176 /**
177 * @return problem handling menue item.
178 */
179 protected JMenu makeProblemMenu() {
180 JMenu prob = new JMenu("Problem");
181 prob.setMnemonic(KeyEvent.VK_P);
182 prob.setBackground( background );
183 prob.setForeground( text );
184 JMenuItem gener = new JMenuItem("Generate");
185 gener.setMnemonic(KeyEvent.VK_G);
186 gener.setBackground( background );
187 gener.setForeground( text );
188 gener.setActionCommand("generate");
189 gener.addActionListener(actionControl);
190 prob.add(gener);
191 JMenuItem sol = new JMenuItem("Solve");
192 sol.setMnemonic(KeyEvent.VK_S);
193 sol.setBackground( background );
194 sol.setForeground( text );
195 sol.setActionCommand("solve");
196 sol.addActionListener(actionControl);
197 prob.add(sol);
198 JMenuItem stp = new JMenuItem("Stop");
199 stp.setMnemonic(KeyEvent.VK_T);
200 stp.setBackground( background );
201 stp.setForeground( text );
202 stp.setActionCommand("stop");
203 stp.addActionListener(actionControl);
204 prob.add(stp);
205 return prob;
206 }
207
208 /**
209 * @return help menue item.
210 */
211 protected JMenu makeHelpMenu() {
212 JMenu help = new JMenu("Help");
213 help.setMnemonic(KeyEvent.VK_H);
214 help.setBackground( background );
215 help.setForeground( text );
216 JMenuItem about = new JMenuItem("About...");
217 about.setMnemonic(KeyEvent.VK_A);
218 about.setBackground( background );
219 about.setForeground( text );
220 about.setActionCommand("about");
221 about.addActionListener(actionControl);
222 help.add(about);
223 return help;
224 }
225
226 /**
227 * @return center panel with control planel, status and graph panel.
228 */
229 protected JPanel makeGraphPane() {
230 JPanel centerPanel = new JPanel();
231 centerPanel.setBorder( BorderFactory.createEtchedBorder() );
232 centerPanel.setBackground( background );
233 centerPanel.setForeground( text );
234 centerPanel.setFont( schrift );
235 // set its layout
236 centerPanel.setLayout(new BorderLayout());
237
238 JLabel mesg = new JLabel(" Welcome at TSPgui");
239 mesg.setForeground( text );
240 mesg.setFont( schrift );
241 centerPanel.add(mesg,BorderLayout.NORTH);
242
243 JComponent control = makeControlPane();
244 centerPanel.add(control,BorderLayout.WEST);
245
246 JPanel graph = new GraphPanel(model);
247 graph.setBackground( background );
248 graph.setForeground( text );
249 graph.setFont( schrift );
250 centerPanel.add(graph,BorderLayout.CENTER);
251 graphPanel = graph; // global static
252
253 JTextArea status = new JTextArea(4,0);
254 status.setFont( schrift2 );
255 JScrollPane scroll = new JScrollPane( status );
256 scroll.setBackground( background );
257 scroll.setBorder( BorderFactory.createTitledBorder("Status") );
258 centerPanel.add(scroll,BorderLayout.SOUTH);
259 statusArea = status; // global static
260
261 return centerPanel;
262 }
263
264
265 /**
266 * @return right status and control panel.
267 */
268 protected JComponent makeControlPane() {
269 final int cols = 16;
270 // Box rightPanel = new Box( BoxLayout.Y_AXIS );
271 JPanel rightPanel = new JPanel();
272 BoxLayout lay = new BoxLayout( rightPanel, BoxLayout.Y_AXIS );
273 rightPanel.setLayout( lay );
274 //rightPanel.setBorder( BorderFactory.createEtchedBorder() );
275 rightPanel.setBorder( BorderFactory.createTitledBorder("Parameters") );
276 rightPanel.setBackground( background );
277 rightPanel.setForeground( text );
278 rightPanel.setFont( schrift2 );
279
280 JLabel sizeL = new JLabel("Problem size:");
281 sizeL.setForeground( text );
282 sizeL.setFont( schrift2 );
283 rightPanel.add(sizeL);
284 JTextField size = new JTextField(""+model.getProbSize(),cols);
285 size.setForeground( text2 );
286 size.setFont( schrift2 );
287 size.setHorizontalAlignment( JTextField.RIGHT );
288 size.setMaximumSize(size.getPreferredSize());
289 size.setActionCommand("size");
290 size.addActionListener(actionControl);
291 rightPanel.add(size);
292
293 JLabel probF = new JLabel("Problem file:");
294 probF.setForeground( text );
295 probF.setFont( schrift2 );
296 rightPanel.add(probF);
297 JTextField prob = new JTextField("random",cols);
298 prob.setForeground( text2 );
299 prob.setFont( schrift2 );
300 prob.setMaximumSize(prob.getPreferredSize());
301 prob.setActionCommand("file");
302 prob.addActionListener(actionControl);
303 rightPanel.add(prob);
304
305 JLabel algoL = new JLabel("Algorithm:");
306 algoL.setForeground( text );
307 algoL.setFont( schrift2 );
308 rightPanel.add(algoL);
309 JTextField algo = new JTextField(""+model.getAlgorithm(),cols);
310 algo.setForeground( text2 );
311 algo.setBackground( background );
312 algo.setFont( schrift2 );
313 algo.setEditable(false);
314 algo.setMaximumSize(algo.getPreferredSize());
315 rightPanel.add(algo);
316 algorithmText = algo; // global static
317
318 JLabel maxT = new JLabel("max Threads:");
319 maxT.setForeground( text );
320 maxT.setFont( schrift2 );
321 rightPanel.add(maxT);
322 /*
323 SpinnerNumberModel thmodel = new SpinnerNumberModel(
324 model.getThreads(), 1, 1000, 1);
325 JSpinner thspin = new JSpinner( thmodel );
326 thspin.setForeground( text2 );
327 thspin.setFont( schrift2 );
328 thspin.setMaximumSize(thspin.getPreferredSize());
329 thspin.addChangeListener(changeControl);
330 //rightPanel.add(thspin);
331 */
332 JTextField maxth = new JTextField(""+model.getThreads(),cols);
333 maxth.setForeground( text2 );
334 maxth.setFont( schrift2 );
335 maxth.setHorizontalAlignment( JTextField.RIGHT );
336 maxth.setMaximumSize(maxth.getPreferredSize());
337 maxth.setActionCommand("threads");
338 maxth.addActionListener(actionControl);
339 rightPanel.add(maxth);
340
341 JLabel maxI = new JLabel("max Iterations:");
342 maxI.setForeground( text );
343 maxI.setFont( schrift2 );
344 rightPanel.add(maxI);
345 JTextField maxiter = new JTextField(""+model.getMaxIterations(),cols);
346 maxiter.setForeground( text2 );
347 maxiter.setFont( schrift2 );
348 maxiter.setHorizontalAlignment( JTextField.RIGHT );
349 maxiter.setMaximumSize(maxiter.getPreferredSize());
350 maxiter.setActionCommand("maxiter");
351 maxiter.addActionListener(actionControl);
352 rightPanel.add(maxiter);
353
354 JLabel iterL = new JLabel("Iterations:");
355 iterL.setForeground( text );
356 iterL.setFont( schrift2 );
357 rightPanel.add(iterL);
358 JTextField stat = new JTextField("0",cols);
359 stat.setForeground( text );
360 stat.setBackground( background );
361 stat.setFont( schrift2 );
362 stat.setEditable(false);
363 stat.setHorizontalAlignment( JTextField.RIGHT );
364 stat.setMaximumSize(stat.getPreferredSize());
365 rightPanel.add(stat);
366 statusLabel = stat; // global static
367
368 JLabel serv = new JLabel("Server:");
369 serv.setForeground( text );
370 serv.setFont( schrift2 );
371 rightPanel.add(serv);
372 JTextField server = new JTextField(""+model.getServer(),cols);
373 server.setForeground( text2 );
374 server.setFont( schrift2 );
375 server.setMaximumSize(server.getPreferredSize());
376 server.setActionCommand("server");
377 server.addActionListener(actionControl);
378 rightPanel.add(server);
379
380 JLabel port = new JLabel("Port:");
381 port.setForeground( text );
382 port.setFont( schrift2 );
383 rightPanel.add(port);
384 JTextField serverPort = new JTextField(""+model.getPort(),cols);
385 serverPort.setForeground( text2 );
386 serverPort.setFont( schrift2 );
387 serverPort.setHorizontalAlignment( JTextField.RIGHT );
388 serverPort.setMaximumSize(serverPort.getPreferredSize());
389 serverPort.setActionCommand("port");
390 serverPort.addActionListener(actionControl);
391 rightPanel.add(serverPort);
392
393 //rightPanel.setMaximumSize(rightPanel.getPreferredSize());
394 return rightPanel;
395 }
396
397
398 public synchronized void modelUpdated() {
399 if ( graphPanel != null ) {
400 graphPanel.repaint();
401 }
402 updateStatusLabel();
403 updateAlgorithm();
404 }
405
406 public synchronized void modelStatus() {
407 updateStatusArea();
408 }
409
410 protected void updateStatusArea() {
411 if ( statusArea == null ) {
412 return;
413 }
414 StringBuffer s = new StringBuffer();
415 s.append(" Algorithm( " + model.getAlgorithm());
416 if ( ! model.getAlgorithm().equals("sequential") ) {
417 s.append("/" + model.getThreads() );
418 }
419 s.append(" ) ");
420 s.append("Iterations( " + model.getIterations() );
421 s.append(", " + model.getIterPercent() );
422 s.append(" % of " + (model.getProbSize()-1) + "! ) " );
423 Path path = model.getActualBestPath();
424 if ( path != null ) {
425 if ( model.isBestPath() ) {
426 s.append("best");
427 }
428 s.append("Path = " + path );
429 }
430 s.append("\n");
431 statusArea.append( s.toString() );
432 }
433
434 protected void updateStatusLabel() {
435 if ( statusLabel == null ) {
436 return;
437 }
438 statusLabel.setText( ""+model.getIterations() );
439 }
440
441 protected void updateAlgorithm() {
442 if ( algorithmText == null ) {
443 return;
444 }
445 algorithmText.setText( model.getAlgorithm() );
446 }
447
448 /**
449 * @return true if user requests exit, else false.
450 */
451 protected static boolean doExitDialog() {
452 JOptionPane pane = new JOptionPane("Wollen Sie TSP verlassen?",
453 JOptionPane.WARNING_MESSAGE,
454 JOptionPane.YES_NO_OPTION);
455 pane.setBackground( background );
456 pane.setForeground( text );
457 pane.setFont( schrift2 );
458 pane.setOpaque(true);
459 JDialog dialog = pane.createDialog(null, "Exit Dialog");
460 dialog.setBackground( background );
461 dialog.setForeground( text );
462 dialog.setFont( schrift2 );
463 /*
464 pane.getRootPane().setOpaque(true);
465 dialog.getLayeredPane().setOpaque(true);
466 pane.getRootPane().setBackground( background );
467 pane.getRootPane().setForeground( text );
468 dialog.getContentPane().setBackground( background );
469 dialog.getContentPane().setForeground( text );
470 dialog.getGlassPane().setBackground( background );
471 dialog.getGlassPane().setForeground( text );
472 dialog.getLayeredPane().setBackground( background );
473 dialog.getLayeredPane().setForeground( text );
474 */
475 dialog.show();
476 Object selectedValue = pane.getValue();
477 if ( selectedValue == null ) {
478 return false;
479 }
480 if ( ! (selectedValue instanceof Integer) ) {
481 return false;
482 }
483 int r = ((Integer)selectedValue).intValue();
484 if ( r == JOptionPane.OK_OPTION ) {
485 return true;
486 }
487 return false;
488 /*
489 int r = JOptionPane.showConfirmDialog(
490 null,
491 "Wollen Sie TSP verlassen?",
492 "Exit Dialog",
493 JOptionPane.YES_NO_OPTION,
494 JOptionPane.WARNING_MESSAGE
495 );
496 */
497 }
498
499 protected static void doAboutDialog() {
500 JOptionPane pane = new JOptionPane(
501 "A GUI for the Traveling Salesman Problem (TSP)\n\n"
502 + "Author:\n"
503 + "Heinz Kredel, kredel@rz.uni-mannheim.de\n"
504 + "with the help of students from BA Mannheim\n"
505 + "Date: December 2004\n"
506 , JOptionPane.INFORMATION_MESSAGE);
507 pane.setBackground( background );
508 pane.setForeground( text );
509 pane.setFont( schrift2 );
510 pane.setOpaque(true);
511 JDialog dialog = pane.createDialog(null, "About TSPgui");
512 dialog.setBackground( background );
513 dialog.setForeground( text );
514 dialog.setFont( schrift2 );
515 dialog.show();
516 }
517 }
518
519 /**
520 * Class to handle the display of the points, paths and graphs.
521 */
522 class GraphPanel extends JPanel {
523
524 protected TSPguiModel model;
525 protected byte[] oldPath = null;
526
527 /**
528 * @param model the TSPguiModel.
529 */
530 public GraphPanel(TSPguiModel model) {
531 super();
532 this.model = model;
533 setPreferredSize(new Dimension(850,500));
534 setBorder( BorderFactory.createTitledBorder("Points and Path") );
535 }
536
537 public void paintComponent(Graphics g0) {
538 super.paintComponent(g0);
539 Point[] points = model.getScaledPoints();
540 if ( points == null ) {
541 return;
542 }
543 Graphics2D g = null;
544 if ( g0 instanceof Graphics2D ) {
545 g = (Graphics2D)g0;
546 } else {
547 return;
548 }
549 g.setColor( TSPguiMain.text );
550 double scaleX = this.getWidth()*0.9;
551 double scaleY = this.getHeight()*0.9;
552 double offX = this.getWidth()*0.05; // 5 % leerer rand
553 double offY = this.getHeight()*0.05;
554 int[] X = new int[ points.length ];
555 int[] Y = new int[ points.length ];
556 for ( int i = 0; i < points.length; i++ ) {
557 X[i] = (int)(offX + points[i].x * scaleX);
558 Y[i] = (int)(offY + points[i].y * scaleY);
559 g.fillRect(X[i]-5,Y[i]-5,10,10);
560 g.drawString(""+points[i].n,X[i]+8,Y[i]+8);
561 }
562 PathByteArray bestPath = (PathByteArray)model.getActualBestPath();
563 if ( bestPath == null ) {
564 oldPath = null;
565 return;
566 }
567 if ( bestPath.length() > points.length ) {
568 oldPath = null;
569 return;
570 }
571 if ( oldPath != null ) {
572 if ( oldPath.length == bestPath.length() ) {
573 g.setColor( Color.green );
574 drawPath(g, X, Y, oldPath);
575 }
576 }
577 if ( bestPath.used != null ) {
578 g.setColor( Color.darkGray );
579 drawPath(g, X, Y, bestPath.used);
580 oldPath = bestPath.used;
581 }
582 }
583
584 /**
585 * @param g a Graphics2D context.
586 * @param X array of x-coordinates.
587 * @param Y array of x-coordinates.
588 * @param path to display.
589 */
590 protected void drawPath(Graphics2D g, int[] X, int[] Y, byte[] path) {
591 for ( int i = 0; i < path.length-1 && i < X.length-1; i++ ) {
592 int i0 = path[i];
593 int i1 = path[i+1]; // % path.length];
594 g.drawLine(X[i0],Y[i0],X[i1],Y[i1]);
595 }
596 if (path.length == X.length) {
597 int i0 = path[path.length-1];
598 int i1 = path[0];
599 g.drawLine(X[i0],Y[i0],X[i1],Y[i1]);
600 }
601 }
602
603 }