package com.kartoflane.superluminal2.ui; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import com.kartoflane.superluminal2.components.interfaces.Predicate; import com.kartoflane.superluminal2.utils.UIUtils; /** * A general search dialog framework. Allows to construct a filter for the specified type.<br> * <br> * Child classes should only call the {@link #AbstractSearchDialog(Shell)} constructor, and use {@link #createContents(Shell)} to create their * widgets.<br> * After instantiation, the dialog has to be opened using {@link #open()} - this method blocks until the user dismisses the dialog.<br> * <br> * Whenever the dialog is dismissed, {@link #dispose()} has to be called, preceded by one of the following methods to set the result:<br> * - {@link #setResultCurrent()} to construct a new filter using values selected by the user.<br> * - {@link #setResultDefault()} to return a constant indicating that the default filter should be used.<br> * - {@link #setResultUnchanged()} to return a constant indicating that the previous filter should be used. * * @author kartoFlane * * @param <T> * the type of objects that this dialog filters */ public abstract class AbstractSearchDialog<T> { /** * Indicates that the default filter should be used. */ public static final Predicate<?> RESULT_DEFAULT = new Predicate<Object>() { public boolean accept(Object object) { return false; } }; /** * Indicates that no changes should be made to the filter as a result of this dialog. */ public static final Predicate<?> RESULT_UNCHANGED = new Predicate<Object>() { public boolean accept(Object object) { return false; } }; private Predicate<?> result = RESULT_DEFAULT; protected Shell shell = null; /** * Child classes should always call this constructor. * * @param parent * parent of this dialog * @throws IllegalStateException * if the shell is null (must be used for {@link #open()} to work) */ public AbstractSearchDialog(Shell parent) { createContents(parent); if (shell == null) throw new IllegalStateException("Shell must be instantiated!"); } /** * Create contents for this search dialog, as well as listeners governing how the UI widgets behave.<br> * Widgets should modify variables, thereby changing the kind of predicate returned by {@link #getFilter()}. * * @param parent * parent of this dialog */ public abstract void createContents(Shell parent); /** * @return the predicate that is used as filter, ie. result of the dialog */ protected abstract Predicate<T> getFilter(); /** * Sets the result of the dialog to a newly constructed filter, based on parameters selected in the dialog. */ protected final void setResultCurrent() { result = getFilter(); } /** * Sets the result of the dialog to a constant indicating that the default filter is to be used. */ protected final void setResultDefault() { result = RESULT_DEFAULT; } /** * Sets the result of the dialog to a constant indicating that the previous filter is to be used. */ protected final void setResultUnchanged() { result = RESULT_UNCHANGED; } /** * Disposes the shell and nullifies the instance, triggering the dialog to return the filter.<br> * <br> * Call one of the following to set the filter before invoking this method:<br> * - {@link #setResultCurrent()} to construct a new filter using values selected by the user.<br> * - {@link #setResultDefault()} to return a constant indicating that the default filter should be used.<br> * - {@link #setResultUnchanged()} to return a constant indicating that the previous filter should be used. */ public void dispose() { shell.dispose(); } /** * Opens this dialog. This method blocks until the user exits the dialog (by calling {@link #dispose()}). * * @return the filter selected by the user * @throws IllegalStateException * if the result is null */ @SuppressWarnings("unchecked") public Predicate<T> open() { shell.open(); Display display = UIUtils.getDisplay(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } if (result == null) throw new IllegalStateException("Result must not be null!"); return (Predicate<T>) result; } }