Browse Source

Setting Items in the inventory to use Count/CountEquipped as listener targets, instead of rebuilding the entire thing

Sam Jaffe 8 năm trước cách đây
mục cha
commit
b4c9695fa8

+ 44 - 38
src/main/lombok/org/leumasjaffe/charsheet/controller/EquipItemController.java

@@ -15,9 +15,9 @@ import lombok.RequiredArgsConstructor;
 public class EquipItemController {	
 public class EquipItemController {	
 
 
 	public static void accept(final DDInventory inv, final DDItem item) {
 	public static void accept(final DDInventory inv, final DDItem item) {
-		if ( item.getUnequippedCount() == 0 ) { return; }
-		if ( inv.canEquip(item) || new Helper(inv).getReplaceItem(item.getSlot()) ) {
-			item.setCountEquipped(item.getCountEquipped() + 1);
+		if (item.getUnequippedCount() == 0) { return; }
+		if (inv.canEquip(item) || new Helper(inv).getReplaceItem(item.getSlot())) {
+			item.adjustCounEquipped(+1);
 			inv.equipNext(item);
 			inv.equipNext(item);
 			ObserverDispatch.notifySubscribers(inv, null);
 			ObserverDispatch.notifySubscribers(inv, null);
 		}
 		}
@@ -26,32 +26,28 @@ public class EquipItemController {
 	@RequiredArgsConstructor
 	@RequiredArgsConstructor
 	private static class Helper {
 	private static class Helper {
 		final DDInventory inv;
 		final DDInventory inv;
+		private static final String QUERY_REPLACE = "Replace Equipped Item";
+		private static final String REPLACE_EITHER = "Which of the following items would you like to replace?";
+		private static final String REPLACE_BOTH = "Do you want to replace both of the following items?";
+		private static final String REPLACE_ONE = "Do you want to replace the following item?";
 		
 		
 		private boolean getReplaceItem(final EquipmentSlot slot) {
 		private boolean getReplaceItem(final EquipmentSlot slot) {
-			switch ( slot ) {
-			case TWO_HANDS: return selectToReplaceAllOf( TWO_HANDS, MAIN_HAND, OFF_HAND );
-			case ONE_HAND: return selectToReplaceOneOf( MAIN_HAND, OFF_HAND );
-			case RING: return selectToReplaceOneOf( RING1, RING2 );
-			default: return selectToReplace( slot );
+			switch (slot) {
+			case TWO_HANDS: return selectToReplaceAllOf(TWO_HANDS, MAIN_HAND, OFF_HAND);
+			case ONE_HAND: return selectToReplaceOneOf(MAIN_HAND, OFF_HAND);
+			case RING: return selectToReplaceOneOf(RING1, RING2);
+			default: return selectToReplace(slot);
 			}
 			}
 		}
 		}
 
 
 		private boolean selectToReplaceAllOf(final EquipmentSlot base,
 		private boolean selectToReplaceAllOf(final EquipmentSlot base,
 				final EquipmentSlot slot1, final EquipmentSlot slot2) {
 				final EquipmentSlot slot1, final EquipmentSlot slot2) {
-			final EquipItemDialog panel;
-			if ( inv.getEquipment().get(slot1).getSlot() == base ) {
-				panel = new EquipItemDialog("Do you want to replace the following item?", 
-						slot1, inv.getEquipment().get(slot1));
-			} else {
-				panel = new EquipItemDialog("Do you want to replace both of the following items?", 
-						new EquipItemDialog.Tuple(slot1, inv.getEquipment().get(slot1)),
-						new EquipItemDialog.Tuple(slot2, inv.getEquipment().get(slot2)));
-			}
-			if ( JOptionPane.showConfirmDialog(null, 
-					panel, "Replace Equipped Item", JOptionPane.YES_NO_OPTION) 
-					== JOptionPane.YES_OPTION ) {
-				inv.unequip( slot1 );
-				inv.unequip( slot2 );
+			if (inv.getEquipment().get(slot1).getSlot() == base) {
+				return selectToReplace(slot1);
+			} else if (JOptionPane.showConfirmDialog(null, createDialogTwoSlots(REPLACE_BOTH, slot1, slot2), 
+					QUERY_REPLACE, JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
+				doUnequip(slot1);
+				doUnequip(slot2);
 				return true;
 				return true;
 			}
 			}
 			return false;
 			return false;
@@ -59,32 +55,42 @@ public class EquipItemController {
 
 
 		private boolean selectToReplaceOneOf(final EquipmentSlot slot1, 
 		private boolean selectToReplaceOneOf(final EquipmentSlot slot1, 
 				final EquipmentSlot slot2) {
 				final EquipmentSlot slot2) {
-			final int choice = JOptionPane.showOptionDialog(null, 
-					new EquipItemDialog("Which of the following items would you like to replace?", 
-							new EquipItemDialog.Tuple(slot1, inv.getEquipment().get(slot1)),
-							new EquipItemDialog.Tuple(slot2, inv.getEquipment().get(slot2))), 
-					"Replace Equipped Item", JOptionPane.YES_NO_CANCEL_OPTION,
-					JOptionPane.QUESTION_MESSAGE, null, 
-					new String[] {"Cancel", slot1.toString(), slot2.toString()}, null );
-			if ( choice == JOptionPane.YES_OPTION ) {
-				inv.unequip( slot1 );
+			final int choice = JOptionPane.showOptionDialog(null, createDialogTwoSlots(REPLACE_EITHER, slot1, slot2), 
+					QUERY_REPLACE, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, 
+					new String[] {"Cancel", slot1.toString(), slot2.toString()}, null);
+			if (choice == JOptionPane.YES_OPTION) {
+				doUnequip(slot1);
 				return true;
 				return true;
-			} else if ( choice == JOptionPane.NO_OPTION ) {
-				inv.unequip( slot2 );
+			} else if (choice == JOptionPane.NO_OPTION) {
+				doUnequip(slot2);
 				return true;
 				return true;
 			}
 			}
 			return false;
 			return false;
 		}
 		}
 
 
 		private boolean selectToReplace(final EquipmentSlot slot) {
 		private boolean selectToReplace(final EquipmentSlot slot) {
-			if ( JOptionPane.showConfirmDialog(null, 
-					new EquipItemDialog("Do you want to replace the following item?", slot, inv.getEquipment().get(slot)), 
-					"Replace Equipped Item", JOptionPane.YES_NO_OPTION) 
-					== JOptionPane.YES_OPTION ) {
-				inv.unequip( slot );
+			if (JOptionPane.showConfirmDialog(null, createDialogOneSlot(slot), QUERY_REPLACE, JOptionPane.YES_NO_OPTION) 
+					== JOptionPane.YES_OPTION) {
+				doUnequip(slot);
 				return true;
 				return true;
 			}
 			}
 			return false;
 			return false;
 		}
 		}
+
+		private void doUnequip(final EquipmentSlot slot) {
+			inv.getEquipment().get(slot).adjustCounEquipped(-1);
+			inv.unequip(slot);
+		}		
+
+		private EquipItemDialog createDialogOneSlot(final EquipmentSlot slot) {
+			return new EquipItemDialog(REPLACE_ONE, slot, inv.getEquipment().get(slot));
+		}
+		
+		private EquipItemDialog createDialogTwoSlots(final String message, 
+				final EquipmentSlot slot1, final EquipmentSlot slot2) {
+			return new EquipItemDialog(message,
+					new EquipItemDialog.Tuple(slot1, inv.getEquipment().get(slot1)),
+					new EquipItemDialog.Tuple(slot2, inv.getEquipment().get(slot2)));
+		}
 	}
 	}
 }
 }

+ 11 - 4
src/main/lombok/org/leumasjaffe/charsheet/model/inventory/DDItem.java

@@ -16,14 +16,13 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.NoArgsConstructor;
 import lombok.experimental.FieldDefaults;
 import lombok.experimental.FieldDefaults;
 
 
-@AllArgsConstructor
+@AllArgsConstructor @NoArgsConstructor
 @Data
 @Data
-@NoArgsConstructor
 @FieldDefaults(level=AccessLevel.PRIVATE)
 @FieldDefaults(level=AccessLevel.PRIVATE)
 public class DDItem {
 public class DDItem {
 	String name = "";
 	String name = "";
 	IntValue count = new IntValue(1);
 	IntValue count = new IntValue(1);
-	int countEquipped = 0;
+	IntValue countEquipped = new IntValue(0);
 	float weight = 0.f;
 	float weight = 0.f;
 	Money value = new Money(0, 0, 0, 0);
 	Money value = new Money(0, 0, 0, 0);
 	StringValue page = new StringValue();
 	StringValue page = new StringValue();
@@ -46,12 +45,20 @@ public class DDItem {
 		properties.put(key, prop);
 		properties.put(key, prop);
 	}
 	}
 	
 	
+	public void adjustCount(int amt) {
+		this.count.value(this.count.value() + amt);
+	}
+	
+	public void adjustCounEquipped(int amt) {
+		this.countEquipped.value(this.countEquipped.value() + amt);
+	}
+	
 	@JsonAnyGetter 
 	@JsonAnyGetter 
 	private Map<String, Object> getProperties() { 
 	private Map<String, Object> getProperties() { 
 		return Collections.unmodifiableMap(properties);
 		return Collections.unmodifiableMap(properties);
 	}
 	}
 	
 	
 	public int getUnequippedCount() {
 	public int getUnequippedCount() {
-		return count.value() - countEquipped;
+		return count.value() - countEquipped.value();
 	}
 	}
 }
 }

+ 7 - 8
src/main/lombok/org/leumasjaffe/charsheet/view/dialog/BuySellItemDialog.java

@@ -4,7 +4,6 @@ import javax.swing.JPanel;
 import javax.swing.JSpinner;
 import javax.swing.JSpinner;
 import javax.swing.SpinnerNumberModel;
 import javax.swing.SpinnerNumberModel;
 
 
-import org.leumasjaffe.charsheet.model.inventory.DDItem;
 import org.leumasjaffe.charsheet.model.inventory.Money;
 import org.leumasjaffe.charsheet.model.inventory.Money;
 import org.leumasjaffe.format.StringHelper;
 import org.leumasjaffe.format.StringHelper;
 
 
@@ -33,8 +32,7 @@ public class BuySellItemDialog extends JPanel {
 	
 	
 	JSpinner spinner;
 	JSpinner spinner;
 
 
-	public BuySellItemDialog(final DDItem item, int cap) {
-		final int rawValue = item.getValue().asCopper();
+	public BuySellItemDialog(final String itemName, final int rawValue, int cap) {
 		spinner = new JSpinner(new SpinnerNumberModel(1, 1, cap, 1));
 		spinner = new JSpinner(new SpinnerNumberModel(1, 1, cap, 1));
 
 
 		GridBagLayout gridBagLayout = new GridBagLayout();
 		GridBagLayout gridBagLayout = new GridBagLayout();
@@ -58,7 +56,7 @@ public class BuySellItemDialog extends JPanel {
 		gbc_lblName.gridy = 0;
 		gbc_lblName.gridy = 0;
 		add(lblName, gbc_lblName);
 		add(lblName, gbc_lblName);
 
 
-		JTextField txtName = new JTextField(item.getName());
+		JTextField txtName = new JTextField(itemName);
 		txtName.setEditable(false);
 		txtName.setEditable(false);
 		GridBagConstraints gbc_txtName = new GridBagConstraints();
 		GridBagConstraints gbc_txtName = new GridBagConstraints();
 		gbc_txtName.insets = new Insets(0, 0, 0, 0);
 		gbc_txtName.insets = new Insets(0, 0, 0, 0);
@@ -130,7 +128,7 @@ public class BuySellItemDialog extends JPanel {
 		gbc_lblCp.gridy = 1;
 		gbc_lblCp.gridy = 1;
 		add(lblCp, gbc_lblCp);
 		add(lblCp, gbc_lblCp);
 		
 		
-		JTextField txtPp = new JTextField(StringHelper.toString(item.getValue().getPp()));
+		JTextField txtPp = new JTextField();
 		txtPp.setEditable(false);
 		txtPp.setEditable(false);
 		txtPp.setColumns(6);
 		txtPp.setColumns(6);
 		GridBagConstraints gbc_txtPp = new GridBagConstraints();
 		GridBagConstraints gbc_txtPp = new GridBagConstraints();
@@ -140,7 +138,7 @@ public class BuySellItemDialog extends JPanel {
 		gbc_txtPp.gridy = 2;
 		gbc_txtPp.gridy = 2;
 		add(txtPp, gbc_txtPp);
 		add(txtPp, gbc_txtPp);
 		
 		
-		JTextField txtGp = new JTextField(StringHelper.toString(item.getValue().getGp()));
+		JTextField txtGp = new JTextField();
 		txtGp.setEditable(false);
 		txtGp.setEditable(false);
 		txtGp.setColumns(3);
 		txtGp.setColumns(3);
 		GridBagConstraints gbc_txtGp = new GridBagConstraints();
 		GridBagConstraints gbc_txtGp = new GridBagConstraints();
@@ -150,7 +148,7 @@ public class BuySellItemDialog extends JPanel {
 		gbc_txtGp.gridy = 2;
 		gbc_txtGp.gridy = 2;
 		add(txtGp, gbc_txtGp);
 		add(txtGp, gbc_txtGp);
 		
 		
-		JTextField txtSp = new JTextField(StringHelper.toString(item.getValue().getSp()));
+		JTextField txtSp = new JTextField();
 		txtSp.setEditable(false);
 		txtSp.setEditable(false);
 		txtSp.setColumns(3);
 		txtSp.setColumns(3);
 		GridBagConstraints gbc_txtSp = new GridBagConstraints();
 		GridBagConstraints gbc_txtSp = new GridBagConstraints();
@@ -160,7 +158,7 @@ public class BuySellItemDialog extends JPanel {
 		gbc_txtSp.gridy = 2;
 		gbc_txtSp.gridy = 2;
 		add(txtSp, gbc_txtSp);
 		add(txtSp, gbc_txtSp);
 		
 		
-		JTextField txtCp = new JTextField(StringHelper.toString(item.getValue().getCp()));
+		JTextField txtCp = new JTextField();
 		txtCp.setEditable(false);
 		txtCp.setEditable(false);
 		txtCp.setColumns(3);
 		txtCp.setColumns(3);
 		GridBagConstraints gbc_txtCp = new GridBagConstraints();
 		GridBagConstraints gbc_txtCp = new GridBagConstraints();
@@ -184,6 +182,7 @@ public class BuySellItemDialog extends JPanel {
 			txtSp.setText(StringHelper.toString(value.getSp()));
 			txtSp.setText(StringHelper.toString(value.getSp()));
 			txtCp.setText(StringHelper.toString(value.getCp()));
 			txtCp.setText(StringHelper.toString(value.getCp()));
 		});
 		});
+		spinner.getChangeListeners()[0].stateChanged(null);
 	}
 	}
 	
 	
 	public int getSelectedNumber() {
 	public int getSelectedNumber() {

+ 2 - 2
src/main/lombok/org/leumasjaffe/charsheet/view/inventory/EquipmentInfoMenu.java

@@ -35,9 +35,9 @@ class EquipmentInfoMenu extends JPopupMenu {
 					"Are you sure you want to unequip your " + item.getName(), 
 					"Are you sure you want to unequip your " + item.getName(), 
 					"Unequip", JOptionPane.YES_NO_OPTION) 
 					"Unequip", JOptionPane.YES_NO_OPTION) 
 					== JOptionPane.YES_OPTION) {
 					== JOptionPane.YES_OPTION) {
-				item.setCountEquipped(item.getCountEquipped()-1);
 				inv.unequip(slot);
 				inv.unequip(slot);
-				ObserverDispatch.notifySubscribers(inv, null);
+				item.adjustCounEquipped(-1);
+				ObserverDispatch.notifySubscribers(item.getCountEquipped(), null);
 			}
 			}
 		});
 		});
 		add(mntmEquip);
 		add(mntmEquip);

+ 17 - 6
src/main/lombok/org/leumasjaffe/charsheet/view/inventory/InventoryPanel.java

@@ -11,7 +11,9 @@ import org.jdesktop.swingx.VerticalLayout;
 import org.leumasjaffe.charsheet.model.DDCharacter;
 import org.leumasjaffe.charsheet.model.DDCharacter;
 import org.leumasjaffe.charsheet.model.inventory.DDInventory;
 import org.leumasjaffe.charsheet.model.inventory.DDInventory;
 import org.leumasjaffe.charsheet.model.inventory.DDItem;
 import org.leumasjaffe.charsheet.model.inventory.DDItem;
+import org.leumasjaffe.charsheet.model.observable.IntValue;
 import org.leumasjaffe.event.PopClickListener;
 import org.leumasjaffe.event.PopClickListener;
+import org.leumasjaffe.observer.IndirectObservableListener;
 import org.leumasjaffe.observer.ObservableListener;
 import org.leumasjaffe.observer.ObservableListener;
 
 
 import lombok.AccessLevel;
 import lombok.AccessLevel;
@@ -21,6 +23,7 @@ import java.awt.Color;
 import java.awt.Font;
 import java.awt.Font;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
 import java.awt.GridBagLayout;
+import java.util.stream.Stream;
 
 
 @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
 @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
 public class InventoryPanel extends JPanel {
 public class InventoryPanel extends JPanel {
@@ -30,7 +33,7 @@ public class InventoryPanel extends JPanel {
 	private static final long serialVersionUID = 1L;
 	private static final long serialVersionUID = 1L;
 	JComponent inventory;
 	JComponent inventory;
 	ObservableListener<InventoryPanel, DDInventory> inventoryObserver;
 	ObservableListener<InventoryPanel, DDInventory> inventoryObserver;
-
+	
 	public InventoryPanel() {
 	public InventoryPanel() {
 		GridBagLayout gridBagLayout = new GridBagLayout();
 		GridBagLayout gridBagLayout = new GridBagLayout();
 		gridBagLayout.columnWidths = new int[]{0};
 		gridBagLayout.columnWidths = new int[]{0};
@@ -67,9 +70,7 @@ public class InventoryPanel extends JPanel {
 
 
 	private void updateModel(DDInventory inv) {
 	private void updateModel(DDInventory inv) {
 		inventory.removeAll();
 		inventory.removeAll();
-		
-		inv.getItems().stream().forEach( 
-				item -> createWithRightClickMenu(inv, item) );
+		inv.getItems().stream().forEach(item -> createWithRightClickMenu(inv, item));
 	}
 	}
 
 
 	public void setModel(DDCharacter model) {
 	public void setModel(DDCharacter model) {
@@ -78,8 +79,18 @@ public class InventoryPanel extends JPanel {
 
 
 	private void createWithRightClickMenu(final DDInventory inv, final DDItem item) {
 	private void createWithRightClickMenu(final DDInventory inv, final DDItem item) {
 		final ItemPanel panel = new ItemPanel(item);
 		final ItemPanel panel = new ItemPanel(item);
-		panel.addMouseListener(new PopClickListener(
-				new ItemInfoMenu(inv, 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);
 		inventory.add(panel);
 	}
 	}
 	
 	

+ 40 - 21
src/main/lombok/org/leumasjaffe/charsheet/view/inventory/ItemInfoMenu.java

@@ -8,6 +8,11 @@ import org.leumasjaffe.charsheet.model.inventory.DDItem;
 import org.leumasjaffe.charsheet.model.inventory.EquipmentSlot;
 import org.leumasjaffe.charsheet.model.inventory.EquipmentSlot;
 import org.leumasjaffe.charsheet.model.inventory.Money;
 import org.leumasjaffe.charsheet.model.inventory.Money;
 import org.leumasjaffe.charsheet.view.dialog.BuySellItemDialog;
 import org.leumasjaffe.charsheet.view.dialog.BuySellItemDialog;
+import org.leumasjaffe.observer.ObserverDispatch;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.experimental.FieldDefaults;
 
 
 import javax.swing.JFrame;
 import javax.swing.JFrame;
 import javax.swing.JMenuItem;
 import javax.swing.JMenuItem;
@@ -21,7 +26,10 @@ class ItemInfoMenu extends JPopupMenu {
 
 
 	public ItemInfoMenu(final DDInventory inv, final DDItem item) {
 	public ItemInfoMenu(final DDInventory inv, final DDItem item) {
 		final int rawWealth = inv.getWealth().asCopper();
 		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());
+
 		JMenuItem mntmInfo = new JMenuItem("Info");
 		JMenuItem mntmInfo = new JMenuItem("Info");
 		mntmInfo.addActionListener(e -> {
 		mntmInfo.addActionListener(e -> {
 			JFrame frame = new JFrame(item.getName());
 			JFrame frame = new JFrame(item.getName());
@@ -33,31 +41,14 @@ class ItemInfoMenu extends JPopupMenu {
 
 
 		JMenuItem mntmBuy = new JMenuItem("Purchase");
 		JMenuItem mntmBuy = new JMenuItem("Purchase");
 		mntmBuy.addActionListener(e -> {
 		mntmBuy.addActionListener(e -> {
-			final BuySellItemDialog dialog = new BuySellItemDialog(item, rawWealth / item.getValue().asCopper());
-			if (JOptionPane.showConfirmDialog(null, dialog, "Purchase How Many " + item.getName() + "?", 
-					JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
-				final int selected = dialog.getSelectedNumber();
-				item.getCount().value(item.getCount().value() + selected);
-				final Money wealth = inv.getWealth();
-				wealth.assign(wealth.difference(Money.fromCopper(selected * item.getValue().asCopper())));
-				// TODO: update model
-			}
+			doTxn.applyTransaction(dlg.getNumUnits("Purchase", rawValue, rawWealth / rawValue), rawValue);
 		});
 		});
 		mntmBuy.setEnabled(rawWealth >= item.getValue().asCopper());
 		mntmBuy.setEnabled(rawWealth >= item.getValue().asCopper());
 		add(mntmBuy);
 		add(mntmBuy);
 
 
 		JMenuItem mntmSell = new JMenuItem("Sell");	
 		JMenuItem mntmSell = new JMenuItem("Sell");	
 		mntmSell.addActionListener(e -> {
 		mntmSell.addActionListener(e -> {
-			// TODO: Adjust display to show sale value of 1/2
-			final BuySellItemDialog dialog = new BuySellItemDialog(item, item.getCount().value());
-			if (JOptionPane.showConfirmDialog(null, dialog, "Sell How Many " + item.getName() + "?", 
-					JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
-				final int selected = dialog.getSelectedNumber();
-				item.getCount().value(item.getCount().value() - selected);
-				final Money wealth = inv.getWealth();
-				wealth.assign(wealth.sum(Money.fromCopper(selected * item.getValue().asCopper() / 2)));
-				// TODO: remove item if count is 0
-			}
+			doTxn.applyTransaction(-dlg.getNumUnits("Sell", rawValue / 2, item.getCount().value()), rawValue / 2);
 		});
 		});
 		mntmSell.setEnabled(item.getUnequippedCount() > 0);
 		mntmSell.setEnabled(item.getUnequippedCount() > 0);
 		add(mntmSell);
 		add(mntmSell);
@@ -65,9 +56,37 @@ class ItemInfoMenu extends JPopupMenu {
 		if (item.getSlot() != EquipmentSlot.NONE) {
 		if (item.getSlot() != EquipmentSlot.NONE) {
 			JMenuItem mntmEquip = new JMenuItem("Equip");
 			JMenuItem mntmEquip = new JMenuItem("Equip");
 			mntmEquip.setEnabled(item.getUnequippedCount() > 0);
 			mntmEquip.setEnabled(item.getUnequippedCount() > 0);
-			mntmEquip.addActionListener(e -> EquipItemController.accept(inv, item));
+			mntmEquip.addActionListener(e -> EquipItemController.accept(inv.getEquipment(), item));
 			add(mntmEquip);
 			add(mntmEquip);
 		}
 		}
 	}
 	}
 
 
+	@AllArgsConstructor
+	@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
+	private static final class BuySellDialogHelper {
+		String name;
+		public int getNumUnits(String word, int txnPrice, int maxUnits) {
+			final BuySellItemDialog dialog = new BuySellItemDialog(name, txnPrice, maxUnits);
+			if (JOptionPane.showConfirmDialog(null, dialog, word + " How Many " + name + "?", 
+					JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
+				return dialog.getSelectedNumber();
+			}
+			return 0;
+		}
+	}
+	
+	@AllArgsConstructor
+	@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
+	private static final class BuySellAction {
+		DDInventory inv;
+		DDItem item;
+		
+		public void applyTransaction(int selected, int txnPrice) {
+			if (selected == 0) return;
+			item.getCount().value(item.getCount().value() + selected);
+			final Money wealth = inv.getWealth();
+			wealth.assign(wealth.difference(Money.fromCopper(selected * txnPrice)));
+			ObserverDispatch.notifySubscribers(item.getCount(), null);
+		}
+	}
 }
 }

+ 10 - 1
src/main/lombok/org/leumasjaffe/charsheet/view/inventory/ItemPanel.java

@@ -13,7 +13,9 @@ import java.awt.Color;
 import javax.swing.SwingConstants;
 import javax.swing.SwingConstants;
 
 
 import org.leumasjaffe.charsheet.model.inventory.DDItem;
 import org.leumasjaffe.charsheet.model.inventory.DDItem;
+import org.leumasjaffe.charsheet.model.observable.IntValue;
 import org.leumasjaffe.format.StringHelper;
 import org.leumasjaffe.format.StringHelper;
+import org.leumasjaffe.observer.ObservableListener;
 
 
 import java.awt.Component;
 import java.awt.Component;
 import javax.swing.Box;
 import javax.swing.Box;
@@ -23,6 +25,8 @@ public class ItemPanel extends JPanel {
 	 * 
 	 * 
 	 */
 	 */
 	private static final long serialVersionUID = 1L;
 	private static final long serialVersionUID = 1L;
+	
+	ObservableListener<JTextField, IntValue> countListener;
 
 
 	public ItemPanel(DDItem item) {
 	public ItemPanel(DDItem item) {
 		setPreferredSize(new Dimension(280, 40));
 		setPreferredSize(new Dimension(280, 40));
@@ -105,7 +109,7 @@ public class ItemPanel extends JPanel {
 		add(nameField, gbc_nameField);
 		add(nameField, gbc_nameField);
 		nameField.setColumns(10);
 		nameField.setColumns(10);
 		
 		
-		JTextField countField = new JTextField(Integer.toString(item.getCount().value()));
+		JTextField countField = new JTextField();
 		countField.setHorizontalAlignment(SwingConstants.CENTER);
 		countField.setHorizontalAlignment(SwingConstants.CENTER);
 		GridBagConstraints gbc_countField = new GridBagConstraints();
 		GridBagConstraints gbc_countField = new GridBagConstraints();
 		gbc_countField.insets = new Insets(0, 0, 0, 0);
 		gbc_countField.insets = new Insets(0, 0, 0, 0);
@@ -134,6 +138,11 @@ public class ItemPanel extends JPanel {
 		gbc_valueField.gridy = 2;
 		gbc_valueField.gridy = 2;
 		add(valueField, gbc_valueField);
 		add(valueField, gbc_valueField);
 		valueField.setColumns(10);
 		valueField.setColumns(10);
+		
+		countListener = new ObservableListener<JTextField, IntValue>(countField, (c, v) -> {
+			c.setText(StringHelper.toString(v.value()));
+		});
+		countListener.setObserved(item.getCount());
 	}
 	}
 
 
 }
 }