001package com.ganteater.ae.desktop; 002 003import java.awt.BorderLayout; 004import java.awt.Component; 005import java.awt.Container; 006import java.awt.Frame; 007import java.awt.HeadlessException; 008import java.awt.event.WindowAdapter; 009import java.awt.event.WindowEvent; 010import java.io.BufferedReader; 011import java.io.File; 012import java.io.FileOutputStream; 013import java.io.FileReader; 014import java.io.FileWriter; 015import java.io.IOException; 016import java.io.InputStream; 017import java.net.URL; 018import java.util.List; 019 020import javax.swing.Icon; 021import javax.swing.JDialog; 022import javax.swing.JFileChooser; 023import javax.swing.JLabel; 024import javax.swing.JOptionPane; 025import javax.swing.JPanel; 026import javax.swing.JPasswordField; 027import javax.swing.JScrollPane; 028import javax.swing.JTable; 029import javax.swing.WindowConstants; 030import javax.swing.filechooser.FileFilter; 031import javax.swing.table.AbstractTableModel; 032 033import org.apache.commons.io.FilenameUtils; 034import org.apache.commons.io.IOUtils; 035import org.apache.commons.lang.ObjectUtils; 036import org.apache.commons.lang.StringUtils; 037import org.apache.commons.lang.SystemUtils; 038 039import com.ganteater.ae.AEWorkspace; 040import com.ganteater.ae.ConfigConstants; 041import com.ganteater.ae.ConfigurationException; 042import com.ganteater.ae.ILogger; 043import com.ganteater.ae.MultiTaskRunDialog; 044import com.ganteater.ae.RecipeRunner; 045import com.ganteater.ae.desktop.editor.TaskEditor; 046import com.ganteater.ae.desktop.ui.AEFrame; 047import com.ganteater.ae.desktop.ui.CheckPointBox; 048import com.ganteater.ae.desktop.ui.InputTableModel; 049import com.ganteater.ae.desktop.ui.OptionPane; 050import com.ganteater.ae.desktop.ui.AEFrame.UIChoiceTaskRunner; 051import com.ganteater.ae.desktop.util.SoundManager; 052import com.ganteater.ae.desktop.util.UIUtils; 053import com.ganteater.ae.processor.MessageHandler; 054import com.ganteater.ae.processor.Processor; 055import com.ganteater.ae.util.xml.easyparser.EasyParser; 056import com.ganteater.ae.util.xml.easyparser.Node; 057 058public class DesktopWorkspace extends AEWorkspace { 059 060 private static final String INPUT_FILE_NAME = ".inputFile"; 061 062 private final class JFileChooserExtension extends JFileChooser { 063 private static final long serialVersionUID = 1L; 064 private final String name; 065 private int returnValue; 066 067 private JFileChooserExtension(String name) { 068 this.name = name; 069 } 070 071 @Override 072 protected JDialog createDialog(Component parent) throws HeadlessException { 073 JDialog dialog = super.createDialog(parent); 074 Container contentPane = dialog.getContentPane(); 075 CheckPointBox vip = new CheckPointBox(name, null, InputDialogType.FILE); 076 contentPane.add(vip, BorderLayout.SOUTH); 077 078 dialog.addWindowListener(new WindowAdapter() { 079 080 @Override 081 public void windowClosing(WindowEvent e) { 082 returnValue = -1; 083 } 084 }); 085 return dialog; 086 } 087 088 @Override 089 public int showDialog(Component parent, String approveButtonText) throws HeadlessException { 090 int showDialog = super.showDialog(parent, approveButtonText); 091 return returnValue == -1 ? -1 : showDialog; 092 } 093 } 094 095 private AEFrame frame; 096 097 public DesktopWorkspace(AEFrame frame) { 098 this.frame = frame; 099 } 100 101 @Override 102 protected String selectConfiguration(String[] aPossibleValues) { 103 String theValue; 104 105 String theDefaultConfiguration = aPossibleValues[0]; 106 theDefaultConfiguration = AEWorkspace.getInstance().getDefaultUserConfiguration(".defaultConfiguration", 107 theDefaultConfiguration); 108 109 frame.setAlwaysOnTop(true); 110 Icon fWelcomeLogo = AEFrame.getIcon(AEFrame.LOGO_JPG); 111 theValue = (String) JOptionPane.showInputDialog(frame, "Environments:", "Giant anteater looking for food ...", 112 JOptionPane.QUESTION_MESSAGE, fWelcomeLogo, aPossibleValues, theDefaultConfiguration); 113 frame.setAlwaysOnTop(false); 114 if (theValue == null) 115 throw new IllegalArgumentException("Configuration is not selected."); 116 117 AEWorkspace.getInstance().setDefaultUserConfiguration(".defaultConfiguration", theValue); 118 119 return theValue; 120 } 121 122 @Override 123 public MultiTaskRunDialog tasksChoice(MultiTaskRunDialog dialog, String[] list, boolean exceptionIgnoreFlag, 124 Object setup, Processor taskProcessor, boolean visible) { 125 UIChoiceTaskRunner runner = frame.getChoiceTaskRunner(dialog, taskProcessor, setup); 126 127 String name = runner.getName(); 128 boolean consoleDefaultInput = isConsoleDefaultInput(name, null); 129 130 if (setup != null) { 131 if (setup instanceof String[]) 132 runner.select((String[]) setup, consoleDefaultInput); 133 else if (setup instanceof List) { 134 @SuppressWarnings("unchecked") 135 List<String> setupList = (List<String>) setup; 136 String[] array = setupList.toArray(new String[setupList.size()]); 137 runner.select(array, consoleDefaultInput); 138 } else if (setup instanceof String) { 139 String[] attribute = new String[] { (String) setup }; 140 runner.select(attribute, consoleDefaultInput); 141 } 142 } 143 144 runner.setExceptionIgnore(exceptionIgnoreFlag); 145 runner.setVisible(visible); 146 boolean notifyMe = taskProcessor.getListener().isNotifyMe(); 147 148 runner.showDialog(name, list, notifyMe); 149 150 return runner; 151 } 152 153 @Override 154 public void startTaskNotify(RecipeRunner task) { 155 TaskEditor editor = (TaskEditor) task; 156 super.startTaskNotify(editor); 157 frame.startTaskNotify(editor); 158 } 159 160 @Override 161 public void progressValue(int i, int length, boolean success) { 162 frame.progressValue(i, length, success); 163 } 164 165 @Override 166 public void removeRunner(RecipeRunner testRunner) { 167 super.removeRunner(testRunner); 168 frame.endTask(testRunner); 169 } 170 171 @Override 172 public String inputValue(String name, String description, String value, ILogger log, String type, boolean notifyMe, 173 Processor processor) { 174 String inputValue = null; 175 if ("path".equalsIgnoreCase(type)) { 176 File defaultFile; 177 if (value != null) { 178 defaultFile = new File(value); 179 } else { 180 defaultFile = new File(getWorkingDir()); 181 } 182 inputValue = inputFile(name, description, defaultFile, log, processor); 183 } else { 184 inputValue = frame.inputValue(name, description, value, type, notifyMe); 185 } 186 return inputValue; 187 } 188 189 @Override 190 public boolean isConsoleDefaultInput(String varName, String description) { 191 varName = StringUtils.defaultString(description, varName); 192 boolean consoleDefaultInput = "Error Trace".equals(varName) || frame.isConsoleDefaultInput(); 193 if (varName != null && consoleDefaultInput) { 194 Boolean checkPointFlag = false; 195 InputDialogType[] values = InputDialogType.values(); 196 for (InputDialogType inputDialogType : values) { 197 checkPointFlag = CheckPointBox.getCheckPointFlag(inputDialogType, varName); 198 if (checkPointFlag != null) { 199 break; 200 } 201 } 202 consoleDefaultInput = checkPointFlag != null && !checkPointFlag; 203 } 204 return consoleDefaultInput; 205 } 206 207 @Override 208 protected RecipeRunner createTestRunner(String name) { 209 return frame.editTask(name); 210 } 211 212 @Override 213 public String inputChoice(String name, String description, String[] aValues, String aDefaultValue, 214 Processor taskProcessor, boolean notifyMe) { 215 return frame.inputSelectChoice(name, description, aValues, aDefaultValue, notifyMe); 216 } 217 218 public String inputFile(String name, String description, File defaultFile, ILogger log, Processor taskProcessor) { 219 String result = null; 220 description = StringUtils.defaultString(description, name); 221 222 String defaultUserConfiguration = getDefaultUserConfiguration(INPUT_FILE_NAME, 223 defaultFile == null ? null : defaultFile.getAbsolutePath()); 224 if (defaultUserConfiguration != null) 225 defaultFile = new File(defaultUserConfiguration); 226 227 result = defaultUserConfiguration; 228 229 if (defaultUserConfiguration == null || !isConsoleDefaultInput(name, null)) { 230 231 JFileChooser chooser = new JFileChooserExtension(name); 232 233 if (defaultFile != null) { 234 String path = defaultFile.getPath(); 235 if (path != null && !"null".equals(path)) { 236 if (defaultFile.isDirectory()) { 237 chooser.setCurrentDirectory(defaultFile.getParentFile()); 238 } else { 239 chooser.setSelectedFile(defaultFile); 240 } 241 } 242 } 243 244 chooser.setDialogTitle(description); 245 chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); 246 int showOpenDialog = chooser.showOpenDialog(JOptionPane.getRootFrame()); 247 if (showOpenDialog == JFileChooser.APPROVE_OPTION) { 248 result = new File(chooser.getCurrentDirectory(), chooser.getSelectedFile().getName()).getAbsolutePath(); 249 setDefaultUserConfiguration(INPUT_FILE_NAME, result); 250 } else if (showOpenDialog == JFileChooser.CANCEL_OPTION) { 251 result = null; 252 setDefaultUserConfiguration(INPUT_FILE_NAME, result); 253 } else { 254 taskProcessor.stop(); 255 result = null; 256 } 257 258 } 259 260 CheckPointBox.setCheckPointFlag(InputDialogType.FILE, name, (boolean) ObjectUtils 261 .defaultIfNull(CheckPointBox.getCheckPointFlag(InputDialogType.FILE, name), false)); 262 263 return result; 264 } 265 266 @Override 267 public boolean confirmation(String name, String message, Processor unit, boolean notifyMe) throws Exception { 268 269 name = StringUtils.defaultIfEmpty(name, "Confirmation"); 270 if (notifyMe) { 271 frame.getSoundManager().play(); 272 } 273 274 JOptionPane pane = new JOptionPane(message, JOptionPane.WARNING_MESSAGE, JOptionPane.YES_NO_OPTION); 275 JDialog dialog = pane.createDialog(frame, name); 276 dialog.setModal(false); 277 dialog.setResizable(true); 278 279 dialog.setVisible(true); 280 if (!UIUtils.applyPreferedView(dialog, name)) { 281 dialog.pack(); 282 } 283 284 Object value = null; 285 do { 286 value = pane.getValue(); 287 Thread.sleep(100); 288 } while (value == "uninitializedValue"); 289 290 if (notifyMe) { 291 SoundManager.stop(); 292 } 293 294 UIUtils.saveDialogPreferedView(dialog, name); 295 dialog.dispose(); 296 297 if (value == null) { 298 value = -1; 299 } 300 301 int confirm = (int) value; 302 if (confirm < 0) { 303 unit.stop(); 304 } 305 return confirm == JOptionPane.YES_OPTION; 306 } 307 308 @Override 309 public MessageHandler message(final Processor taskProcessor, String title, String message, boolean notifyMe) { 310 String dialogTitle = StringUtils.defaultIfEmpty(title, "Message"); 311 312 JOptionPane pane = new JOptionPane(message, JOptionPane.INFORMATION_MESSAGE); 313 314 JDialog dialog = pane.createDialog(frame, dialogTitle); 315 dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 316 317 MessageHandler handle = new MessageHandler() { 318 @Override 319 public void close() { 320 dialog.dispose(); 321 super.close(); 322 } 323 }; 324 325 dialog.addWindowListener(new WindowAdapter() { 326 @Override 327 public void windowClosed(WindowEvent var1) { 328 if (!handle.isProcessDone()) { 329 taskProcessor.stop(); 330 } 331 UIUtils.saveDialogPreferedView(dialog, dialogTitle); 332 SoundManager.stop(); 333 frame.pushOnTop(); 334 } 335 }); 336 dialog.setModal(false); 337 dialog.setResizable(true); 338 339 if (!UIUtils.applyPreferedView(dialog, dialogTitle)) { 340 dialog.pack(); 341 } 342 343 frame.pushOnTop(); 344 345 if (notifyMe) { 346 frame.getSoundManager().play(); 347 } 348 349 dialog.setVisible(true); 350 351 return handle; 352 } 353 354 public void inputDataTable(Processor unit, Node aTableNode, boolean notifyMe) throws IOException { 355 Node[] theVariablesNodes = aTableNode.getNodes("var"); 356 357 String fileName = aTableNode.getAttribute("file"); 358 if (unit != null) 359 fileName = unit.replaceProperties(aTableNode.getAttribute("file")); 360 361 if (fileName != null) { 362 File file = unit.getFile(fileName); 363 if (file.exists()) { 364 BufferedReader theFileReader = new BufferedReader(new FileReader(file)); 365 String line = null; 366 while ((line = theFileReader.readLine()) != null) { 367 line = line.trim(); 368 if (!line.isEmpty() && line.charAt(0) != '#') { 369 int thePbrk = line.indexOf('='); 370 371 String theName = line.substring(0, thePbrk); 372 String theValue = line.substring(thePbrk + 1); 373 374 Node theNode = new Node("var"); 375 theNode.setAttribute("name", theName); 376 theNode.setAttribute("value", theValue); 377 378 for (Node node : theVariablesNodes) { 379 if (node.getAttribute("name").equalsIgnoreCase(theName)) { 380 node.setAttribute("value", theValue); 381 } 382 } 383 } 384 } 385 theFileReader.close(); 386 } 387 } 388 389 String title = aTableNode.getAttribute("name"); 390 AbstractTableModel dataModel = new InputTableModel(unit, title, theVariablesNodes); 391 392 JTable table = new JTable(dataModel); 393 table.setRowHeight(20); 394 JScrollPane scrollpane = new JScrollPane(table); 395 CheckPointBox vip = new CheckPointBox(title, null, InputDialogType.MAP); 396 397 if ((!Processor.isSilentMode(unit) && !isConsoleDefaultInput(title, null)) || vip.isSelected()) { 398 JPanel jPanel = new JPanel(); 399 jPanel.add(new JLabel(), BorderLayout.NORTH); 400 jPanel.setLayout(new BorderLayout()); 401 jPanel.add(scrollpane, BorderLayout.CENTER); 402 403 jPanel.add(vip, BorderLayout.SOUTH); 404 405 if (notifyMe) { 406 frame.getSoundManager().play(); 407 } 408 409 int showConfirmDialog = OptionPane.showConfirmDialog(frame, jPanel, title); 410 411 if (notifyMe) { 412 SoundManager.stop(); 413 } 414 415 if (showConfirmDialog == -1 || showConfirmDialog == 2) { 416 unit.stop(); 417 } 418 } 419 420 FileWriter theFileReader = null; 421 if (fileName != null) { 422 File file = unit.getFile(fileName); 423 file.getParentFile().mkdirs(); 424 theFileReader = new FileWriter(file); 425 } 426 427 try { 428 for (int row = 0; row < dataModel.getRowCount(); row++) { 429 430 String name = StringUtils.upperCase((String) dataModel.getValueAt(row, 0)); 431 Object valueAt = dataModel.getValueAt(row, -1); 432 if (valueAt != null) { 433 if (theFileReader != null) { 434 theFileReader.write(name + "=" + valueAt + "\n"); 435 } 436 String value = null; 437 if (valueAt instanceof String) { 438 value = (String) valueAt; 439 } else if (valueAt instanceof String[] && ((String[]) valueAt).length > 0) { 440 value = ((String[]) valueAt)[0]; 441 } 442 value = unit.replaceProperties(value); 443 AEWorkspace.getInstance().setDefaultUserConfiguration(".inputValue." + title + "." + name, value); 444 unit.setVariableValue(name, value); 445 } 446 447 } 448 } finally { 449 if (theFileReader != null) { 450 theFileReader.close(); 451 } 452 } 453 } 454 455 @Override 456 public String choiceValue(String name, String description, Object[] aPossibleValues, ILogger log, boolean notifyMe, 457 Processor processor) { 458 return frame.choiceValue(name, description, aPossibleValues, notifyMe); 459 } 460 461 @Override 462 protected String choicePriorityRecipeFolder(String text, String[] possibleValues) { 463 return (String) JOptionPane.showInputDialog(frame, text, "Conflict of the names", 464 JOptionPane.INFORMATION_MESSAGE, null, possibleValues, possibleValues[0]); 465 } 466 467 @Override 468 protected Node getConfiguration() throws IOException { 469 470 File configFile = getConfigurationFile(); 471 472 if (configFile == null) { 473 throw new ConfigurationException(AEWorkspace.ENVIRONMENT_FILE_TITLE + " (" + ConfigConstants.AE_CONFIG_XML 474 + ") must be defined in " + getHomeWorkingDir() + " or " + getStartDir() + "."); 475 } 476 477 setBaseDir(configFile.getParentFile()); 478 Node object = null; 479 480 if (configFile.exists()) { 481 object = new EasyParser().getObject(configFile); 482 } else { 483 try { 484 URL resource = new URL(configFile.toString()); 485 try (InputStream openStream = resource.openStream()) { 486 String recipeXml = IOUtils.toString(openStream); 487 object = new EasyParser().getObject(recipeXml); 488 } 489 } catch (Exception e) { 490 object = null; 491 } 492 } 493 494 return object; 495 } 496 497 @Override 498 protected File findAlternativeConfiguration() { 499 File userDir = SystemUtils.getUserDir(); 500 String config = AEWorkspace.getInstance() 501 .getDefaultUserConfiguration(userDir.getPath() + CONFIG_SUFIX_PROP_NAME, null); 502 503 JFileChooser chooser; 504 if (config == null) { 505 chooser = new JFileChooser(); 506 chooser.setCurrentDirectory(userDir); 507 } else { 508 File file = new File(config); 509 chooser = new JFileChooser(file.getParent()); 510 chooser.setSelectedFile(file); 511 } 512 513 chooser.setDialogTitle("Configuration File"); 514 chooser.addChoosableFileFilter(new FileFilter() { 515 @Override 516 public String getDescription() { 517 return AEWorkspace.CONFIGURATION_TITLE; 518 } 519 520 @Override 521 public boolean accept(File f) { 522 return FilenameUtils.isExtension(f.getName(), "xml"); 523 } 524 }); 525 526 int returnVal = chooser.showOpenDialog(JOptionPane.getRootFrame()); 527 if (returnVal == JFileChooser.APPROVE_OPTION) { 528 File selectedFile = chooser.getSelectedFile(); 529 AEWorkspace.getInstance().setDefaultUserConfiguration(userDir.getPath() + CONFIG_SUFIX_PROP_NAME, 530 selectedFile.getAbsolutePath()); 531 return selectedFile; 532 } 533 534 return null; 535 } 536 537 public void resetConfiguration() { 538 super.resetConfiguration(); 539 frame.resetConfiguration(); 540 } 541 542 @Override 543 public void initUserPreferencesEncryption(String password) { 544 Node configNode = getConfigNode(); 545 boolean userPreferencesEncryption = Boolean.parseBoolean(configNode.getAttribute("userPreferencesEncryption")); 546 547 if (userPreferencesEncryption) { 548 do { 549 if (password == null) { 550 551 JPanel panel = new JPanel(new BorderLayout(4, 4)); 552 JLabel label = new JLabel( 553 "<html>" + AEWorkspace.MESSAGE_PASSWORD_REQUIRED.replace("\n", "<br/>") + "</html>"); 554 JPasswordField pass = new JPasswordField(20); 555 pass.putClientProperty("JPasswordField.cutCopyAllowed", true); 556 557 panel.add(label, BorderLayout.NORTH); 558 panel.add(pass, BorderLayout.CENTER); 559 560 Frame rootFrame = JOptionPane.getRootFrame(); 561 562 int option = JOptionPane.showOptionDialog(rootFrame, panel, "User Preferences Encryption", 563 JOptionPane.NO_OPTION, JOptionPane.WARNING_MESSAGE, null, new String[] { "OK" }, "OK"); 564 565 if (option == JOptionPane.CLOSED_OPTION) { 566 System.exit(1); 567 } 568 569 password = new String(pass.getPassword()); 570 try { 571 super.initUserPreferencesEncryption(password); 572 573 } catch (Exception e) { 574 575 int showConfirmDialog = JOptionPane.showConfirmDialog(frame, 576 "Incorrect key!\nReset the user preferences data?", "Error", JOptionPane.ERROR_MESSAGE, 577 JOptionPane.YES_NO_OPTION); 578 579 if (showConfirmDialog == JOptionPane.YES_OPTION) { 580 getUserPreferences().clear(); 581 try { 582 File preferencesFile = getPreferencesFile(); 583 FileOutputStream fileInputStream = new FileOutputStream(preferencesFile); 584 585 getUserPreferences().store(fileInputStream, null); 586 fileInputStream.close(); 587 588 } catch (IOException e1) { 589 e1.printStackTrace(); 590 } 591 } 592 if (showConfirmDialog == JOptionPane.CLOSED_OPTION) { 593 System.exit(1); 594 } 595 596 password = null; 597 } 598 } 599 } while (password == null); 600 } 601 } 602}