Parcourir la source

Merge branch 'refactor/better-shrink'

* refactor/better-shrink:
  Fix test cases for AutoGrow panels
  Change the ShrinkOnEmpty listener to use a FocusListener.
Sam Jaffe il y a 5 ans
Parent
commit
0e86b3ee7c

+ 17 - 13
src/main/lombok/org/leumasjaffe/recipe/view/AutoGrowPanel.java

@@ -1,6 +1,8 @@
 package org.leumasjaffe.recipe.view;
 
 import java.awt.Component;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Consumer;
@@ -10,6 +12,7 @@ import java.util.function.Supplier;
 import javax.swing.JPanel;
 import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
+import javax.swing.text.JTextComponent;
 
 import org.jdesktop.swingx.VerticalLayout;
 
@@ -31,8 +34,10 @@ public class AutoGrowPanel<C extends Component & AutoGrowPanel.ChildComponent, T
 	private static interface SetGap { void setGap(int gap); }
 
 	public static interface ChildComponent {
-		void addGrowShrinkListener(DocumentListener dl);
-		void removeGrowShrinkListener(DocumentListener dl);
+		void addGrowListener(DocumentListener dl);
+		void removeGrowListener(DocumentListener dl);
+		void addShrinkListener(FocusListener fl);
+		void removeShrinkListener(FocusListener fl);
 		default void setListPosition(int zeroIndex) {}
 	}
 	
@@ -50,8 +55,8 @@ public class AutoGrowPanel<C extends Component & AutoGrowPanel.ChildComponent, T
 		public void insertUpdate(DocumentEvent e) {
 			if (model != null) {
 				models.add(model);
-				last().removeGrowShrinkListener(this);
-				last().addGrowShrinkListener(new ShrinkOnEmpty(last()));
+				last().removeGrowListener(this);
+				last().addShrinkListener(new ShrinkOnEmpty(last()));
 			}
 			
 			model = makeEmptyModel.get();
@@ -59,28 +64,27 @@ public class AutoGrowPanel<C extends Component & AutoGrowPanel.ChildComponent, T
 
 			members.add(comp);
 			add(comp);
-			comp.addGrowShrinkListener(this);
+			comp.addGrowListener(this);
 			comp.setListPosition(lastIndex());
 			revalidate();
 			callback.accept(true);
-		}		
+		}
 	}
 	
 	@AllArgsConstructor
