001package com.ganteater.ae.desktop.editor;
002
003import java.awt.BorderLayout;
004import java.awt.Dimension;
005import java.awt.Point;
006import java.awt.event.FocusAdapter;
007import java.awt.event.FocusEvent;
008import java.awt.event.KeyAdapter;
009import java.awt.event.KeyEvent;
010import java.awt.event.MouseAdapter;
011import java.awt.event.MouseEvent;
012import java.lang.reflect.Method;
013import java.util.ArrayList;
014import java.util.Arrays;
015import java.util.HashMap;
016import java.util.LinkedHashMap;
017import java.util.List;
018import java.util.Map;
019import java.util.Set;
020
021import javax.swing.BorderFactory;
022import javax.swing.DefaultListModel;
023import javax.swing.JDialog;
024import javax.swing.JList;
025import javax.swing.JScrollPane;
026import javax.swing.SwingUtilities;
027import javax.swing.event.ListSelectionEvent;
028import javax.swing.event.ListSelectionListener;
029
030import org.apache.commons.lang.ClassUtils;
031import org.apache.commons.lang.StringUtils;
032
033import com.ganteater.ae.processor.Processor;
034import com.ganteater.ae.processor.annotation.CommandExamples;
035import com.ganteater.ae.util.xml.easyparser.Node;
036
037public class CommandHelperPopup extends JDialog {
038
039        private static final long serialVersionUID = 1L;
040
041        private CodeHelper codeHelper;
042        private DefaultListModel<String> commandListModel = new DefaultListModel<>();
043        private JList<String> commands = new JList<String>(commandListModel);
044
045        private DefaultListModel<String> examplesListModel = new DefaultListModel<>();
046        private JList<String> examples = new JList<String>(examplesListModel);
047
048        private String startSymbols;
049
050        private Map<String, List<String>> exampleMap = new HashMap<>();
051
052        public CommandHelperPopup(CodeHelper codeHelper) {
053                this.codeHelper = codeHelper;
054                setAlwaysOnTop(true);
055                setUndecorated(true);
056                JScrollPane comp = new JScrollPane(commands);
057                comp.setPreferredSize(new Dimension(150, 200));
058
059                getContentPane().add(comp, BorderLayout.WEST);
060                commands.setBorder(BorderFactory.createEmptyBorder());
061                commands.setBackground(getBackground());
062                commands.addFocusListener(new FocusAdapter() {
063                        @Override
064                        public void focusLost(FocusEvent e) {
065                                if (e.getOppositeComponent() != CommandHelperPopup.this && e.getOppositeComponent() != examples) {
066                                        setVisible(false);
067                                }
068                        }
069                });
070                commands.addMouseListener(new MouseAdapter() {
071                        @Override
072                        public void mouseClicked(MouseEvent e) {
073                                String commandName = commands.getSelectedValue();
074                                if (e.getClickCount() == 2) {
075                                        if (examples.getModel().getSize() > 1) {
076                                                if (examples.isSelectionEmpty()) {
077                                                        examples.requestFocus();
078                                                        examples.setSelectedIndex(0);
079                                                } else {
080                                                        perform(commandName);
081                                                }
082                                        } else {
083                                                perform(commandName);
084                                        }
085                                } else {
086                                        fillExamples(commandName);
087                                }
088                        }
089                });
090                commands.addListSelectionListener(new ListSelectionListener() {
091                        @Override
092                        public void valueChanged(ListSelectionEvent e) {
093                                String commandName = commands.getSelectedValue();
094                                fillExamples(commandName);
095                        }
096                });
097                commands.addKeyListener(new KeyAdapter() {
098                        @Override
099                        public void keyPressed(KeyEvent e) {
100                                int keyCode = e.getKeyCode();
101                                if (keyCode == KeyEvent.VK_ESCAPE) {
102                                        setVisible(false);
103                                } else {
104                                        if (keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_ENTER) {
105                                                if (examples.getModel().getSize() > 1) {
106                                                        examples.requestFocus();
107                                                        examples.setSelectedIndex(0);
108                                                } else {
109                                                        String commandName = commands.getSelectedValue();
110                                                        perform(commandName);
111                                                }
112                                        }
113                                }
114                        }
115                });
116
117                JScrollPane comp1 = new JScrollPane(examples);
118                comp1.setPreferredSize(new Dimension(400, 200));
119                getContentPane().add(comp1, BorderLayout.CENTER);
120
121                examples.setBackground(getBackground());
122                examples.addMouseListener(new MouseAdapter() {
123                        @Override
124                        public void mouseClicked(MouseEvent e) {
125                                String commandName = examples.getSelectedValue();
126                                if (e.getClickCount() == 2) {
127                                        perform(commandName);
128                                }
129                        }
130                });
131                examples.addFocusListener(new FocusAdapter() {
132                        @Override
133                        public void focusLost(FocusEvent e) {
134                                if (e.getOppositeComponent() != CommandHelperPopup.this && e.getOppositeComponent() != commands) {
135                                        setVisible(false);
136                                }
137                        }
138                });
139                examples.addKeyListener(new KeyAdapter() {
140                        @Override
141                        public void keyPressed(KeyEvent e) {
142                                int keyCode = e.getKeyCode();
143                                if (keyCode == KeyEvent.VK_ESCAPE) {
144                                        setVisible(false);
145                                } else {
146                                        if (keyCode == KeyEvent.VK_ENTER) {
147                                                String commandName = examples.getSelectedValue();
148                                                perform(commandName);
149                                        } else if (keyCode == KeyEvent.VK_LEFT) {
150                                                commands.requestFocus();
151                                        }
152                                }
153                        }
154                });
155
156        }
157
158        private void perform(String commandName) {
159                List<String> examples = exampleMap.get(commandName);
160                setVisible(false);
161                if (examples != null && !examples.isEmpty()) {
162                        int selectedIndex = this.examples.getSelectedIndex();
163                        if(selectedIndex < 0) {
164                                selectedIndex = 0;
165                        }
166                        
167                        String text = examples.get(selectedIndex).trim();
168                        if (!StringUtils.startsWith(text, "<") && StringUtils.contains(text, ":")) {
169                                text = StringUtils.substringAfter(text, ":");
170                        }
171                        codeHelper.insertTag(startSymbols, text);
172                }
173                if (examples == null) {
174                        commandName = commandName.trim();
175                        if (!StringUtils.startsWith(commandName, "<") && StringUtils.contains(commandName, ":")) {
176                                commandName = StringUtils.substringAfter(commandName, ":");
177                        }
178                        codeHelper.insertTag(startSymbols, commandName);
179                }
180        }
181
182        private void fillExamples(String commandName) {
183                List<String> list = exampleMap.get(commandName);
184                if (list != null) {
185                        examplesListModel.removeAllElements();
186                        for (String example : list) {
187                                examplesListModel.addElement(example);
188                        }
189                        if(!list.isEmpty()) {
190                                examples.setSelectedIndex(0);
191                        }
192                }
193        }
194
195        private List<String> getExampleList(Class class1, String[] names) {
196                List<String> menu = new ArrayList<>();
197                Arrays.sort(names);
198                for (final String name : names) {
199                        String[] examples = null;
200                        try {
201                                Method method = null;
202                                try {
203                                        method = class1.getMethod(CodeHelper.RUN_COMMAND_METHODE_PREFIX + name, new Class[] { Node.class });
204                                        CommandExamples annotation = method.getAnnotation(CommandExamples.class);
205                                        if (annotation != null) {
206                                                examples = annotation.value();
207                                        }
208
209                                } catch (NoSuchMethodException e) {
210                                }
211
212                                if (examples != null) {
213                                        menu.add(name);
214                                        List<String> exampleList = new ArrayList<String>();
215                                        for (String example : examples) {
216                                                exampleList.add(example);
217                                        }
218                                        exampleMap.put(name, exampleList);
219                                }
220
221                        } catch (Exception e1) {
222                                // log.error("Popup menu creation failed.", e1);
223                        }
224                }
225
226                return menu;
227        }
228
229        public void getCommandList(String text, Processor makeProcessor) {
230                this.startSymbols = text;
231                text = StringUtils.substring(text, 1);
232                commandListModel.removeAllElements();
233                Map<Class<? extends Processor>, List<String>> namesMap = new LinkedHashMap<>();
234
235                Class<? extends Processor> processorClass = makeProcessor.getClass();
236                Method[] methods = processorClass.getMethods();
237
238                for (Method method : methods) {
239                        if (StringUtils.startsWith(method.getName(), CodeHelper.RUN_COMMAND_METHODE_PREFIX)) {
240                                Class<?> declaringClass = method.getDeclaringClass();
241
242                                String name = StringUtils.substringAfter(method.getName(), CodeHelper.RUN_COMMAND_METHODE_PREFIX);
243                                if (name.startsWith(text) && ClassUtils.isAssignable(declaringClass, Processor.class)) {
244                                        List<String> list = namesMap.get(declaringClass);
245                                        if (list == null) {
246                                                list = new ArrayList<>();
247                                                @SuppressWarnings("unchecked")
248                                                Class<? extends Processor> clazz = (Class<? extends Processor>) declaringClass;
249                                                namesMap.put(clazz, list);
250                                        }
251                                        list.add(name);
252                                }
253                        }
254                }
255
256                Set<Class<? extends Processor>> keySet = namesMap.keySet();
257                for (Class<? extends Processor> processor : keySet) {
258                        List<String> list = namesMap.get(processor);
259                        String[] names = list.toArray(new String[list.size()]);
260                        Arrays.sort(names);
261                        for (String command : names) {
262                                commandListModel.addElement(command);
263                        }
264
265                        getExampleList(processor, names);
266                }
267
268                if (commandListModel.getSize() > 1 || exampleMap.get(commandListModel.firstElement()).size() > 1) {
269                        AeEditPanel editor = codeHelper.getEditor();
270                        Point magicCaretPosition = editor.getMagicCaretPosition();
271                        Point locationOnScreen = editor.getEditor().getLocationOnScreen();
272                        setLocation(locationOnScreen.x + magicCaretPosition.x,
273                                        locationOnScreen.y + magicCaretPosition.y + editor.getEditor().getFont().getSize() + 4);
274                        pack();
275
276                        setVisible(true);
277
278                        SwingUtilities.invokeLater(() -> {
279                                requestFocusInWindow();
280                                commands.requestFocusInWindow();
281                                commands.setSelectedIndex(0);
282                                fillExamples(commands.getSelectedValue());
283                        });
284                } else {
285                        String firstElement = commandListModel.firstElement();
286                        perform(firstElement);
287                }
288        }
289}