Browse Source

Refactor PreparationPanel to use ReplaceChildController.

Sam Jaffe 5 years ago
parent
commit
b18f5f0396

+ 3 - 1
src/main/lombok/org/leumasjaffe/recipe/model/Preparation.java

@@ -6,6 +6,8 @@ import java.util.List;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
+import org.leumasjaffe.observer.Observable;
+
 import com.fasterxml.jackson.annotation.JsonIgnore;
 
 import lombok.AllArgsConstructor;
@@ -13,7 +15,7 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 
 @Data @AllArgsConstructor @NoArgsConstructor
-public class Preparation implements RecipeComponent {
+public class Preparation extends Observable.Instance implements RecipeComponent {
 	Duration duration;
 	@JsonIgnore Supplier<Collection<Ingredient>> producer = Collections::emptyList;
 	

+ 10 - 4
src/main/lombok/org/leumasjaffe/recipe/view/IngredientPanel.java

@@ -26,7 +26,8 @@ import javax.swing.JLabel;
 @SuppressWarnings("serial")
 @FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
 public class IngredientPanel extends JPanel implements AutoGrowPanel.DocumentListenable {
-	ObservableController<JTextField, Ingredient> controller;
+	ObservableController<JTextField, Ingredient> nameController;
+	ObservableController<JTextField, Ingredient> preparationController;
 	@Getter(AccessLevel.PACKAGE) JTextField txtName;
 	@Getter(AccessLevel.PACKAGE) JFormattedTextField txtAmount;
 	@Getter(AccessLevel.PACKAGE) JTextField txtUnit;
@@ -95,10 +96,15 @@ public class IngredientPanel extends JPanel implements AutoGrowPanel.DocumentLis
 		
 		// I technically don't need to listen here as of this change,
 		// but if I ever restore support for it, it will be convenient.
-		controller = new ObservableController<>(txtName,
+		nameController = new ObservableController<>(txtName,
 				Ingredient::getName, Ingredient::setName,
 				JTextField::setText);
-		controller.setObserved(ingredient);
+		preparationController = new ObservableController<>(txtPreparation,
+				Ingredient::getPreparation, Ingredient::setPreparation,
+				JTextField::setText);
+
+		nameController.setObserved(ingredient);
+		preparationController.setObserved(ingredient);
 	}
 
 	@Override
@@ -114,7 +120,7 @@ public class IngredientPanel extends JPanel implements AutoGrowPanel.DocumentLis
 	@Override
 	public void removeNotify() {
 		super.removeNotify();
-		ObserverDispatch.unsubscribeAll(controller);
+		ObserverDispatch.unsubscribeAll(nameController);
 	}
 
 }

+ 3 - 1
src/main/lombok/org/leumasjaffe/recipe/view/IngredientPreparationPanel.java

@@ -98,8 +98,10 @@ public class IngredientPreparationPanel extends JPanel {
 		txtPreparation.setColumns(10);
 		
 		listener = new ObservableListener<>(this, (c, t) -> {
-			if (txtName.getText().equals(t.getName())) return;
 			txtName.setText(t.getName());
+			txtAmount.setValue(t.getAmount().getValue());
+			txtUnit.setText(t.getAmount().unitName());
+			txtPreparation.setText(t.getPreparation());
 		});
 		listener.setObserved(ingredient);
 	}

+ 23 - 10
src/main/lombok/org/leumasjaffe/recipe/view/PreparationPanel.java

@@ -3,6 +3,9 @@ package org.leumasjaffe.recipe.view;
 import javax.swing.JPanel;
 
 import org.jdesktop.swingx.VerticalLayout;
+import org.leumasjaffe.observer.ObservableListener;
+import org.leumasjaffe.recipe.controller.ReplaceChildrenController;
+import org.leumasjaffe.recipe.model.Ingredient;
 import org.leumasjaffe.recipe.model.Preparation;
 
 import lombok.AccessLevel;
@@ -19,12 +22,17 @@ import java.awt.Component;
 import javax.swing.Box;
 
 @SuppressWarnings("serial")
-@FieldDefaults(level=AccessLevel.PRIVATE, makeFinal=true)
+@FieldDefaults(level=AccessLevel.PRIVATE)
 public class PreparationPanel extends JPanel {
-	@Getter(AccessLevel.PACKAGE) JLabel lblDuration;
+	ReplaceChildrenController<Preparation, Ingredient> controller;
+	ObservableListener<JPanel, Preparation> childListener;
+	
 	@Getter(AccessLevel.PACKAGE) JPanel panelIngredients;
 		
-	public PreparationPanel(Preparation step) {
+	public PreparationPanel(Preparation preparation) {
+		controller = new ReplaceChildrenController<>(Preparation::getIngredients,
+				IngredientPreparationPanel::new);
+		
 		GridBagLayout gridBagLayout = new GridBagLayout();
 		gridBagLayout.columnWidths = new int[]{0, 0, 0};
 		gridBagLayout.rowHeights = new int[]{0, 0};
@@ -61,12 +69,12 @@ public class PreparationPanel extends JPanel {
 		gbc_horizontalGlue.gridy = 0;
 		panelLeft.add(horizontalGlue, gbc_horizontalGlue);
 		
-		lblDuration = new JLabel("Requires: " + step.getDuration().toString());
-		GridBagConstraints gbc_lblDuration = new GridBagConstraints();
-		gbc_lblDuration.insets = new Insets(0, 0, 5, 0);
-		gbc_lblDuration.gridx = 2;
-		gbc_lblDuration.gridy = 0;
-		panelLeft.add(lblDuration, gbc_lblDuration);
+		DurationPanel panelDuration = new DurationPanel("Requires", preparation.getDuration());
+		GridBagConstraints gbc_panelDuration = new GridBagConstraints();
+		gbc_panelDuration.insets = new Insets(0, 0, 5, 0);
+		gbc_panelDuration.gridx = 2;
+		gbc_panelDuration.gridy = 0;
+		panelLeft.add(panelDuration, gbc_panelDuration);
 		
 		panelIngredients = new JPanel();
 		panelIngredients.setLayout(new VerticalLayout(5));
@@ -77,7 +85,12 @@ public class PreparationPanel extends JPanel {
 		gbc_panelIngredients.gridx = 0;
 		gbc_panelIngredients.gridy = 1;
 		panelLeft.add(panelIngredients, gbc_panelIngredients);
-		step.getIngredientsAsStream().map(IngredientPreparationPanel::new).forEach(panelIngredients::add);
+	
+		// This indirection allows for testing of controller
+		childListener = new ObservableListener<>(panelIngredients,
+				(c, v) -> controller.accept(c, v));
+		
+		childListener.setObserved(preparation);
 	}
 
 }

+ 51 - 5
src/test/java/org/leumasjaffe/recipe/view/IngredientPanelTest.java

@@ -50,26 +50,72 @@ class IngredientPanelTest extends SwingTestCase {
 	@Test
 	void testIsSubscribedToUpdates() {
 		stuff.setName("Bacon");
+		stuff.setPreparation("Cut into Lardons");
+		stuff.setAmount(new Amount("0.25 lb"));
+		
 		assertEquals("Onions", panel.getTxtName().getText());
 		ObserverDispatch.notifySubscribers(stuff);
+		
 		assertEquals("Bacon", panel.getTxtName().getText());
-		// TODO: I need to add hook-ups for the rest of the fields, too
+		assertEquals(100.0, panel.getTxtAmount().getValue());
+		assertEquals("g", panel.getTxtUnit().getText());
+		assertEquals("Cut into Lardons", panel.getTxtPreparation().getText());
 	}
 
-	// TODO: I need to add hook-ups for the rest of the fields, too
 	@Test
-	void testViewUpdateAltersModel() {
+	void testViewUpdateToNameAltersModel() {
 		panel.getTxtName().setText("Bacon");
 		waitForSwing();
 		assertEquals("Bacon", stuff.getName());
 	}
+	
+	@Test
+	void testViewUpdateToPreparationAltersModel() {
+		panel.getTxtPreparation().setText("Cut into Lardons");
+		waitForSwing();
+		assertEquals("Cut into Lardons", stuff.getPreparation());
+	}
+	
+	@Test
+	void testViewUpdateToAmountDoesNotAltersModel() {
+		panel.getTxtAmount().setValue(0.25);
+		waitForSwing();
+		assertEquals(100.0, stuff.getAmount().getValue());
+	}
+	
+	@Test
+	void testViewUpdateToUnitDoesNotAltersModel() {
+		panel.getTxtUnit().setText("lb");
+		waitForSwing();
+		assertEquals("g", stuff.getAmount().unitName());
+	}
 
-	// TODO: I need to add hook-ups for the rest of the fields, too
 	@Test
-	void testViewUpdateSendsNotify() {
+	void testUpdateToNameSendsNotify() {
 		panel.getTxtName().setText("Bacon");
 		waitForSwing();
 		verify(listener).updateWasSignalled();
 	}
+	
+	@Test
+	void testUpdateToPreparationSendsNotify() {
+		panel.getTxtPreparation().setText("Cut into Lardons");
+		waitForSwing();
+		verify(listener).updateWasSignalled();
+	}
+
+	@Test
+	void testUpdateToAmountSendsNotify() {
+		panel.getTxtAmount().setValue(0.25);
+		waitForSwing();
+		verify(listener, never()).updateWasSignalled();
+	}
+	
+	@Test
+	void testUpdateToUnitSendsNotify() {
+		panel.getTxtUnit().setText("lb");
+		waitForSwing();
+		verify(listener, never()).updateWasSignalled();
+	}
 
 }

+ 19 - 13
src/test/java/org/leumasjaffe/recipe/view/PreparationPanelTest.java

@@ -2,51 +2,57 @@ package org.leumasjaffe.recipe.view;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.collection.IsArrayWithSize.arrayWithSize;
-import static org.hamcrest.core.StringContains.containsString;
 import static org.mockito.Mockito.*;
 
-import java.util.stream.Stream;
+import java.util.Arrays;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.platform.runner.JUnitPlatform;
 import org.junit.runner.RunWith;
+import org.leumasjaffe.observer.ObserverDispatch;
 import org.leumasjaffe.recipe.model.Amount;
 import org.leumasjaffe.recipe.model.Duration;
 import org.leumasjaffe.recipe.model.Ingredient;
 import org.leumasjaffe.recipe.model.Preparation;
-import org.mockito.Mock;
+import org.mockito.Spy;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 @ExtendWith(MockitoExtension.class)
 @RunWith(JUnitPlatform.class)
 class PreparationPanelTest extends SwingTestCase {
 	
-	Duration dur;
-	@Mock Preparation stuff;
+	@Spy Preparation stuff;
 	PreparationPanel panel;
 	
 	@BeforeEach
 	void setUp() {
-		dur = new Duration(Duration.Display.SECONDS, 0, 30);
+		Duration dur = new Duration(Duration.Display.SECONDS, 0, 30);
 		doReturn(dur).when(stuff).getDuration();
-		doReturn(Stream.of(
+		doReturn(Arrays.asList(
 				new Ingredient("Butter", "", new Amount("10 g")),
 				new Ingredient("Salt", "", new Amount("0.25 tsp"))
-				)).when(stuff).getIngredientsAsStream();
-		
+				)).when(stuff).getIngredients();
+
 		panel = new PreparationPanel(stuff);
 	}
 
 	@Test
 	void testHasContent() {
-		assertThat(panel.getLblDuration().getText(),
-				containsString(dur.toString()));
 		assertThat(panel.getPanelIngredients().getComponents(),
 				arrayWithSize(2));
 	}
 
-	// TODO: Hook-ups for editing the preparation time
-	// TODO: Hook-ups for changes to the preparation model
+	@Test
+	void testUpdatesNumberOfChildrenWhenNotified() {
+		doReturn(Arrays.asList(
+				new Ingredient("Salt", "", new Amount("0.25 tsp"))
+				)).when(stuff).getIngredients();
+		
+		ObserverDispatch.notifySubscribers(stuff);
+		
+		assertThat(panel.getPanelIngredients().getComponents(),
+				arrayWithSize(1));
+	}
 }