ソースを参照

Refactor to unsubscribe ObservableListeners when the holding Panel is dropped.

Sam Jaffe 8 年 前
コミット
fca56885b7

+ 8 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/ClassTab.java

@@ -13,6 +13,7 @@ import org.leumasjaffe.charsheet.model.observable.IntValue;
 import org.leumasjaffe.charsheet.view.magic.SpellPanel;
 import org.leumasjaffe.format.StringHelper;
 import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import java.awt.GridBagConstraints;
 import java.awt.Insets;
@@ -185,4 +186,11 @@ public class ClassTab extends JPanel {
 	public String getName() {
 		return title;
 	}
+	
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(levelListener);
+		ObserverDispatch.unsubscribeAll(expListener);
+	}
 }

+ 7 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/inventory/EquipmentPanel.java

@@ -13,6 +13,7 @@ import org.leumasjaffe.charsheet.model.inventory.DDItem;
 import org.leumasjaffe.charsheet.model.inventory.EquipmentSlot;
 import org.leumasjaffe.event.PopClickListener;
 import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
 import lombok.experimental.FieldDefaults;
@@ -140,4 +141,10 @@ public class EquipmentPanel extends JPanel {
 		panel.addMouseListener(new PopClickListener(
 				new EquipmentInfoMenu(equip, item, slot)));
 	}
+	
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(equipmentObserver);
+	}
 }

+ 7 - 23
src/main/lombok/org/leumasjaffe/charsheet/view/inventory/InventoryPanel.java

@@ -10,11 +10,8 @@ import javax.swing.border.MatteBorder;
 import org.jdesktop.swingx.VerticalLayout;
 import org.leumasjaffe.charsheet.model.DDCharacter;
 import org.leumasjaffe.charsheet.model.inventory.DDInventory;
-import org.leumasjaffe.charsheet.model.inventory.DDItem;
-import org.leumasjaffe.charsheet.model.observable.IntValue;
-import org.leumasjaffe.event.PopClickListener;
-import org.leumasjaffe.observer.IndirectObservableListener;
 import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
 import lombok.experimental.FieldDefaults;
@@ -23,7 +20,6 @@ import java.awt.Color;
 import java.awt.Font;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
-import java.util.stream.Stream;
 
 @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
 public class InventoryPanel extends JPanel {
@@ -70,28 +66,16 @@ public class InventoryPanel extends JPanel {
 
 	private void updateModel(DDInventory inv) {
 		inventory.removeAll();
-		inv.getItems().stream().forEach(item -> createWithRightClickMenu(inv, item));
+		inv.getItems().stream().forEach(item -> inventory.add(new ItemPanel(inv, item)));
 	}
 
 	public void setModel(DDCharacter model) {
 		inventoryObserver.setObserved(model.getInventory());
 	}
-
-	private void createWithRightClickMenu(final DDInventory inv, final DDItem item) {
-		final ItemPanel panel = new ItemPanel(item);
-		panel.addMouseListener(new PopClickListener(new ItemInfoMenu(inv, item)));
-		// FIXME: this is horrible, deal with the else clause better
-		IndirectObservableListener<ItemPanel, IntValue> listen = new IndirectObservableListener<>(panel, (c, v) -> {
-			if (v.value() == 0) {
-				inventory.remove(c);
-				inventory.repaint();
-			} else {
-				Stream.of(panel.getMouseListeners()).forEach(m -> c.removeMouseListener(m));
-				c.addMouseListener(new PopClickListener(new ItemInfoMenu(inv, item)));
-			}
-		});
-		listen.setObserved(item.getCount(), item.getCount(), item.getCountEquipped());
-		inventory.add(panel);
-	}
 	
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(inventoryObserver);
+	}
 }

+ 27 - 5
src/main/lombok/org/leumasjaffe/charsheet/view/inventory/ItemInfoMenu.java

@@ -7,7 +7,10 @@ import org.leumasjaffe.charsheet.model.inventory.DDInventory;
 import org.leumasjaffe.charsheet.model.inventory.DDItem;
 import org.leumasjaffe.charsheet.model.inventory.EquipmentSlot;
 import org.leumasjaffe.charsheet.model.inventory.Money;
+import org.leumasjaffe.charsheet.model.observable.IntValue;
 import org.leumasjaffe.charsheet.view.dialog.BuySellItemDialog;
+import org.leumasjaffe.observer.IndirectObservableListener;
+import org.leumasjaffe.observer.ObservableListener;
 import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
