浏览代码

Switch RecipeCardPanel to use AutoGrow.

Sam Jaffe 5 年之前
父节点
当前提交
40aa7662a9

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

@@ -14,9 +14,9 @@ import lombok.EqualsAndHashCode;
 
 @Data @EqualsAndHashCode(callSuper=false)
 public class RecipeCard extends Observable.Instance implements CompoundRecipeComponent {
-	String title;
-	String description;
-	int servings;
+	String title = "";
+	String description = "";
+	int servings = 1;
 	// TODO: Nutrition information
 	Optional<ImageIcon> photo = Optional.empty(); // TODO JSONIZATION	
 	List<Element> elements = new ArrayList<>();

+ 13 - 1
src/main/lombok/org/leumasjaffe/recipe/view/ElementPanel.java

@@ -19,6 +19,7 @@ import org.jdesktop.swingx.VerticalLayout;
 import javax.swing.JSeparator;
 import javax.swing.JTextField;
 import javax.swing.ScrollPaneConstants;
+import javax.swing.event.DocumentListener;
 
 import java.awt.GridBagLayout;
 import java.awt.GridBagConstraints;
@@ -30,7 +31,7 @@ import javax.swing.Box;
 
 @SuppressWarnings("serial")
 @FieldDefaults(level=AccessLevel.PRIVATE)
-public class ElementPanel extends JScrollPane {
+public class ElementPanel extends JScrollPane implements AutoGrowPanel.ChildComponent {
 	ForwardingObservableListener<Element> listener = new ForwardingObservableListener<>();
 	ObservableListener<JTextField, Element> nameController;
 	ObservableListener<CollatedDurationPanel, Element> durationListener;
@@ -107,4 +108,15 @@ public class ElementPanel extends JScrollPane {
 		ObserverDispatch.unsubscribeAll(nameController);
 		ObserverDispatch.unsubscribeAll(durationListener);
 	}
+
+	@Override
+	public void addGrowShrinkListener(DocumentListener dl) {
+		this.txtName.getDocument().addDocumentListener(dl);
+	}
+
+	@Override
+	public void removeGrowShrinkListener(DocumentListener dl) {
+		this.txtName.getDocument().removeDocumentListener(dl);
+	}
+	
 }

+ 12 - 7
src/main/lombok/org/leumasjaffe/recipe/view/RecipeCardPanel.java

@@ -2,19 +2,19 @@ package org.leumasjaffe.recipe.view;
 
 import javax.swing.JSplitPane;
 
-import org.jdesktop.swingx.VerticalLayout;
 import org.leumasjaffe.observer.ForwardingObservableListener;
 import org.leumasjaffe.observer.ObservableListener;
 import org.leumasjaffe.observer.ObserverDispatch;
+import org.leumasjaffe.recipe.model.Element;
 import org.leumasjaffe.recipe.model.RecipeCard;
 import org.leumasjaffe.recipe.view.summary.SummaryPanel;
 
 import lombok.AccessLevel;
+import lombok.Getter;
 import lombok.experimental.FieldDefaults;
 
 import java.awt.Dimension;
 
-import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.ScrollPaneConstants;
 
@@ -25,16 +25,16 @@ public class RecipeCardPanel extends JSplitPane {
 	ForwardingObservableListener<RecipeCard> listener;
 	
 	SummaryPanel summaryPanel;
-	JPanel rightPanel;
+	@Getter(AccessLevel.PACKAGE) AutoGrowPanel<ElementPanel, Element> panelElements;
 	
 	public RecipeCardPanel() {
 		setPreferredSize(new Dimension(1050, 600));
 
 		summaryPanel = new SummaryPanel();
-		rightPanel = new JPanel();
-		rightPanel.setLayout(new VerticalLayout(5));
+		panelElements = new AutoGrowPanel<>(Element::new, ElementPanel::new);
+		panelElements.setGap(5);
 
-		final JScrollPane scrollPane = new JScrollPane(rightPanel);
+		final JScrollPane scrollPane = new JScrollPane(panelElements);
 		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
 		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
 		setRightComponent(scrollPane);
@@ -51,7 +51,12 @@ public class RecipeCardPanel extends JSplitPane {
 	
 	public void setModel(final RecipeCard card) {
 		summaryPanel.setModel(card);
-		card.getComponents().map(ElementPanel::new).forEach(rightPanel::add);
+		panelElements.setModel(card.getElements(), added -> {
+			listener.setObserved(card, card.getElements());
+			if (!added) {
+				ObserverDispatch.notifySubscribers(card);
+			}
+		});
 
 		listener.setObserved(card, card.getElements());
 		updateUI.setObserved(card);		

+ 93 - 0
src/test/java/org/leumasjaffe/recipe/view/RecipeCardPanelIT.java

@@ -0,0 +1,93 @@
+package org.leumasjaffe.recipe.view;
+
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.leumasjaffe.mock.MockObserverListener;
+import org.leumasjaffe.observer.ObserverDispatch;
+import org.leumasjaffe.recipe.model.Element;
+import org.leumasjaffe.recipe.model.RecipeCard;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class RecipeCardPanelIT extends SwingTestCase {
+	@Spy MockObserverListener listener;
+
+	List<Element> elements;
+	RecipeCard stuff;
+	
+	RecipeCardPanel panel = new RecipeCardPanel();
+
+	@BeforeEach
+	void setUp() {
+		elements = new ArrayList<>(Arrays.asList(new Element()));
+		elements.get(0).setName("Stuff");
+		stuff = new RecipeCard();
+		stuff.setElements(elements);
+				
+		panel.setModel(stuff);
+		
+		listener.setObserved(stuff);
+		// setObserved invokes our callback.
+		clearInvocations(listener);
+	}
+	
+	private AutoGrowPanel<ElementPanel, Element> getPanelIngredients() {
+		return panel.getPanelElements();
+	}
+
+	@Test
+	void testRecievesSignalWhenNewElementAdded() {
+		final ElementPanel newElement =
+				(ElementPanel) getPanelIngredients().getComponent(1);
+		
+		newElement.getTxtName().setText("Bacon");
+		waitForSwing();
+		
+		verify(listener, times(1)).updateWasSignalled();
+	}
+
+	@Test
+	void testNewItemCanProduceUpdate() {
+		final ElementPanel newElement =
+				(ElementPanel) getPanelIngredients().getComponent(1);
+		newElement.getTxtName().setText("Bacon");
+		waitForSwing();
+
+		ObserverDispatch.notifySubscribers(elements.get(1));
+		
+		verify(listener, times(2)).updateWasSignalled();
+	}
+
+	@Test
+	void testReceivesSignalWhenElementRemoved() {
+		final ElementPanel oldElement =
+				(ElementPanel) getPanelIngredients().getComponent(0);
+		oldElement.getTxtName().setText("");
+		waitForSwing();
+
+		verify(listener, times(1)).updateWasSignalled();
+	}
+
+	@Test
+	void testIgnoresOldItemUpdates() {
+		final Element elem = elements.get(0);
+		final ElementPanel oldElement =
+				(ElementPanel) getPanelIngredients().getComponent(0);
+		oldElement.getTxtName().setText("");
+
+		waitForSwing();
+		clearInvocations(listener);
+
+		ObserverDispatch.notifySubscribers(elem);
+		verify(listener, never()).updateWasSignalled();
+	}
+
+}

+ 23 - 28
src/test/java/org/leumasjaffe/recipe/view/RecipeCardPanelTest.java

@@ -2,10 +2,9 @@ package org.leumasjaffe.recipe.view;
 
 import static org.mockito.Mockito.*;
 
-import java.awt.Component;
+import java.util.ArrayList;
 import java.util.Arrays;
-
-import javax.swing.JPanel;
+import java.util.List;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -23,45 +22,41 @@ import org.mockito.junit.jupiter.MockitoExtension;
 @ExtendWith(MockitoExtension.class)
 class RecipeCardPanelTest {
 	
-	@Spy MockObserverListener listener;
-	
+	List<Element> elements;
+	RecipeCard stuff;
+
 	@Mock SummaryPanel summaryPanel;
-	@Mock JPanel rightPanel;
-	@Spy RecipeCard card;
+	@Spy AutoGrowPanel<ElementPanel, Element> panelElements =
+			new AutoGrowPanel<>(Element::new, ElementPanel::new);
+	
 	@InjectMocks RecipeCardPanel panel = new RecipeCardPanel();
 	
 	@BeforeEach
 	void setUp() {
-		listener.setObserved(card);
-		clearInvocations(listener);
-	}
+		elements = new ArrayList<>(Arrays.asList(new Element()));
+		stuff = new RecipeCard();
+		stuff.setTitle("Peanut Curry");
+		stuff.setElements(elements);
+		stuff.setDescription("I am delicious");
 
-	@Test
-	void testModelIsPropogated() {
-		panel.setModel(card);
-		verify(summaryPanel).setModel(same(card));
-		verify(rightPanel, never()).add(any(Component.class));
+		panel.setModel(stuff);
 	}
 
 	@Test
-	void testModelWithChildrenAddsElements() {
-		final Element element = new Element();
-		doReturn(Arrays.asList(element)).when(card).getElements();
-
-		panel.setModel(card);
-		verify(rightPanel, times(1)).add(any(Component.class));
+	void testFilledOutWithContent() {
+		verify(summaryPanel).setModel(same(stuff));
+		verify(panelElements).setModel(any(), any());
 	}
 
 	@Test
-	void testToChildElementsIsPropogated() {
-		final Element element = new Element();
-		doReturn(Arrays.asList(element)).when(card).getElements();
+	void testPropogatesNotifications() {
+		final MockObserverListener listener = spy(MockObserverListener.class);
+		listener.setObserved(stuff);
+		// setObserved invokes our callback.
+		clearInvocations(listener);
 
-		panel.setModel(card);
+		ObserverDispatch.notifySubscribers(elements.get(0));
 		verify(listener).updateWasSignalled();
-		
-		ObserverDispatch.notifySubscribers(element);
-		verify(listener, times(2)).updateWasSignalled();
 	}
 
 }