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}