package ie.dcu.segment.options; import ie.dcu.segment.Segmenter; import java.util.*; import java.util.List; import org.eclipse.jface.dialogs.*; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; /** * Dynamically builds a dialog box for the segmentation algorithms options. * * @author Kevin McGuinness */ public class SegmenterOptionDialog extends TitleAreaDialog { private final List editors; private final Segmenter segmenter; public SegmenterOptionDialog(Shell parent, Segmenter segmenter) { super(parent); // Setup final fields this.editors = new LinkedList(); this.segmenter = segmenter; // Make it resizable setShellStyle(getShellStyle() | SWT.RESIZE); } @Override protected void okPressed() { // Apply changes for (OptionEditor editor : editors) { editor.apply(); } // Close super.okPressed(); } @Override protected Control createContents(Composite parent) { Control contents = super.createContents(parent); // Set dialog title getShell().setText("Segmenter Options"); // Set title area title setTitle("Configure Segmenter Options"); // Set message setMessage(String.format("Configure parameters for %s", segmenter.getName())); // Done return contents; } @Override protected Control createDialogArea(Composite parent) { Composite composite = (Composite) super.createDialogArea(parent); // Create scrolled area ScrolledComposite scroller = new ScrolledComposite(composite, SWT.H_SCROLL | SWT.V_SCROLL); // Configure scrolled area scroller.setLayoutData(new GridData(GridData.FILL_BOTH)); scroller.setExpandHorizontal(true); scroller.setExpandVertical(true); scroller.setAlwaysShowScrollBars(false); // Create content Composite content = new Composite(scroller, SWT.NONE); // Create content layout GridLayout layout = new GridLayout(); layout.marginTop = layout.marginBottom = 10; layout.marginLeft = layout.marginRight = 5; layout.numColumns = 2; content.setLayout(layout); // Create listener StatusListener listener = new StatusListener(); // Add options for (Option opt : segmenter.getOptions()) { // Create option label Label label = new Label(content, SWT.NONE); label.setText(opt.getName()); label.setToolTipText(opt.getDescription()); // Create editor layout GridData data = new GridData(); data.horizontalIndent = 25; data.grabExcessHorizontalSpace = true; data.horizontalAlignment = SWT.FILL; // Create editor OptionEditor editor = createEditor(content, opt); editor.getControl().setLayoutData(data); editor.addConversionListener(listener); } // Set scroll area content scroller.setContent(content); // Compute scroll area min size scroller.setMinSize(content.computeSize( SWT.DEFAULT, SWT.DEFAULT) ); // Done return composite; } @Override protected Point getInitialSize() { return new Point(450,350); } public OptionEditor createEditor(Composite parent, Option option) { OptionEditor editor; // Use an combo editor for enums, otherwise use a text editor switch (option.getType()) { case Enumeration: editor = new ComboEditor(parent, option); break; case Toggle: editor = new ToggleEditor(parent, option); break; default: editor = new TextEditor(parent, option); } editors.add(editor); return editor; } /** * Updates error message and OK button status when a conversion occurs. * * @param conversion * The conversion. */ private void handleConversion(Conversion conversion) { boolean ok = false; if (conversion.isOk()) { // Check all others Conversion conv = null; for (OptionEditor editor : editors) { Conversion current = editor.convert(); if (!current.isOk()) { conv = current; break; } } if (conv == null) { setErrorMessage(null); ok = true; } else { setErrorMessage(conv.getMessage()); } } else { setErrorMessage(conversion.getMessage()); } getButton(IDialogConstants.OK_ID).setEnabled(ok); } /** * Updates error message when edits and focus changes occur. */ private final class StatusListener implements ConversionListener { public void conversionPerformed(Conversion conversion) { handleConversion(conversion); } } } interface ConversionListener { public void conversionPerformed(Conversion conversion); } interface OptionEditor { public Control getControl(); public void addConversionListener(ConversionListener listener); public void removeConversionListener(ConversionListener listener); public void apply(); public Conversion convert(); } abstract class AbstractEditor implements OptionEditor { private final List listeners; protected final Option option; protected final Control control; public AbstractEditor(Composite parent, Option option) { this.listeners = new ArrayList(1); this.option = option; this.control = createControl(parent, option); } public Control getControl() { return control; } public void addConversionListener(ConversionListener listener) { listeners.add(listener); } public void removeConversionListener(ConversionListener listener) { listeners.remove(listener); } protected void fireConversionPerformed(Conversion conversion) { for (ConversionListener listener : listeners) { listener.conversionPerformed(conversion); } } protected abstract Control createControl( Composite parent, Option option ); } class TextEditor extends AbstractEditor { private Text text; public TextEditor(Composite parent, Option option) { super(parent, option); } @Override protected Control createControl(Composite parent, Option opt) { text = new Text(parent, SWT.BORDER); text.setToolTipText(opt.getDescription()); text.setText(opt.getValue().toString()); Verifier verifier = new Verifier(); text.addModifyListener(verifier); text.addFocusListener(verifier); return text; } public void apply() { option.setValue(text.getText()); } public Conversion convert() { return option.convert(text.getText()); } private final class Verifier extends FocusAdapter implements ModifyListener { public void focusLost(FocusEvent e) { fireConversionPerformed(convert()); } public void modifyText(ModifyEvent e) { fireConversionPerformed(convert()); } } } class ComboEditor extends AbstractEditor { private Combo combo; private Object[] values; public ComboEditor(Composite parent, Option option) { super(parent, option); } @Override protected Control createControl(Composite parent, Option opt) { values = opt.values(); combo = new Combo(parent, SWT.READ_ONLY); combo.setToolTipText(opt.getDescription()); for (Object v : values) { combo.add(v.toString()); } combo.setText(opt.getValue().toString()); return combo; } public void apply() { int idx = combo.getSelectionIndex(); option.setValue(values[idx]); } public Conversion convert() { int idx = combo.getSelectionIndex(); return option.convert(values[idx]); } } class ToggleEditor extends AbstractEditor { private Button check; public ToggleEditor(Composite parent, Option option) { super(parent, option); } @Override protected Control createControl(Composite parent, Option opt) { check = new Button(parent, SWT.CHECK); Boolean value = (Boolean) opt.getValue(); check.setSelection(value); check.addSelectionListener(new ToggleListener()); updateText(); return check; } private void updateText() { boolean selection = check.getSelection(); check.setText(selection ? "Yes" : "No"); } public void apply() { option.setValue(check.getSelection()); } public Conversion convert() { return option.convert(check.getSelection()); } private final class ToggleListener extends SelectionAdapter { public void widgetSelected(SelectionEvent e) { updateText(); // No need to fire conversion event, will always be correct } } }