@@ -23,9 +26,11 @@ class ItemInfoMenu extends JPopupMenu {
 	 * 
 	 */
 	private static final long serialVersionUID = 1L;
+	
+	IndirectObservableListener<JMenuItem, IntValue> sellListener, equipListener = null;
+	ObservableListener<JMenuItem, DDInventory> buyListener;
 
 	public ItemInfoMenu(final DDInventory inv, final DDItem item) {
-		final int rawWealth = inv.getWealth().asCopper();
 		final int rawValue = item.getValue().asCopper();
 		final BuySellAction doTxn = new BuySellAction(inv, item);
 		final BuySellDialogHelper dlg = new BuySellDialogHelper(item.getName());
@@ -41,25 +46,42 @@ class ItemInfoMenu extends JPopupMenu {
 
 		JMenuItem mntmBuy = new JMenuItem("Purchase");
 		mntmBuy.addActionListener(e -> {
-			doTxn.applyTransaction(dlg.getNumUnits("Purchase", rawValue, rawWealth / rawValue), rawValue);
+			doTxn.applyTransaction(dlg.getNumUnits("Purchase", rawValue, inv.getWealth().asCopper() / rawValue), rawValue);
+		});
+		buyListener = new ObservableListener<>(mntmBuy, (c, v) -> {
+			c.setEnabled(inv.getWealth().asCopper() >= item.getValue().asCopper());
 		});
-		mntmBuy.setEnabled(rawWealth >= item.getValue().asCopper());
+		buyListener.setObserved(inv);
 		add(mntmBuy);
 
 		JMenuItem mntmSell = new JMenuItem("Sell");	
 		mntmSell.addActionListener(e -> {
 			doTxn.applyTransaction(-dlg.getNumUnits("Sell", rawValue / 2, item.getCount().value()), rawValue / 2);
 		});
-		mntmSell.setEnabled(item.getUnequippedCount() > 0);
+		sellListener = new IndirectObservableListener<>(mntmSell, (c, v) -> {
+			c.setEnabled(item.getUnequippedCount() > 0);
+		});
+		sellListener.setObserved(item.getCount(), item.getCountEquipped());
 		add(mntmSell);
 
 		if (item.getSlot() != EquipmentSlot.NONE) {
 			JMenuItem mntmEquip = new JMenuItem("Equip");
-			mntmEquip.setEnabled(item.getUnequippedCount() > 0);
 			mntmEquip.addActionListener(e -> EquipItemController.accept(inv.getEquipment(), item));
+			equipListener = new IndirectObservableListener<>(mntmEquip, (c, v) -> {
+				c.setEnabled(item.getUnequippedCount() > 0);
+			});
+			equipListener.setObserved(item.getCount(), item.getCountEquipped());
 			add(mntmEquip);
 		}
 	}
+	
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(buyListener);
+		ObserverDispatch.unsubscribeAll(sellListener);
+		ObserverDispatch.unsubscribeAll(equipListener);
+	}
 
 	@AllArgsConstructor
 	@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)

+ 21 - 5
src/main/lombok/org/leumasjaffe/charsheet/view/inventory/ItemPanel.java

@@ -12,12 +12,17 @@ import java.awt.Font;
 import java.awt.Color;
 import javax.swing.SwingConstants;
 
+import org.leumasjaffe.charsheet.model.inventory.DDInventory;
 import org.leumasjaffe.charsheet.model.inventory.DDItem;
 import org.leumasjaffe.charsheet.model.observable.IntValue;
+import org.leumasjaffe.event.PopClickListener;
 import org.leumasjaffe.format.StringHelper;
