From: Jakob Cornell Date: Thu, 4 Feb 2021 01:26:20 +0000 (-0600) Subject: Add support for multiple tile sets X-Git-Url: https://jcornell.net/gitweb/gitweb.cgi?a=commitdiff_plain;h=5ae81b1f423effc7081dbe8b9dbb004da7c371c2;p=tile-draw.git Add support for multiple tile sets This is a breaking change in the save format; the application discards previously saved data if it's incompatible. --- diff --git a/src/net/jcornell/tile_draw/Main.java b/src/net/jcornell/tile_draw/Main.java index c9bbf56..98cf8c7 100644 --- a/src/net/jcornell/tile_draw/Main.java +++ b/src/net/jcornell/tile_draw/Main.java @@ -1,10 +1,12 @@ package net.jcornell.tile_draw; +import javax.swing.JFrame; import java.awt.Window; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.awt.Dimension; import net.jcornell.tile_draw.util.Util; @@ -16,20 +18,16 @@ public class Main { data = Util.loadData(); } catch (IOException | ClassNotFoundException | Util.ImageLoadException e) { e.printStackTrace(); + data = new SaveData(new ArrayList<>(), null); } - List tileModels; - File chooserDir; - if (data == null) { - tileModels = new ArrayList<>(); - chooserDir = null; - } else { - tileModels = data.tileModels; - chooserDir = data.fileChooserDir; - } - - TileSelectController tsController = new TileSelectController(tileModels, chooserDir); - Window window = tsController.view.window; + JFrame window = new JFrame("Tile Draw"); + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + TileSetsController controller = new TileSetsController(data.tileSets, data.fileChooserDir); + TileSetsSwingView view = new TileSetsSwingView(controller); + controller.view = view; + window.setContentPane(view.contentPane); + window.pack(); window.setLocationRelativeTo(null); window.setVisible(true); } diff --git a/src/net/jcornell/tile_draw/SaveData.java b/src/net/jcornell/tile_draw/SaveData.java index 79b3e27..2b077c5 100644 --- a/src/net/jcornell/tile_draw/SaveData.java +++ b/src/net/jcornell/tile_draw/SaveData.java @@ -4,17 +4,19 @@ import java.io.Serializable; import java.io.File; import java.util.List; +import net.jcornell.tile_draw.TileSetsController.TileSet; + public class SaveData implements Serializable { - private static final long serialVersionUID = 0; + private static final long serialVersionUID = 1; - public List tileModels; + public List tileSets; public File fileChooserDir; public SaveData() {} - public SaveData(List tileModels, File fileChooserDir) { - this.tileModels = tileModels; + public SaveData(List tileSets, File fileChooserDir) { + this.tileSets = tileSets; this.fileChooserDir = fileChooserDir; } } diff --git a/src/net/jcornell/tile_draw/TileConfigModel.java b/src/net/jcornell/tile_draw/TileConfigModel.java index 3d5d3e7..f518c2e 100644 --- a/src/net/jcornell/tile_draw/TileConfigModel.java +++ b/src/net/jcornell/tile_draw/TileConfigModel.java @@ -24,7 +24,15 @@ public class TileConfigModel implements Serializable { public void loadImage() throws Util.ImageLoadException { imageView = new ImageIcon( - Util.extractImage(imageFile).getScaledInstance(-1, TileSelectController.THUMBNAIL_HEIGHT, 0) + Util.extractImage(imageFile).getScaledInstance(-1, TileSetEditController.THUMBNAIL_HEIGHT, 0) ); } + + public TileConfigModel copy() { + try { + return new TileConfigModel(imageFile, multiplicity); + } catch (Util.ImageLoadException e) { + throw new RuntimeException(e); + } + } } diff --git a/src/net/jcornell/tile_draw/TileSelectController.java b/src/net/jcornell/tile_draw/TileSelectController.java deleted file mode 100644 index c2dd379..0000000 --- a/src/net/jcornell/tile_draw/TileSelectController.java +++ /dev/null @@ -1,242 +0,0 @@ -package net.jcornell.tile_draw; - -import java.awt.Dialog; -import java.awt.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Image; -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JSpinner; -import javax.swing.JTable; -import javax.swing.SpinnerNumberModel; -import javax.swing.table.AbstractTableModel; - -import net.jcornell.tile_draw.util.Util; -import net.jcornell.tile_draw.util.JSpinnerTableCellEditor; - - -public class TileSelectController extends AbstractTableModel { - public static final int DEFAULT_MULTIPLICITY = 1; - public static final int THUMBNAIL_HEIGHT = 50; - protected static final Class[] COL_CLASSES = new Class[] {Boolean.class, ImageIcon.class, Integer.class}; - protected static final String[] COL_NAMES = new String[] {"", "Tile", "Multiplicity"}; - - public final List tileModels; - public final TileSelectView view; - public File fileChooserDir; - - public TileSelectController(List tileModels, File fileChooserDir) { - this.tileModels = tileModels; - view = new TileSelectView(this); - this.fileChooserDir = fileChooserDir; - view.setCanBegin(!tileModels.isEmpty()); - } - - public void addTiles(List toAdd) { - int oldSize = tileModels.size(); - tileModels.addAll(toAdd); - super.fireTableRowsInserted(oldSize, tileModels.size()); - view.setCanBegin(true); - saveData(); - } - - public void dropTiles(List toDrop) { - for (TileConfigModel m : toDrop) { - int row = tileModels.indexOf(m); - tileModels.remove(m); - super.fireTableRowsDeleted(row, row); - } - view.setCanBegin(!tileModels.isEmpty()); - saveData(); - } - - public List getSelectedTiles() { - return tileModels.stream() - .filter(m -> m.selected) - .collect(Collectors.toList()) - ; - } - - public void beginDraw() { - DrawController c = new DrawController(tileModels); - c.drawTile(); - Dialog dialog = c.view.dialog; - dialog.pack(); - dialog.setResizable(false); - dialog.setLocationRelativeTo(view.window); - dialog.setVisible(true); - } - - public void saveData() { - SaveData data = new SaveData(tileModels, fileChooserDir); - try { - Util.saveData(data); - } catch (IOException e) {} - } - - @Override - public int getRowCount() { - return tileModels.size(); - } - - @Override - public int getColumnCount() { - return COL_CLASSES.length; - } - - @Override - public String getColumnName(int col) { - return COL_NAMES[col]; - } - - @Override - public Object getValueAt(int row, int col) { - TileConfigModel m = tileModels.get(row); - return new Object[] {m.selected, m.imageView, m.multiplicity}[col]; - } - - @Override - public void setValueAt(Object value, int row, int col) { - TileConfigModel m = tileModels.get(row); - if (col == 0) { - m.selected = (boolean) value; - } else if (col == 2) { - m.multiplicity = (int) value; - saveData(); - } else { - throw new AssertionError(); - } - } - - @Override - public Class getColumnClass(int col) { - return COL_CLASSES[col]; - } - - @Override - public boolean isCellEditable(int row, int col) { - return new boolean[] {true, false, true}[col]; - } -} - - -class TileSelectView { - protected final TileSelectController controller; - protected final JTable grid; - protected final JButton beginButton; - public final JFrame window; - - public TileSelectView(TileSelectController controller) { - this.controller = controller; - grid = createGrid(); - beginButton = new JButton("Begin"); - window = createWindow(); - } - - protected JTable createGrid() { - JTable grid = new JTable(controller); - grid.setRowHeight(TileSelectController.THUMBNAIL_HEIGHT); - JSpinner spinner = new JSpinner( - new SpinnerNumberModel(0, 0, Integer.MAX_VALUE, 1) - ); - grid.getColumnModel().getColumn(2).setCellEditor(new JSpinnerTableCellEditor(spinner)); - return grid; - } - - private static TileConfigModel tryTileBuild(File imageFile) { - try { - return new TileConfigModel(imageFile, TileSelectController.DEFAULT_MULTIPLICITY); - } catch (Util.ImageLoadException e) { - return null; - } - } - - protected JFrame createWindow() { - JFrame frame = new JFrame("Select Tiles"); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setLayout(new GridBagLayout()); - - JScrollPane tilesScrollPane = new JScrollPane(grid); - tilesScrollPane.setPreferredSize(new Dimension(400, 150)); - - GridBagConstraints tilesPaneC = new GridBagConstraints(); - tilesPaneC.gridx = 0; - tilesPaneC.gridy = GridBagConstraints.RELATIVE; - tilesPaneC.fill = GridBagConstraints.BOTH; - tilesPaneC.weightx = 1; - tilesPaneC.weighty = 1; - frame.add(tilesScrollPane, tilesPaneC); - - JButton deleteBtn = new JButton("Delete selected"); - deleteBtn.addActionListener(e -> { - controller.dropTiles(controller.getSelectedTiles()); - }); - - JButton addBtn = new JButton("Add…"); - addBtn.addActionListener(e -> { - JFileChooser chooser = new JFileChooser(controller.fileChooserDir); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - chooser.setMultiSelectionEnabled(true); - int result = chooser.showOpenDialog(addBtn); - controller.fileChooserDir = chooser.getCurrentDirectory(); - controller.saveData(); - if (result == JFileChooser.APPROVE_OPTION) { - File[] files = chooser.getSelectedFiles(); - List newModels = Arrays.stream(files) - .map(TileSelectView::tryTileBuild) - .collect(Collectors.toList()) - ; - if (newModels.contains(null)) { - JOptionPane.showMessageDialog( - frame, "Failed to load one or more files as images", "Image load error", JOptionPane.WARNING_MESSAGE - ); - } - List okay = newModels.stream() - .filter(m -> m != null) - .collect(Collectors.toList()) - ; - controller.addTiles(okay); - } - }); - - beginButton.addActionListener(e -> { - controller.beginDraw(); - }); - - JPanel buttonRow = new JPanel(); - buttonRow.setLayout(new BoxLayout(buttonRow, BoxLayout.LINE_AXIS)); - buttonRow.add(deleteBtn); - buttonRow.add(Box.createRigidArea(new Dimension(5, 0))); - buttonRow.add(addBtn); - buttonRow.add(Box.createHorizontalGlue()); - buttonRow.add(beginButton); - buttonRow.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - - GridBagConstraints btnBarC = new GridBagConstraints(); - btnBarC.gridx = 0; - btnBarC.gridy = GridBagConstraints.RELATIVE; - btnBarC.fill = GridBagConstraints.HORIZONTAL; - frame.add(buttonRow, btnBarC); - - frame.pack(); - return frame; - } - - public void setCanBegin(boolean canBegin) { - beginButton.setEnabled(canBegin); - } -} diff --git a/src/net/jcornell/tile_draw/TileSetEditController.java b/src/net/jcornell/tile_draw/TileSetEditController.java new file mode 100644 index 0000000..6f7656a --- /dev/null +++ b/src/net/jcornell/tile_draw/TileSetEditController.java @@ -0,0 +1,259 @@ +package net.jcornell.tile_draw; + +import java.awt.Dialog; +import java.awt.Dimension; +import javax.swing.JTextField; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Image; +import java.io.File; +import java.awt.event.FocusEvent; +import java.io.IOException; +import java.util.Arrays; +import javax.swing.JDialog; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.List; +import java.util.stream.Collectors; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.table.TableCellEditor; +import javax.swing.ImageIcon; +import java.awt.Insets; +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JComponent; +import java.awt.Component; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTable; +import javax.swing.SpinnerNumberModel; +import javax.swing.table.AbstractTableModel; + +import net.jcornell.tile_draw.TileSetsController.TileSet; +import net.jcornell.tile_draw.util.JSpinnerTableCellEditor; +import net.jcornell.tile_draw.util.Util; + + +public class TileSetEditController extends AbstractTableModel { + public static final int DEFAULT_MULTIPLICITY = 1; + public static final int THUMBNAIL_HEIGHT = 50; + protected static final Class[] COL_CLASSES = new Class[] {Boolean.class, ImageIcon.class, Integer.class}; + protected static final String[] COL_NAMES = new String[] {"", "Tile", "Multiplicity"}; + + public static interface EventListener { + public void onSubmitTileSet(TileSet value); + } + + public final TileSet tileSet; + public TileSetEditSwingView view; + public final TileSetsController parent; + public final EventListener listener; + protected final TileSet originalValue; + + public TileSetEditController(TileSet tileSet, EventListener listener, TileSetsController parent) { + this.tileSet = tileSet.copy(); + this.parent = parent; + this.listener = listener; + originalValue = tileSet; + } + + public void addTiles(List toAdd) { + int oldSize = tileSet.tileModels.size(); + tileSet.tileModels.addAll(toAdd); + super.fireTableRowsInserted(oldSize, tileSet.tileModels.size()); + } + + public void dropTiles(List toDrop) { + for (TileConfigModel m : toDrop) { + int row = tileSet.tileModels.indexOf(m); + tileSet.tileModels.remove(m); + super.fireTableRowsDeleted(row, row); + } + } + + public List getSelectedTiles() { + return + tileSet.tileModels.stream() + .filter(m -> m.selected) + .collect(Collectors.toList()) + ; + } + + public File getChooserDir() { + return parent.fileChooserDir; + } + + public void setChooserDir(File newDir) { + parent.setFileChooserDir(newDir); + } + + public void submitChanges() { + listener.onSubmitTileSet(tileSet); + } + + public boolean isClean() { + return tileSet.equals(originalValue); + } + + @Override + public int getRowCount() { + return tileSet.tileModels.size(); + } + + @Override + public int getColumnCount() { + return COL_CLASSES.length; + } + + @Override + public String getColumnName(int col) { + return COL_NAMES[col]; + } + + @Override + public Object getValueAt(int row, int col) { + TileConfigModel m = tileSet.tileModels.get(row); + return new Object[] {m.selected, m.imageView, m.multiplicity}[col]; + } + + @Override + public void setValueAt(Object value, int row, int col) { + TileConfigModel m = tileSet.tileModels.get(row); + if (col == 0) { + m.selected = (boolean) value; + } else if (col == 2) { + m.multiplicity = (int) value; + } else { + throw new AssertionError(); + } + } + + @Override + public Class getColumnClass(int col) { + return COL_CLASSES[col]; + } + + @Override + public boolean isCellEditable(int row, int col) { + return new boolean[] {true, false, true}[col]; + } +} + + +class TileSetEditSwingView { + protected final TileSetEditController controller; + protected JTextField nameField; + protected JTable grid; + protected TableCellEditor multColumnEditor; + public JOptionPane optionPane; + public JDialog dialog; + + public TileSetEditSwingView(TileSetEditController controller, Component dialogParent) { + this.controller = controller; + populateUi(dialogParent); + } + + private static TileConfigModel tryTileBuild(File imageFile) { + try { + return new TileConfigModel(imageFile, TileSetEditController.DEFAULT_MULTIPLICITY); + } catch (Util.ImageLoadException e) { + return null; + } + } + + protected void populateUi(Component dialogParent) { + grid = new JTable(controller); + grid.setRowHeight(TileSetEditController.THUMBNAIL_HEIGHT); + JSpinner spinner = new JSpinner( + new SpinnerNumberModel(1, 1, Integer.MAX_VALUE, 1) + ); + multColumnEditor = new JSpinnerTableCellEditor(spinner); + grid.getColumnModel().getColumn(2).setCellEditor(multColumnEditor); + + JPanel panel = new JPanel(new GridBagLayout()); + + nameField = new JTextField(controller.originalValue.name); + GridBagConstraints nameFieldC = new GridBagConstraints(); + nameFieldC.gridx = 0; + nameFieldC.gridy = GridBagConstraints.RELATIVE; + nameFieldC.fill = GridBagConstraints.HORIZONTAL; + nameFieldC.insets = new Insets(0, 0, 10, 0); + nameFieldC.ipady = 5; + panel.add(nameField, nameFieldC); + + JScrollPane tilesScrollPane = new JScrollPane(grid); + tilesScrollPane.setPreferredSize(new Dimension(400, 150)); + + GridBagConstraints tilesPaneC = new GridBagConstraints(); + tilesPaneC.gridx = 0; + tilesPaneC.gridy = GridBagConstraints.RELATIVE; + tilesPaneC.fill = GridBagConstraints.BOTH; + tilesPaneC.weightx = 1; + tilesPaneC.weighty = 1; + panel.add(tilesScrollPane, tilesPaneC); + + JButton deleteBtn = new JButton("Delete selected"); + deleteBtn.addActionListener(e -> { + controller.dropTiles(controller.getSelectedTiles()); + }); + + JButton addBtn = new JButton("Add…"); + addBtn.addActionListener(e -> { + JFileChooser chooser = new JFileChooser(controller.getChooserDir()); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + chooser.setMultiSelectionEnabled(true); + int result = chooser.showOpenDialog(addBtn); + controller.setChooserDir(chooser.getCurrentDirectory()); + if (result == JFileChooser.APPROVE_OPTION) { + File[] files = chooser.getSelectedFiles(); + List newModels = Arrays.stream(files) + .map(TileSetEditSwingView::tryTileBuild) + .collect(Collectors.toList()) + ; + if (newModels.contains(null)) { + JOptionPane.showMessageDialog( + panel, "Failed to load one or more files as images", "Image load error", JOptionPane.WARNING_MESSAGE + ); + } + List okay = + newModels.stream() + .filter(m -> m != null) + .collect(Collectors.toList()) + ; + controller.addTiles(okay); + } + }); + + JPanel buttonRow = new JPanel(); + buttonRow.setLayout(new BoxLayout(buttonRow, BoxLayout.LINE_AXIS)); + buttonRow.add(deleteBtn); + buttonRow.add(Box.createRigidArea(new Dimension(5, 0))); + buttonRow.add(addBtn); + buttonRow.add(Box.createHorizontalGlue()); + + GridBagConstraints btnBarC = new GridBagConstraints(); + btnBarC.gridx = 0; + btnBarC.gridy = GridBagConstraints.RELATIVE; + btnBarC.fill = GridBagConstraints.HORIZONTAL; + btnBarC.insets = new Insets(10, 0, 5, 0); + panel.add(buttonRow, btnBarC); + + optionPane = new JOptionPane(panel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION); + dialog = optionPane.createDialog(dialogParent, "Tile set editor"); + dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + } + + public void finishEditing() { + multColumnEditor.stopCellEditing(); + } + + public void submitChanges() { + controller.tileSet.name = nameField.getText(); + controller.submitChanges(); + } +} diff --git a/src/net/jcornell/tile_draw/TileSetsController.java b/src/net/jcornell/tile_draw/TileSetsController.java new file mode 100644 index 0000000..aa88821 --- /dev/null +++ b/src/net/jcornell/tile_draw/TileSetsController.java @@ -0,0 +1,243 @@ +package net.jcornell.tile_draw; + +import javax.swing.JComponent; +import javax.swing.DefaultListModel; +import javax.swing.JList; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JDialog; +import javax.swing.JScrollPane; +import javax.swing.JFrame; +import java.util.stream.Collectors; +import javax.swing.ListSelectionModel; +import javax.swing.JOptionPane; +import java.util.List; +import java.util.ArrayList; +import java.io.Serializable; +import java.io.File; +import java.io.IOException; +import java.awt.BorderLayout; +import java.awt.Dialog; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import net.jcornell.tile_draw.TileSetsController.TileSet; +import net.jcornell.tile_draw.util.Util; + + +public class TileSetsController { + public static class TileSet implements Serializable { + private static final long serialVersionUID = 0; + + public String name; + public List tileModels; + + public TileSet(String name, List tileModels) { + this.name = name; + this.tileModels = tileModels; + } + + public TileSet copy() { + return new TileSet(name, tileModels.stream().map(TileConfigModel::copy).collect(Collectors.toList())); + } + + @Override public boolean equals(Object otherObj) { + TileSet other = (TileSet) otherObj; + return other.name.equals(name) && other.tileModels.equals(tileModels); + } + } + + protected final List tileSets; + protected TileSetsSwingView view; + public File fileChooserDir; + + public TileSetsController(List tileSets, File fileChooserDir) { + this.tileSets = tileSets; + this.fileChooserDir = fileChooserDir; + } + + public void addSet(TileSet set) { + tileSets.add(set); + view.addSet(set); + saveData(); + } + + protected void setSetAt(int index, TileSet value) { + tileSets.set(index, value); + view.setSetAt(index, value); + saveData(); + } + + public void deleteSetAt(int index) { + tileSets.remove(index); + view.deleteSetAt(index); + saveData(); + } + + public void saveData() { + try { + Util.saveData(new SaveData(tileSets, fileChooserDir)); + } catch (IOException e) { + view.onSaveFailed(e); + throw new RuntimeException(e); + } + } + + public void setFileChooserDir(File value) { + fileChooserDir = value; + saveData(); + } + + public void beginEdit(int setIndex) { + TileSetEditController.EventListener listener = new TileSetEditController.EventListener() { + @Override public void onSubmitTileSet(TileSet value) { + setSetAt(setIndex, value); + } + }; + + TileSet target = tileSets.get(setIndex); + TileSetEditController subController = new TileSetEditController(target, listener, this); + TileSetEditSwingView subView = view.getEditView(subController); + subController.view = subView; + view.doEdit(subView); + } + + public void beginDraw(int setIndex) { + DrawController c = new DrawController(tileSets.get(setIndex).tileModels); + c.drawTile(); + Dialog dialog = c.view.dialog; + dialog.pack(); + dialog.setResizable(false); + dialog.setLocationRelativeTo(view.contentPane); + dialog.setVisible(true); + } +} + + +class TileSetsSwingView { + protected final TileSetsController controller; + protected final DefaultListModel viewModel; + protected final JList setList; + protected final JButton deleteButton, editButton, beginButton; + + public final JComponent contentPane; + + protected static class TileSetWrapper { + protected final TileSet tileSet; + + public TileSetWrapper(TileSet tileSet) { + this.tileSet = tileSet; + } + + public String toString() { + return tileSet.name; + } + } + + public TileSetsSwingView(TileSetsController controller) { + this.controller = controller; + viewModel = new DefaultListModel<>(); + for (TileSet tileSet : controller.tileSets) { + viewModel.addElement(new TileSetWrapper(tileSet)); + } + setList = new JList<>(viewModel); + setList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + contentPane = new JPanel(new BorderLayout()); + JPanel buttonBar = new JPanel(); + + JButton addButton = new JButton("Add"); + addButton.addActionListener(e -> { + String newName = (String) JOptionPane.showInputDialog( + contentPane, + "Enter a name for the new tile set", + "New tile set", + JOptionPane.PLAIN_MESSAGE + ); + if (newName != null) { + controller.addSet(new TileSet(newName, new ArrayList<>())); + } + }); + buttonBar.add(addButton); + + deleteButton = new JButton("Delete"); + deleteButton.addActionListener(e -> { + int sel = setList.getSelectedIndex(); + if (sel != -1) { + int response = JOptionPane.showConfirmDialog( + contentPane, "Delete this tile set?", "Confirm delete", + JOptionPane.OK_CANCEL_OPTION + ); + if (response == JOptionPane.OK_OPTION) { + controller.deleteSetAt(sel); + } + } + }); + buttonBar.add(deleteButton); + + editButton = new JButton("Edit"); + editButton.addActionListener(e -> { + controller.beginEdit(setList.getSelectedIndex()); + }); + buttonBar.add(editButton); + + beginButton = new JButton("Begin"); + beginButton.addActionListener(e -> { + controller.beginDraw(setList.getSelectedIndex()); + }); + buttonBar.add(beginButton); + + setList.addListSelectionListener(e -> updateButtonStates()); + + JScrollPane setPane = new JScrollPane(setList); + + contentPane.add(setPane, BorderLayout.CENTER); + contentPane.add(buttonBar, BorderLayout.PAGE_END); + updateButtonStates(); + } + + public void addSet(TileSet set) { + viewModel.addElement(new TileSetWrapper(set)); + } + + public void setSetAt(int index, TileSet value) { + viewModel.set(index, new TileSetWrapper(value)); + updateButtonStates(); + } + + public void deleteSetAt(int index) { + viewModel.removeElementAt(index); + } + + public TileSetEditSwingView getEditView(TileSetEditController subController) { + return new TileSetEditSwingView(subController, contentPane); + } + + public void doEdit(TileSetEditSwingView editView) { + editView.dialog.setVisible(true); + editView.finishEditing(); + Object value = editView.optionPane.getValue(); + if (value != null && (int) value == JOptionPane.OK_OPTION) { + editView.submitChanges(); + } + } + + public void updateButtonStates() { + int selIndex = setList.getSelectedIndex(); + boolean hasSelection = selIndex != -1; + deleteButton.setEnabled(hasSelection); + editButton.setEnabled(hasSelection); + + boolean canBegin = hasSelection && !controller.tileSets.get(selIndex).tileModels.isEmpty(); + beginButton.setEnabled(canBegin); + } + + public void onSaveFailed(Throwable exception) { + JOptionPane.showMessageDialog( + contentPane, + "Error saving data: " + exception.toString(), + "Save error", + JOptionPane.ERROR_MESSAGE + ); + } +} diff --git a/src/net/jcornell/tile_draw/util/Util.java b/src/net/jcornell/tile_draw/util/Util.java index 225c45a..a890411 100644 --- a/src/net/jcornell/tile_draw/util/Util.java +++ b/src/net/jcornell/tile_draw/util/Util.java @@ -21,6 +21,7 @@ import javax.swing.JOptionPane; import net.jcornell.tile_draw.SaveData; import net.jcornell.tile_draw.TileConfigModel; +import net.jcornell.tile_draw.TileSetsController.TileSet; public final class Util { @@ -93,12 +94,15 @@ public final class Util { ); public static SaveData loadData() throws IOException, ClassNotFoundException, Util.ImageLoadException { + Files.createDirectories(SAVE_LOCATION.getParent()); SaveData data; try (InputStream input = Files.newInputStream(SAVE_LOCATION)) { data = (SaveData) new ObjectInputStream(input).readObject(); } - for (TileConfigModel m : data.tileModels) { - m.loadImage(); + for (TileSet set : data.tileSets) { + for (TileConfigModel m : set.tileModels) { + m.loadImage(); + } } return data; }