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 }