Prechádzať zdrojové kódy

Merge branch 'boolgate' into level_up

* boolgate:
  Creating a handle wrapper, so that BoolGate objects don't need to extend beyond their creation scope.
  Converting to using BoolGate
Sam Jaffe 8 rokov pred
rodič
commit
d105d76604

+ 58 - 0
src/main/lombok/org/leumasjaffe/charsheet/model/observable/BoolGate.java

@@ -0,0 +1,58 @@
+package org.leumasjaffe.charsheet.model.observable;
+
+import java.util.Arrays;
+
+import org.leumasjaffe.observer.Observable;
+import org.leumasjaffe.observer.ObserverDispatch;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.experimental.FieldDefaults;
+
+@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
+public class BoolGate extends Observable {
+	boolean[] data;
+	int size;
+	
+	@AllArgsConstructor
+	@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
+	public class Handle {
+		int index;
+		public boolean get() { return BoolGate.this.get(index); }
+		public void set(Object source, boolean bool) {
+			if (bool != get()) {
+				BoolGate.this.set(index, bool);
+				ObserverDispatch.notifySubscribers(BoolGate.this, source);
+			}
+		}
+	}
+	
+	public BoolGate(int dim) {
+		size = dim;
+		data = new boolean[dim];
+		Arrays.fill(data, false);
+	}
+	
+	public boolean all() {
+		for (int i = 0; i < size; ++i) {
+			if (!data[i]) return false;
+		}
+		return true;
+	}
+	
+	public Handle handle(int idx) {
+		return this.new Handle(idx);
+	}
+	
+	public boolean get(int idx) {
+		return data[idx];
+	}
+	
+	public void set(int idx, boolean bool) {
+		data[idx] = bool;
+	}
+	
+	public boolean some(int...idxs) {
+		return Arrays.stream(idxs).mapToObj(this::get).allMatch(Boolean::booleanValue);
+	}
+}

+ 17 - 11
src/main/lombok/org/leumasjaffe/charsheet/view/level/LevelUpSpellPanel.java

@@ -4,10 +4,11 @@ import javax.swing.JPanel;
 
 import org.jdesktop.swingx.VerticalLayout;
 import org.leumasjaffe.charsheet.model.magic.DDSpell;
+import org.leumasjaffe.charsheet.model.observable.BoolGate;
 import org.leumasjaffe.charsheet.model.observable.IntValue;
-import org.leumasjaffe.charsheet.view.level.UpdateClassWithLevelPanel.BoolArray;
 import org.leumasjaffe.charsheet.view.magic.SelectSpellsPanel;
 import org.leumasjaffe.charsheet.view.magic.SelectSpellsPanel.Info;
+import org.leumasjaffe.observer.ObservableListener;
 import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
