|
@@ -0,0 +1,271 @@
|
|
|
|
|
+package org.leumasjaffe.charsheet.view.magic;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
|
+import java.util.Arrays;
|
|
|
|
|
+import java.util.Collection;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+
|
|
|
|
|
+import javax.swing.JPanel;
|
|
|
|
|
+import javax.swing.JPopupMenu;
|
|
|
|
|
+import javax.swing.JTable;
|
|
|
|
|
+import javax.swing.ListSelectionModel;
|
|
|
|
|
+
|
|
|
|
|
+import org.leumasjaffe.charsheet.model.DDCharacter;
|
|
|
|
|
+import org.leumasjaffe.charsheet.model.DDCharacterClass;
|
|
|
|
|
+import org.leumasjaffe.charsheet.model.magic.DDSpell;
|
|
|
|
|
+import org.leumasjaffe.charsheet.model.magic.DDSpellbook;
|
|
|
|
|
+import org.leumasjaffe.charsheet.util.AbilityHelper;
|
|
|
|
|
+import org.leumasjaffe.event.SelectTableRowPopupMenuListener;
|
|
|
|
|
+import org.leumasjaffe.format.StringHelper;
|
|
|
|
|
+
|
|
|
|
|
+import lombok.AccessLevel;
|
|
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
|
|
+import lombok.Getter;
|
|
|
|
|
+import lombok.experimental.FieldDefaults;
|
|
|
|
|
+import java.awt.GridBagLayout;
|
|
|
|
|
+import java.awt.Dimension;
|
|
|
|
|
+import java.awt.GridBagConstraints;
|
|
|
|
|
+import java.awt.Insets;
|
|
|
|
|
+
|
|
|
|
|
+import javax.swing.border.BevelBorder;
|
|
|
|
|
+import javax.swing.border.SoftBevelBorder;
|
|
|
|
|
+import javax.swing.table.AbstractTableModel;
|
|
|
|
|
+import javax.swing.JButton;
|
|
|
|
|
+import javax.swing.JFrame;
|
|
|
|
|
+import javax.swing.JMenuItem;
|
|
|
|
|
+import javax.swing.JOptionPane;
|
|
|
|
|
+import javax.swing.JScrollPane;
|
|
|
|
|
+
|
|
|
|
|
+@SuppressWarnings("serial")
|
|
|
|
|
+@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
|
|
|
|
|
+public class SelectSpellsPanel extends JPanel {
|
|
|
|
|
+
|
|
|
|
|
+ @AllArgsConstructor
|
|
|
|
|
+ private static class SelectSpellModel extends AbstractTableModel {
|
|
|
|
|
+ /**
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+ private static final long serialVersionUID = 1L;
|
|
|
|
|
+
|
|
|
|
|
+ final Object[] data;
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int getRowCount() {
|
|
|
|
|
+ return data == null ? 0 : data.length;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int getColumnCount() {
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Object getValueAt(int rowIndex, int columnIndex) {
|
|
|
|
|
+ if (columnIndex != 0) { throw new IllegalArgumentException("There is only 1 column"); }
|
|
|
|
|
+ return data[rowIndex];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
|
|
|
|
+ if (columnIndex != 0) { throw new IllegalArgumentException("There is only 1 column"); }
|
|
|
|
|
+ data[rowIndex] = aValue;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @AllArgsConstructor
|
|
|
|
|
+ @FieldDefaults(level=AccessLevel.PUBLIC, makeFinal=true)
|
|
|
|
|
+ public static class Info {
|
|
|
|
|
+ DDCharacter chara;
|
|
|
|
|
+ DDCharacterClass dclass;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static final String READY = "Is Filled Out";
|
|
|
|
|
+
|
|
|
|
|
+ @Getter Collection<DDSpell> prepared;
|
|
|
|
|
+ boolean allowsDuplicates;
|
|
|
|
|
+ SelectSpellModel modelPrepared, modelKnown;
|
|
|
|
|
+
|
|
|
|
|
+ public SelectSpellsPanel(Info info, int level, Collection<DDSpell> prepared, int toPrepare,
|
|
|
|
|
+ Collection<DDSpell> avail, boolean allowsDuplicates) {
|
|
|
|
|
+ this(info.chara, level, info.dclass, prepared, toPrepare, avail, allowsDuplicates);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public SelectSpellsPanel(DDCharacter chara, int level,
|
|
|
|
|
+ DDCharacterClass dclass, Collection<DDSpell> prepared, int toPrepare,
|
|
|
|
|
+ Collection<DDSpell> avail, boolean allowsDuplicates) {
|
|
|
|
|
+ this.allowsDuplicates = allowsDuplicates;
|
|
|
|
|
+ putClientProperty(READY, true);
|
|
|
|
|
+ final DDSpellbook spellBook = dclass.getSpellBook().get();
|
|
|
|
|
+ this.prepared = new ArrayList<>(prepared);
|
|
|
|
|
+ final List<DDSpell> known = new ArrayList<>(avail);
|
|
|
|
|
+ this.modelPrepared = new SelectSpellModel(createPrepareModel(prepared, toPrepare));
|
|
|
|
|
+ this.modelKnown = new SelectSpellModel(known.stream().map(DDSpell::getName).toArray());
|
|
|
|
|
+
|
|
|
|
|
+ GridBagLayout gridBagLayout = new GridBagLayout();
|
|
|
|
|
+ gridBagLayout.columnWidths = new int[]{0, 40, 0, 0};
|
|
|
|
|
+ gridBagLayout.rowHeights = new int[]{20, 0, 0};
|
|
|
|
|
+ gridBagLayout.columnWeights = new double[]{1.0, 0.0, 1.0, Double.MIN_VALUE};
|
|
|
|
|
+ gridBagLayout.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
|
|
|
|
|
+ setLayout(gridBagLayout);
|
|
|
|
|
+
|
|
|
|
|
+ JPanel panel = new ChooseSpellsPerDayHeader(level, spellBook, AbilityHelper.get(chara, dclass));
|
|
|
|
|
+ GridBagConstraints gbc_panel = new GridBagConstraints();
|
|
|
|
|
+ gbc_panel.gridwidth = 3;
|
|
|
|
|
+ gbc_panel.insets = new Insets(0, 0, 5, 5);
|
|
|
|
|
+ gbc_panel.fill = GridBagConstraints.BOTH;
|
|
|
|
|
+ gbc_panel.gridx = 0;
|
|
|
|
|
+ gbc_panel.gridy = 0;
|
|
|
|
|
+ add(panel, gbc_panel);
|
|
|
|
|
+
|
|
|
|
|
+ JScrollPane scrollPane_1 = new JScrollPane();
|
|
|
|
|
+ scrollPane_1.setPreferredSize(new Dimension(175, 200));
|
|
|
|
|
+ scrollPane_1.setViewportBorder(new SoftBevelBorder(BevelBorder.LOWERED, null, null, null, null));
|
|
|
|
|
+ GridBagConstraints gbc_scrollPane_1 = new GridBagConstraints();
|
|
|
|
|
+ gbc_scrollPane_1.insets = new Insets(0, 0, 0, 5);
|
|
|
|
|
+ gbc_scrollPane_1.fill = GridBagConstraints.BOTH;
|
|
|
|
|
+ gbc_scrollPane_1.gridx = 0;
|
|
|
|
|
+ gbc_scrollPane_1.gridy = 1;
|
|
|
|
|
+ add(scrollPane_1, gbc_scrollPane_1);
|
|
|
|
|
+
|
|
|
|
|
+ JTable tablePrepared = new JTable(modelPrepared);
|
|
|
|
|
+ tablePrepared.setTableHeader(null);
|
|
|
|
|
+ scrollPane_1.setViewportView(tablePrepared);
|
|
|
|
|
+ tablePrepared.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
|
|
|
|
+
|
|
|
|
|
+ JPanel panelDivider = new JPanel();
|
|
|
|
|
+ GridBagConstraints gbc_panelDivider = new GridBagConstraints();
|
|
|
|
|
+ gbc_panelDivider.insets = new Insets(0, 0, 0, 5);
|
|
|
|
|
+ gbc_panelDivider.fill = GridBagConstraints.BOTH;
|
|
|
|
|
+ gbc_panelDivider.gridx = 1;
|
|
|
|
|
+ gbc_panelDivider.gridy = 1;
|
|
|
|
|
+ add(panelDivider, gbc_panelDivider);
|
|
|
|
|
+ GridBagLayout gbl_panelDivider = new GridBagLayout();
|
|
|
|
|
+ gbl_panelDivider.columnWidths = new int[]{0, 0};
|
|
|
|
|
+ gbl_panelDivider.rowHeights = new int[]{0, 0, 0, 0, 0};
|
|
|
|
|
+ gbl_panelDivider.columnWeights = new double[]{0.0, Double.MIN_VALUE};
|
|
|
|
|
+ gbl_panelDivider.rowWeights = new double[]{1.0, 0.0, 0.0, 1.0, Double.MIN_VALUE};
|
|
|
|
|
+ panelDivider.setLayout(gbl_panelDivider);
|
|
|
|
|
+
|
|
|
|
|
+ JScrollPane scrollPane = new JScrollPane();
|
|
|
|
|
+ scrollPane.setPreferredSize(new Dimension(175, 200));
|
|
|
|
|
+ scrollPane.setViewportBorder(new SoftBevelBorder(BevelBorder.LOWERED, null, null, null, null));
|
|
|
|
|
+ GridBagConstraints gbc_scrollPane = new GridBagConstraints();
|
|
|
|
|
+ gbc_scrollPane.insets = new Insets(0, 0, 0, 5);
|
|
|
|
|
+ gbc_scrollPane.fill = GridBagConstraints.BOTH;
|
|
|
|
|
+ gbc_scrollPane.gridx = 2;
|
|
|
|
|
+ gbc_scrollPane.gridy = 1;
|
|
|
|
|
+ add(scrollPane, gbc_scrollPane);
|
|
|
|
|
+
|
|
|
|
|
+ JTable tableKnown = new JTable(modelKnown);
|
|
|
|
|
+ tableKnown.setTableHeader(null);
|
|
|
|
|
+ scrollPane.setViewportView(tableKnown);
|
|
|
|
|
+ tableKnown.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
|
|
|
|
+
|
|
|
|
|
+ JPopupMenu popup = new JPopupMenu();
|
|
|
|
|
+ popup.addPopupMenuListener(new SelectTableRowPopupMenuListener(popup, tableKnown));
|
|
|
|
|
+ JMenuItem mntmInfo = new JMenuItem("Info");
|
|
|
|
|
+ mntmInfo.addActionListener( e -> {
|
|
|
|
|
+ DDSpell spell = known.get(tableKnown.getSelectedRow());
|
|
|
|
|
+ JFrame frame = new JFrame(spell.getName() + " (" + dclass.getName() + " " + level + ")");
|
|
|
|
|
+ frame.add(new SpellInfoPanel(chara, dclass, spell));
|
|
|
|
|
+ frame.pack();
|
|
|
|
|
+ frame.setVisible(true);
|
|
|
|
|
+ });
|
|
|
|
|
+ popup.add(mntmInfo);
|
|
|
|
|
+ tableKnown.setComponentPopupMenu(popup);
|
|
|
|
|
+
|
|
|
|
|
+ JButton button = new JButton(">>");
|
|
|
|
|
+ button.setMargin(new Insets(2, 8, 2, 8));
|
|
|
|
|
+ GridBagConstraints gbc_button = new GridBagConstraints();
|
|
|
|
|
+ gbc_button.insets = new Insets(0, 0, 5, 0);
|
|
|
|
|
+ gbc_button.gridx = 0;
|
|
|
|
|
+ gbc_button.gridy = 1;
|
|
|
|
|
+ panelDivider.add(button, gbc_button);
|
|
|
|
|
+ button.addActionListener(e -> {
|
|
|
|
|
+ final int row = tablePrepared.getSelectedRow();
|
|
|
|
|
+ if (row != -1) {
|
|
|
|
|
+ modelPrepared.setValueAt("<none>", row, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ tablePrepared.getSelectionModel().clearSelection();
|
|
|
|
|
+ tablePrepared.repaint();
|
|
|
|
|
+ if ((Boolean) getClientProperty(READY)) {
|
|
|
|
|
+ putClientProperty(READY, false);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ JButton button_1 = new JButton("<<");
|
|
|
|
|
+ button_1.setMargin(new Insets(2, 8, 2, 8));
|
|
|
|
|
+ GridBagConstraints gbc_button_1 = new GridBagConstraints();
|
|
|
|
|
+ gbc_button_1.insets = new Insets(0, 0, 5, 0);
|
|
|
|
|
+ gbc_button_1.gridx = 0;
|
|
|
|
|
+ gbc_button_1.gridy = 2;
|
|
|
|
|
+ panelDivider.add(button_1, gbc_button_1);
|
|
|
|
|
+
|
|
|
|
|
+ button_1.addActionListener(e -> {
|
|
|
|
|
+ final int[] rows = tableKnown.getSelectedRows();
|
|
|
|
|
+ final int[] orows = tablePrepared.getSelectedRows();
|
|
|
|
|
+ if (orows.length >= rows.length) {
|
|
|
|
|
+ for (int i = 0; i < rows.length; ++i) {
|
|
|
|
|
+ if (wouldHaveIllegalDuplicate(rows[i])) continue;
|
|
|
|
|
+ modelPrepared.data[orows[i]] = modelKnown.data[rows[i]];
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (orows.length == 0 && countNone() >= rows.length) {
|
|
|
|
|
+ replace(rows);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ final String message = StringHelper.format("Unable to assign new spells, more spells were selected ({}) than were avaliable ({})",
|
|
|
|
|
+ rows.length, orows.length == 0 ? countNone() : orows.length);
|
|
|
|
|
+ JOptionPane.showMessageDialog(this, message, "Error", JOptionPane.ERROR_MESSAGE);
|
|
|
|
|
+ }
|
|
|
|
|
+ tableKnown.getSelectionModel().clearSelection();
|
|
|
|
|
+ tablePrepared.getSelectionModel().clearSelection();
|
|
|
|
|
+ tablePrepared.repaint();
|
|
|
|
|
+
|
|
|
|
|
+ if (!(Boolean) getClientProperty(READY) && !Arrays.asList(modelPrepared.data).contains("<none>")) {
|
|
|
|
|
+ this.prepared.clear();
|
|
|
|
|
+ for (Object o : modelPrepared.data) {
|
|
|
|
|
+ this.prepared.add(DDSpell.fromString((String) o)); // TODO
|
|
|
|
|
+ }
|
|
|
|
|
+ putClientProperty(READY, true);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean wouldHaveIllegalDuplicate(int row) {
|
|
|
|
|
+ return !this.allowsDuplicates && Arrays.asList(modelPrepared.data).contains(modelKnown.data[row]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String[] createPrepareModel(Collection<DDSpell> prepared, int toPrepare) {
|
|
|
|
|
+ if (toPrepare <= prepared.size()) {
|
|
|
|
|
+ return prepared.stream().map(DDSpell::getName).toArray(String[]::new);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ String[] data = new String[toPrepare];
|
|
|
|
|
+ int i = 0;
|
|
|
|
|
+ for (DDSpell sp : prepared) {
|
|
|
|
|
+ data[i++] = sp.getName();
|
|
|
|
|
+ }
|
|
|
|
|
+ for (; i < toPrepare; ++i) {
|
|
|
|
|
+ data[i] = "<none>";
|
|
|
|
|
+ }
|
|
|
|
|
+ return data;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void replace(int[] rows) {
|
|
|
|
|
+ for (int i = 0; i < rows.length; ++i) {
|
|
|
|
|
+ if (wouldHaveIllegalDuplicate(i)) continue;
|
|
|
|
|
+ for (int j = 0; j < modelPrepared.data.length; ++j) {
|
|
|
|
|
+ if (!modelPrepared.data[j].equals("<none>")) continue;
|
|
|
|
|
+ modelPrepared.data[j] = modelKnown.data[i];
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private int countNone() {
|
|
|
|
|
+ int cnt = 0;
|
|
|
|
|
+ for (Object o : modelPrepared.data) {
|
|
|
|
|
+ if (o.equals("<none>")) ++cnt;
|
|
|
|
|
+ }
|
|
|
|
|
+ return cnt;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|