Selaa lähdekoodia

Merge branch 'refactor/autoGrowPanel/growModel'

* refactor/autoGrowPanel/growModel:
  Fix deleting an ingredient not propagating.
  Fix onDelete not being used.
  Remove old code from AutoGrowPanel
  Update StepPanel to use the new AutoGrowPanel features.
  Create new AutoGrowPanel that will handle models correctly.
  Fix regression
Sam Jaffe 5 vuotta sitten
vanhempi
commit
19316d62b6

+ 2 - 0
src/main/lombok/org/leumasjaffe/recipe/model/Duration.java

@@ -2,12 +2,14 @@ package org.leumasjaffe.recipe.model;
 
 import lombok.AccessLevel;
 import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
 
 @AllArgsConstructor @NoArgsConstructor
 @Getter(AccessLevel.PACKAGE) @Setter(AccessLevel.PRIVATE)
+@EqualsAndHashCode
 public class Duration {
 	@AllArgsConstructor
 	public enum Display {

+ 2 - 2
src/main/lombok/org/leumasjaffe/recipe/model/Ingredient.java

@@ -9,9 +9,9 @@ import lombok.NoArgsConstructor;
 
 @Data @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode(callSuper=false)
 public class Ingredient extends Observable.Instance {
-	String name;
+	String name = "";
 	String preparation = "";
-	Amount amount;
+	Amount amount = new Amount("1");
 	
 	boolean hasPreparation() {
 		return preparation != null && !preparation.isEmpty();

+ 41 - 33
src/main/lombok/org/leumasjaffe/recipe/view/AutoGrowPanel.java

@@ -3,7 +3,9 @@ package org.leumasjaffe.recipe.view;
 import java.awt.Component;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.IntConsumer;
 import java.util.function.IntFunction;
 import java.util.function.Supplier;
 
@@ -31,7 +33,7 @@ public class AutoGrowPanel extends JPanel {
 			if (e.getDocument().getLength() == 0) {
 				content.removeDocumentListener(this);
 				int index = members.indexOf(content);
-				members.remove(index);
+				onDelete.accept(index);
 				for (final int size = members.size(); index < size; ++index) {
 					members.get(index).setListPosition(index);
 				}
@@ -41,51 +43,57 @@ public class AutoGrowPanel extends JPanel {
 		}
 	}
 	
-	private class GrowAction implements AnyActionDocumentListener {
+	@AllArgsConstructor
+	private class ExtendAction<T, C extends Component & DocumentListenable> implements AnyActionDocumentListener {
+		final Function<T, C> factory;
+		final Consumer<? super T> previous;
+		final Supplier<? extends T> next;
+		T current = null;
+
 		@Override
 		public void update(DocumentEvent e) {
-			getBack().removeDocumentListener(this);
-			getBack().addDocumentListener(new DeleteOnEmpty(getBack()));
-			extend();
-			getBack().addDocumentListener(this);
+			previous.accept(current);
+			
+			final C object = factory.apply(current = next.get());
+			final DocumentListenable back = getBack();
+			
+			back.removeDocumentListener(this);
+			back.addDocumentListener(new DeleteOnEmpty(back));			
+			object.addDocumentListener(this);
+			
+			members.add(object);
+			add(object);
+
 			getParent().getParent().validate();
 		}
+		
 	}
 	
 	IntFunction<DocumentListenable> prod;
 	AnyActionDocumentListener grow;
+	IntConsumer onDelete;
 	List<DocumentListenable> members = new ArrayList<>();
 	
-	/**
-	 * @wbp.parser.constructor
-	 */
-	public AutoGrowPanel(Supplier<DocumentListenable> prod) {
-		this(i -> prod.get(), 1);
-	}
-	
-	public AutoGrowPanel(IntFunction<DocumentListenable> prod, int create) {
-		this.prod = prod;
-		this.grow = new GrowAction();
-
+	@SafeVarargs
+	public <T, C extends Component & DocumentListenable> AutoGrowPanel(Function<T, C> function,
+			Supplier<T> newItem, Consumer<? super T> onData, IntConsumer onDelete, T...ts) {
 		setLayout(new VerticalLayout(5));
-		if (create == 0) return; // TODO
-		while (create-- > 1) {
-			extend();
-			getBack().addDocumentListener(new DeleteOnEmpty(getBack()));
+		
+		T next = newItem.get();
+		this.onDelete = onDelete;
+		this.grow = new ExtendAction<T, C>(function, onData, newItem, next);
+		
+		for (T value : ts) {
+			C listen = function.apply(value);
+			members.add(listen);
+			add(listen);
+			listen.addDocumentListener(new DeleteOnEmpty(listen));
 		}
-		extend();
-		getBack().addDocumentListener(grow);
-	}
-
-	public <T> AutoGrowPanel(Function<T, DocumentListenable> function, List<T> ingredients) {
-		this(i -> function.apply(ingredients.get(i)), ingredients.size());
 		
-	}
-
-	private void extend() {
-		members.add(prod.apply(members.size()));
-		add((Component) getBack());
-		getBack().addDocumentListener(grow);
+		C empty = function.apply(next);
+		members.add(empty);
+		add(empty);
+		empty.addDocumentListener(this.grow);
 	}
 
 	private DocumentListenable getBack() {

+ 8 - 1
src/main/lombok/org/leumasjaffe/recipe/view/StepPanel.java

@@ -5,6 +5,7 @@ import javax.swing.event.DocumentListener;
 
 import org.leumasjaffe.observer.ForwardingObservableListener;
 import org.leumasjaffe.observer.ObserverDispatch;
+import org.leumasjaffe.recipe.model.Ingredient;
 import org.leumasjaffe.recipe.model.Step;
 
 import lombok.AccessLevel;
@@ -15,6 +16,7 @@ import java.awt.GridBagLayout;
 
 import java.awt.GridBagConstraints;
 import java.awt.Insets;
+import java.util.List;
 
 import javax.swing.JLabel;
 import javax.swing.JTextPane;
@@ -75,7 +77,12 @@ public class StepPanel extends JPanel implements AutoGrowPanel.DocumentListenabl
 		gbc_lblDuration.gridy = 0;
 		panelLeft.add(lblDuration, gbc_lblDuration);
 		
-		panelIngredients = new AutoGrowPanel(IngredientPanel::new, step.getIngredients());
+		final List<Ingredient> ingredients = step.getIngredients();
+		panelIngredients = new AutoGrowPanel(IngredientPanel::new,
+				Ingredient::new, ingredients::add, i -> {
+					ingredients.remove((int) i);
+					ObserverDispatch.notifySubscribers(step);
+				}, ingredients.toArray(new Ingredient[0]));
 		GridBagConstraints gbc_panelIngredients = new GridBagConstraints();
 		gbc_panelIngredients.gridwidth = 3;
 		gbc_panelIngredients.insets = new Insets(0, 0, 0, 5);

+ 45 - 53
src/test/java/org/leumasjaffe/recipe/view/AutoGrowPanelTest.java

@@ -4,6 +4,11 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.collection.IsArrayWithSize.arrayWithSize;
 import static org.mockito.Mockito.*;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.IntConsumer;
+
 import javax.swing.JTextField;
 import javax.swing.event.DocumentListener;
 import javax.swing.text.BadLocationException;
@@ -13,6 +18,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.platform.runner.JUnitPlatform;
 import org.junit.runner.RunWith;
 import org.leumasjaffe.recipe.view.AutoGrowPanel.DocumentListenable;
+import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 @ExtendWith(MockitoExtension.class)
@@ -38,96 +44,82 @@ class AutoGrowPanelTest extends SwingTestCase {
 		}
 	}
 	
-	@Test
-	void testAlwaysHasAtLeastOneComponent() {
-		final MockComponent wrapper = spy(new MockComponent());
-		
-		AutoGrowPanel panel = new AutoGrowPanel(() -> wrapper);
-		
-		assertThat(panel.getComponents(), arrayWithSize(1));
+	@Mock Consumer<MockComponent> add;
+	@Mock IntConsumer remove;
+	List<MockComponent> components = new ArrayList<>();
+	
+	private MockComponent mocked() {
+		final MockComponent mock = spy(new MockComponent());
+		components.add(mock);
+		return mock;
 	}
-
+	
+	private AutoGrowPanel create(MockComponent... mocks) {
+		return new AutoGrowPanel(m -> m, this::mocked, add, remove, mocks);
+	}
+	
 	@Test
-	void testInputParamIsZeroIndex() {
-		final MockComponent[] wrapper = {
-				spy(new MockComponent()),
-				spy(new MockComponent())
-		};
+	void testAlwaysHasAtLeastOneComponent() {		
+		AutoGrowPanel panel = create();
 		
-		AutoGrowPanel panel = new AutoGrowPanel((i) -> wrapper[i], 1);
-
-		verify(wrapper[0]).addDocumentListener(any());
-		verify(wrapper[1], never()).addDocumentListener(any());
 		assertThat(panel.getComponents(), arrayWithSize(1));
+		verify(add, never()).accept(any());
 	}
 
 	@Test
-	void testCreatesGivenNumberOfChildren() {
-		final MockComponent[] wrapper = {
-				spy(new MockComponent()),
-				spy(new MockComponent())
-		};
-		
-		AutoGrowPanel panel = new AutoGrowPanel((i) -> wrapper[i], 2);
+	void testCreatesGivenNumberOfChildrenPlusOne() {
+		AutoGrowPanel panel = create(mocked(), mocked());
 
-		assertThat(panel.getComponents(), arrayWithSize(2));
+		assertThat(panel.getComponents(), arrayWithSize(3));
+		verify(add, never()).accept(any());
 	}
 
 	@Test
 	void testEnteringContentTriggersNewRow() {
-		final MockComponent[] wrapper = {
-				spy(new MockComponent()),
-				spy(new MockComponent())
-		};
-		
-		AutoGrowPanel panel = new AutoGrowPanel((i) -> wrapper[i], 1);
+		AutoGrowPanel panel = create();
 		getTestFrame().add(panel);
-		wrapper[0].setText("A");
-		
+
+		components.get(0).setText("A");
 		assertThat(panel.getComponents(), arrayWithSize(2));
+		
+		components.get(1).setText("B");
+		assertThat(panel.getComponents(), arrayWithSize(3));
+		verify(add, times(2)).accept(any());
 	}
 
 	@Test
 	void testEnteringEmptyContentDoesNotTrigger() {
-		final MockComponent[] wrapper = {
-				spy(new MockComponent()),
-				spy(new MockComponent())
-		};
-		
-		AutoGrowPanel panel = new AutoGrowPanel((i) -> wrapper[i], 1);
+		AutoGrowPanel panel = create();
 		getTestFrame().add(panel);
-		wrapper[0].setText("");
+		components.get(0).setText("");
 		
 		assertThat(panel.getComponents(), arrayWithSize(1));
-		verify(wrapper[0], never()).removeDocumentListener(any());
+		verify(add, never()).accept(any());
+		verify(remove, never()).accept(anyInt());
 	}
 
 	@Test
 	void testEmptyingContentClearsPanel() {
-		final MockComponent[] wrapper = {
-				spy(new MockComponent("A")),
-				spy(new MockComponent())
-		};
+		final MockComponent mock = spy(new MockComponent("A"));
 		
-		AutoGrowPanel panel = new AutoGrowPanel((i) -> wrapper[i], 2);
+		AutoGrowPanel panel = create(mock);
 		getTestFrame().add(panel);
-		wrapper[0].setText("");
+		mock.setText("");
 		
 		assertThat(panel.getComponents(), arrayWithSize(1));
+		verify(remove, times(1)).accept(0);
 	}
 
 
 	@Test
 	void testChangingTextDoesNotDeleteRow() throws BadLocationException {
-		final MockComponent[] wrapper = {
-				spy(new MockComponent("A")),
-				spy(new MockComponent())
-		};
+		final MockComponent mock = spy(new MockComponent("A"));
 		
-		AutoGrowPanel panel = new AutoGrowPanel((i) -> wrapper[i], 2);
+		AutoGrowPanel panel = create(mock);
 		getTestFrame().add(panel);
-		wrapper[0].getDocument().insertString(0, "B", null);
+		mock.getDocument().insertString(0, "B", null);
 		
 		assertThat(panel.getComponents(), arrayWithSize(2));
+		verify(remove, never()).accept(anyInt());
 	}
 }

+ 2 - 1
src/test/java/org/leumasjaffe/recipe/view/StepPanelTest.java

@@ -3,6 +3,7 @@ package org.leumasjaffe.recipe.view;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.collection.IsArrayWithSize.arrayWithSize;
+import static org.hamcrest.number.OrderingComparison.greaterThanOrEqualTo;
 import static org.hamcrest.core.StringContains.containsString;
 import static org.mockito.Mockito.*;
 
@@ -51,7 +52,7 @@ class StepPanelTest extends SwingTestCase {
 				containsString(dur.toString()));
 		assertEquals("These are test instructions", panel.getTxtpnInstructions().getText());
 		assertThat(panel.getPanelIngredients().getComponents(),
-				arrayWithSize(1));
+				arrayWithSize(greaterThanOrEqualTo(1)));
 	}
 
 }