@@ -66,9 +67,10 @@ class LevelUpSpellPanel extends JPanel {
 	SpellPicker pick;
 	SelectSpellsPanel.Info info;
 	@Getter List<SelectSpellsPanel> panels;
+	ObservableListener<LevelUpSpellPanel, BoolGate> allReady;
 
 	public LevelUpSpellPanel(SpellPicker pick, SelectSpellsPanel.Info info, 
-			BoolArray readyCount, int index) {
+			BoolGate.Handle readyCount) {
 		this.pick = pick;
 		this.info = info;
 		this.toLevel = info.dclass.getLevel().value();
@@ -97,21 +99,21 @@ class LevelUpSpellPanel extends JPanel {
 		final IntValue val = getSharedAllowedSlots(info);
 		final Map<Integer, Integer> spells = getNewSpells(val);
 		final int sharedSlots = val.value();
+		BoolGate gate = new BoolGate(newHighestSpellLevel);
 		for (int i = 0; i < newHighestSpellLevel; ++i) {
-			if (spells.get(i) < 0) { panels.add(null); continue; }
+			if (spells.get(i) < 0) { gate.set(i, true); panels.add(null); continue; }
 			++spellLevelsGrown;
-			SelectSpellsPanel lvl = new SelectSpellsPanel(info, i,
-					new LinkedHashSet<>(), Math.max(spells.get(i), sharedSlots), pick.getAvailableSpells(info, i),
+			SelectSpellsPanel lvl = new SelectSpellsPanel(info, gate.handle(i), i,
+					new LinkedHashSet<>(), Math.max(spells.get(i), sharedSlots), 
+					pick.getAvailableSpells(info, i),
 					pick != SpellPickType.LEARN, val);
 			panels.add(lvl);
-			lvl.addPropertyChangeListener(SelectSpellsPanel.READY, e -> {
-				if ((Boolean) e.getNewValue()) ++ready[0];
-				else --ready[0];
-				readyCount.data[index] = (ready[0] == spellLevelsGrown);
-				ObserverDispatch.notifySubscribers(readyCount, this);
-			});
 			panel.add(lvl);
 		}
+		allReady = new ObservableListener<>(this, (c, v) -> {
+			readyCount.set(this, v.all());
+		});
+		allReady.setObserved(gate);
 	}
 	
 	private Map<Integer, Integer> getNewSpells(IntValue sharedSpellCountLimit) {
@@ -142,4 +144,8 @@ class LevelUpSpellPanel extends JPanel {
 		else return current.get(level) - previous.get(level);
 	}
 
+	@Override
+	public void removeNotify() {
+		ObserverDispatch.unsubscribeAll(allReady);
+	}
 }

+ 14 - 18
src/main/lombok/org/leumasjaffe/charsheet/view/level/UpdateClassWithLevelPanel.java

@@ -6,17 +6,16 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.function.Consumer;
-import java.util.stream.IntStream;
 
 import javax.swing.JPanel;
 
 import org.jdesktop.swingx.VerticalLayout;
 import org.leumasjaffe.charsheet.model.magic.DDSpell;
+import org.leumasjaffe.charsheet.model.observable.BoolGate;
 import org.leumasjaffe.charsheet.view.magic.SelectSpellsPanel;
 import org.leumasjaffe.charsheet.view.magic.SelectSpellsPanel.Info;
 import org.leumasjaffe.charsheet.view.skills.SkillLevelUpPanel;
 import org.leumasjaffe.function.VoidVoidFunction;
-import org.leumasjaffe.observer.Observable;
 import org.leumasjaffe.observer.ObservableListener;
 import org.leumasjaffe.observer.ObserverDispatch;
 
@@ -37,17 +36,15 @@ import javax.swing.JLabel;
 @SuppressWarnings("serial")
 @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
 class UpdateClassWithLevelPanel extends JPanel {
+	static int CHOOSE_SKILL_INDEX = 0;
 	static int LEARN_SPELL_INDEX = 1;
+	static int PREPARE_SPELL_INDEX = 2;
 
-	@FieldDefaults(level=AccessLevel.PUBLIC, makeFinal=true)
-	public class BoolArray extends Observable {
-		boolean data[] = new boolean[] {false, false, false};
-	}
-	BoolArray readyCount = new BoolArray();
-	ObservableListener<Consumer<Boolean>, BoolArray> listener;
+	BoolGate readyCount = new BoolGate(3);
+	ObservableListener<Consumer<Boolean>, BoolGate> listener;
 	JTabbedPane tabbedPane;
 	@NonFinal LevelUpSpellPanel learnSpells = null;
-	@NonFinal ObservableListener<UpdateClassWithLevelPanel, BoolArray> learnAndPrepareListener = null;
+	@NonFinal ObservableListener<UpdateClassWithLevelPanel, BoolGate> learnAndPrepareListener = null;
 	
 	public UpdateClassWithLevelPanel(LevelUpClassInfo info, VoidVoidFunction back,
 			Consumer<Boolean> setReady) {
@@ -75,23 +72,23 @@ class UpdateClassWithLevelPanel extends JPanel {
 
 		JPanel skills = new SkillLevelUpPanel(info.ddCharacter, info.ddClass) {
 			@Override public void setIsReady(boolean b) {
-				readyCount.data[0] = b;
+				readyCount.set(CHOOSE_SKILL_INDEX, b);
 				ObserverDispatch.notifySubscribers(readyCount, null);
 			}
 		};
 		tabbedPane.addTab("Skills", null, skills, null);
 
 		info.ddClass.getSpellBook().ifPresent(sb -> {
-			readyCount.data[1] = !sb.learnsSpells();
-			readyCount.data[2] = !sb.preparesSpells();
+			readyCount.set(1, !sb.learnsSpells());
+			readyCount.set(2, !sb.preparesSpells());
 			if (sb.learnsSpells()) {
 				LevelUpSpellPanel spells = new LevelUpSpellPanel(LEARN,
 						new SelectSpellsPanel.Info(info.ddCharacter, info.ddClass),
-						readyCount, LEARN_SPELL_INDEX);
+						readyCount.handle(LEARN_SPELL_INDEX));
 				tabbedPane.addTab("Learn Spells", null, spells, null);
 				if (sb.preparesSpells()) {
 					learnAndPrepareListener = new ObservableListener<>(this, (c, v) -> {
-						if (v.data[LEARN_SPELL_INDEX]) {
+						if (v.get(LEARN_SPELL_INDEX)) {
 							c.createPrepareLearnedSpellPanel(info, spells);
 						} else {
 							c.tabbedPane.remove(learnSpells);
@@ -104,7 +101,7 @@ class UpdateClassWithLevelPanel extends JPanel {
 			else if (sb.preparesSpells()) {
 				LevelUpSpellPanel spells = new LevelUpSpellPanel(PREPARE,
 						new SelectSpellsPanel.Info(info.ddCharacter, info.ddClass),
-						readyCount, 2);
+						readyCount.handle(PREPARE_SPELL_INDEX));
 				tabbedPane.addTab("Prepare Spells", null, spells, null);
 			}
 		});
@@ -137,8 +134,7 @@ class UpdateClassWithLevelPanel extends JPanel {
 		panel.add(horizontalGlue, gbc_horizontalGlue);
 
 		listener = new ObservableListener<>(setReady, (c, v) -> {
-			c.accept(IntStream.range(0, v.data.length)
-					.mapToObj(i -> v.data[i]).allMatch(b -> b));
+			c.accept(v.all());
 		});
 		listener.setObserved(readyCount);
 	}
@@ -162,7 +158,7 @@ class UpdateClassWithLevelPanel extends JPanel {
 
 		learnSpells = new LevelUpSpellPanel(pick,
 				new SelectSpellsPanel.Info(info.ddCharacter, info.ddClass),
-				readyCount, 2);
+				readyCount.handle(PREPARE_SPELL_INDEX));
 		tabbedPane.addTab("Prepare Spells", null, learnSpells, null);
 	}
 	

+ 16 - 13
src/main/lombok/org/leumasjaffe/charsheet/view/magic/PrepareSpellsDialog.java

@@ -6,6 +6,9 @@ import org.jdesktop.swingx.VerticalLayout;
 import org.leumasjaffe.charsheet.model.DDCharacter;
 import org.leumasjaffe.charsheet.model.DDCharacterClass;
 import org.leumasjaffe.charsheet.model.magic.impl.Prepared;
+import org.leumasjaffe.charsheet.model.observable.BoolGate;
+import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
 import lombok.experimental.FieldDefaults;
@@ -22,16 +25,12 @@ import javax.swing.JButton;
 import javax.swing.JDialog;
 import javax.swing.ScrollPaneConstants;
 
+@SuppressWarnings("serial")
 @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
-public class PrepareSpellsDialog extends JPanel {
-
-	/**
-	 * 
-	 */
-	private static final long serialVersionUID = 1L;
-	
+public class PrepareSpellsDialog extends JPanel {	
 	int[] ready = {0};
 	int highestSpellLevel;
+	ObservableListener<PrepareSpellsDialog, BoolGate> allReady;
 
 	public PrepareSpellsDialog(DDCharacter chara, DDCharacterClass dclass) {
 		highestSpellLevel = dclass.getHighestSpellLevel();
@@ -77,14 +76,14 @@ public class PrepareSpellsDialog extends JPanel {
 		scrollPane.setViewportView(panel);
 		
 		List<SelectPreparedSpellsPanel> panels = new ArrayList<>();
+		final BoolGate gate = new BoolGate(highestSpellLevel);
+		allReady = new ObservableListener<>(this, (c, v) -> {
+			btnPrepareTheseSpells.setEnabled(v.all());
+		});
+		allReady.setObserved(gate);
 		for (int i = 0; i < highestSpellLevel; ++i) {
-			SelectPreparedSpellsPanel lvl = new SelectPreparedSpellsPanel(chara, i, dclass);
+			SelectPreparedSpellsPanel lvl = new SelectPreparedSpellsPanel(chara, dclass, gate.handle(i), i);
 			panels.add(lvl);
-			lvl.addPropertyChangeListener(SelectPreparedSpellsPanel.READY, e -> {
-				if ((Boolean) e.getNewValue()) ++ready[0];
-				else --ready[0];
-				btnPrepareTheseSpells.setEnabled(ready[0] == highestSpellLevel);
-			});
 			panel.add(lvl);
 		}
 		
@@ -97,4 +96,8 @@ public class PrepareSpellsDialog extends JPanel {
 		});
 	}
 
+	@Override
+	public void removeNotify() {
+		ObserverDispatch.unsubscribeAll(allReady);
+	}
 }

+ 8 - 5
src/main/lombok/org/leumasjaffe/charsheet/view/magic/SelectPreparedSpellsPanel.java

@@ -3,6 +3,7 @@ package org.leumasjaffe.charsheet.view.magic;
 import org.leumasjaffe.charsheet.model.DDCharacter;
 import org.leumasjaffe.charsheet.model.DDCharacterClass;
 import org.leumasjaffe.charsheet.model.magic.impl.Prepared;
+import org.leumasjaffe.charsheet.model.observable.BoolGate;
 
 import lombok.AccessLevel;
 import lombok.experimental.FieldDefaults;
@@ -11,13 +12,15 @@ import lombok.experimental.FieldDefaults;
 @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
 class SelectPreparedSpellsPanel extends SelectSpellsPanel {
 	
-	private SelectPreparedSpellsPanel(DDCharacter chara, int level, DDCharacterClass dclass, Prepared prep) {
-		super(chara, level, dclass, prep.getSpellsPreparedPreviouslyForLevel(level),
-				prep.getSpellsPreparedPreviouslyForLevel(level));
+	private SelectPreparedSpellsPanel(DDCharacter chara, DDCharacterClass dclass, 
+			BoolGate.Handle gate, int level, Prepared prep) {
+		super(new SelectSpellsPanel.Info(chara, dclass), gate, level,
+				prep.getSpellsPreparedPreviouslyForLevel(level),
+				prep.spellsKnownAtLevel(level));
 	}
 
-	public SelectPreparedSpellsPanel(DDCharacter chara, int level, DDCharacterClass dclass) {
-		this(chara, level, dclass, ((Prepared) dclass.getSpellBook().get()));
+	public SelectPreparedSpellsPanel(DDCharacter chara, DDCharacterClass dclass, BoolGate.Handle gate, int level) {
+		this(chara, dclass, gate, level, ((Prepared) dclass.getSpellBook().get()));
 	}
 
 }

+ 12 - 16
src/main/lombok/org/leumasjaffe/charsheet/view/magic/SelectSpellsPanel.java

@@ -14,6 +14,7 @@ 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.model.observable.BoolGate;
 import org.leumasjaffe.charsheet.model.observable.IntValue;
 import org.leumasjaffe.charsheet.util.AbilityHelper;
 import org.leumasjaffe.event.SelectTableRowPopupMenuListener;
@@ -89,17 +90,11 @@ public class SelectSpellsPanel extends JPanel {
 	IntValue sharedValue;
 	SelectSpellModel modelPrepared, modelKnown;
 	
-	public SelectSpellsPanel(Info info, int level, Collection<DDSpell> prepared, int toPrepare,
-			Collection<DDSpell> avail, boolean allowsDuplicates, IntValue val) {
-		this(info.chara, level, info.dclass, prepared, toPrepare, avail, allowsDuplicates, val);
-	}
-
-	public SelectSpellsPanel(DDCharacter chara, int level, 
-			DDCharacterClass dclass, Collection<DDSpell> prepared, int toPrepare,
+	public SelectSpellsPanel(Info info, BoolGate.Handle gate, int level, Collection<DDSpell> prepared, int toPrepare,
 			Collection<DDSpell> avail, boolean allowsDuplicates, IntValue sharedValue) {
 		this.allowsDuplicates = allowsDuplicates;
 		this.sharedValue = sharedValue;
-		final DDSpellbook spellBook = dclass.getSpellBook().get();
+		final DDSpellbook spellBook = info.dclass.getSpellBook().get();
 		this.prepared = new ArrayList<>(prepared);
 		final List<DDSpell> known = new ArrayList<>(avail);
 		this.modelPrepared = new SelectSpellModel(createPrepareModel(prepared, toPrepare));
@@ -114,7 +109,7 @@ public class SelectSpellsPanel extends JPanel {
 		gridBagLayout.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
 		setLayout(gridBagLayout);
 		
-		JPanel panel = new ChooseSpellsPerDayHeader(level, spellBook, AbilityHelper.get(chara, dclass));
+		JPanel panel = new ChooseSpellsPerDayHeader(level, spellBook, AbilityHelper.get(info.chara, info.dclass));
 		GridBagConstraints gbc_panel = new GridBagConstraints();
 		gbc_panel.gridwidth = 3;
 		gbc_panel.insets = new Insets(0, 0, 5, 5);
@@ -172,8 +167,8 @@ public class SelectSpellsPanel extends JPanel {
 		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));
+			JFrame frame = new JFrame(spell.getName() +  " (" + info.dclass.getName() + " " + level + ")");
+			frame.add(new SpellInfoPanel(info.chara, info.dclass, spell));
 			frame.pack();
 			frame.setVisible(true);
 		});
@@ -223,7 +218,8 @@ public class SelectSpellsPanel extends JPanel {
 			} 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 ({})", 
+				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);
 			}
@@ -231,19 +227,19 @@ public class SelectSpellsPanel extends JPanel {
 			tablePrepared.getSelectionModel().clearSelection();
 			tablePrepared.repaint();
 			
-			if (!(Boolean) getClientProperty(READY) && !Arrays.asList(modelPrepared.data).contains(NONE)) {
+			if (!gate.get() && !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);
+				gate.set(this, true);
 			}
 		});
 	}
 
-	public SelectSpellsPanel(DDCharacter chara, int level, DDCharacterClass dclass,
+	public SelectSpellsPanel(Info info, BoolGate.Handle gate, int level,
 			Collection<DDSpell> prepared, Collection<DDSpell> avail) {
-		this(chara, level, dclass, prepared, 0, avail, true, new IntValue(-1));
+		this(info, gate, level, prepared, 0, avail, true, new IntValue(-1));
 	}
 
 	private boolean wouldHaveIllegalDuplicate(int row) {