package org.leumasjaffe.charsheet.view; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JTabbedPane; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import lombok.AccessLevel; import lombok.NonNull; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import lombok.experimental.NonFinal; import java.awt.BorderLayout; import javax.swing.JPanel; import javax.swing.JMenuBar; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.KeyStroke; import javax.swing.UIManager; import org.leumasjaffe.charsheet.model.DDCharacter; import org.leumasjaffe.charsheet.view.dev.DeveloperMenu; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.io.File; import java.util.ArrayList; import java.util.List; import java.awt.event.InputEvent; @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true) public class D20Sheet extends JFrame { /** * */ private static final long serialVersionUID = 1L; ObjectMapper mapper = new ObjectMapper(); @NonFinal File currentlyOpenFile = null; @NonFinal @NonNull DDCharacter model = new DDCharacter(); JTabbedPane tabbedPane; SummaryTab summaryTab; List classTabs = new ArrayList<>(); JPanel abilitiesTab; SkillTab skillTab; EquipmentTab equipmentTab; private DeveloperMenu developerMenu; public D20Sheet() { UIManager.put("CheckBox.disabledText", UIManager.get("CheckBox.foreground")); // Set up local state variables final JFileChooser fc = new JFileChooser("resources"); mapper.registerModule(new Jdk8Module()); // Set up GUI Data (WindowBuilder) tabbedPane = new JTabbedPane(JTabbedPane.TOP); getContentPane().add(tabbedPane, BorderLayout.CENTER); summaryTab = new SummaryTab(); abilitiesTab = new JPanel(); skillTab = new SkillTab(); equipmentTab = new EquipmentTab(); JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); JMenu mnFile = new JMenu("File"); menuBar.add(mnFile); JMenuItem mntmNew = new JMenuItem("New"); mntmNew.addActionListener(e -> { setModel(new DDCharacter()); }); mntmNew.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK)); mnFile.add(mntmNew); JMenuItem mntmOpen = new JMenuItem("Open"); mntmOpen.addActionListener(e -> { int rv = fc.showOpenDialog(this); if ( rv == JFileChooser.APPROVE_OPTION ) { loadModelResource( fc.getSelectedFile() ); tabbedPane.setSelectedIndex(0); } }); mntmOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK)); mnFile.add(mntmOpen); JMenuItem mntmSave = new JMenuItem("Save"); mntmSave.addActionListener( e -> { if ( currentlyOpenFile == null ) { saveAs(fc); } else { saveModelResource(); } } ); mntmSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK)); mnFile.add(mntmSave); JMenuItem mntmSaveAs = new JMenuItem("Save As"); mntmSaveAs.addActionListener( e -> saveAs(fc) ); mntmSaveAs.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK)); mnFile.add(mntmSaveAs); JMenuItem mntmExit = new JMenuItem("Exit"); mntmExit.addActionListener( e -> { this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); } ); mntmExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_MASK)); mnFile.add(mntmExit); developerMenu = new DeveloperMenu(); menuBar.add(developerMenu); // Set up post-GUI dependencies setModel(model); } public D20Sheet(final String initialFile) { this(); loadModelResource(new File(initialFile)); } private void reorderTabs() { this.tabbedPane.removeAll(); tabbedPane.addTab("Summary", null, summaryTab, null); classTabs.forEach( t -> tabbedPane.addTab(t.getName(), null, t, null) ); tabbedPane.addTab("Abilities", null, abilitiesTab, "Racial and Class Abilities, Feats, etc."); tabbedPane.addTab("Skills", null, skillTab, null); tabbedPane.addTab("Gear & Items", null, equipmentTab, null); } private void saveAs(final JFileChooser fc) { int rv = fc.showSaveDialog(this); if ( rv == JFileChooser.APPROVE_OPTION ) { currentlyOpenFile = fc.getSelectedFile(); saveModelResource(); } } @SneakyThrows private void loadModelResource(File selectedFile) { currentlyOpenFile = selectedFile; setModel(mapper.readValue(selectedFile, DDCharacter.class)); } @SneakyThrows private void saveModelResource() { if ( currentlyOpenFile != null ) { mapper.writeValue(currentlyOpenFile, model); } } private void setModel(DDCharacter model) { classTabs.clear(); this.model = model; summaryTab.setModel(model); model.getClasses().stream().forEach(cc -> classTabs.add(new ClassTab(model, cc))); equipmentTab.setModel(model); skillTab.setModel(model); developerMenu.setModel(model); reorderTabs(); } }