001    // GraphLab Project: http://graphlab.sharif.edu
002    // Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology
003    // Distributed under the terms of the GNU General Public License (GPL): http://www.gnu.org/licenses/
004    package graphlab.plugins.algorithmanimator.core;
005    
006    import graphlab.graph.atributeset.GraphAttrSet;
007    import graphlab.graph.graph.GraphModel;
008    import graphlab.library.algorithms.AutomatedAlgorithm;
009    import graphlab.library.event.AlgorithmStep;
010    import graphlab.library.event.Event;
011    import graphlab.library.event.EventDispatcher;
012    import graphlab.platform.core.BlackBoard;
013    import graphlab.plugins.algorithmanimator.AnimatorGUI;
014    import graphlab.plugins.algorithmanimator.core.atoms.*;
015    
016    import javax.swing.*;
017    import java.awt.event.ActionEvent;
018    import java.awt.event.ActionListener;
019    import java.util.Vector;
020    
021    /**
022     * Actually the class which animates the algorithms!
023     *
024     * @author Azin Azadi
025     */
026    public class AlgorithmAnimator implements EventDispatcher, ActionListener {
027        static Vector<AtomAnimator> animators = new Vector<AtomAnimator>();
028        BlackBoard blackboard;
029        private boolean paused = true;
030        private JFrame f;
031        /**
032         * running algorithm just one step
033         */
034        private boolean oneStep;
035    
036        public AlgorithmAnimator(BlackBoard blackboard) {
037            this.blackboard = blackboard;
038            registerAtomAnimation(new VertexSelect());
039            registerAtomAnimation(new GraphSelect());
040            registerAtomAnimation(new PrePostWork());
041            registerAtomAnimation(new NewGraph());
042            registerAtomAnimation(new DelayEventHandler());
043            registerAtomAnimation(new ShowMessage());
044        }
045    
046        /**
047         * registers a new kind of AtomAnimator
048         *
049         * @param a
050         */
051        static public void registerAtomAnimation(AtomAnimator a) {
052            animators.add(a);
053        }
054    
055        public Event animateEvent(Event ae) {
056            for (AtomAnimator _ : animators)
057                if (_.isAnimatable(ae)) {
058                    return _.animate(ae, blackboard);
059                }
060            return ae;
061        }
062    
063        /**
064         * The main method, Animates an algorithm
065         *
066         * @param aa
067         */
068        public void animateAlgorithm(final AutomatedAlgorithm aa) {
069            new Thread() {
070                public void run() {
071                    GraphModel g = blackboard.getData(GraphAttrSet.name);
072                    boolean b = g.isShowChangesOnView();
073                    g.setShowChangesOnView(true);
074                    aa.acceptEventDispatcher(AlgorithmAnimator.this);
075                    aa.doAlgorithm();
076                    g.setShowChangesOnView(b);
077                }
078            }.start();
079    
080        }
081    
082        /**
083         * dispatchs events that recieved from the algorithm
084         *
085         * @param event
086         * @return
087         */
088        public Event dispatchEvent(Event event) {
089            try {
090    
091                if (event instanceof AlgorithmStep) {
092                    if (!oneStep) {
093                        double s = 100.0 - alggui.speedSlider.getValue();
094                        Thread.sleep((long) (10 * s));
095                    }
096                    if (oneStep) {
097                        paused = true;
098                    }
099                }
100            } catch (InterruptedException e) {
101                System.err.println("Thread sleep has error.");
102            }
103            Event event1 = animateEvent(event);
104    
105            JTextArea txt = alggui.algorithmOutputTextArea;
106            int cursorDot = txt.getCaret().getDot();
107            int cursorMark = txt.getCaret().getMark();
108            boolean isCursorInEnd = cursorDot == txt.getText().length();
109            if (event1 != null && event1.getMessage() != null && event1.getMessage() != "") {
110                alggui.algorithmOutputTextArea.setText(alggui.algorithmOutputTextArea.getText() + "\n" + event1.getMessage());
111                if (isCursorInEnd)
112                    txt.getCaret().setDot(txt.getText().length());
113                else {
114                    txt.getCaret().setDot(cursorMark);
115                    txt.getCaret().moveDot(cursorDot);
116                }
117                txt.getCaret().setVisible(true);
118    
119            }
120    
121            if (oneStep && event instanceof AlgorithmStep) {
122                alggui.playOneStepButton.setEnabled(true);
123                oneStep = false;
124            }
125            while (paused)
126                try {
127                    Thread.sleep(100);
128                } catch (InterruptedException e) {
129                    e.printStackTrace();
130                }
131    
132            return event1;
133        }
134    
135        /**
136         * handles gui control events
137         *
138         * @param e
139         */
140        public void actionPerformed(ActionEvent e) {
141            oneStep = false;
142            alggui.pauseButton.setEnabled(true);
143            alggui.playButton.setEnabled(true);
144            alggui.playOneStepButton.setEnabled(true);
145    
146            if (e.getActionCommand().contains("Pause")) {
147                alggui.pauseButton.setEnabled(false);
148                paused = true;
149            } else if (e.getActionCommand().equals("Play")) {
150                alggui.playButton.setEnabled(false);
151                paused = false;
152            } else if (e.getActionCommand().contains("One Step")) {
153                alggui.playOneStepButton.setEnabled(false);
154                oneStep = true;
155                paused = false;
156            } else System.out.println("Sooti !");
157        }
158    
159        AnimatorGUI alggui;
160    
161        /**
162         * creates the GUI control frame
163         *
164         * @param algorithmName
165         */
166        public void createControlDialog(String algorithmName) {
167            f = new JFrame();
168            f.setTitle("Algorithm Runner: " + algorithmName);
169            f.setAlwaysOnTop(true);
170            alggui = new AnimatorGUI(this);
171            //moves the carret to the end of text, see dispatch event
172            alggui.algorithmOutputTextArea.getCaret().setDot(alggui.algorithmOutputTextArea.getText().length());
173    
174            f.add(alggui.animatorFrame);
175            f.pack();
176            f.setVisible(true);
177    //        f = new JFrame("Controls");
178    //        f.setLayout(new GridBagLayout());
179    //        addBtn("Pause", new Dimension(75, 25));
180    //        addBtn("Play", new Dimension(75, 25));
181    //        addBtn("Play One Step", new Dimension(95, 25));
182    //        f.setSize(245,70);
183    //        f.setAlwaysOnTop(true);
184    //        f.setLocation(300,300);
185    //        f.setVisible(true);
186    ////        System.out.println("frame created");
187    //        try {
188    //            Thread.sleep(1000);
189    //        } catch (InterruptedException e) {
190    //            System.out.println("Error");
191    //        }
192        }
193    
194    //    private void addBtn(String lbl, Dimension d) {
195    //        JButton play = new JButton(lbl);
196    //        play.setSize(d);
197    //        play.addActionListener(this);
198    //        f.add(play);
199    //    }
200    
201    }