package name.admitriev.jhelper.ui; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.LabeledComponent; import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.ui.DocumentAdapter; import com.intellij.ui.components.JBList; import com.intellij.ui.components.JBScrollPane; import net.egork.chelper.task.Test; import net.egork.chelper.ui.VariableGridLayout; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.DocumentEvent; import java.awt.*; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class EditTestsDialog extends DialogWrapper { private static final int HEIGHT = new JLabel("Test").getPreferredSize().height; private static final double LIST_PANEL_FRACTION = 0.35; private static final Dimension PREFERRED_SIZE = new Dimension(600, 400); private static final int GRID_LAYOUT_GAP = 5; private List<Test> tests; private int currentTest; private JBList<Test> testList; private JTextArea input; private JTextArea output; private List<JCheckBox> checkBoxes = new ArrayList<>(); private JPanel checkBoxesPanel; private JCheckBox knowAnswer; private JPanel outputPanel; private boolean updating = false; private JComponent component; public EditTestsDialog(Test[] tests, Project project) { super(project); setTitle("Tests"); this.tests = new ArrayList<>(Arrays.asList(tests)); VariableGridLayout mainLayout = new VariableGridLayout(1, 2, GRID_LAYOUT_GAP, GRID_LAYOUT_GAP); mainLayout.setColFraction(0, LIST_PANEL_FRACTION); JPanel mainPanel = new JPanel(mainLayout); JPanel selectorAndButtonsPanel = new JPanel(new BorderLayout()); selectorAndButtonsPanel.add( LabeledComponent.create( new JBScrollPane( generateListPanel(), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER ), "Tests" ) ); selectorAndButtonsPanel.add(createButtonPanel(), BorderLayout.PAGE_END); mainPanel.add(selectorAndButtonsPanel); mainPanel.add(generateTestPanel()); mainPanel.setPreferredSize(PREFERRED_SIZE); component = mainPanel; setSelectedTest(Math.min(0, tests.length - 1)); init(); } private JPanel generateListPanel() { JPanel checkBoxesAndSelectorPanel = new JPanel(new BorderLayout()); checkBoxesPanel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, false, false)); for (Test test : tests) { JCheckBox checkBox = createCheckBox(test); checkBoxesPanel.add(checkBox); } checkBoxesAndSelectorPanel.add(checkBoxesPanel, BorderLayout.WEST); testList = new JBList<>(tests); testList.setFixedCellHeight(HEIGHT); testList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); testList.setLayoutOrientation(JList.VERTICAL); testList.addListSelectionListener( e -> { if (updating) { return; } int index = testList.getSelectedIndex(); if (index >= 0 && index < testList.getItemsCount()) { saveCurrentTest(); setSelectedTest(index); } } ); checkBoxesAndSelectorPanel.add(testList, BorderLayout.CENTER); return checkBoxesAndSelectorPanel; } private JPanel generateTestPanel() { JPanel testPanel = new JPanel(new GridLayout(2, 1, GRID_LAYOUT_GAP, GRID_LAYOUT_GAP)); input = generateSavingTextArea(); JPanel inputPanel = LabeledComponent.create(new JBScrollPane(input), "Input"); output = generateSavingTextArea(); outputPanel = LabeledComponent.create(new JBScrollPane(output), "Output"); knowAnswer = new JCheckBox("Know answer?"); knowAnswer.addActionListener(e -> saveCurrentTest()); JPanel outputAndCheckBoxPanel = new JPanel(new BorderLayout()); outputAndCheckBoxPanel.add(knowAnswer, BorderLayout.NORTH); outputAndCheckBoxPanel.add(outputPanel, BorderLayout.CENTER); testPanel.add(inputPanel); testPanel.add(outputAndCheckBoxPanel); return testPanel; } private JTextArea generateSavingTextArea() { JTextArea result = new JTextArea(); result.setFont(Font.decode(Font.MONOSPACED)); result.getDocument().addDocumentListener( new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { saveCurrentTest(); } } ); return result; } private JPanel createButtonPanel() { JPanel buttonsPanel = new JPanel(new GridLayout(2, 2)); JButton allButton = new JButton("All"); allButton.addActionListener( e -> { int index = 0; for (JCheckBox checkBox : checkBoxes) { checkBox.setSelected(true); tests.set( index, tests.get(index).setActive(true) ); index++; } setSelectedTest(currentTest); } ); buttonsPanel.add(allButton); JButton noneButton = new JButton("None"); noneButton.addActionListener( e -> { int index = 0; for (JCheckBox checkBox : checkBoxes) { checkBox.setSelected(false); tests.set( index, tests.get(index).setActive(false) ); index++; } setSelectedTest(currentTest); } ); buttonsPanel.add(noneButton); JButton newTestButton = new JButton("New"); newTestButton.addActionListener( e -> { saveCurrentTest(); int index = tests.size(); Test test = new Test("", "", index); tests.add(test); checkBoxesPanel.add(createCheckBox(test)); setSelectedTest(index); } ); buttonsPanel.add(newTestButton); JButton removeButton = new JButton("Remove"); removeButton.addActionListener( e -> { if (currentTest == -1) { return; } while (checkBoxes.size() > currentTest) { checkBoxesPanel.remove(checkBoxes.get(currentTest)); checkBoxes.remove(currentTest); } tests.remove(currentTest); int size = tests.size(); for (int i = currentTest; i < size; i++) { Test test = tests.get(i); test = new Test(test.input, test.output, i, test.active); tests.set(i, test); checkBoxesPanel.add(createCheckBox(test)); } if (currentTest < size) { setSelectedTest(currentTest); return; } if (size > 0) { setSelectedTest(0); return; } setSelectedTest(-1); } ); buttonsPanel.add(removeButton); return buttonsPanel; } private JCheckBox createCheckBox(Test test) { JCheckBox checkBox = new JCheckBox("", test.active); Dimension preferredSize = new Dimension(checkBox.getPreferredSize().width, HEIGHT); checkBox.setPreferredSize(preferredSize); checkBox.addActionListener( e -> { tests.set(test.index, tests.get(test.index).setActive(checkBox.isSelected())); setSelectedTest(currentTest); } ); checkBoxes.add(checkBox); return checkBox; } private void setSelectedTest(int index) { updating = true; currentTest = -1; if (index == -1) { input.setVisible(false); output.setVisible(false); } else { input.setVisible(true); output.setVisible(true); input.setText(tests.get(index).input); knowAnswer.setSelected(tests.get(index).output != null); output.setText(knowAnswer.isSelected() ? tests.get(index).output : ""); outputPanel.setVisible(knowAnswer.isSelected()); } currentTest = index; testList.setListData(tests.toArray(new Test[tests.size()])); if (testList.getSelectedIndex() != currentTest) { testList.setSelectedIndex(currentTest); } testList.repaint(); checkBoxesPanel.repaint(); updating = false; } private void saveCurrentTest() { if (currentTest == -1) { return; } tests.set( currentTest, new Test( input.getText(), knowAnswer.isSelected() ? output.getText() : null, currentTest, checkBoxes.get(currentTest).isSelected() ) ); outputPanel.setVisible(knowAnswer.isSelected()); } public Test[] getTests() { return tests.toArray(new Test[tests.size()]); } @Nullable @Override protected JComponent createCenterPanel() { return component; } }