001package com.ganteater.ae.desktop.editor; 002 003import java.awt.BorderLayout; 004import java.awt.Dimension; 005import java.awt.FileDialog; 006import java.awt.Point; 007import java.awt.event.ActionEvent; 008import java.awt.event.ActionListener; 009import java.awt.event.FocusAdapter; 010import java.awt.event.FocusEvent; 011import java.awt.event.KeyAdapter; 012import java.awt.event.KeyEvent; 013import java.awt.event.MouseAdapter; 014import java.awt.event.MouseEvent; 015import java.util.ArrayList; 016import java.util.Arrays; 017import java.util.Comparator; 018import java.util.HashMap; 019import java.util.List; 020import java.util.Map; 021import java.util.Properties; 022import java.util.Set; 023import java.util.StringTokenizer; 024import java.util.stream.Collectors; 025 026import javax.swing.DefaultListModel; 027import javax.swing.JList; 028import javax.swing.JMenuItem; 029import javax.swing.JOptionPane; 030import javax.swing.JRootPane; 031import javax.swing.JScrollPane; 032import javax.swing.SwingUtilities; 033import javax.swing.event.ListSelectionEvent; 034import javax.swing.event.ListSelectionListener; 035import javax.swing.text.BadLocationException; 036 037import org.apache.commons.lang.StringEscapeUtils; 038import org.apache.commons.lang3.StringUtils; 039 040import com.ganteater.ae.AEWorkspace; 041import com.ganteater.ae.OperationHolder; 042import com.ganteater.ae.TaskCancelingException; 043import com.ganteater.ae.desktop.ui.DialogPopupMenu; 044import com.ganteater.ae.desktop.ui.OptionPane; 045import com.ganteater.ae.desktop.view.View; 046import com.ganteater.ae.processor.BaseProcessor; 047import com.ganteater.ae.processor.CommandInfo; 048import com.ganteater.ae.processor.Processor; 049import com.ganteater.ae.util.AEUtils; 050import com.ganteater.ae.util.ClassUtils; 051import com.ganteater.ae.util.xml.easyparser.EasyParser; 052import com.ganteater.ae.util.xml.easyparser.Node; 053 054public class CommandHelperDialog extends HelperDialog { 055 056 private static final long serialVersionUID = 1L; 057 058 private DefaultListModel<String> commandListModel = new DefaultListModel<>(); 059 private JList<String> commands = new JList<String>(commandListModel); 060 061 private DefaultListModel<String> examplesListModel = new DefaultListModel<>(); 062 private JList<String> examples = new JList<String>(examplesListModel); 063 064 private String startSymbols; 065 066 private Map<String, List<String>> exampleMap = new HashMap<>(); 067 068 public CommandHelperDialog(CodeHelper codeHelper) { 069 super(codeHelper); 070 071 setAlwaysOnTop(true); 072 setUndecorated(true); 073 JScrollPane comp = new JScrollPane(commands); 074 comp.setPreferredSize(new Dimension(150, 200)); 075 076 getContentPane().add(comp, BorderLayout.WEST); 077 078 commands.setBackground(getBackground()); 079 commands.addFocusListener(new FocusAdapter() { 080 @Override 081 public void focusLost(FocusEvent e) { 082 if (e.getOppositeComponent() != CommandHelperDialog.this && e.getOppositeComponent() != examples) { 083 setVisible(false); 084 } 085 } 086 }); 087 commands.addMouseListener(new MouseAdapter() { 088 @Override 089 public void mouseClicked(MouseEvent e) { 090 String commandName = commands.getSelectedValue(); 091 if (e.getClickCount() == 2) { 092 if (examples.getModel().getSize() > 1) { 093 if (examples.isSelectionEmpty()) { 094 examples.requestFocus(); 095 examples.setSelectedIndex(0); 096 } else { 097 perform(commandName); 098 } 099 } else { 100 perform(commandName); 101 } 102 } else { 103 fillExamples(commandName); 104 } 105 } 106 }); 107 commands.addListSelectionListener(new ListSelectionListener() { 108 @Override 109 public void valueChanged(ListSelectionEvent e) { 110 String commandName = commands.getSelectedValue(); 111 fillExamples(commandName); 112 } 113 }); 114 commands.addKeyListener(new KeyAdapter() { 115 @Override 116 public void keyPressed(KeyEvent e) { 117 int keyCode = e.getKeyCode(); 118 if (keyCode == KeyEvent.VK_ESCAPE) { 119 setVisible(false); 120 } else { 121 if (keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_ENTER) { 122 if (examples.getModel().getSize() > 1) { 123 examples.requestFocus(); 124 examples.setSelectedIndex(0); 125 } else { 126 String commandName = commands.getSelectedValue(); 127 perform(commandName); 128 } 129 } 130 } 131 } 132 }); 133 134 JScrollPane comp1 = new JScrollPane(examples); 135 comp1.setPreferredSize(new Dimension(400, 200)); 136 137 getContentPane().add(comp1, BorderLayout.CENTER); 138 139 examples.setBackground(getBackground()); 140 examples.addMouseListener(new MouseAdapter() { 141 @Override 142 public void mouseClicked(MouseEvent e) { 143 String commandName = examples.getSelectedValue(); 144 if (e.getClickCount() == 2) { 145 perform(commandName); 146 } 147 } 148 }); 149 examples.addFocusListener(new FocusAdapter() { 150 @Override 151 public void focusLost(FocusEvent e) { 152 if (e.getOppositeComponent() != CommandHelperDialog.this && e.getOppositeComponent() != commands) { 153 setVisible(false); 154 } 155 } 156 }); 157 examples.addKeyListener(new KeyAdapter() { 158 @Override 159 public void keyPressed(KeyEvent e) { 160 int keyCode = e.getKeyCode(); 161 if (keyCode == KeyEvent.VK_ESCAPE) { 162 setVisible(false); 163 } else { 164 if (keyCode == KeyEvent.VK_ENTER) { 165 String commandName = examples.getSelectedValue(); 166 perform(commandName); 167 } else if (keyCode == KeyEvent.VK_LEFT) { 168 commands.requestFocus(); 169 } 170 } 171 } 172 }); 173 174 } 175 176 private void perform(String commandName) { 177 List<String> examples = exampleMap.get(commandName); 178 setVisible(false); 179 if (examples != null && !examples.isEmpty()) { 180 int selectedIndex = this.examples.getSelectedIndex(); 181 if (selectedIndex < 0) { 182 selectedIndex = 0; 183 } 184 185 String text = examples.get(selectedIndex); 186 if (!StringUtils.startsWith(text, "<") && StringUtils.contains(text, ":")) { 187 text = StringUtils.substringAfter(text, ":"); 188 } 189 insertTag(startSymbols, text); 190 } 191 if (examples == null) { 192 commandName = commandName.trim(); 193 if (!StringUtils.startsWith(commandName, "<") && StringUtils.contains(commandName, ":")) { 194 commandName = StringUtils.substringAfter(commandName, ":"); 195 } 196 insertTag(startSymbols, commandName); 197 } 198 } 199 200 private void fillExamples(String commandName) { 201 List<String> list = exampleMap.get(commandName); 202 if (list != null) { 203 examplesListModel.removeAllElements(); 204 for (String example : list) { 205 examplesListModel.addElement(example); 206 } 207 if (!list.isEmpty()) { 208 examples.setSelectedIndex(0); 209 } 210 } 211 } 212 213 public void fillCommandList(String text, Processor makeProcessor) { 214 this.startSymbols = text; 215 text = StringUtils.substring(text, 1); 216 commandListModel.removeAllElements(); 217 exampleMap.clear(); 218 219 List<CommandInfo> commandInfos = getCodeHelper().getCommandList(text, makeProcessor.getClass()); 220 commandInfos.sort(Comparator.comparing(CommandInfo::getName)); 221 List<CommandInfo> active = commandInfos.stream() 222 .filter((a) -> !a.getClassName().equals(BaseProcessor.class.getSimpleName())) 223 .collect(Collectors.toList()); 224 List<CommandInfo> base = commandInfos.stream() 225 .filter((a) -> a.getClassName().equals(BaseProcessor.class.getSimpleName())) 226 .collect(Collectors.toList()); 227 228 List<CommandInfo> sortedCommandInfos = new ArrayList<CommandInfo>(active); 229 sortedCommandInfos.addAll(base); 230 231 for (CommandInfo commandInfo : sortedCommandInfos) { 232 String name = commandInfo.getName(); 233 commandListModel.addElement(name); 234 exampleMap.put(name, commandInfo.getExamples()); 235 } 236 237 if (commandListModel.isEmpty() || commandListModel.getSize() > 1 238 || exampleMap.get(commandListModel.firstElement()).size() > 1) { 239 showDialog(); 240 241 SwingUtilities.invokeLater(() -> { 242 commands.requestFocusInWindow(); 243 commands.setSelectedIndex(0); 244 fillExamples(commands.getSelectedValue()); 245 }); 246 } else { 247 String firstElement = commandListModel.firstElement(); 248 perform(firstElement); 249 } 250 } 251 252 public void helpWith(String text, boolean isCommand) { 253 if (isCommand && (StringUtils.startsWith(text, "<") || StringUtils.isBlank(text))) { 254 Processor taskProcessor = getCurrentProcessor(); 255 fillCommandList(text, taskProcessor); 256 } else { 257 DialogPopupMenu menu = new DialogPopupMenu(getCodeHelper().getEditor()); 258 menu.setAutoscrolls(true); 259 if (!isCommand) { 260 showMacroPopupMenu(text, menu); 261 } else { 262 menu = getCodeHelper().getEditor().getRecipePanel().contextHelp(menu); 263 } 264 Point magicCaretPosition = getCodeHelper().getEditor().getRecipePanel().getMagicCaretPosition(); 265 if (magicCaretPosition == null) 266 magicCaretPosition = new Point(); 267 menu.show(getCodeHelper().getEditor(), magicCaretPosition.x, magicCaretPosition.y); 268 } 269 } 270 271 private Processor getCurrentProcessor() { 272 TaskEditor recipePanel = getCodeHelper().getRecipePanel(); 273 TextEditor editor = recipePanel.getEditor(); 274 String text = editor.getText(); 275 int curpos = editor.getCaretPosition(); 276 277 Processor makeProcessor = recipePanel.getTaskProcessor(); 278 String substring = StringUtils.substring(text, 0, curpos); 279 int startExternTag = StringUtils.lastIndexOf(substring, "<Extern"); 280 int closeExternTag = StringUtils.lastIndexOf(substring, "</Extern"); 281 if (closeExternTag < 0 || closeExternTag < startExternTag) { 282 int endExternTag = StringUtils.indexOf(substring, '>', startExternTag); 283 String externTag = StringUtils.substring(substring, startExternTag, endExternTag); 284 if (StringUtils.isNotBlank(externTag)) { 285 externTag = externTag + "/>"; 286 try { 287 Node externNode = new EasyParser().getObject(externTag); 288 makeProcessor = makeProcessor.makeProcessor(externNode); 289 290 } catch (Exception e1) { 291 // do nothing. 292 } 293 } 294 } 295 return makeProcessor; 296 } 297 298 private void showMacroPopupMenu(final String theStartMacroIns, DialogPopupMenu menu) { 299 300 JMenuItem menuItem = new JMenuItem("$var{type:property,type:data}"); 301 if ("var{".startsWith(theStartMacroIns)) { 302 menu.add(menuItem); 303 menuItem.addActionListener(new ActionListener() { 304 public void actionPerformed(ActionEvent e) { 305 Node object; 306 try { 307 object = new EasyParser() 308 .getObject("<Data variable_name='type:property' default_value='type:data'/>"); 309 parsingCommandParamters(object); 310 String theStartMacroIns = getStartMacroIns(); 311 String text = "var{" + object.getAttribute("variable_name") + "," 312 + object.getAttribute("default_value") + "}"; 313 insertText(theStartMacroIns, text); 314 } catch (Exception e1) { 315 e1.printStackTrace(); 316 } 317 } 318 }); 319 } 320 321 menuItem = new JMenuItem("$tag{type:property,type:data}"); 322 if ("tag{".startsWith(theStartMacroIns)) { 323 menu.add(menuItem); 324 menuItem.addActionListener(new ActionListener() { 325 326 public void actionPerformed(ActionEvent e) { 327 Node object; 328 try { 329 object = new EasyParser() 330 .getObject("<Data variable_name='type:property' default_value='type:data'/>"); 331 parsingCommandParamters(object); 332 333 String theStartMacroIns = getStartMacroIns(); 334 335 insertText(theStartMacroIns, "tag{" + object.getAttribute("variable_name") + "," 336 + object.getAttribute("default_value") + "}"); 337 } catch (Exception e1) { 338 e1.printStackTrace(); 339 } 340 } 341 }); 342 } 343 344 if ("call{".startsWith(theStartMacroIns)) { 345 menuItem = new JMenuItem("$call{type:task,type:data}"); 346 menu.add(menuItem); 347 menuItem.addActionListener(new ActionListener() { 348 public void actionPerformed(ActionEvent e) { 349 Node object; 350 try { 351 object = new EasyParser() 352 .getObject("<Data task_name='type:task' return_variable='type:property'/>"); 353 parsingCommandParamters(object); 354 String return_variable = object.getAttribute("return_variable"); 355 insertText(getStartMacroIns(), "call{" + object.getAttribute("task_name") 356 + (return_variable == null ? "" : "," + return_variable) + "}"); 357 } catch (Exception e1) { 358 e1.printStackTrace(); 359 } 360 } 361 }); 362 } 363 364 if ("file{".startsWith(theStartMacroIns)) 365 366 { 367 menuItem = new JMenuItem("$file{type:path}"); 368 menu.add(menuItem); 369 menuItem.addActionListener(e -> { 370 Node object; 371 try { 372 object = new EasyParser().getObject("<Data file_name='type:path'/>"); 373 parsingCommandParamters(object); 374 insertText(getStartMacroIns(), "file{" + object.getAttribute("file_name") + "}"); 375 } catch (Exception e1) { 376 e1.printStackTrace(); 377 } 378 }); 379 } 380 } 381 382 private boolean parsingCommandParamters(Node node) { 383 boolean isHelpRequired = true; 384 Properties attributes = new Properties(); 385 Node example = node; 386 if (example.isEmpty()) { 387 example = new Node("example"); 388 example.add(node); 389 } 390 for (Node object : example) { 391 for (Object name : object.getAttributes().keySet()) { 392 String attribute = object.getAttribute((String) name); 393 String theName = ((String) name).replace('_', ' '); 394 if (attribute.startsWith("type:")) { 395 attribute = attribute.substring(5); 396 JRootPane rootPane = SwingUtilities.getRootPane(getCodeHelper().getEditor()); 397 if (attribute.equals("integer")) { 398 boolean valid = true; 399 do { 400 attribute = JOptionPane.showInputDialog(rootPane, 401 "Type: " + attribute + "\nAttribute: " + theName); 402 if (attribute == null) { 403 isHelpRequired = false; 404 break; 405 } 406 407 object.setAttribute((String) name, attribute); 408 409 } while (!valid); 410 411 } else if (attribute.equals("operation")) { 412 Map<String, OperationHolder> operationsMethods = AEWorkspace.getInstance() 413 .getOperationsMethods(); 414 Set<String> keySet = operationsMethods.keySet(); 415 showListDialog(object, name, attribute, keySet.toArray(new String[keySet.size()]), false, 416 "Operations:"); 417 String operationName = object.getAttribute("method"); 418 if (!StringUtils.isEmpty(operationName)) { 419 OperationHolder operationsMethod = AEWorkspace.getInstance() 420 .getOperationsMethod(operationName); 421 object.setAttribute("description", operationsMethod.getDescription()); 422 Processor processor = getCodeHelper().getEditor().getRecipePanel().getTaskProcessor(); 423 String[] array = processor.getVariables().keySet().toArray(new String[keySet.size()]); 424 Class<?> returnType = operationsMethod.getMethod().getReturnType(); 425 if (returnType != void.class) { 426 object.setAttribute("name", "type:property"); 427 428 if (!showListDialog(object, "name", "property", array, true, "Return: " 429 + operationsMethod.getReturnDescription() + "\nSelect variable name:")) { 430 isHelpRequired = false; 431 break; 432 } 433 } 434 435 Class<?>[] parameterTypes = operationsMethod.getMethod().getParameterTypes(); 436 for (int i = 0; i < parameterTypes.length; i++) { 437 String type = parameterTypes[i].getName(); 438 439 object.setAttribute("arg" + (i + 1), type); 440 String value = (String) JOptionPane.showInputDialog(rootPane, 441 "Type: " + type + "\nAttribute: " + operationsMethod.getParameterName(i), 442 "Input parameter", JOptionPane.INFORMATION_MESSAGE, null, null, null); 443 if (attribute == null) { 444 isHelpRequired = false; 445 break; 446 } 447 448 object.setAttribute("arg" + (i + 1), value); 449 } 450 } 451 isHelpRequired = false; 452 break; 453 } else if (attribute.equals("attr")) { 454 attribute = attributes.getProperty(theName); 455 object.setAttribute((String) name, attribute); 456 } else if (StringUtils.containsAny(attribute, "string", "url", "regex")) { 457 String value = OptionPane.showInputDialog(rootPane, "Input command attribute", "Attribute: " + theName + ", Type: " + attribute, ""); 458 if (value == null) { 459 isHelpRequired = false; 460 break; 461 } 462 463 value = StringEscapeUtils.escapeXml(value); 464 object.setAttribute((String) name, value); 465 } else if (attribute.equals("xpath")) { 466 attribute = JOptionPane.showInputDialog(rootPane, "Attribute: " + theName + "\nType: xpath", 467 ""); 468 if (attribute != null) { 469 attribute = attribute.replace("\"", "\'"); 470 } 471 if (attribute == null) { 472 isHelpRequired = false; 473 break; 474 } 475 object.setAttribute((String) name, attribute); 476 } else if (attribute.equals("time")) { 477 String[] choiceArray = new String[] { "", "s", "m", "h", "d", "M", "Y" }; 478 if (!showListDialog(object, name, "time", choiceArray, false, null)) { 479 isHelpRequired = false; 480 break; 481 } 482 } else if (attribute.equals("task")) { 483 if (!showListDialog(object, name, attribute, 484 getCodeHelper().getEditor().getRecipePanel().getManager().getTestsList(), true)) { 485 isHelpRequired = false; 486 break; 487 } 488 } else if (attribute.equals("double")) { 489 attribute = JOptionPane.showInputDialog(rootPane, "Attribute: " + theName + "\nType: double", 490 ""); 491 if (attribute == null) { 492 isHelpRequired = false; 493 break; 494 } 495 object.setAttribute((String) name, attribute); 496 } else if (attribute.equals("property")) { 497 Processor processor = getCodeHelper().getEditor().getRecipePanel().getTaskProcessor(); 498 if (processor == null) { 499 TaskEditor recipePanel = getCodeHelper().getEditor().getRecipePanel(); 500 processor = new BaseProcessor(recipePanel.getManager(), recipePanel.getLogger(), 501 getCodeHelper().getEditor().getRecipePanel().getManager().getStartDir()); 502 } 503 Set<String> keySet = processor.getVariables().keySet(); 504 if (!showListDialog(object, name, attribute, keySet.toArray(new String[keySet.size()]), true)) { 505 isHelpRequired = false; 506 break; 507 } 508 } else if (attribute.equals("path")) { 509 FileDialog theFileDialog = new FileDialog(JOptionPane.getRootFrame(), "Input path", 510 FileDialog.LOAD); 511 String absolutePath = getCodeHelper().getEditor().getRecipePanel().getTaskProcessor() 512 .getBaseDir().getAbsolutePath(); 513 theFileDialog.setDirectory(absolutePath); 514 theFileDialog.setVisible(true); 515 if (theFileDialog.getFile() != null) { 516 String prefDir = theFileDialog.getDirectory(); 517 if (theFileDialog.getDirectory().startsWith(absolutePath)) { 518 prefDir = prefDir.substring(absolutePath.length() + 1, prefDir.length()); 519 } 520 object.setAttribute((String) name, prefDir + theFileDialog.getFile()); 521 } 522 } else if (attribute.startsWith("boolean")) { 523 String type = "boolean"; 524 String[] choiceArray = new String[] { "true", "false" }; 525 if (!showListDialog(object, name, type, choiceArray, false)) { 526 isHelpRequired = false; 527 break; 528 } 529 } else if (attribute.startsWith("processor")) { 530 String[] processors = ClassUtils.findAssignable(Processor.class, Processor.class.getPackage()); 531 532 if (!showListDialog(object, name, attribute, processors, false)) { 533 isHelpRequired = false; 534 break; 535 } 536 } else if (attribute.startsWith("view")) { 537 String[] processors = ClassUtils.findAssignable(View.class, View.class.getPackage()); 538 539 if (!showListDialog(object, name, attribute, processors, false)) { 540 isHelpRequired = false; 541 break; 542 } 543 } 544 545 } else if (attribute.startsWith("enum:")) { 546 String type = attribute.substring(0, 4); 547 String choice = attribute.substring(5); 548 StringTokenizer stringTokenizer = new StringTokenizer(choice, "|"); 549 String[] choiceArray = new String[stringTokenizer.countTokens()]; 550 for (int i = 0; i < choiceArray.length; i++) { 551 choiceArray[i] = stringTokenizer.nextToken(); 552 } 553 if (!showListDialog(object, name, type, choiceArray, false)) { 554 isHelpRequired = false; 555 break; 556 } 557 } 558 } 559 attributes.putAll(object.getAttributes()); 560 } 561 return isHelpRequired; 562 } 563 564 private boolean showListDialog(Node object, Object name, String type, String[] sourceList, boolean b) { 565 Arrays.sort(sourceList); 566 return showListDialog(object, name, type, sourceList, b, null); 567 } 568 569 private boolean showListDialog(Node object, Object name, String type, String[] sourceList, boolean b, 570 String description) { 571 572 String prefix = "Attribute: "; 573 574 String message = StringUtils.defaultString(description, prefix + name + ", Type: " + type); 575 JRootPane rootPane = SwingUtilities.getRootPane(getCodeHelper().getEditor().getRecipePanel().getEditor()); 576 String value = OptionPane.showInputDialog(rootPane, message, "Input command attribute", sourceList, ""); 577 578 if (value == null) { 579 return false; 580 } 581 582 object.setAttribute((String) name, value); 583 return true; 584 } 585 586 void insertTag(final String startSymbols, String text) { 587 try { 588 Node object = new EasyParser().getObject("<example>" + text + "</example>"); 589 parsingCommandParamters(object); 590 StringBuilder code = new StringBuilder(); 591 for (Node node : object) { 592 code.append(node.getXMLText()); 593 } 594 insertText(startSymbols, code.toString().trim()); 595 } catch (TaskCancelingException e) { 596 } catch (Exception e) { 597 JOptionPane.showMessageDialog(JOptionPane.getRootFrame(), e.getMessage()); 598 } 599 } 600 601 private String getStartMacroIns() { 602 int curpos = getCodeHelper().getEditor().getCaretPosition(); 603 String text = getCodeHelper().getEditor().getText(); 604 String theStartMacroIns = null; 605 606 int i; 607 for (i = curpos - 1; i >= 0; i--) { 608 char charAt = text.charAt(i); 609 610 if (charAt == '$') { 611 theStartMacroIns = text.substring(i + 1, curpos); 612 break; 613 } 614 } 615 616 return (i > curpos - 7) ? theStartMacroIns : ""; 617 } 618 619 private void insertText(String theStartCommand, String text) { 620 int caretPosition2 = getCodeHelper().getEditor().getCaretPosition(); 621 int i = caretPosition2 - theStartCommand.length(); 622 try { 623 String text2 = getCodeHelper().getEditor().getRecipePanel().getEditor().getText(i - 1, 1); 624 if ("<".equals(text2)) { 625 i--; 626 } 627 } catch (BadLocationException e) { 628 e.printStackTrace(); 629 } 630 getCodeHelper().getEditor().replaceRange(text, i, caretPosition2); 631 } 632 633}