-import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.IndirectObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import java.awt.Component;
+import java.awt.Container;
+
 import javax.swing.Box;
 
 public class ItemPanel extends JPanel {
@@ -26,9 +31,9 @@ public class ItemPanel extends JPanel {
 	 */
 	private static final long serialVersionUID = 1L;
 	
-	ObservableListener<JTextField, IntValue> countListener;
+	IndirectObservableListener<JTextField, IntValue> countListener;
 
-	public ItemPanel(DDItem item) {
+	public ItemPanel(DDInventory inv, DDItem item) {
 		setPreferredSize(new Dimension(280, 40));
 		GridBagLayout gbl_panel = new GridBagLayout();
 		gbl_panel.columnWidths = new int[]{120, 0, 0, 0, 0};
@@ -139,10 +144,21 @@ public class ItemPanel extends JPanel {
 		add(valueField, gbc_valueField);
 		valueField.setColumns(10);
 		
-		countListener = new ObservableListener<JTextField, IntValue>(countField, (c, v) -> {
+		countListener = new IndirectObservableListener<>(countField, (c, v) -> {
 			c.setText(StringHelper.toString(v.value()));
+			if (v.value() == 0) {
+				Container comp = getParent();
+				comp.remove(this);
+				comp.repaint();
+			}
 		});
-		countListener.setObserved(item.getCount());
+		countListener.setObserved(item.getCount(), item.getCountEquipped());
+		addMouseListener(new PopClickListener(new ItemInfoMenu(inv, item)));
 	}
 
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(countListener);
+	}
 }

+ 7 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/magic/SpellLevelPanel.java

@@ -13,6 +13,7 @@ import org.leumasjaffe.charsheet.model.Ability;
 import org.leumasjaffe.charsheet.model.DDCharacterClass;
 import org.leumasjaffe.charsheet.model.magic.DDSpell;
 import org.leumasjaffe.observer.IndirectObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
 import lombok.experimental.FieldDefaults;
@@ -72,4 +73,10 @@ class SpellLevelPanel extends JPanel {
 	}
 	
 	public boolean isCastableFromHere() { return false; }
+
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(listener);
+	}
 }

+ 8 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/magic/SpellPanel.java

@@ -15,6 +15,7 @@ import org.leumasjaffe.charsheet.model.DDCharacterClass;
 import org.leumasjaffe.charsheet.util.AbilityHelper;
 import org.leumasjaffe.function.TriFunction;
 import org.leumasjaffe.observer.IndirectObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
 import lombok.RequiredArgsConstructor;
@@ -82,4 +83,11 @@ public class SpellPanel extends JPanel {
 			previousHighestSpellLevel = dclass.getHighestSpellLevel();
 		}
 	}
+	
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(listenerKnown);
+		ObserverDispatch.unsubscribeAll(listenerPerDay);
+	}
 }

+ 7 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/magic/SpellsPerDayHeader.java

@@ -11,6 +11,7 @@ import javax.swing.JTextField;
 import org.leumasjaffe.charsheet.model.Ability;
 import org.leumasjaffe.charsheet.model.magic.DDSpellbook;
 import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import java.awt.Dimension;
 
@@ -106,4 +107,10 @@ class SpellsPerDayHeader extends JPanel {
 		});
 		listener.setObserved(model);
 	}
+	
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(listener);
+	}
 }

+ 8 - 1
src/main/lombok/org/leumasjaffe/charsheet/view/skills/SkillLevelUpDialog.java

@@ -15,6 +15,7 @@ import org.leumasjaffe.charsheet.model.DDCharacterClass;
 import org.leumasjaffe.charsheet.model.observable.IntValue;
 import org.leumasjaffe.charsheet.model.skill.DDSkills;
 import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import java.awt.GridBagConstraints;
 import java.awt.Insets;
@@ -33,6 +34,7 @@ public class SkillLevelUpDialog extends JPanel {
 	 * 
 	 */
 	private static final long serialVersionUID = 1L;
+	private ObservableListener<JTextField, IntValue> purchaseListener;
 	
 	public SkillLevelUpDialog(final DDCharacter chara, final DDCharacterClass cclass) {
 		final IntValue pointsAvaliable = new IntValue(Math.max(1, cclass.getSkillPoints() + 
@@ -104,7 +106,7 @@ public class SkillLevelUpDialog extends JPanel {
 			lines.add(line);
 		});
 		
-		ObservableListener<JTextField, IntValue> purchaseListener = new ObservableListener<>(pointsRemaining, (c, v) -> {
+		purchaseListener = new ObservableListener<>(pointsRemaining, (c, v) -> {
 			btnSubmitSkillChange.setEnabled(v.value() == 0);
 			c.setText(Integer.toString(v.value()));
 		});
@@ -118,4 +120,9 @@ public class SkillLevelUpDialog extends JPanel {
 		});
 	}
 	
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(purchaseListener);
+	}
 }

+ 6 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/skills/SkillLevelUpLine.java

@@ -235,4 +235,10 @@ class SkillLevelUpLine extends JPanel {
 		skill.spendPoints(current.value(), !isClassSkill);
 		ObserverDispatch.notifySubscribers(skill.getRanks(), this);
 	}
+	
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(totalListener);
+	}
 }

