diff --git a/src/main/java/link/infra/packwiz/installer/Main.java b/src/main/java/link/infra/packwiz/installer/Main.java index 2811a73..8f73a8f 100644 --- a/src/main/java/link/infra/packwiz/installer/Main.java +++ b/src/main/java/link/infra/packwiz/installer/Main.java @@ -109,15 +109,12 @@ public class Main { // Start update process! // TODO: start in SwingWorker? try { - ui.executeManager(new Runnable(){ - @Override - public void run() { - try { - new UpdateManager(uOptions, ui); - } catch (Exception e) { - // TODO: better error message? - ui.handleExceptionAndExit(e); - } + ui.executeManager(() -> { + try { + new UpdateManager(uOptions, ui); + } catch (Exception e) { + // TODO: better error message? + ui.handleExceptionAndExit(e); } }); } catch (Exception e) { diff --git a/src/main/java/link/infra/packwiz/installer/ui/InstallWindow.java b/src/main/java/link/infra/packwiz/installer/ui/InstallWindow.java index 2f756ac..2c6e033 100644 --- a/src/main/java/link/infra/packwiz/installer/ui/InstallWindow.java +++ b/src/main/java/link/infra/packwiz/installer/ui/InstallWindow.java @@ -4,6 +4,7 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; @@ -161,8 +162,12 @@ public class InstallWindow implements IUserInterface { } @Override - public Future showOptions(List option) { - return null; + public Future showOptions(List opts) { + CompletableFuture future = new CompletableFuture(); + OptionsSelectWindow dialog = new OptionsSelectWindow(opts, future); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + return future; } } diff --git a/src/main/java/link/infra/packwiz/installer/ui/OptionTempHandler.java b/src/main/java/link/infra/packwiz/installer/ui/OptionTempHandler.java new file mode 100644 index 0000000..7fbf3c9 --- /dev/null +++ b/src/main/java/link/infra/packwiz/installer/ui/OptionTempHandler.java @@ -0,0 +1,33 @@ +package link.infra.packwiz.installer.ui; + +// Serves as a proxy for IOptionDetails, so that setOptionValue isn't called until OK is clicked +public class OptionTempHandler implements IOptionDetails { + private final IOptionDetails opt; + private boolean tempValue; + + public OptionTempHandler(IOptionDetails opt) { + this.opt = opt; + tempValue = opt.getOptionValue(); + } + + public String getName() { + return opt.getName(); + } + + public String getOptionDescription() { + return opt.getOptionDescription(); + } + + public boolean getOptionValue() { + return tempValue; + } + + public void setOptionValue(boolean value) { + tempValue = value; + } + + public void finalise() { + opt.setOptionValue(tempValue); + } + +} diff --git a/src/main/java/link/infra/packwiz/installer/ui/OptionsSelectWindow.java b/src/main/java/link/infra/packwiz/installer/ui/OptionsSelectWindow.java new file mode 100644 index 0000000..69db155 --- /dev/null +++ b/src/main/java/link/infra/packwiz/installer/ui/OptionsSelectWindow.java @@ -0,0 +1,200 @@ +package link.infra.packwiz.installer.ui; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TableModelListener; +import javax.swing.table.TableModel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public class OptionsSelectWindow extends JDialog implements ActionListener { + + private static final long serialVersionUID = 1L; + private final JPanel contentPanel = new JPanel(); + private final JLabel lblOptionDescription; + private final OptionTableModel tableModel; + private final CompletableFuture future; + + /** + * Create the dialog. + */ + public OptionsSelectWindow(List optList, CompletableFuture future) { + tableModel = new OptionTableModel(optList); + this.future = future; + + setModal(true); + setTitle("Select optional mods..."); + setBounds(100, 100, 450, 300); + getContentPane().setLayout(new BorderLayout()); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel, BorderLayout.CENTER); + contentPanel.setLayout(new BorderLayout(0, 0)); + { + JSplitPane splitPane = new JSplitPane(); + splitPane.setResizeWeight(0.5); + contentPanel.add(splitPane); + { + JTable table = new JTable(); + table.setShowVerticalLines(false); + table.setShowHorizontalLines(false); + table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + table.setShowGrid(false); + table.setModel(tableModel); + table.getColumnModel().getColumn(0).setResizable(false); + table.getColumnModel().getColumn(0).setPreferredWidth(15); + table.getColumnModel().getColumn(0).setMaxWidth(15); + table.getColumnModel().getColumn(1).setResizable(false); + table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + int i = table.getSelectedRow(); + if (i > -1) { + lblOptionDescription.setText(tableModel.getDescription(i)); + } else { + lblOptionDescription.setText("Select an option..."); + } + } + }); + table.setTableHeader(null); + JScrollPane scrollPane = new JScrollPane(table); + scrollPane.getViewport().setBackground(UIManager.getColor("List.background")); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0)); + splitPane.setLeftComponent(scrollPane); + } + { + lblOptionDescription = new JLabel("Select an option..."); + lblOptionDescription.setBackground(UIManager.getColor("List.background")); + lblOptionDescription.setOpaque(true); + lblOptionDescription.setVerticalAlignment(SwingConstants.TOP); + lblOptionDescription.setBorder(new EmptyBorder(10, 10, 10, 10)); + JScrollPane scrollPane = new JScrollPane(lblOptionDescription); + scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0)); + splitPane.setRightComponent(scrollPane); + } + } + { + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + { + JButton okButton = new JButton("OK"); + okButton.setActionCommand("OK"); + okButton.addActionListener(this); + buttonPane.add(okButton); + getRootPane().setDefaultButton(okButton); + } + { + JButton cancelButton = new JButton("Cancel"); + cancelButton.setActionCommand("Cancel"); + cancelButton.addActionListener(this); + buttonPane.add(cancelButton); + } + } + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + future.complete(false); + } + + @Override + public void windowClosed(WindowEvent e) { + // Just in case closing didn't get triggered - if something else called dispose() the + // future will have already completed + future.complete(false); + } + }); + } + + private class OptionTableModel implements TableModel { + private List opts = new ArrayList(); + + public OptionTableModel(List givenOpts) { + for (IOptionDetails opt : givenOpts) { + opts.add(new OptionTempHandler(opt)); + } + } + + @Override + public int getRowCount() { + return opts.size(); + } + + @Override + public int getColumnCount() { + return 2; + } + + private final String[] columnNames = {"Enabled", "Mod name"}; + private final Class[] columnTypes = {Boolean.class, String.class}; + private final boolean[] columnEditables = {true, false}; + + @Override + public String getColumnName(int columnIndex) { + return columnNames[columnIndex]; + } + + @Override + public Class getColumnClass(int columnIndex) { + return columnTypes[columnIndex]; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnEditables[columnIndex]; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + OptionTempHandler opt = opts.get(rowIndex); + return columnIndex == 0 ? opt.getOptionValue() : opt.getName(); + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + if (columnIndex == 0) { + OptionTempHandler opt = opts.get(rowIndex); + opt.setOptionValue((boolean) aValue); + } + } + + // Noop, the table model doesn't change! + @Override + public void addTableModelListener(TableModelListener l) {} + + @Override + public void removeTableModelListener(TableModelListener l) {} + + public String getDescription(int rowIndex) { + return opts.get(rowIndex).getOptionDescription(); + } + + public void finalise() { + for (OptionTempHandler opt : opts) { + opt.finalise(); + } + } + + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("OK")) { + tableModel.finalise(); + future.complete(true); + dispose(); + } else if (e.getActionCommand().equals("Cancel")) { + future.complete(false); + dispose(); + } + } + +}