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    }