-	private class ShrinkOnEmpty implements DocumentListener {
+	private class ShrinkOnEmpty implements FocusListener {
 		C component;
 		
-		@Override public void insertUpdate(DocumentEvent e) {}
-		@Override public void changedUpdate(DocumentEvent e) {}
+		@Override public void focusGained(FocusEvent e) {}
 
 		@Override
-		public void removeUpdate(DocumentEvent e) {
-			if (e.getDocument().getLength() > 0) {
+		public void focusLost(FocusEvent e) {
+			if (!((JTextComponent) e.getComponent()).getText().isEmpty()) {
 				return;
 			}
 			
 			component.setVisible(false);
-			component.removeGrowShrinkListener(this);
+			component.removeShrinkListener(this);
 			remove(members.indexOf(component));
 			callback.accept(false);
 		}
@@ -135,7 +139,7 @@ public class AutoGrowPanel<C extends Component & AutoGrowPanel.ChildComponent, T
 		this.members.subList(0, lastIndex()).clear();
 		models.forEach(model -> {
 			final C comp = this.grow.makeComponent.apply(model);
-			comp.addGrowShrinkListener(new ShrinkOnEmpty(comp));
+			comp.addShrinkListener(new ShrinkOnEmpty(comp));
 			add(comp, lastIndex());
 			comp.setListPosition(lastIndex());
 			this.members.add(lastIndex(), comp);

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

@@ -25,6 +25,7 @@ import javax.swing.event.DocumentListener;
 import java.awt.GridBagLayout;
 import java.awt.GridBagConstraints;
 import java.awt.Insets;
+import java.awt.event.FocusListener;
 import java.awt.Component;
 import java.awt.Dimension;
 
@@ -129,13 +130,23 @@ public class ElementPanel extends JScrollPane implements AutoGrowPanel.ChildComp
 	}
 
 	@Override
-	public void addGrowShrinkListener(DocumentListener dl) {
+	public void addGrowListener(DocumentListener dl) {
 		this.txtName.getDocument().addDocumentListener(dl);
 	}
 
 	@Override
-	public void removeGrowShrinkListener(DocumentListener dl) {
+	public void removeGrowListener(DocumentListener dl) {
 		this.txtName.getDocument().removeDocumentListener(dl);
 	}
+
+	@Override
+	public void addShrinkListener(FocusListener fl) {
+		this.txtName.addFocusListener(fl);
+	}
+
+	@Override
+	public void removeShrinkListener(FocusListener fl) {
+		this.txtName.removeFocusListener(fl);
+	}
 	
 }

+ 13 - 2
src/main/lombok/org/leumasjaffe/recipe/view/IngredientPanel.java

@@ -5,6 +5,7 @@ import java.awt.GridBagLayout;
 import javax.swing.JTextField;
 import java.awt.GridBagConstraints;
 import java.awt.Insets;
+import java.awt.event.FocusListener;
 
 import javax.swing.event.DocumentListener;
 
@@ -108,13 +109,23 @@ public class IngredientPanel extends JPanel implements AutoGrowPanel.ChildCompon
 	}
 
 	@Override
-	public void addGrowShrinkListener(DocumentListener dl) {
+	public void addGrowListener(DocumentListener dl) {
 		this.txtName.getDocument().addDocumentListener(dl);
 	}
 
 	@Override
-	public void removeGrowShrinkListener(DocumentListener dl) {
+	public void removeGrowListener(DocumentListener dl) {
 		this.txtName.getDocument().removeDocumentListener(dl);
 	}
 
+	@Override
+	public void addShrinkListener(FocusListener fl) {
+		this.txtName.addFocusListener(fl);
+	}
+
+	@Override
+	public void removeShrinkListener(FocusListener fl) {
+		this.txtName.removeFocusListener(fl);
+	}
+
 }

+ 13 - 2
src/main/lombok/org/leumasjaffe/recipe/view/StepPanel.java

@@ -19,6 +19,7 @@ import java.awt.GridBagLayout;
 
 import java.awt.GridBagConstraints;
 import java.awt.Insets;
+import java.awt.event.FocusListener;
 
 import javax.swing.JLabel;
 import javax.swing.JTextPane;
@@ -139,12 +140,22 @@ public class StepPanel extends JPanel implements AutoGrowPanel.ChildComponent {
 	}
 
 	@Override
-	public void addGrowShrinkListener(DocumentListener dl) {
+	public void addGrowListener(DocumentListener dl) {
 		this.txtpnInstructions.getDocument().addDocumentListener(dl);
 	}
 
 	@Override
-	public void removeGrowShrinkListener(DocumentListener dl) {
+	public void removeGrowListener(DocumentListener dl) {
 		this.txtpnInstructions.getDocument().removeDocumentListener(dl);		
 	}
+
+	@Override
+	public void addShrinkListener(FocusListener fl) {
+		this.txtpnInstructions.addFocusListener(fl);
+	}
+
+	@Override
+	public void removeShrinkListener(FocusListener fl) {
+		this.txtpnInstructions.removeFocusListener(fl);
+	}
 }

+ 26 - 0
src/test/java/org/leumasjaffe/mock/ListenerInjector.java

@@ -0,0 +1,26 @@
+package org.leumasjaffe.mock;
+
+import java.awt.Component;
+import java.awt.event.FocusEvent;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+public abstract class ListenerInjector {
+	private ListenerInjector() {}
+	
+	private static final Supplier<IllegalStateException> noMatch(final String expected) {
+		return () -> new IllegalStateException("No listener whose classname is: " + expected);
+	}
+	
+	private static final <C> Predicate<C> classNameIs(final String name) {
+		return obj -> obj.getClass().getSimpleName().equals(name);
+	}
+
+	public static final <C extends Component> void injectFocusLost(
+			final C context, final String toListenerClass) {
+		Stream.of(context.getFocusListeners()).filter(classNameIs(toListenerClass))
+			.findFirst().orElseThrow(noMatch(toListenerClass))
+			.focusLost(new FocusEvent(context, FocusEvent.FOCUS_LOST));
+	}
+}

+ 22 - 7
src/test/java/org/leumasjaffe/recipe/view/AutoGrowPanelTest.java

@@ -3,7 +3,9 @@ package org.leumasjaffe.recipe.view;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.collection.IsArrayWithSize.arrayWithSize;
 import static org.mockito.Mockito.*;
+import static org.leumasjaffe.mock.ListenerInjector.*;
 
+import java.awt.event.FocusListener;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -32,14 +34,24 @@ class AutoGrowPanelTest extends SwingTestCase {
 		}
 
 		@Override
-		public void addGrowShrinkListener(DocumentListener dl) {
+		public void addGrowListener(DocumentListener dl) {
 			super.getDocument().addDocumentListener(dl);
 		}
 
 		@Override
-		public void removeGrowShrinkListener(DocumentListener dl) {
+		public void removeGrowListener(DocumentListener dl) {
 			super.getDocument().removeDocumentListener(dl);
 		}
+
+		@Override
+		public void addShrinkListener(FocusListener fl) {
+			super.addFocusListener(fl);
+		}
+
+		@Override
+		public void removeShrinkListener(FocusListener fl) {
+			super.removeFocusListener(fl);
+		}
 	}
 	
 	@Mock Consumer<Boolean> callback;
@@ -140,27 +152,29 @@ class AutoGrowPanelTest extends SwingTestCase {
 	}
 
 	@Test
-	void testEmptyingContentClearsPanel() {
+	void testLosingFocusWithoutContentClearsPanel() {
 		final MockComponent mock = spy(new MockComponent("A"));
 		
 		AutoGrowPanel<MockComponent, MockComponent> panel = create(mock);
 		getTestFrame().add(panel);
 		mock.setText("");
-		
+		injectFocusLost(mock, "ShrinkOnEmpty");
+
 		assertThat(panel.getComponents(), arrayWithSize(1));
 		verify(shared, times(1)).remove(0);
 	}
 
 
 	@Test
-	void testEmptyingContentAdjustsAllPositions() {
+	void testLosingFocusWithoutContentAdjustsAllPositions() {
 		final MockComponent mock = spy(new MockComponent("A"));
 		
 		@SuppressWarnings("unused")
 		AutoGrowPanel<MockComponent, MockComponent> panel = create(mock);
 		
 		mock.setText("");
-		
+		injectFocusLost(mock, "ShrinkOnEmpty");
+	
 		verify(internal.get(0), times(2)).setListPosition(0);
 	}
 
@@ -182,7 +196,7 @@ class AutoGrowPanelTest extends SwingTestCase {
 		
 		AutoGrowPanel<MockComponent, MockComponent> panel = create(mock);
 		getTestFrame().add(panel);
-		mock.getDocument().insertString(0, "B", null);
+		mock.setText("B");
 		
 		assertThat(panel.getComponents(), arrayWithSize(2));
 		verify(shared, never()).remove(anyInt());
@@ -199,6 +213,7 @@ class AutoGrowPanelTest extends SwingTestCase {
 		verify(callback).accept(true);
 
 		internal.get(0).setText("");
+		injectFocusLost(internal.get(0), "ShrinkOnEmpty");
 		verify(callback).accept(false);
 	}
 	

+ 3 - 2
src/test/java/org/leumasjaffe/recipe/view/PhasePanelIT.java

@@ -1,5 +1,6 @@
 package org.leumasjaffe.recipe.view;
 
+import static org.leumasjaffe.mock.ListenerInjector.injectFocusLost;
 import static org.mockito.Mockito.*;
 
 import java.util.ArrayList;
@@ -64,7 +65,7 @@ class PhasePanelIT extends SwingTestCase {
 		final StepPanel oldIngredient =
 				(StepPanel) panel.getPanelSteps().getComponent(0);
 		oldIngredient.getTxtpnInstructions().setText("");
-		waitForSwing();
+		injectFocusLost(oldIngredient.getTxtpnInstructions(), "ShrinkOnEmpty");
 
 		verify(listener, times(1)).updateWasSignalled();
 	}
@@ -75,8 +76,8 @@ class PhasePanelIT extends SwingTestCase {
 		final StepPanel oldIngredient =
 				(StepPanel) panel.getPanelSteps().getComponent(0);
 		oldIngredient.getTxtpnInstructions().setText("");
+		injectFocusLost(oldIngredient.getTxtpnInstructions(), "ShrinkOnEmpty");
 
-		waitForSwing();
 		clearInvocations(listener);
 
 		ObserverDispatch.notifySubscribers(st);

+ 3 - 2
src/test/java/org/leumasjaffe/recipe/view/RecipeCardPanelIT.java

@@ -1,5 +1,6 @@
 package org.leumasjaffe.recipe.view;
 
+import static org.leumasjaffe.mock.ListenerInjector.injectFocusLost;
 import static org.mockito.Mockito.*;
 
 import java.util.ArrayList;
@@ -72,7 +73,7 @@ class RecipeCardPanelIT extends SwingTestCase {
 		final ElementPanel oldElement =
 				(ElementPanel) getPanelIngredients().getComponent(0);
 		oldElement.getTxtName().setText("");
-		waitForSwing();
+		injectFocusLost(oldElement.getTxtName(), "ShrinkOnEmpty");
 
 		verify(listener, times(1)).updateWasSignalled();
 	}
@@ -83,8 +84,8 @@ class RecipeCardPanelIT extends SwingTestCase {
 		final ElementPanel oldElement =
 				(ElementPanel) getPanelIngredients().getComponent(0);
 		oldElement.getTxtName().setText("");
+		injectFocusLost(oldElement.getTxtName(), "ShrinkOnEmpty");
 
-		waitForSwing();
 		clearInvocations(listener);
 
 		ObserverDispatch.notifySubscribers(elem);

+ 3 - 2
src/test/java/org/leumasjaffe/recipe/view/StepPanelIT.java

@@ -1,5 +1,6 @@
 package org.leumasjaffe.recipe.view;
 
+import static org.leumasjaffe.mock.ListenerInjector.injectFocusLost;
 import static org.mockito.Mockito.*;
 
 import java.util.ArrayList;
@@ -72,7 +73,7 @@ class StepPanelIT extends SwingTestCase {
 		final IngredientPanel oldIngredient =
 				(IngredientPanel) getPanelIngredients().getComponent(0);
 		oldIngredient.getTxtName().setText("");
-		waitForSwing();
+		injectFocusLost(oldIngredient.getTxtName(), "ShrinkOnEmpty");
 
 		verify(listener, times(1)).updateWasSignalled();
 	}
@@ -83,8 +84,8 @@ class StepPanelIT extends SwingTestCase {
 		final IngredientPanel oldIngredient =
 				(IngredientPanel) getPanelIngredients().getComponent(0);
 		oldIngredient.getTxtName().setText("");
+		injectFocusLost(oldIngredient.getTxtName(), "ShrinkOnEmpty");
 
-		waitForSwing();
 		clearInvocations(listener);
 
 		ObserverDispatch.notifySubscribers(ing);