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}