001package com.ganteater.ae.desktop.editor;
002
003import java.awt.BorderLayout;
004import java.awt.CardLayout;
005import java.awt.Color;
006import java.awt.Component;
007import java.awt.Desktop;
008import java.awt.Dimension;
009import java.awt.FileDialog;
010import java.awt.Font;
011import java.awt.Point;
012import java.awt.Toolkit;
013import java.awt.event.ActionEvent;
014import java.awt.event.ActionListener;
015import java.awt.event.KeyAdapter;
016import java.awt.event.KeyEvent;
017import java.awt.event.MouseAdapter;
018import java.awt.event.MouseEvent;
019import java.io.File;
020import java.io.FileOutputStream;
021import java.io.IOException;
022import java.lang.reflect.Constructor;
023import java.lang.reflect.InvocationTargetException;
024import java.util.ArrayList;
025import java.util.HashMap;
026import java.util.Map;
027import java.util.Properties;
028import java.util.Set;
029import java.util.Vector;
030
031import javax.swing.BorderFactory;
032import javax.swing.JButton;
033import javax.swing.JCheckBox;
034import javax.swing.JLabel;
035import javax.swing.JMenu;
036import javax.swing.JMenuBar;
037import javax.swing.JMenuItem;
038import javax.swing.JOptionPane;
039import javax.swing.JPanel;
040import javax.swing.JScrollPane;
041import javax.swing.JSeparator;
042import javax.swing.JSlider;
043import javax.swing.JSplitPane;
044import javax.swing.JTabbedPane;
045import javax.swing.JToolBar;
046import javax.swing.JTree;
047import javax.swing.JTree.DynamicUtilTreeNode;
048import javax.swing.KeyStroke;
049import javax.swing.SwingConstants;
050import javax.swing.SwingUtilities;
051import javax.swing.table.AbstractTableModel;
052import javax.swing.tree.DefaultMutableTreeNode;
053import javax.swing.tree.DefaultTreeModel;
054import javax.swing.tree.TreePath;
055import javax.swing.tree.TreeSelectionModel;
056
057import org.apache.commons.io.FilenameUtils;
058import org.apache.commons.lang.StringUtils;
059import org.apache.commons.lang.SystemUtils;
060import org.apache.commons.lang.exception.ExceptionUtils;
061
062import com.ganteater.ae.AEManager;
063import com.ganteater.ae.AEWorkspace;
064import com.ganteater.ae.CommandException;
065import com.ganteater.ae.ConfigurationException;
066import com.ganteater.ae.ILogger;
067import com.ganteater.ae.desktop.WorkPlace;
068import com.ganteater.ae.desktop.ui.AEFrame;
069import com.ganteater.ae.desktop.ui.AEPanel;
070import com.ganteater.ae.desktop.ui.DialogPopupMenu;
071import com.ganteater.ae.desktop.ui.TaskPanel;
072import com.ganteater.ae.desktop.view.ListLogPresenter;
073import com.ganteater.ae.desktop.view.LogPresenter;
074import com.ganteater.ae.desktop.view.PresentationPanel;
075import com.ganteater.ae.processor.BaseProcessor;
076import com.ganteater.ae.processor.Processor;
077import com.ganteater.ae.util.xml.easyparser.EasyParser;
078import com.ganteater.ae.util.xml.easyparser.EasyUtils;
079import com.ganteater.ae.util.xml.easyparser.Node;
080import com.ganteater.ae.util.xml.easyparser.Node.TreeVector;
081
082/**
083 * @author victort
084 * @version 1.0, 29-Jul-2005
085 */
086public class TaskEditor extends WorkPlace implements AEPanel, AeEditPanel {
087
088        private static final String EDITOR_STD_PACKAGE = "com.ganteater.ae.desktop.editor.";
089        private static final String ABOUT = "About";
090        private static final Color ACTIVE_COLOR = Color.GREEN.darker();
091        private static final Font font = new Font("Monospaced", Font.PLAIN, 12);
092
093        private static final String TASK_EDITOR = "Editor";
094        private static final String TASK_TREE = "Processing";
095
096        private String fTaskFile;
097        private Vector<?> fTreeVector;
098        private Map<String, Object> fPresentationPanels = new HashMap<String, Object>();
099
100        private AEFrame frame;
101        private JTree taskTree;
102        private TextEditor fTaskText = new TextEditor();
103        private JTabbedPane fOutputTabbedPane;
104        private TaskPanel thePanel;
105        private JMenuItem fRunMenuItem = new JMenuItem("Run");
106        private JMenuItem fContinueMenuItem = new JMenuItem("Continue");
107        private JMenuItem fStopMenuItem = new JMenuItem("Stop");
108        private JMenuItem fPauseMenuItem = new JMenuItem("Pause");
109        private JButton fRunButton = new JButton("Run");
110        private JCheckBox notifyMeCheckBox = new JCheckBox();
111        private JMenuItem saveMenuItem;
112        private JSplitPane fOutputSplitPanel;
113        private JSlider speed = new JSlider(0, 100, 100);
114        private JTabbedPane createEditorPanel;
115        private JLabel changedLabel = new JLabel("");
116
117        private JLabel lblTitle = new JLabel();
118        private JTabbedPane tabbedPanel;
119
120        private boolean openIn;
121
122        private CodeHelper codeHelper = new CodeHelper(this, getLogger());
123
124        public TaskEditor(AEFrame aFrame, Node aConfigNode, Map<String, Object> aSystemVariables) {
125                super(aFrame, aConfigNode, aSystemVariables);
126                this.frame = aFrame;
127
128                this.thePanel = new TaskPanel(this);
129
130                fOutputTabbedPane = new JTabbedPane();
131                fOutputTabbedPane.setPreferredSize(new Dimension(200, 800));
132                fOutputTabbedPane.addKeyListener(new KeyAdapter() {
133                        @Override
134                        public void keyReleased(KeyEvent e) {
135                                if (e.getKeyCode() == KeyEvent.VK_F4 && e.isControlDown()) {
136                                        removeActivePresentationPanel();
137                                }
138                        }
139                });
140
141                fOutputTabbedPane.addMouseListener(new MouseAdapter() {
142                        @Override
143                        public void mouseClicked(MouseEvent e) {
144                                JTabbedPane outputTabbedPane = (JTabbedPane) e.getSource();
145                                if (e.getButton() == MouseEvent.BUTTON2) {
146                                        if (outputTabbedPane.findComponentAt(e.getX(), e.getY()) == outputTabbedPane
147                                                        && outputTabbedPane.indexAtLocation(e.getX(), e.getY()) != -1) {
148
149                                                Component selectedComponent = outputTabbedPane.getSelectedComponent();
150                                                Object frameId = ((PresentationPanel) selectedComponent).getName();
151                                                removeActivePresentationPanel();
152                                                fPresentationPanels.remove(frameId);
153                                        }
154                                }
155                                if (e.getButton() == MouseEvent.BUTTON3) {
156                                        if (outputTabbedPane.findComponentAt(e.getX(), e.getY()) == outputTabbedPane
157                                                        && outputTabbedPane.indexAtLocation(e.getX(), e.getY()) != -1) {
158
159                                                PresentationPanel selectedComponent = (PresentationPanel) outputTabbedPane
160                                                                .getSelectedComponent();
161
162                                                if (selectedComponent instanceof LogPresenter
163                                                                && !((LogPresenter) selectedComponent).isEmpty()) {
164                                                        if (fLoggers.contains(selectedComponent)) {
165                                                                String frameId = selectedComponent.getName();
166                                                                LogPresenter findLogger = findLogger(frameId);
167                                                                LogPresenter bakPresenter = findLogger.copyAndClean();
168                                                                outputTabbedPane.addTab(frameId, AEFrame.getIcon("copied.png"), bakPresenter);
169                                                        }
170                                                }
171                                        }
172                                }
173                        }
174                });
175                createEditorPanel = createEditorPanel();
176
177                fOutputSplitPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT, createEditorPanel, fOutputTabbedPane);
178                fOutputSplitPanel.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, e -> {
179                        int dividerLocation = fOutputSplitPanel.getDividerLocation();
180                        String divider = Integer.toString(dividerLocation);
181                        int selectedIndex = createEditorPanel.getSelectedIndex();
182                        AEWorkspace.getInstance().setDefaultUserConfiguration("splitPanel.divider." + selectedIndex, divider);
183                });
184
185                setSplitPanel();
186
187                thePanel.add(fOutputSplitPanel, BorderLayout.CENTER);
188                JMenuBar menuBar = new JMenuBar();
189
190                createFileMenu(menuBar);
191                createProcessMenu(menuBar);
192
193                Node taskNode = getTaskNode();
194                if (taskNode != null && taskNode.findNode(ABOUT, null, null) != null) {
195                        showAbout();
196                }
197
198                JToolBar panel2 = new JToolBar();
199                panel2.setBorderPainted(false);
200                panel2.setFloatable(false);
201                panel2.add(fRunButton);
202                notifyMeCheckBox.setIcon(AEFrame.getIcon("shout-off.png"));
203                notifyMeCheckBox.setSelectedIcon(AEFrame.getIcon("shout.png"));
204                panel2.add(notifyMeCheckBox);
205
206                notifyMeCheckBox.addActionListener(e -> {
207                        if (getTaskName() != null) {
208                                String aName = getTaskName() + ".notifyMe";
209                                String value = Boolean.toString(notifyMeCheckBox.isSelected());
210                                AEWorkspace.getInstance().setDefaultUserConfiguration(aName, value);
211                                AEWorkspace.getInstance().setDefaultUserConfiguration("notifyMe", value);
212                        }
213                });
214
215                speed.setPreferredSize(new Dimension(30, 18));
216                speed.setToolTipText("Action speed");
217
218                speed.addChangeListener(e -> {
219                        String text;
220                        long traceDelay = getTraceDelay();
221                        if (traceDelay < 1000) {
222                                text = traceDelay + "ms.";
223                        } else {
224                                text = String.format("%.2f", traceDelay / 1000.0) + "s";
225                        }
226
227                        speed.setToolTipText("Delay: " + text);
228                        fTitleTest.setText("Slow motion time: " + text);
229                });
230
231                JPanel panel = new JPanel(new BorderLayout(4, 4));
232                panel.setBorder(BorderFactory.createEtchedBorder());
233                panel.add(menuBar, BorderLayout.WEST);
234
235                JButton closeBtn = new JButton(AEFrame.getIcon("close.png"));
236                closeBtn.addActionListener(e -> {
237                        stopTest();
238                        closeTab();
239                });
240                panel.add(closeBtn, BorderLayout.EAST);
241
242                thePanel.add(panel, BorderLayout.NORTH);
243
244                JPanel aboutPanel = new JPanel(new BorderLayout(0, 0));
245                aboutButtonPanel.setBorderPainted(false);
246                aboutButtonPanel.setFloatable(false);
247                aboutPanel.add(panel2, BorderLayout.WEST);
248
249                JPanel titlePanel = new JPanel(new BorderLayout(0, 0));
250                titlePanel.add(aboutButtonPanel, BorderLayout.WEST);
251                titlePanel.add(fTitleTest, BorderLayout.CENTER);
252                aboutPanel.add(titlePanel, BorderLayout.CENTER);
253                panel.add(aboutPanel, BorderLayout.CENTER);
254        }
255
256        public void setSplitPanel() {
257                fOutputSplitPanel.setOneTouchExpandable(true);
258        }
259
260        private String getTaskName() {
261                String name = null;
262                if (getTaskNode() != null) {
263                        name = getTaskNode().getAttribute("name");
264                }
265                return name;
266        }
267
268        public TaskEditor(AEFrame aeFrame) {
269                this(aeFrame, aeFrame.getWorkspace().getConfigNode(), aeFrame.getWorkspace().getSystemVariables());
270                setRunButtonAction(true);
271        }
272
273        private void createFileMenu(JMenuBar menuBar) {
274                JMenu menu = new JMenu("File");
275
276                JMenuItem menuItem;
277                menuItem = new JMenuItem("Save");
278                try {
279                        menuItem.setAccelerator(KeyStroke.getKeyStroke('S', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
280                } catch (Exception e) {
281                }
282
283                this.saveMenuItem = menuItem;
284                menuItem.addActionListener(new ActionListener() {
285                        public void actionPerformed(ActionEvent arg0) {
286
287                                SwingUtilities.invokeLater(() -> {
288                                        try {
289                                                save();
290                                        } catch (IOException e) {
291                                                JOptionPane.showMessageDialog(JOptionPane.getRootFrame(),
292                                                                "Error: Unable to Save File: " + fTaskFile);
293                                        }
294                                });
295                        }
296                });
297                menu.add(menuItem);
298
299                menuItem = new JMenuItem("Reload");
300                final JMenuItem reloadmenuItem = menuItem;
301                try {
302                        menuItem.setAccelerator(KeyStroke.getKeyStroke('R', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
303                } catch (Exception e) {
304                }
305                menuItem.addActionListener(arg0 -> {
306                        reload();
307                });
308                menu.add(menuItem);
309
310                menuItem = new JMenuItem("Format");
311                try {
312                        menuItem.setAccelerator(KeyStroke.getKeyStroke('F', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
313                } catch (Exception e) {
314                }
315                menuItem.addActionListener(arg0 -> {
316                        format();
317                });
318                menu.add(menuItem);
319
320                menuItem = new JMenuItem("Open In");
321                try {
322                        menuItem.setAccelerator(KeyStroke.getKeyStroke('E', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
323                } catch (Exception e) {
324                }
325                menuItem.addActionListener(arg0 -> {
326                        File file = new File(fTaskFile);
327                        if (file.exists()) {
328                                try {
329                                        Desktop.getDesktop().open(file);
330                                        openIn = true;
331                                        reloadmenuItem.setText("Reload [Before Run]");
332
333                                } catch (IOException e) {
334                                        getLogger().error(e.getMessage(), e);
335                                }
336                        }
337                });
338                menu.add(menuItem);
339
340                menu.add(new JSeparator());
341                menuItem = new JMenuItem("Close");
342                try {
343                        menuItem.setAccelerator(KeyStroke.getKeyStroke('X', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
344                } catch (Exception e) {
345                }
346                menuItem.addActionListener(e -> {
347                        closeTab();
348                });
349                menu.add(menuItem);
350                menuBar.add(menu);
351        }
352
353        public void reload() {
354                openTaskFile(fTaskFile);
355        }
356
357        public void save() throws IOException {
358                changedLabel.setText("");
359                format();
360                saveTask();
361        }
362
363        public void format() {
364                try {
365                        compileTask();
366                        refreshTaskTree();
367
368                        Node taskNode = getTaskNode();
369                        applyText(taskNode);
370
371                        if (taskNode != null && taskNode.findNode(ABOUT, null, null) != null) {
372                                showAbout();
373                        }
374
375                } catch (Exception e) {
376                        getLogger().error("Save action failed.", e);
377                }
378        }
379
380        private void createProcessMenu(JMenuBar menuBar) {
381                JMenu menu = new JMenu("Process");
382
383                JMenuItem compileMenuItem = new JMenuItem("Compile");
384                menu.add(compileMenuItem);
385                compileMenuItem.addActionListener(arg0 -> {
386                        try {
387                                compileTask();
388                        } catch (Exception e) {
389                                getLogger().error("Compilation failed.", e);
390                        }
391                });
392
393                menu.add(fRunMenuItem);
394
395                try {
396                        fRunMenuItem.setAccelerator(
397                                        KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
398                } catch (Exception e) {
399                }
400
401                fRunMenuItem.addActionListener(e -> {
402                        runTask();
403                });
404                menu.add(speed);
405
406                fRunButton.addActionListener(e -> {
407                        boolean isCurrentRunAction = "Run".equals(e.getActionCommand());
408
409                        if (isCurrentRunAction) {
410                                runTask();
411                        } else {
412                                stopTest();
413                                if (getTaskProcessor().isStoppedTest()) {
414                                        setRunButtonAction(true);
415                                }
416                        }
417                });
418
419                menu.add(fPauseMenuItem);
420
421                try {
422                        fPauseMenuItem
423                                        .setAccelerator(KeyStroke.getKeyStroke('P', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
424                } catch (Exception e) {
425                }
426
427                fPauseMenuItem.addActionListener(e -> {
428                        getTaskProcessor().pause();
429                });
430
431                menu.add(fContinueMenuItem);
432
433                try {
434                        fContinueMenuItem
435                                        .setAccelerator(KeyStroke.getKeyStroke('P', Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
436                } catch (Exception e) {
437                }
438
439                fContinueMenuItem.addActionListener(arg0 -> getTaskProcessor().resume());
440
441                try {
442                        fStopMenuItem.setAccelerator(
443                                        KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
444                } catch (Exception e) {
445                }
446
447                fStopMenuItem.addActionListener(arg0 -> stopTask());
448                menu.add(fStopMenuItem);
449                menuBar.add(menu);
450        }
451
452        @Override
453        public void setProgress(String message, long aMaxTags, long aCurrTags, boolean aErrorState) {
454                manager.progressValue((int) (((double) aCurrTags / aMaxTags) * 100), 100, true);
455                fTitleTest.setText(message);
456        }
457
458        public void stopTask() {
459                super.stopTest();
460        }
461
462        private JTabbedPane createEditorPanel() {
463                JTabbedPane editorPanel = new JTabbedPane();
464                editorPanel.setTabPlacement(SwingConstants.BOTTOM);
465
466                JScrollPane scrollPane = new JScrollPane();
467                scrollPane.getViewport().add(fTaskText);
468
469                fTaskText.addKeyListener(codeHelper);
470                fTaskText.addMouseListener(codeHelper);
471
472                fTaskText.setEditable(true);
473                fTaskText.addKeyListener(new KeyAdapter() {
474                        @Override
475                        public void keyPressed(KeyEvent e) {
476                                if (!(e.isControlDown()
477                                                && (e.getKeyCode() == 17 || e.getKeyChar() == 0 || e.getKeyCode() == KeyEvent.VK_C))) {
478                                        changedLabel.setText("*");
479                                }
480                        }
481                });
482
483                fTaskText.setFont(font);
484
485                JScrollPane theScroll = new JScrollPane();
486                theScroll.getViewport().removeAll();
487                taskTree = new JTree();
488                taskTree.setRootVisible(false);
489                taskTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
490
491                taskTree.addMouseListener(new MouseAdapter() {
492                        @Override
493                        public void mousePressed(MouseEvent e) {
494                                if (e.getClickCount() == 2) {
495                                        DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) taskTree
496                                                        .getLastSelectedPathComponent();
497                                        TreeVector userObject = (TreeVector) selectedNode.getUserObject();
498                                        Node node = userObject.getNode();
499
500                                        String tagName = node.getTag();
501                                        if ("Task".equals(tagName)) {
502                                                String name = node.getAttribute("name");
503                                                TaskEditor editTask = getAeFrame().editTask(name);
504                                                editTask.setRunButtonAction(true);
505                                        }
506                                }
507                        }
508                });
509
510                theScroll.getViewport().add(taskTree);
511
512                editorPanel.addTab(TASK_TREE, theScroll);
513                editorPanel.addTab(TASK_EDITOR, scrollPane);
514
515                editorPanel.addChangeListener(e -> {
516
517                        int selectedIndex = editorPanel.getSelectedIndex();
518                        String divider = AEWorkspace.getInstance()
519                                        .getDefaultUserConfiguration("splitPanel.divider." + selectedIndex, null);
520                        if (divider != null) {
521                                fOutputSplitPanel.setDividerLocation(Integer.parseInt(divider));
522                        }
523
524                        Component selectedComponent = editorPanel.getSelectedComponent();
525                        if (selectedComponent instanceof VariableViewPanel) {
526                                VariableViewPanel panel = (VariableViewPanel) selectedComponent;
527                                panel.refreshData();
528                        }
529                });
530
531                return editorPanel;
532        }
533
534        public void compileTask() {
535                try {
536                        Node object = new EasyParser().getObject(fTaskText.getText());
537                        setTaskNode(object);
538
539                } catch (Exception e1) {
540                        JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), "Incorrect code!\nError: " + e1.getMessage());
541                        throw e1;
542                }
543        }
544
545        public void showPanel(JTabbedPane panel, String name) {
546                if (name == null) {
547                        name = getPanelName();
548                }
549                tabbedPanel = panel;
550                String tabNameId = Integer.toString(thePanel.hashCode());
551                panel.addTab(tabNameId, thePanel);
552                panel.setSelectedComponent(thePanel);
553
554                JPanel pnlTab = new JPanel(new BorderLayout());
555                pnlTab.setOpaque(false);
556                pnlTab.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
557
558                setTitle(name);
559                lblTitle.addMouseListener(new MouseAdapter() {
560                        @Override
561                        public void mouseClicked(MouseEvent var1) {
562                                int index = tabbedPanel.indexOfTab(tabNameId);
563                                int button = var1.getButton();
564                                if (button == MouseEvent.BUTTON2) {
565                                        TaskEditor.this.frame.removeTab(TaskEditor.this);
566                                } else {
567                                        tabbedPanel.setSelectedIndex(index);
568                                }
569                        }
570                });
571
572                pnlTab.add(lblTitle, BorderLayout.CENTER);
573                pnlTab.add(changedLabel, BorderLayout.EAST);
574
575                int index = tabbedPanel.indexOfTab(tabNameId);
576                tabbedPanel.setTabComponentAt(index, pnlTab);
577        }
578
579        private void setTitle(String name) {
580                lblTitle.setText(StringUtils.abbreviate(name, 12));
581                lblTitle.setToolTipText(name);
582        }
583
584        public JPanel getMainPanel() {
585                return thePanel;
586        }
587
588        @Override
589        public void endTask(boolean aErrorState) {
590                super.endTask(aErrorState);
591                fRunMenuItem.setEnabled(true);
592                setRunButtonAction(true);
593        }
594
595        private void openTaskFile(String filePath) {
596                fTaskFile = filePath;
597                if (new File(fTaskFile).exists() && !openIn) {
598                        setEditable(true);
599                }
600
601                try {
602                        Node node = new EasyParser().load(filePath);
603                        applyText(node);
604                        changedLabel.setText("");
605                } catch (Exception e1) {
606                        throw new ConfigurationException("Invalide recipe file.", e1);
607                }
608
609        }
610
611        private void applyText(Node node) {
612                setTaskNode(node);
613                int caretPosition = fTaskText.getCaretPosition();
614                EasyUtils.removeTagId(node);
615
616                fTaskText.setOriginalText(node.getXMLText());
617                if (caretPosition < fTaskText.getDocument().getLength()) {
618                        fTaskText.setCaretPosition(caretPosition);
619                }
620                refreshTaskTree();
621        }
622
623        private void addExternTabs() {
624                Node taskNode = getConfigNode();
625                if (taskNode != null) {
626                        Node[] editors = taskNode.getNodes(TASK_EDITOR);
627                        createEditors(editors);
628                }
629
630                taskNode = getTaskNode();
631                if (taskNode != null) {
632                        Node[] editors = taskNode.getNodes(TASK_EDITOR);
633                        createEditors(editors);
634                }
635        }
636
637        private void createEditors(Node[] editors) {
638                for (Node editorNode : editors) {
639                        String className = editorNode.getAttribute("class");
640                        if (className != null) {
641                                Class<?> filterClass;
642                                try {
643                                        if (!className.startsWith(EDITOR_STD_PACKAGE)) {
644                                                className = EDITOR_STD_PACKAGE + className;
645                                        }
646
647                                        filterClass = Class.forName(className);
648                                        Constructor<?> constructor = filterClass.getConstructor();
649
650                                        String name = editorNode.getAttribute("name");
651                                        String tabName = StringUtils.defaultIfEmpty(name, StringUtils.substringAfterLast(className, "."));
652
653                                        JPanel editor = (JPanel) constructor.newInstance();
654                                        if (editor instanceof Editor) {
655                                                ((Editor) editor).init(this, editorNode);
656                                        }
657                                        createEditorPanel.addTab(tabName, editor);
658
659                                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException
660                                                | IllegalAccessException | IllegalArgumentException | InvocationTargetException
661                                                | CommandException e) {
662                                        e.printStackTrace();
663                                        JOptionPane.showMessageDialog(JOptionPane.getRootFrame(),
664                                                        "The creation of the extended panel failed.\nError: "
665                                                                        + ExceptionUtils.getRootCauseMessage(e));
666                                }
667                        }
668                }
669        }
670
671        private void setEditable(boolean editable) {
672                saveMenuItem.setEnabled(editable);
673                fTaskText.setEditable(editable);
674        }
675
676        protected void refreshTaskTree() {
677                if (getTaskNode() != null) {
678                        fTreeVector = getTaskNode().getVector(true);
679
680                        DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
681                        DynamicUtilTreeNode.createChildren(root, fTreeVector);
682                        DefaultTreeModel model = new DefaultTreeModel(root, false);
683                        taskTree.setModel(model);
684
685                        taskTree.setEditable(false);
686                        taskTree.setEnabled(true);
687
688                        taskTree.setFont(font);
689                        taskTree.setForeground(ACTIVE_COLOR);
690                        for (int i = 0; i < taskTree.getRowCount(); i++) {
691                                taskTree.expandRow(i);
692                        }
693                }
694        }
695
696        @Override
697        public void changeVariable(String aAttribut, Object aValue) {
698        }
699
700        static class JBorderedPanel extends JPanel {
701                private static final long serialVersionUID = 1L;
702
703                public JBorderedPanel(Component aNorth, Component aWest, Component aCenter, Component aEast, Component aSouth) {
704                        setLayout(new BorderLayout());
705                        if (aNorth != null) {
706                                add(aNorth, BorderLayout.NORTH);
707                        }
708                        if (aWest != null) {
709                                add(aWest, BorderLayout.WEST);
710                        }
711                        if (aCenter != null) {
712                                add(aCenter, BorderLayout.CENTER);
713                        }
714                        if (aEast != null) {
715                                add(aEast, BorderLayout.EAST);
716                        }
717                        if (aSouth != null) {
718                                add(aSouth, BorderLayout.SOUTH);
719                        }
720                }
721        }
722
723        @Override
724        public void startCommand(int aNumberCommand) {
725                setRunButtonAction(false);
726                try {
727                        if (taskTree != null) {
728                                taskTree.setSelectionRow(aNumberCommand);
729                                long delay = getTraceDelay();
730                                if (delay > 0) {
731                                        try {
732                                                Thread.sleep(delay);
733                                        } catch (Exception e) {
734                                                Thread.currentThread().interrupt();
735                                        }
736                                }
737                        }
738                } catch (Exception e) {
739                        //
740                }
741        }
742
743        private long getTraceDelay() {
744                return (int) ((Math.pow(1.5, (double) (100 - speed.getValue()) / 4)) - 1);
745        }
746
747        @Override
748        public void aboutTest(String theTaskName, Node aCurrentAction) {
749                try {
750                        setAbout(theTaskName, aCurrentAction);
751                        aboutButtonPanel.setVisible(true);
752                } catch (Exception e) {
753                        getLogger().error("Error", e);
754                }
755        }
756
757        @Override
758        public void runCommandFrame(Properties params) {
759                String theFrameId = params.getProperty("frameId");
760                String title = params.getProperty("title");
761
762                String reuse = params.getProperty("reuse");
763                if ("true".equals(reuse)) {
764                        PresentationPanel thePPanel = (PresentationPanel) fPresentationPanels.get(theFrameId);
765                        if (thePPanel != null && thePPanel.isValid()) {
766                                return;
767                        }
768                }
769
770                createFrame(theFrameId, params, title);
771        }
772
773        private PresentationPanel createFrame(String theFrameId, Properties linkedMap, String title) {
774
775                if (title == null) {
776                        title = theFrameId;
777                }
778
779                String className = linkedMap.getProperty("type", "TextPanel");
780
781                if (className.indexOf('.') < 0) {
782                        className = "com.ganteater.ae.desktop.view." + className;
783                }
784
785                Class<?> ppClass;
786                try {
787                        ppClass = Class.forName(className);
788                        Constructor<?> constructor = ppClass.getConstructor(Properties.class, AEManager.class);
789                        PresentationPanel pPanel = (PresentationPanel) constructor.newInstance(linkedMap, manager);
790
791                        fPresentationPanels.put(theFrameId, pPanel);
792                        fOutputTabbedPane.add(title, pPanel);
793
794                        fOutputTabbedPane.setSelectedComponent(pPanel);
795                        return pPanel;
796
797                } catch (Exception e) {
798                        throw new IllegalArgumentException(e);
799                }
800        }
801
802        @Override
803        public void outToFrame(Processor processor, Properties properties, Object value) {
804                String frameId = processor.replaceProperties((String) properties.get("frameId"));
805                if (frameId != null) {
806                        PresentationPanel panel = (PresentationPanel) fPresentationPanels.get(frameId);
807                        if (panel != null) {
808                                Properties params = panel.getParams();
809
810                                if (fOutputTabbedPane.getComponentZOrder(panel) < 0) {
811                                        fPresentationPanels.remove(frameId);
812                                        panel = null;
813                                }
814
815                                if (panel == null) {
816                                        createFrame(frameId, params, null);
817                                } else {
818                                        panel.out(value, properties);
819                                }
820                        }
821                }
822        }
823
824        public void removeActivePresentationPanel() {
825                int selectedIndex = fOutputTabbedPane.getSelectedIndex();
826
827                Component theComp = fOutputTabbedPane.getComponent(selectedIndex);
828                if (theComp instanceof PresentationPanel) {
829                        PresentationPanel thePPanel = (PresentationPanel) theComp;
830                        fPresentationPanels.remove(thePPanel.getName());
831                }
832
833                fOutputTabbedPane.remove(selectedIndex);
834                fLoggers.remove(findLogger(theComp));
835        }
836
837        int fNumberLog = 1;
838
839        private ArrayList<LogPresenter> fLoggers = new ArrayList<LogPresenter>();
840        private boolean isRunning;
841
842        public ILogger createLog(String aLogName, boolean mainLog) {
843
844                LogPresenter loggPanel = findLogger(aLogName);
845
846                if (loggPanel == null) {
847                        if (aLogName == null || aLogName.length() == 0)
848                                aLogName = "Log #" + String.valueOf(fNumberLog++);
849                        loggPanel = new ListLogPresenter(this, aLogName, mainLog);
850                        outputPaneAdd(loggPanel);
851                }
852
853                setLog(loggPanel);
854                return loggPanel;
855        }
856
857        public void setLog(ILogger log) {
858                super.setLog(log);
859                codeHelper.setLog(log);
860        }
861
862        private LogPresenter findLogger(String aLogName) {
863                if (aLogName == null && fLoggers.size() > 0) {
864                        return fLoggers.get(0);
865                }
866
867                int tabCount = fLoggers.size();
868                for (int i = 0; i < tabCount; i++) {
869                        LogPresenter logger = (LogPresenter) fLoggers.get(i);
870                        if (logger.getName().equals(aLogName)) {
871                                return logger;
872                        }
873                }
874
875                return null;
876        }
877
878        private LogPresenter findLogger(Component comp) {
879                int tabCount = fLoggers.size();
880                for (int i = 0; i < tabCount; i++) {
881                        LogPresenter logger = (LogPresenter) fLoggers.get(i);
882                        if (logger == comp) {
883                                return logger;
884                        }
885                }
886                return null;
887        }
888
889        @Override
890        public void errorInformation(Processor processor, Throwable exception, Node command) throws CommandException {
891                try {
892                        frame.errorInformation(processor, exception, command, notifyMeCheckBox.isSelected());
893                } catch (CommandException e) {
894                        throw e;
895                } catch (Throwable e) {
896                        throw new CommandException(e, processor, command);
897                }
898        }
899
900        class VarTableModel extends AbstractTableModel {
901                private static final long serialVersionUID = 1L;
902                private String[][] fRows;
903
904                public VarTableModel() throws Exception {
905                        Set<String> enumeration = getSystemVariables().keySet();
906                        fRows = new String[getSystemVariables().size()][2];
907                        int i = 0;
908                        for (String theName : enumeration) {
909                                String theValue = (String) getSystemVariables().get(theName);
910                                fRows[i][0] = theName;
911                                fRows[i][1] = theValue;
912                                i++;
913                        }
914                }
915
916                public int getColumnCount() {
917                        return 2;
918                }
919
920                public int getRowCount() {
921                        return getSystemVariables().size();
922                }
923
924                public Class<String> getColumnClass(int columnIndex) {
925                        return String.class;
926                }
927
928                public Object getValueAt(int row, int col) {
929                        return fRows[row][col];
930                }
931
932                public boolean isCellEditable(int rowIndex, int columnIndex) {
933                        return columnIndex > 0;
934                }
935
936                public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
937                        if (columnIndex == 1) {
938                                getSystemVariables().put(fRows[rowIndex][0], aValue);
939                                fRows[rowIndex][1] = (String) aValue;
940                        }
941                }
942
943                public String getColumnName(int column) {
944                        if (column == 0) {
945                                return "Name";
946                        } else {
947                                return "Value";
948                        }
949                }
950
951        }
952
953        public void outputPaneAdd(LogPresenter logPanel) {
954                fLoggers.add(logPanel);
955                LogPresenter panel = logPanel;
956                fOutputTabbedPane.add(logPanel.getName(), panel);
957                fPresentationPanels.put(logPanel.getName(), logPanel);
958                fOutputTabbedPane.setSelectedComponent(panel);
959        }
960
961        @Override
962        public void setActiveTest(String theActiveTest) {
963                String fileName = manager.getTestPath(theActiveTest);
964                if (fileName == null) {
965                        throw new IllegalArgumentException("Task file is not found. Recipe: " + theActiveTest);
966                }
967
968                setActiveTestFile(fileName);
969
970                addExternTabs();
971        }
972
973        private void setActiveTestFile(String fileName) {
974                openTaskFile(fileName);
975                recipeFilePath = fileName;
976
977                boolean editable = new File(fTaskFile).exists();
978                saveMenuItem.setEnabled(editable);
979                fTaskText.setEditable(editable);
980
981                Node taskNode = getTaskNode();
982                boolean c = taskNode != null && taskNode.findNode(ABOUT, null, null) != null;
983                if (c) {
984                        showAbout();
985                }
986        }
987
988        public void runTaskNode() {
989
990                Thread thread = new Thread() {
991                        public void run() {
992                                try {
993                                        Processor processor;
994
995                                        File parentFile = SystemUtils.getUserDir();
996                                        if (fTaskFile != null) {
997                                                parentFile = new File(fTaskFile).getParentFile();
998                                        }
999
1000                                        String selectedText = fTaskText.getSelectedText();
1001
1002                                        Node taskNode;
1003                                        Map<String, Object> hashtable;
1004                                        if (selectedText == null) {
1005                                                compileTask();
1006                                                taskNode = getTaskNode();
1007                                                processor = createProcessor();
1008                                                hashtable = processor.startVariables;
1009                                        } else {
1010                                                String code = fTaskText.getText(0, fTaskText.getSelectionStart());
1011                                                code = StringUtils.substringAfterLast(code, "<Extern ");
1012                                                if (!StringUtils.isEmpty(code)) {
1013                                                        code = "<Extern " + code;
1014                                                        selectedText = StringUtils.substringBefore(code, ">") + ">" + selectedText + "</Extern>";
1015                                                }
1016
1017                                                code = "<Task>" + selectedText + "</Task>";
1018
1019                                                taskNode = new EasyParser().getObject(code);
1020                                                setRunButtonAction(false);
1021
1022                                                processor = getTaskProcessor();
1023                                                hashtable = processor.getVariables();
1024                                        }
1025                                        taskNode.getVector(true);
1026
1027                                        processor.processTesting(taskNode, hashtable, parentFile);
1028                                        processor.getListener().endTask(false);
1029                                        endTask(false);
1030                                        setRunButtonAction(true);
1031
1032                                } catch (Exception e) {
1033                                        e.printStackTrace();
1034                                }
1035                        }
1036
1037                };
1038
1039                thread.start();
1040        }
1041
1042        private void runProcessTreeLine() {
1043                TreePath[] selectedPaths = taskTree.getSelectionPaths();
1044                if (createEditorPanel.getSelectedIndex() == 0 && selectedPaths != null) {
1045                        Processor processor = getTaskProcessor();
1046                        Node taskNode = new Node("Task");
1047                        setRunButtonAction(false);
1048                        for (TreePath path : selectedPaths) {
1049                                DefaultMutableTreeNode lastPathComponent = (DefaultMutableTreeNode) path.getLastPathComponent();
1050                                TreeVector userObject = (TreeVector) lastPathComponent.getUserObject();
1051                                Node node = userObject.getNode();
1052                                if ("Recipe".equals(node.getTag())) {
1053                                        taskNode = node;
1054                                        processor = createProcessor();
1055                                        Map<String, Object> hashtable = processor.startVariables;
1056                                } else {
1057                                        taskNode.add(node);
1058                                        processor = getTaskProcessor();
1059                                }
1060                        }
1061                }
1062        }
1063
1064        private Processor createProcessor() {
1065                String attribute = getTaskNode().getAttribute("name");
1066                if (attribute == null || attribute.isEmpty())
1067                        attribute = getTaskNode().getAttribute("description");
1068
1069                ILogger createLog = createLog(attribute, true);
1070                setProcessor(null);
1071                Processor processor = new BaseProcessor(getManager(), createLog, getManager().getStartDir());
1072                processor.init(fConfigNode, getSystemVariables(), this, getManager().getStartDir(), createLog);
1073                processor.setTestListener(this);
1074
1075                setProcessor(processor);
1076                return processor;
1077        }
1078
1079        public void start(String name) {
1080                if (StringUtils.isNotBlank(name)) {
1081                        setActiveTest(name);
1082                        runTaskNode();
1083                }
1084                fRunMenuItem.setEnabled(false);
1085        }
1086
1087        public void setRunButtonAction(boolean runAction) {
1088                this.isRunning = !runAction;
1089                if (runAction) {
1090                        try {
1091                                fRunButton.setText("Run");
1092                                fRunButton.setToolTipText("Run");
1093                                fContinueMenuItem.setEnabled(false);
1094                                fRunMenuItem.setEnabled(true);
1095                                fStopMenuItem.setEnabled(false);
1096                                fPauseMenuItem.setEnabled(false);
1097                                lblTitle.setBorder(BorderFactory.createEmptyBorder());
1098                        } catch (Exception e) {
1099                                e.printStackTrace();
1100                        }
1101
1102                } else {
1103                        try {
1104                                fRunButton.setText("Stop");
1105                                fRunButton.setToolTipText("Stop");
1106                                fContinueMenuItem.setEnabled(false);
1107                                fRunMenuItem.setEnabled(false);
1108                                fStopMenuItem.setEnabled(true);
1109                                fPauseMenuItem.setEnabled(true);
1110                                lblTitle.setBorder(BorderFactory.createMatteBorder(0, 0, 2, 0, ACTIVE_COLOR));
1111                        } catch (Exception e) {
1112                                e.printStackTrace();
1113                        }
1114                }
1115        }
1116
1117        public void edit(String name) {
1118                ListLogPresenter log = new ListLogPresenter(this, name);
1119                setLog(log);
1120                outputPaneAdd(log);
1121                fRunMenuItem.setEnabled(true);
1122        }
1123
1124        public void create(String name) {
1125                ListLogPresenter log = new ListLogPresenter(this, name);
1126                setLog(log);
1127
1128                fRunMenuItem.setEnabled(true);
1129                Node node = new EasyParser().getObject("<Recipe name=\"" + name + "\">\n<!-- your recipe code -->\n</Recipe>");
1130                applyText(node);
1131
1132                runTest(new Node[] { node });
1133                fContinueMenuItem.setEnabled(false);
1134        }
1135
1136        public String getPanelName() {
1137                Processor processor = getTaskProcessor();
1138                return processor.getTestName();
1139        }
1140
1141        public void saveTask() throws IOException {
1142                String recipeName = getTaskNode().getAttribute("name");
1143                if (fTaskFile == null || !fTaskFile.startsWith("jar:")) {
1144
1145                        if (fTaskFile == null) {
1146                                FileDialog theFileDialog = new FileDialog(JOptionPane.getRootFrame(), "Save Recipe File",
1147                                                FileDialog.SAVE);
1148                                if (getTaskNode() != null) {
1149                                        theFileDialog.setFile(recipeName + ".recipe");
1150                                }
1151                                theFileDialog.setVisible(true);
1152                                if (theFileDialog.getFile() == null)
1153                                        return;
1154                                fTaskFile = new File(theFileDialog.getDirectory() + theFileDialog.getFile()).getAbsolutePath();
1155                        }
1156
1157                        if (getTaskNode() != null) {
1158                                File file = new File(fTaskFile);
1159                                String name = FilenameUtils.getBaseName(file.getName());
1160                                String oldName = getTaskNode().getAttribute("name");
1161                                if (!StringUtils.equals(name, oldName)) {
1162                                        File newfile = new File(file.getParent(), oldName + ".recipe");
1163                                        if (file.renameTo(newfile)) {
1164                                                file = newfile;
1165                                                fTaskFile = file.getAbsolutePath();
1166                                        }
1167                                }
1168
1169                                Node theNode = (Node) getTaskNode().clone();
1170                                String newName = theNode.getAttribute("name");
1171
1172                                AEWorkspace workspace = frame.getWorkspace();
1173                                workspace.removeTestPath(oldName);
1174                                workspace.setTestPath(newName, fTaskFile);
1175
1176                                EasyUtils.removeTagId(theNode);
1177
1178                                byte[] bytes = getTaskNode().getXMLText().getBytes("UTF-8");
1179
1180                                try (FileOutputStream theFileOutputStream = new FileOutputStream(fTaskFile)) {
1181                                        theFileOutputStream.write(bytes);
1182                                }
1183
1184                                setTitle(recipeName);
1185                        }
1186                }
1187        }
1188
1189        public void runTask() {
1190                try {
1191                        final String selectedText = fTaskText.getSelectedText();
1192
1193                        if (openIn && selectedText == null) {
1194                                reload();
1195                        }
1196
1197                        getManager().startTaskNotify(this);
1198                        runTaskNode();
1199
1200                } catch (Exception e) {
1201                        getLogger().error("Running failed.", e);
1202                }
1203        }
1204
1205        @Override
1206        public void criticalError(final CommandException exception, final Processor processor) {
1207                frame.criticalError(TaskEditor.this);
1208                lblTitle.setBorder(BorderFactory.createMatteBorder(0, 0, 2, 0, Color.RED));
1209
1210                if (isNotifyMe()) {
1211                        getFrame().fireBuzzAction(() -> super.criticalError(exception, processor));
1212                } else {
1213                        super.criticalError(exception, processor);
1214                }
1215        }
1216
1217        @Override
1218        public void checkFailure(final CommandException exception, final Processor processor) {
1219                frame.checkFailure(TaskEditor.this);
1220
1221                if (isNotifyMe()) {
1222                        getFrame().fireBuzzAction(() -> super.checkFailure(exception, processor));
1223                } else {
1224                        super.checkFailure(exception, processor);
1225                }
1226        }
1227
1228        public void closeTab() {
1229                frame.removeTab(TaskEditor.this);
1230        }
1231
1232        public void showAbout() {
1233                Node taskNode = getTaskNode();
1234                aboutTest(taskNode.getAttribute("name"), taskNode.findNode(ABOUT, null, null));
1235        }
1236
1237        public void showTaskTreePane() {
1238                CardLayout cl = (CardLayout) (createEditorPanel.getLayout());
1239                cl.show(createEditorPanel, TASK_TREE);
1240        }
1241
1242        public int getCaretPosition() {
1243                return fTaskText.getCaretPosition();
1244        }
1245
1246        public Point getMagicCaretPosition() {
1247                return fTaskText.getCaret().getMagicCaretPosition();
1248        }
1249
1250        public String getText() {
1251                return fTaskText.getText();
1252        }
1253
1254        public void replaceRange(String text, int i, int caretPosition2) {
1255                fTaskText.replaceRange(text, i, caretPosition2);
1256        }
1257
1258        public DialogPopupMenu contextHelp(DialogPopupMenu menu) {
1259                return menu;
1260        }
1261
1262        @Override
1263        public void runTest(Node testNode[]) {
1264                Node object = testNode[0];
1265                object.getVector(true);
1266                setTaskNode(object);
1267                refreshTaskTree();
1268                runTaskNode();
1269        }
1270
1271        public AEFrame getFrame() {
1272                return frame;
1273        }
1274
1275        public void pause() {
1276                fRunMenuItem.setEnabled(false);
1277                fContinueMenuItem.setEnabled(true);
1278                fPauseMenuItem.setEnabled(false);
1279
1280                fTitleTest.setText(" Suspended execution ...");
1281                fTitleTest.setForeground(Color.YELLOW.darker());
1282                lblTitle.setBorder(BorderFactory.createMatteBorder(0, 0, 2, 0, Color.YELLOW));
1283        }
1284
1285        @Override
1286        public void resume() {
1287                fRunMenuItem.setEnabled(false);
1288                fContinueMenuItem.setEnabled(false);
1289                fPauseMenuItem.setEnabled(true);
1290
1291                fTitleTest.setText("");
1292                fTitleTest.setForeground(Color.GRAY.darker());
1293                lblTitle.setBorder(BorderFactory.createMatteBorder(0, 0, 2, 0, ACTIVE_COLOR));
1294        }
1295
1296        public boolean isRunning() {
1297                return isRunning;
1298        }
1299
1300        public TextEditor getEditor() {
1301                return fTaskText;
1302        }
1303
1304        public void select() {
1305                getFrame().setSelectedComponent(getMainPanel());
1306        }
1307
1308        @Override
1309        public void setTaskNode(Node taskNode) {
1310                super.setTaskNode(taskNode);
1311                String aName = getTaskName() + ".notifyMe";
1312                String defaultNotify = AEWorkspace.getInstance().getDefaultUserConfiguration("notifyMe", "true");
1313                boolean notify = Boolean
1314                                .parseBoolean(AEWorkspace.getInstance().getDefaultUserConfiguration(aName, defaultNotify));
1315                notifyMeCheckBox.setSelected(notify);
1316        }
1317
1318        public boolean isNotifyMe() {
1319                return notifyMeCheckBox.isSelected();
1320        }
1321
1322}