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