浏览代码

Create new AutoGrowPanel that will handle models correctly.

Sam Jaffe 5 年之前
父节点
当前提交
1482694bb2

+ 60 - 7
src/main/lombok/org/leumasjaffe/recipe/view/AutoGrowPanel.java

@@ -3,6 +3,7 @@ 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.IntFunction;
 import java.util.function.Supplier;
@@ -15,6 +16,7 @@ import org.jdesktop.swingx.VerticalLayout;
 import org.leumasjaffe.event.AnyActionDocumentListener;
 
 import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
 
 @SuppressWarnings("serial")
 public class AutoGrowPanel extends JPanel {
@@ -44,14 +46,43 @@ public class AutoGrowPanel extends JPanel {
 	private class GrowAction implements AnyActionDocumentListener {
 		@Override
 		public void update(DocumentEvent e) {
-			getBack().removeDocumentListener(this);
-			getBack().addDocumentListener(new DeleteOnEmpty(getBack()));
+			final DocumentListenable back = getBack();
+			back.removeDocumentListener(this);
+			back.addDocumentListener(new DeleteOnEmpty(back));
 			extend();
 			getBack().addDocumentListener(this);
 			getParent().getParent().validate();
 		}
 	}
 	
+	@RequiredArgsConstructor
+	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) {
+			if (current != null) {
+				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;
 	List<DocumentListenable> members = new ArrayList<>();
@@ -77,15 +108,37 @@ public class AutoGrowPanel extends JPanel {
 		getBack().addDocumentListener(grow);
 	}
 
-	public <T> AutoGrowPanel(Function<T, DocumentListenable> function, List<T> ingredients) {
-		this(i -> function.apply(ingredients.get(i)), ingredients.size());
+	public <T> AutoGrowPanel(Function<T, DocumentListenable> function, List<T> list) {
+		this(i -> list.size() > i ? function.apply(list.get(i)) : null, list.size());
+	}
+	
+	@SafeVarargs
+	public <T, C extends Component & DocumentListenable> AutoGrowPanel(Function<T, C> function,
+			Supplier<T> newItem, Consumer<? super T> onData, Consumer<Integer> onDelete, T...ts) {
+		setLayout(new VerticalLayout(5));
+		
+		this.grow = new ExtendAction<T, C>(function, onData, newItem);
 		
+		for (T value : ts) {
+			C listen = function.apply(value);
+			members.add(listen);
+			add(listen);
+			listen.addDocumentListener(new DeleteOnEmpty(listen));
+		}
+		
+		T next = newItem.get();
+		C empty = function.apply(next);
+		members.add(empty);
+		add(empty);
+		empty.addDocumentListener(this.grow);
 	}
 
 	private void extend() {
-		members.add(prod.apply(members.size()));
-		add((Component) getBack());
-		getBack().addDocumentListener(grow);
+		DocumentListenable value = prod.apply(members.size());
+		if (value != null) {
+			members.add(value);
+			add((Component) getBack());
+		}
 	}
 
 	private DocumentListenable getBack() {

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

@@ -4,6 +4,9 @@ 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 javax.swing.JTextField;
 import javax.swing.event.DocumentListener;
 import javax.swing.text.BadLocationException;
@@ -38,80 +41,62 @@ class AutoGrowPanelTest extends SwingTestCase {
 		}
 	}
 	
-	@Test
-	void testAlwaysHasAtLeastOneComponent() {
-		final MockComponent wrapper = spy(new MockComponent());
-		
-		AutoGrowPanel panel = new AutoGrowPanel(() -> wrapper);
-		
-		assertThat(panel.getComponents(), arrayWithSize(1));
+	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,
+				m -> {}, i -> {}, 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));
 	}
 
 	@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));
 	}
 
 	@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));
 	}
 
 	@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(components.get(0), never()).removeDocumentListener(any());
 	}
 
 	@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));
 	}
@@ -119,14 +104,11 @@ class AutoGrowPanelTest extends SwingTestCase {
 
 	@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));
 	}