package edu.ualberta.med.biobank.widgets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.forms.widgets.FormToolkit;
import edu.ualberta.med.biobank.common.action.scanprocess.SpecimenHierarchyInfo;
import edu.ualberta.med.biobank.common.wrappers.SpecimenTypeWrapper;
import edu.ualberta.med.biobank.common.wrappers.SpecimenWrapper;
import edu.ualberta.med.biobank.gui.common.widgets.BgcBaseWidget;
import edu.ualberta.med.biobank.gui.common.widgets.utils.BgcWidgetCreator;
/**
* Create widgets to show types selection for specimens on a pallet: one label,
* one combo with different source types, one combo with different result types
* and one text showing total number of samples found
*/
public class AliquotedSpecimenSelectionWidget {
private ComboViewer cvSource;
private ComboViewer cvResult;
private ControlDecoration rowControlDecoration;
private ControlDecoration sourceControlDecoration;
private ControlDecoration resultControlDecoration;
private Label textNumber;
private Integer number;
private final IObservableValue bothSelected = new WritableValue(
Boolean.FALSE, Boolean.class);
private final IObservableValue sourceSelected = new WritableValue(
Boolean.FALSE, Boolean.class);
private final IObservableValue resultSelected = new WritableValue(
Boolean.FALSE, Boolean.class);
private Binding oneRowBinding;
private Binding sourceBinding;
private Binding resultBinding;
private Object nextWidget;
private BgcWidgetCreator widgetCreator;
private boolean oneRow;
private Label sourceLabel;
private Label resultLabel;
private List<SpecimenTypeWrapper> sourceChildTypes =
new ArrayList<SpecimenTypeWrapper>();
public AliquotedSpecimenSelectionWidget(Composite parent, Character letter,
BgcWidgetCreator widgetCreator, boolean oneRow) {
this.widgetCreator = widgetCreator;
this.oneRow = oneRow;
if (letter != null) {
widgetCreator.getToolkit().createLabel(parent, letter.toString(),
SWT.LEFT);
}
if (!oneRow) {
sourceLabel = widgetCreator.createLabel(parent,
Messages.AliquotedSpecimenSelectionWidget_sources_spec_title);
sourceControlDecoration =
BgcBaseWidget
.createDecorator(
sourceLabel,
Messages.AliquotedSpecimenSelectionWidget_selections_validation_msg);
}
cvSource = widgetCreator.createComboViewerWithoutLabel(parent, null,
null, new BiobankLabelProvider());
setComboProperties(cvSource, widgetCreator.getToolkit(), 0);
cvSource.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
SpecimenWrapper spc = (SpecimenWrapper) element;
return spc.getSpecimenType().getNameShort() + "(" //$NON-NLS-1$
+ spc.getInventoryId() + ")"; //$NON-NLS-1$
}
});
cvSource.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
if (!event.getSelection().isEmpty()) {
SpecimenWrapper spc =
(SpecimenWrapper) ((IStructuredSelection) event
.getSelection()).getFirstElement();
sourceChildTypes = spc.getSpecimenType()
.getChildSpecimenTypeCollection(false);
}
if (cvResult != null)
cvResult.refresh();
}
});
if (!oneRow) {
resultLabel = widgetCreator.createLabel(parent,
Messages.AliquotedSpecimenSelectionWidget_aliquoted_spec_title);
resultControlDecoration =
BgcBaseWidget
.createDecorator(
resultLabel,
Messages.AliquotedSpecimenSelectionWidget_selections_validation_msg);
}
cvResult = widgetCreator.createComboViewerWithoutLabel(parent, null,
null, new BiobankLabelProvider());
setComboProperties(cvResult, widgetCreator.getToolkit(), 1);
cvResult.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
return ((SpecimenTypeWrapper) element).getName();
}
});
cvResult.addFilter(new ViewerFilter() {
@Override
public boolean select(Viewer viewer, Object parentElement,
Object element) {
return (getSourceSelection() != null && getSourceSelection()
.hasUnknownImportType())
|| sourceChildTypes.contains(element);
}
});
if (oneRow) {
textNumber = widgetCreator.getToolkit().createLabel(parent, "", //$NON-NLS-1$
SWT.BORDER);
GridData gd = new GridData();
gd.widthHint = 20;
gd.horizontalAlignment = SWT.LEFT;
textNumber.setLayoutData(gd);
rowControlDecoration =
BgcBaseWidget
.createDecorator(
textNumber,
Messages.AliquotedSpecimenSelectionWidget_selections_validation_msg);
}
}
private void setComboProperties(ComboViewer cv, FormToolkit toolkit,
final int selectionPosition) {
GridData gd = new GridData(SWT.FILL, SWT.TOP, true, false);
int parentColumns = ((GridLayout) cv.getControl().getParent()
.getLayout()).numColumns;
if (oneRow) {
if (selectionPosition == 0)
gd.widthHint = 300;
} else if (parentColumns > 2)
gd.horizontalSpan = parentColumns - 1;
cv.getControl().setLayoutData(gd);
toolkit.adapt(cv.getControl(), true, true);
cv.setContentProvider(new ArrayContentProvider());
cv.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
boolean res = true;
if (event.getSelection() == null
|| ((IStructuredSelection) event.getSelection()).size() == 0) {
res = false;
}
if (selectionPosition == 0)
sourceSelected.setValue(res);
else
resultSelected.setValue(res);
updateBothSelectedField();
}
});
cv.setComparator(new ViewerComparator());
if (selectionPosition != 0)
cv.getControl().addTraverseListener(new TraverseListener() {
@Override
public void keyTraversed(TraverseEvent e) {
if (e.detail == SWT.TRAVERSE_TAB_NEXT
|| e.detail == SWT.TRAVERSE_RETURN) {
e.doit = setNextFocus();
}
}
});
}
private boolean setNextFocus() {
if (nextWidget != null) {
if (nextWidget instanceof Control) {
((Control) nextWidget).setFocus();
return false; // cancel doit
} else if (nextWidget instanceof AliquotedSpecimenSelectionWidget) {
((AliquotedSpecimenSelectionWidget) nextWidget).cvSource
.getControl().setFocus();
}
}
return true;
}
public void addSelectionChangedListener(ISelectionChangedListener listener) {
cvSource.addSelectionChangedListener(listener);
cvResult.addSelectionChangedListener(listener);
}
public void setNumber(Integer number) {
if (textNumber != null) {
this.number = number;
String text = ""; //$NON-NLS-1$
if (number != null) {
text = number.toString();
}
if (number == null || number == 0) {
cvSource.getControl().setEnabled(false);
sourceSelected.setValue(true);
cvResult.getControl().setEnabled(false);
resultSelected.setValue(true);
bothSelected.setValue(true);
} else {
cvSource.getControl().setEnabled(true);
sourceSelected.setValue(getSourceSelection() != null);
cvResult.getControl().setEnabled(true);
resultSelected.setValue(getResultTypeSelection() != null);
updateBothSelectedField();
}
textNumber.setText(text);
}
}
public void increaseNumber() {
if (number == null)
number = 0;
number++;
setNumber(number);
sourceSelected.setValue(getSourceSelection() != null);
resultSelected.setValue(getResultTypeSelection() != null);
updateBothSelectedField();
}
private void updateBothSelectedField() {
bothSelected.setValue((Boolean) sourceSelected.getValue()
&& (Boolean) resultSelected.getValue());
}
public boolean canFocus() {
return cvSource.getControl().isEnabled();
}
/**
* return true if this selection need to be save, i.e. number > 0
*/
public boolean needToSave() {
if (number == null) {
return false;
}
return number > 0;
}
private SpecimenTypeWrapper getResultTypeSelection() {
return (SpecimenTypeWrapper) ((StructuredSelection) cvResult
.getSelection()).getFirstElement();
}
private SpecimenWrapper getSourceSelection() {
return (SpecimenWrapper) ((StructuredSelection) cvSource.getSelection())
.getFirstElement();
}
public void addBindings() {
if (oneRow) {
if (oneRowBinding == null) {
UpdateValueStrategy rowUpdateValue =
createOneRowUpdateValueStrategy(rowControlDecoration);
oneRowBinding = widgetCreator.bindValue(new WritableValue(
Boolean.FALSE, Boolean.class), bothSelected,
rowUpdateValue, rowUpdateValue);
} else {
widgetCreator.addBinding(oneRowBinding);
}
} else {
if (sourceBinding == null || resultBinding == null) {
UpdateValueStrategy sourceUpdateValue =
createOneRowUpdateValueStrategy(sourceControlDecoration);
sourceBinding = widgetCreator.bindValue(new WritableValue(
Boolean.FALSE, Boolean.class), sourceSelected,
sourceUpdateValue, sourceUpdateValue);
UpdateValueStrategy resultUpdateValue =
createOneRowUpdateValueStrategy(resultControlDecoration);
resultBinding = widgetCreator.bindValue(new WritableValue(
Boolean.FALSE, Boolean.class), resultSelected,
resultUpdateValue, resultUpdateValue);
} else {
widgetCreator.addBinding(sourceBinding);
widgetCreator.addBinding(resultBinding);
}
}
}
private UpdateValueStrategy createOneRowUpdateValueStrategy(
final ControlDecoration decoration) {
UpdateValueStrategy uvs = new UpdateValueStrategy();
uvs.setAfterGetValidator(new IValidator() {
@Override
public IStatus validate(Object value) {
if (value instanceof Boolean && !(Boolean) value) {
decoration.show();
return ValidationStatus
.error(Messages.AliquotedSpecimenSelectionWidget_selections_status_msg);
}
decoration.hide();
return Status.OK_STATUS;
}
});
return uvs;
}
public void removeBindings() {
bothSelected.setValue(true);
if (oneRowBinding != null)
widgetCreator.removeBinding(oneRowBinding);
sourceSelected.setValue(true);
if (sourceBinding != null)
widgetCreator.removeBinding(sourceBinding);
resultSelected.setValue(true);
if (resultBinding != null)
widgetCreator.removeBinding(resultBinding);
}
public void resetValues(boolean resetSelection, boolean resetNumber) {
if (resetSelection) {
cvSource.setSelection(null);
cvResult.setSelection(null);
}
if (resetNumber)
setNumber(null);
else
setNumber(number); // to re-do the validation tests
}
public void resetValues(final boolean resetSelection,
final boolean resetNumber, boolean async) {
if (async) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
resetValues(resetSelection, resetNumber);
}
});
} else {
resetValues(resetSelection, resetNumber);
}
}
public void setNextWidget(Object nextWidget) {
this.nextWidget = nextWidget;
}
public void setResultTypes(List<SpecimenTypeWrapper> types) {
cvResult.setInput(types);
}
public void setSourceSpecimens(List<SpecimenWrapper> sourceSpecimens) {
cvSource.setInput(sourceSpecimens);
}
public void setFocus() {
cvSource.getControl().setFocus();
}
/**
* @return an array of [SpecimenLink (source), SpecimenType (result)]
*/
public SpecimenHierarchyInfo getSelection() {
if (getSourceSelection() != null && getResultTypeSelection() != null)
return new SpecimenHierarchyInfo(getSourceSelection(),
getResultTypeSelection());
return null;
}
public void setSelection(SpecimenHierarchyInfo previousSelection) {
if (previousSelection != null) {
cvSource.setSelection(new StructuredSelection(previousSelection
.getParentSpecimen()));
cvResult.setSelection(new StructuredSelection(previousSelection
.getAliquotedSpecimenType()));
}
}
public void setEnabled(boolean enabled) {
cvSource.getControl().setEnabled(enabled);
cvResult.getControl().setEnabled(enabled);
}
public void deselectAll() {
cvSource.setSelection(null);
cvResult.setSelection(null);
}
public void showWidget(boolean enabled) {
if (sourceLabel != null)
widgetCreator.showWidget(sourceLabel, enabled);
widgetCreator.showWidget(cvSource.getControl(), enabled);
if (resultLabel != null)
widgetCreator.showWidget(resultLabel, enabled);
widgetCreator.showWidget(cvResult.getControl(), enabled);
}
public void setReadOnlySelections(SpecimenWrapper sourceSpecimen,
SpecimenTypeWrapper resultType) {
cvSource.setInput(Arrays.asList(sourceSpecimen));
cvSource.setSelection(new StructuredSelection(sourceSpecimen));
cvResult.setInput(Arrays.asList(resultType));
cvResult.setSelection(new StructuredSelection(resultType));
}
}