D20Sheet.java 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. package org.leumasjaffe.charsheet.view;
  2. import javax.swing.JFileChooser;
  3. import javax.swing.JFrame;
  4. import javax.swing.JTabbedPane;
  5. import com.fasterxml.jackson.databind.ObjectMapper;
  6. import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
  7. import lombok.AccessLevel;
  8. import lombok.NonNull;
  9. import lombok.SneakyThrows;
  10. import lombok.experimental.FieldDefaults;
  11. import lombok.experimental.NonFinal;
  12. import java.awt.BorderLayout;
  13. import javax.swing.JPanel;
  14. import javax.swing.JMenuBar;
  15. import javax.swing.JMenu;
  16. import javax.swing.JMenuItem;
  17. import javax.swing.JOptionPane;
  18. import javax.swing.KeyStroke;
  19. import javax.swing.UIManager;
  20. import org.leumasjaffe.charsheet.model.DDCharacter;
  21. import org.leumasjaffe.charsheet.model.DDCharacterClass;
  22. import org.leumasjaffe.charsheet.model.observable.IntValue;
  23. import org.leumasjaffe.charsheet.observer.ObserverHelper;
  24. import org.leumasjaffe.observer.ObserverDispatch;
  25. import java.awt.event.KeyEvent;
  26. import java.awt.event.WindowEvent;
  27. import java.io.File;
  28. import java.util.ArrayList;
  29. import java.util.List;
  30. import java.awt.event.InputEvent;
  31. @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
  32. public class D20Sheet extends JFrame {
  33. /**
  34. *
  35. */
  36. private static final long serialVersionUID = 1L;
  37. ObjectMapper mapper = new ObjectMapper();
  38. @NonFinal File currentlyOpenFile = null;
  39. @NonFinal @NonNull DDCharacter model = new DDCharacter();
  40. JTabbedPane tabbedPane;
  41. SummaryTab summaryTab;
  42. List<ClassTab> classTabs = new ArrayList<>();
  43. JPanel abilitiesTab;
  44. SkillTab skillTab;
  45. EquipmentTab equipmentTab;
  46. private DeveloperMenu developerMenu;
  47. public D20Sheet() {
  48. UIManager.put("CheckBox.disabledText", UIManager.get("CheckBox.foreground"));
  49. // Set up local state variables
  50. final JFileChooser fc = new JFileChooser("resources");
  51. mapper.registerModule(new Jdk8Module());
  52. // Set up GUI Data (WindowBuilder)
  53. tabbedPane = new JTabbedPane(JTabbedPane.TOP);
  54. getContentPane().add(tabbedPane, BorderLayout.CENTER);
  55. summaryTab = new SummaryTab();
  56. abilitiesTab = new JPanel();
  57. skillTab = new SkillTab();
  58. equipmentTab = new EquipmentTab();
  59. JMenuBar menuBar = new JMenuBar();
  60. setJMenuBar(menuBar);
  61. JMenu mnFile = new JMenu("File");
  62. menuBar.add(mnFile);
  63. JMenuItem mntmNew = new JMenuItem("New");
  64. mntmNew.addActionListener(e -> { setModel(new DDCharacter()); });
  65. mntmNew.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
  66. mnFile.add(mntmNew);
  67. JMenuItem mntmOpen = new JMenuItem("Open");
  68. mntmOpen.addActionListener(e -> {
  69. int rv = fc.showOpenDialog(this);
  70. if ( rv == JFileChooser.APPROVE_OPTION ) {
  71. loadModelResource( fc.getSelectedFile() );
  72. tabbedPane.setSelectedIndex(0);
  73. }
  74. });
  75. mntmOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK));
  76. mnFile.add(mntmOpen);
  77. JMenuItem mntmSave = new JMenuItem("Save");
  78. mntmSave.addActionListener( e -> {
  79. if ( currentlyOpenFile == null ) { saveAs(fc); }
  80. else { saveModelResource(); }
  81. } );
  82. mntmSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
  83. mnFile.add(mntmSave);
  84. JMenuItem mntmSaveAs = new JMenuItem("Save As");
  85. mntmSaveAs.addActionListener( e -> saveAs(fc) );
  86. mntmSaveAs.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK));
  87. mnFile.add(mntmSaveAs);
  88. JMenuItem mntmConfig = new JMenuItem("Config");
  89. mntmConfig.addActionListener( e -> DialogBuilder.showConfigDialog(this) );
  90. mntmConfig.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.ALT_DOWN_MASK));
  91. mnFile.add(mntmConfig);
  92. JMenuItem mntmExit = new JMenuItem("Exit");
  93. mntmExit.addActionListener( e -> { this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); } );
  94. mntmExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_MASK));
  95. mnFile.add(mntmExit);
  96. JMenu mnSession = new JMenu("Session");
  97. menuBar.add(mnSession);
  98. JMenuItem mntmGainExperience = new JMenuItem("Gain Experience");
  99. mntmGainExperience.addActionListener(e -> {
  100. // TODO move to own thing?
  101. final String input = JOptionPane.showInputDialog("How much experience");
  102. if (input == null || input.isEmpty()) return;
  103. final int exp = Integer.parseInt(input);
  104. if (exp <= 0) return;
  105. final IntValue mdlExp = this.model.getExperience();
  106. mdlExp.value(mdlExp.value()+exp);
  107. ObserverDispatch.notifySubscribers(mdlExp, this);
  108. DialogBuilder.showLevelUpDialog(this, this.model, 0);
  109. });
  110. mnSession.add(mntmGainExperience);
  111. JMenuItem mntmTakeRest = new JMenuItem("Take Rest");
  112. mntmTakeRest.addActionListener(e -> {
  113. // Step 0: Gather information about the rest
  114. // Step 0.1: Check if 8-hour or full day
  115. // Step 0.2: Check if Long-Term-Care
  116. // Step 1: Heal Character according to info
  117. // Step 1.1: Heal non-lethal damage
  118. // Step 1.2: Heal ability damage
  119. // Step 2: Regenerate spells prepared
  120. // Step 2.1: If Spontaneous, skip (2)
  121. for (DDCharacterClass dclass : model.getClasses()) {
  122. dclass.getSpellBook().ifPresent(sb -> {
  123. if (sb.preparesSpells()) {
  124. DialogBuilder.createPrepareSpellsDialog(this, model, dclass);
  125. } else {
  126. for (int i = 0; i < dclass.getHighestSpellLevel(); ++i) {
  127. sb.prepareSpells(i, null);
  128. }
  129. }
  130. });
  131. }
  132. // Step N: regenerate spellbooks
  133. for (DDCharacterClass dclass : model.getClasses()) {
  134. ObserverHelper.notifyObservableHierarchy(dclass, this);
  135. }
  136. });
  137. mnSession.add(mntmTakeRest);
  138. developerMenu = new DeveloperMenu(this);
  139. menuBar.add(developerMenu);
  140. // Set up post-GUI dependencies
  141. setModel(model);
  142. }
  143. public D20Sheet(final String initialFile) {
  144. this();
  145. loadModelResource(new File(initialFile));
  146. }
  147. private void reorderTabs() {
  148. this.tabbedPane.removeAll();
  149. tabbedPane.addTab("Summary", null, summaryTab, null);
  150. classTabs.forEach( t -> tabbedPane.addTab(t.getName(), null, t, null) );
  151. tabbedPane.addTab("Abilities", null, abilitiesTab, "Racial and Class Abilities, Feats, etc.");
  152. tabbedPane.addTab("Skills", null, skillTab, null);
  153. tabbedPane.addTab("Gear & Items", null, equipmentTab, null);
  154. }
  155. private void saveAs(final JFileChooser fc) {
  156. int rv = fc.showSaveDialog(this);
  157. if ( rv == JFileChooser.APPROVE_OPTION ) {
  158. currentlyOpenFile = fc.getSelectedFile();
  159. saveModelResource();
  160. }
  161. }
  162. @SneakyThrows
  163. private void loadModelResource(File selectedFile) {
  164. currentlyOpenFile = selectedFile;
  165. setModel(mapper.readValue(selectedFile, DDCharacter.class));
  166. }
  167. @SneakyThrows
  168. private void saveModelResource() {
  169. if ( currentlyOpenFile != null ) {
  170. mapper.writeValue(currentlyOpenFile, model);
  171. }
  172. }
  173. private void setModel(DDCharacter model) {
  174. classTabs.clear();
  175. this.model = model;
  176. summaryTab.setModel(model);
  177. model.getClasses().stream().forEach(cc -> classTabs.add(new ClassTab(model, cc)));
  178. equipmentTab.setModel(model);
  179. skillTab.setModel(model);
  180. developerMenu.setModel(model);
  181. reorderTabs();
  182. }
  183. }