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; import javax.swing.JPanel; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.jdesktop.swingx.VerticalLayout; import org.leumasjaffe.event.AnyActionDocumentListener; import lombok.AllArgsConstructor; @SuppressWarnings("serial") public class AutoGrowPanel extends JPanel { public static interface DocumentListenable { void addDocumentListener(DocumentListener dl); void removeDocumentListener(DocumentListener dl); default void setListPosition(int zeroIndex) {} } @AllArgsConstructor private class DeleteOnEmpty implements AnyActionDocumentListener { DocumentListenable content; @Override public void update(DocumentEvent e) { if (e.getDocument().getLength() == 0) { content.removeDocumentListener(this); int index = members.indexOf(content); onDelete.accept(index); for (final int size = members.size(); index < size; ++index) { members.get(index).setListPosition(index); } remove((Component) content); validateNthParent(4); } } } @AllArgsConstructor private class ExtendAction implements AnyActionDocumentListener { final Function factory; final Consumer previous; final Supplier next; T current = null; @Override public void update(DocumentEvent e) { 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); validateNthParent(4); } } IntFunction prod; AnyActionDocumentListener grow; IntConsumer onDelete; List members = new ArrayList<>(); @SafeVarargs public AutoGrowPanel(Function function, Supplier newItem, Consumer onData, IntConsumer onDelete, T...ts) { setLayout(new VerticalLayout(5)); T next = newItem.get(); this.onDelete = onDelete; this.grow = new ExtendAction(function, onData, newItem, next); for (T value : ts) { C listen = function.apply(value); members.add(listen); add(listen); listen.addDocumentListener(new DeleteOnEmpty(listen)); } C empty = function.apply(next); members.add(empty); add(empty); empty.addDocumentListener(this.grow); } private DocumentListenable getBack() { return members.get(members.size() - 1); } private void validateNthParent(int i) { Component current = getParent(); Component next = current; while (i --> 0 && next != null) { current = next; next = current.getParent(); } current.validate(); } }