+ 8 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/skills/SkillLine.java

@@ -10,6 +10,7 @@ import org.leumasjaffe.charsheet.util.AbilityHelper;
 import org.leumasjaffe.format.StringHelper;
 import org.leumasjaffe.observer.IndirectObservableListener;
 import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
 import lombok.experimental.FieldDefaults;
@@ -188,4 +189,11 @@ public class SkillLine extends JPanel {
 		skillListener.setObserved(skill.getRanks());
 	}
 	
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(totalListener);
+		ObserverDispatch.unsubscribeAll(modifierListener);
+		ObserverDispatch.unsubscribeAll(skillListener);
+	}
 }

+ 7 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/summary/AbilityBox.java

@@ -21,6 +21,7 @@ import org.leumasjaffe.format.StringHelper;
 import org.leumasjaffe.graphics.NumberTextField;
 import org.leumasjaffe.observer.ObservableController;
 import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
 import lombok.experimental.FieldDefaults;
@@ -96,4 +97,10 @@ public class AbilityBox extends JPanel {
 		modListener.setObserved(value);
 	}
 
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(valueListener);
+		ObserverDispatch.unsubscribeAll(modListener);
+	}
 }

+ 9 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/summary/ArmorLine.java

@@ -15,6 +15,7 @@ import org.leumasjaffe.charsheet.model.inventory.EquipmentSlot;
 import org.leumasjaffe.format.StringHelper;
 import org.leumasjaffe.observer.IndirectObservableListener;
 import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
 import lombok.experimental.FieldDefaults;
@@ -421,4 +422,12 @@ public class ArmorLine extends JPanel {
 		armorDexObserver.setObserved(model, inv, dex);
 	}
 
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(armorTotalObserver);
+		ObserverDispatch.unsubscribeAll(armorArmorObserver);
+		ObserverDispatch.unsubscribeAll(armorShieldObserver);
+		ObserverDispatch.unsubscribeAll(armorDexObserver);
+	}
 }

+ 7 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/summary/AttackLine.java

@@ -13,6 +13,7 @@ import org.leumasjaffe.charsheet.observer.helper.AbilModStringify;
 import org.leumasjaffe.format.StringHelper;
 import org.leumasjaffe.observer.IndirectObservableListener;
 import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
 import lombok.experimental.FieldDefaults;
@@ -247,4 +248,10 @@ public class AttackLine extends JPanel {
 		this.grappleMisc.setText(StringHelper.toString(misc));
 	}
 
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(gTtlObserver);
+		ObserverDispatch.unsubscribeAll(gStrObserver);
+	}
 }

+ 7 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/summary/InitiativeLine.java

@@ -14,6 +14,7 @@ import org.leumasjaffe.charsheet.observer.helper.AbilModStringify;
 import org.leumasjaffe.format.StringHelper;
 import org.leumasjaffe.observer.IndirectObservableListener;
 import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
 import lombok.experimental.FieldDefaults;
@@ -138,4 +139,10 @@ public class InitiativeLine extends JPanel {
 		dexObserver.setObserved(dex);
 	}
 
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(ttlObserver);
+		ObserverDispatch.unsubscribeAll(dexObserver);
+	}
 }

+ 8 - 0
src/main/lombok/org/leumasjaffe/charsheet/view/summary/ResistanceLine.java

@@ -14,6 +14,7 @@ import org.leumasjaffe.format.StringHelper;
 import org.leumasjaffe.graphics.NumberTextField;
 import org.leumasjaffe.observer.IndirectObservableListener;
 import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.observer.ObserverDispatch;
 
 import lombok.AccessLevel;
 import lombok.experimental.FieldDefaults;
@@ -240,4 +241,11 @@ public class ResistanceLine extends JPanel {
 		abilObserver.setObserved(abil);
 	}
 
+	@Override
+	public void removeNotify() {
+		super.removeNotify();
+		ObserverDispatch.unsubscribeAll(totalObserver);
+		ObserverDispatch.unsubscribeAll(baseObserver);
+		ObserverDispatch.unsubscribeAll(abilObserver);
+	}
 }

+ 1 - 0
src/main/lombok/org/leumasjaffe/observer/ObserverDispatch.java

@@ -28,6 +28,7 @@ public class ObserverDispatch {
 	}
 	
 	public void unsubscribeAll(Object src) {
+		if (src == null) return;
 		observers.entries().removeIf( e -> e.getValue().obj == src );
 	}