001package com.ganteater.ae.desktop.ui; 002 003import java.awt.BorderLayout; 004import java.awt.event.KeyAdapter; 005import java.awt.event.KeyEvent; 006import java.awt.event.WindowAdapter; 007import java.awt.event.WindowEvent; 008import java.util.ArrayList; 009import java.util.Collections; 010import java.util.Iterator; 011import java.util.LinkedHashSet; 012import java.util.List; 013import java.util.NoSuchElementException; 014 015import javax.swing.DefaultCellEditor; 016import javax.swing.JButton; 017import javax.swing.JCheckBox; 018import javax.swing.JComboBox; 019import javax.swing.JDialog; 020import javax.swing.JPanel; 021import javax.swing.JScrollPane; 022import javax.swing.JTable; 023import javax.swing.JTextField; 024import javax.swing.plaf.basic.BasicComboBoxEditor; 025import javax.swing.table.AbstractTableModel; 026import javax.swing.table.TableColumn; 027 028import org.apache.commons.lang.ArrayUtils; 029import org.apache.commons.lang.StringUtils; 030 031import com.ganteater.ae.AEWorkspace; 032import com.ganteater.ae.MultiTaskRunDialog; 033import com.ganteater.ae.desktop.InputDialogType; 034import com.ganteater.ae.desktop.util.SoundManager; 035import com.ganteater.ae.desktop.util.UIUtils; 036import com.ganteater.ae.processor.Processor; 037 038class MultiTaskRunDialogImpl extends AbstractTableModel implements MultiTaskRunDialog, Iterator<String> { 039 private static final long serialVersionUID = 1L; 040 private static final String MULTI_TASK_RUN_DIALOG_PROP_NAME = "MultiTaskRunDialog"; 041 042 private AEFrame frame; 043 private String name; 044 private String[] taskNames; 045 private List<String> activeTaskArray = new ArrayList<>(); 046 private String[] status; 047 private boolean start = false; 048 private boolean errorrState = false; 049 private boolean closeDialog = false; 050 private boolean editable = true; 051 private boolean useHistory; 052 private boolean visible = true; 053 private int currentIndex = -1; 054 055 private JComboBox<String> presetBox = new JComboBox<>(); 056 private JDialog dialog; 057 private JTable table; 058 059 private JCheckBox exceptionIgnoreCheck = new JCheckBox(AEFrame.getIcon("not-ignore-exception.png")); 060 private JButton startButton = new JButton(AEFrame.getIcon("run.png")); 061 private JButton selectAllButton = new JButton(AEFrame.getIcon("select-all.png")); 062 private JButton deselectAllButton = new JButton(AEFrame.getIcon("deselect-all.png")); 063 064 public MultiTaskRunDialogImpl(final AEFrame frame, String theChoiceNames, Processor taskProcessor, 065 final boolean useHistory) { 066 this.frame = frame; 067 dialog = new JDialog(frame, theChoiceNames, false); 068 dialog.requestFocus(); 069 dialog.addWindowListener(new WindowAdapter() { 070 @Override 071 public void windowClosed(WindowEvent e) { 072 UIUtils.saveDialogPreferedView(dialog, MULTI_TASK_RUN_DIALOG_PROP_NAME + "." + name); 073 } 074 075 @Override 076 public void windowClosing(WindowEvent e) { 077 if (!start) { 078 activeTaskArray.clear(); 079 closeDialog = true; 080 } 081 082 taskProcessor.stop(); 083 } 084 }); 085 this.name = theChoiceNames; 086 editable = true; 087 this.useHistory = useHistory; 088 } 089 090 public void showDialog(String name, String[] taskNames, boolean notifyMe) { 091 if (frame.getWorkspace().isConsoleDefaultInput(name, null)) { 092 start = true; 093 } 094 095 closeDialog = false; 096 this.taskNames = taskNames; 097 status = new String[taskNames.length]; 098 099 if (visible) { 100 table = new JTable(this); 101 102 TableColumn column = table.getColumnModel().getColumn(0); 103 column.setMaxWidth(40); 104 column.setHeaderValue("Run"); 105 column.setCellEditor(new DefaultCellEditor(new JCheckBox())); 106 107 TableColumn column1 = table.getColumnModel().getColumn(1); 108 column1.setHeaderValue("Task name"); 109 110 TableColumn column2 = table.getColumnModel().getColumn(2); 111 column2.setMaxWidth(60); 112 column2.setHeaderValue("Result"); 113 114 JPanel panel = new JPanel(); 115 String presetListStr = AEWorkspace.getInstance() 116 .getDefaultUserConfiguration(MULTI_TASK_RUN_DIALOG_PROP_NAME + "_preset:" + this.name, ""); 117 if (presetListStr != null) { 118 String[] presetList = StringUtils.split(presetListStr, ";"); 119 for (String presetName : presetList) { 120 presetBox.addItem(presetName); 121 } 122 } 123 presetBox.setEditable(true); 124 presetBox.setEnabled(true); 125 BasicComboBoxEditor anEditor = new BasicComboBoxEditor() { 126 @Override 127 protected JTextField createEditorComponent() { 128 JTextField createEditorComponent = super.createEditorComponent(); 129 createEditorComponent.setEditable(true); 130 return createEditorComponent; 131 } 132 }; 133 presetBox.setEditor(anEditor); 134 135 presetBox.addActionListener(e -> { 136 loadPreset(); 137 presetBox.setEditable(true); 138 BasicComboBoxEditor editor = new BasicComboBoxEditor() { 139 @Override 140 protected JTextField createEditorComponent() { 141 JTextField createEditorComponent = super.createEditorComponent(); 142 createEditorComponent.setEditable(true); 143 return createEditorComponent; 144 } 145 }; 146 presetBox.setEditor(editor); 147 }); 148 dialog.getContentPane().add(presetBox, BorderLayout.NORTH); 149 dialog.getContentPane().add(new JScrollPane(table), BorderLayout.CENTER); 150 151 startButton.addActionListener(arg0 -> { 152 start = true; 153 savePreset(); 154 }); 155 startButton.setToolTipText("Start"); 156 panel.add(startButton); 157 startButton.requestFocus(); 158 159 selectAllButton.addActionListener(arg0 -> { 160 Collections.addAll(activeTaskArray, taskNames); 161 table.repaint(); 162 if (editable && useHistory) 163 saveConfig(); 164 }); 165 panel.add(selectAllButton); 166 167 deselectAllButton.addActionListener(arg0 -> { 168 activeTaskArray.clear(); 169 table.repaint(); 170 if (editable && useHistory) 171 saveConfig(); 172 }); 173 panel.add(deselectAllButton); 174 175 loadPreset(); 176 177 exceptionIgnoreCheck.setSelectedIcon(AEFrame.getIcon("ignore-exception.png")); 178 exceptionIgnoreCheck.setToolTipText("Ignore exception"); 179 panel.add(exceptionIgnoreCheck); 180 JButton closeButton = new JButton("Hide"); 181 closeButton.addActionListener(e -> { 182 savePreset(); 183 dialog.dispose(); 184 closeDialog = true; 185 186 UIUtils.saveDialogPreferedView(dialog, MULTI_TASK_RUN_DIALOG_PROP_NAME + "." + name); 187 }); 188 panel.add(closeButton); 189 190 JPanel comp = new JPanel(new BorderLayout()); 191 comp.add(panel, BorderLayout.CENTER); 192 193 CheckPointBox vip = new CheckPointBox(name, null, InputDialogType.TASKS); 194 comp.add(vip, BorderLayout.SOUTH); 195 vip.saveCheckpointFlag(); 196 197 dialog.getContentPane().add(comp, BorderLayout.SOUTH); 198 dialog.pack(); 199 200 UIUtils.applyPreferedView(dialog, MULTI_TASK_RUN_DIALOG_PROP_NAME + "." + name, taskNames.length * 19 + 250, 201 300); 202 203 if (!frame.getWorkspace().isConsoleDefaultInput(name, null) && visible) { 204 dialog.setVisible(true); 205 } 206 207 table.addKeyListener(new KeyAdapter() { 208 @Override 209 public void keyTyped(KeyEvent e) { 210 if (e.getKeyChar() == '\n' && startButton.isEnabled()) { 211 start = true; 212 } 213 } 214 }); 215 dialog.getRootPane().setDefaultButton(startButton); 216 217 if (notifyMe) { 218 frame.getSoundManager().play(); 219 } 220 221 while (!start && !closeDialog) { 222 try { 223 Thread.sleep(200); 224 } catch (InterruptedException e) { 225 Thread.currentThread().interrupt(); 226 } 227 } 228 229 SoundManager.stop(); 230 231 startButton.setEnabled(false); 232 233 selectAllButton.setEnabled(false); 234 deselectAllButton.setEnabled(false); 235 236 exceptionIgnoreCheck.setEnabled(false); 237 } else { 238 start = true; 239 } 240 } 241 242 private void loadPreset() { 243 if (editable && useHistory) { 244 String aName = getPresetDataName(); 245 String defaultTasks = AEWorkspace.getInstance().getDefaultUserConfiguration(aName, null); 246 if (defaultTasks != null) { 247 activeTaskArray.clear(); 248 String[] strings = StringUtils.split(defaultTasks, ";"); 249 for (String taskName : strings) { 250 if (ArrayUtils.indexOf(taskNames, taskName) >= 0) 251 activeTaskArray.add(taskName); 252 } 253 } 254 } 255 table.repaint(); 256 } 257 258 private void savePreset() { 259 LinkedHashSet<String> presetList = new LinkedHashSet<>(); 260 String item = (String) presetBox.getEditor().getItem(); 261 presetList.add(item); 262 int itemCount = presetBox.getItemCount(); 263 for (int i = 0; i < itemCount; i++) { 264 presetList.add(presetBox.getItemAt(i)); 265 } 266 267 String values = StringUtils.join(presetList.toArray(), ";"); 268 AEWorkspace.getInstance().setDefaultUserConfiguration(MULTI_TASK_RUN_DIALOG_PROP_NAME + "_preset:" + name, 269 values); 270 271 saveConfig(); 272 } 273 274 private void saveConfig() { 275 AEWorkspace.getInstance().setDefaultUserConfiguration(getPresetDataName(), 276 StringUtils.join(activeTaskArray.toArray(), ';')); 277 } 278 279 private String getPresetDataName() { 280 String presetName = (String) presetBox.getEditor().getItem(); 281 String prefName = StringUtils.isNotBlank(presetName) ? "." + presetName : ""; 282 return MULTI_TASK_RUN_DIALOG_PROP_NAME + prefName + ":" + this.name; 283 } 284 285 public Iterator<String> getSelectedTasks() { 286 287 if (closeDialog && !start) 288 return new ArrayList<String>().iterator(); 289 290 return this; 291 } 292 293 @Override 294 public boolean hasNext() { 295 currentIndex++; 296 int i; 297 for (i = currentIndex; i < taskNames.length; i++) { 298 String taskName = taskNames[i]; 299 if (activeTaskArray.contains(taskName)) { 300 break; 301 } 302 } 303 currentIndex = i; 304 305 return currentIndex < taskNames.length; 306 } 307 308 @Override 309 public String next() { 310 if (currentIndex < taskNames.length) { 311 return taskNames[currentIndex]; 312 } else { 313 throw new NoSuchElementException(); 314 } 315 } 316 317 public void begin(String taskName) { 318 int row = ArrayUtils.indexOf(taskNames, taskName); 319 this.status[row] = "in progress"; 320 if (table != null) { 321 table.repaint(); 322 } 323 } 324 325 public void done() { 326 if (table != null) { 327 if (errorrState) { 328 start = false; 329 selectAllButton.setEnabled(true); 330 deselectAllButton.setEnabled(true); 331 table.setEnabled(true); 332 } else { 333 dialog.dispose(); 334 } 335 } 336 errorrState = true; 337 } 338 339 public void end(String taskName, boolean statusOk) { 340 int row = ArrayUtils.indexOf(taskNames, taskName); 341 this.status[row] = statusOk ? "ok" : "failed"; 342 if (table != null) { 343 table.repaint(); 344 } 345 if (!statusOk) { 346 errorrState = true; 347 } 348 } 349 350 public boolean isExceptionIgnore() { 351 return exceptionIgnoreCheck.isSelected(); 352 } 353 354 public int getColumnCount() { 355 return 3; 356 } 357 358 public int getRowCount() { 359 return taskNames.length; 360 } 361 362 public Object getValueAt(int row, int coll) { 363 if (coll == 0) { 364 String rowName = taskNames[row]; 365 return activeTaskArray.contains(rowName); 366 } 367 if (coll == 2) { 368 String rowStatus = this.status[row]; 369 return rowStatus == null ? "" : rowStatus; 370 } 371 return taskNames[row]; 372 } 373 374 @Override 375 public Class<?> getColumnClass(int coll) { 376 if (coll == 0) 377 return Boolean.class; 378 return String.class; 379 } 380 381 @Override 382 public boolean isCellEditable(int rowIndex, int columnIndex) { 383 boolean waiting = rowIndex > currentIndex; 384 return columnIndex == 0 && editable && waiting; 385 } 386 387 @Override 388 public void setValueAt(Object arg0, int row, int coll) { 389 if (coll == 0) { 390 String taskName = taskNames[row]; 391 if (Boolean.TRUE.equals(arg0)) { 392 if (!activeTaskArray.contains(taskName)) { 393 activeTaskArray.add(taskName); 394 } 395 } else { 396 activeTaskArray.remove(taskName); 397 } 398 } 399 if (editable && useHistory) { 400 saveConfig(); 401 } 402 } 403 404 public void setExceptionIgnore(boolean flag) { 405 exceptionIgnoreCheck.setSelected(flag); 406 } 407 408 public void select(String[] activeTaskArray, boolean defaultMode) { 409 this.activeTaskArray.clear(); 410 for (String activeTask : activeTaskArray) 411 this.activeTaskArray.add(activeTask); 412 413 if (defaultMode) { 414 start = true; 415 editable = false; 416 } 417 418 } 419 420 public boolean isStarted() { 421 return start; 422 } 423 424 public String getName() { 425 return name; 426 } 427 428 @Override 429 public boolean isVisible() { 430 return visible; 431 } 432 433 public void setVisible(boolean visible) { 434 this.visible = visible; 435 } 436 437}