001package com.ganteater.ae.desktop.editor;
002
003import java.awt.event.ActionEvent;
004import java.awt.event.KeyAdapter;
005import java.awt.event.KeyEvent;
006import java.lang.reflect.Constructor;
007
008import javax.swing.AbstractAction;
009import javax.swing.JPopupMenu;
010import javax.swing.JTextArea;
011import javax.swing.text.BadLocationException;
012import javax.swing.text.DefaultCaret;
013import javax.swing.text.Document;
014import javax.swing.undo.UndoManager;
015
016import org.apache.commons.lang.StringUtils;
017
018import com.ganteater.ae.CommandException;
019import com.ganteater.ae.desktop.util.UIUtils;
020import com.ganteater.ae.util.xml.easyparser.Node;
021
022public class TextEditor extends JTextArea implements Editor {
023
024        private static final long serialVersionUID = -298735473495909314L;
025        private final UndoManager undo = new UndoManager();
026        private TaskEditor recipePanel;
027        private Node editorNode;
028        private CodeHelper codeHelper;
029
030        public TextEditor() {
031                super();
032                setTabSize(4);
033                Document doc = getDocument();
034                doc.addUndoableEditListener((evt) -> undo.addEdit(evt.getEdit()));
035                addKeyListener(new KeyAdapter() {
036                        @Override
037                        public void keyPressed(KeyEvent e) {
038                                if (e.getKeyCode() == KeyEvent.VK_Z && e.isControlDown()) {
039                                        undo();
040                                } else if (e.getKeyCode() == KeyEvent.VK_Y && e.isControlDown()) {
041                                        redo();
042                                }
043                        }
044                });
045                
046                setCaret(new DefaultCaret() {
047            @Override
048            public void setSelectionVisible(boolean visible) {
049                super.setSelectionVisible(true);
050            }
051        });
052
053                initPopupMenu();
054        }
055
056        protected void initPopupMenu() {
057                JPopupMenu popup = new JPopupMenu();
058
059                popup.add(new AbstractAction("Code Helper") {
060                        private static final long serialVersionUID = 1L;
061
062                        @Override
063                        public void actionPerformed(ActionEvent ae) {
064                                codeHelper.showCommandsMenu();
065                        }
066                });
067                popup.add(new AbstractAction("Run Selection") {
068                        private static final long serialVersionUID = 1L;
069
070                        @Override
071                        public void actionPerformed(ActionEvent ae) {
072                                try {
073                                        getRecipePanel().runCode(true);
074                                } catch (BadLocationException | CommandException e) {
075                                        // TODO Auto-generated catch block
076                                        e.printStackTrace();
077                                }
078                        }
079                });
080                popup.addSeparator();
081
082                UIUtils.addJPopupMenuTo(this, popup);
083        }
084
085        @Override
086        public void init(TaskEditor taskEditor) throws CommandException {
087                this.recipePanel = taskEditor;
088                setFont(TaskEditor.font);
089
090                String helper = null;
091                if (editorNode != null) {
092                        helper = taskEditor.getTaskProcessor().attr(editorNode, "helper");
093                }
094                if (helper == null) {
095                        helper = CodeHelper.class.getName();
096                }
097                if (!helper.startsWith(TaskEditor.EDITOR_STD_PACKAGE)) {
098                        helper = TaskEditor.EDITOR_STD_PACKAGE + helper;
099                }
100
101                try {
102                        @SuppressWarnings("unchecked")
103                        Class<? extends CodeHelper> filterClass = (Class<? extends CodeHelper>) Class.forName(helper);
104                        Constructor<? extends CodeHelper> constructor = filterClass.getConstructor(TextEditor.class);
105                        codeHelper = constructor.newInstance(this);
106                        addKeyListener(codeHelper);
107
108                } catch (Exception e) {
109                        throw new IllegalArgumentException(e);
110                }
111        }
112
113        public void redo() {
114                try {
115                        int caretPosition = getCaretPosition();
116                        if (undo.canRedo()) {
117                                undo.redo();
118                                if (getDocument().getLength() == 0) {
119                                        if (undo.canRedo()) {
120                                                undo.redo();
121                                        } else if (undo.canUndo()) {
122                                                undo.undo();
123                                        }
124                                }
125                        }
126                        setCaretPosition(caretPosition);
127                } catch (Exception e) {
128                        // no nothing.
129                }
130        }
131
132        public void undo() {
133                try {
134                        int caretPosition = getCaretPosition();
135                        if (undo.canUndo()) {
136                                undo.undo();
137                                if (getDocument().getLength() == 0) {
138                                        if (undo.canUndo()) {
139                                                undo.undo();
140                                        } else if (undo.canRedo()) {
141                                                undo.redo();
142                                        }
143                                }
144                        }
145                        setCaretPosition(caretPosition);
146                } catch (Exception e) {
147                        // no nothing.
148                }
149        }
150
151        public void removeLine() {
152                int caretPosition = getCaretPosition();
153                String text = getText();
154                int start = StringUtils.lastIndexOf(text, "\n", caretPosition - 1);
155                start = start < 0 ? 0 : start + 1;
156                int end = StringUtils.indexOf(text, "\n", caretPosition);
157                end = end < 0 ? text.length() - 1 : end + 1;
158                start = start < end ? start : end;
159                replaceRange("", start, end);
160                setCaretPosition(start == 0 ? 0 : start);
161        }
162
163        public void setOriginalText(String xmlText) {
164                setText(xmlText);
165        }
166
167        public TaskEditor getRecipePanel() {
168                return recipePanel;
169        }
170
171        public Node getEditorNode() {
172                return editorNode;
173        }
174
175        public void setEditorNode(Node editorNode) {
176                this.editorNode = editorNode;
177        }
178
179}