package edu.ualberta.med.biobank.widgets;
import java.util.ArrayList;
import java.util.List;
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.Assert;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;
import edu.ualberta.med.biobank.SessionManager;
import edu.ualberta.med.biobank.common.action.search.SpecimenByInventorySearchAction;
import edu.ualberta.med.biobank.common.action.specimen.SpecimenGetInfoAction;
import edu.ualberta.med.biobank.common.action.specimen.SpecimenGetInfoAction.SpecimenBriefInfo;
import edu.ualberta.med.biobank.common.action.specimen.SpecimenInfo;
import edu.ualberta.med.biobank.common.wrappers.SpecimenWrapper;
import edu.ualberta.med.biobank.gui.common.BgcPlugin;
import edu.ualberta.med.biobank.gui.common.widgets.BgcBaseText;
import edu.ualberta.med.biobank.gui.common.widgets.BgcBaseWidget;
import edu.ualberta.med.biobank.gui.common.widgets.IInfoTableDeleteItemListener;
import edu.ualberta.med.biobank.gui.common.widgets.IInfoTableDoubleClickItemListener;
import edu.ualberta.med.biobank.gui.common.widgets.InfoTableEvent;
import edu.ualberta.med.biobank.gui.common.widgets.utils.BgcWidgetCreator;
import edu.ualberta.med.biobank.server.applicationservice.BiobankApplicationService;
import edu.ualberta.med.biobank.widgets.infotables.NewSpecimenInfoTable;
import edu.ualberta.med.biobank.widgets.infotables.NewSpecimenInfoTable.ColumnsShown;
import edu.ualberta.med.biobank.widgets.infotables.entry.NewSpecimenEntryInfoTable;
import edu.ualberta.med.biobank.widgets.listeners.VetoListenerSupport;
import edu.ualberta.med.biobank.widgets.listeners.VetoListenerSupport.VetoException;
import edu.ualberta.med.biobank.widgets.listeners.VetoListenerSupport.VetoListener;
public class SpecimenEntryWidget extends BgcBaseWidget {
private List<SpecimenInfo> specimens;
private List<SpecimenInfo> addedSpecimens =
new ArrayList<SpecimenInfo>();
private List<SpecimenInfo> removedSpecimens =
new ArrayList<SpecimenInfo>();
private NewSpecimenInfoTable specTable;
private BgcBaseText newSpecimenInventoryId;
private boolean editable;
private Button addButton;
private IObservableValue hasSpecimens = new WritableValue(Boolean.FALSE,
Boolean.class);
// TODO: not sure these should all be interruptable
public static enum ItemAction {
PRE_ADD,
POST_ADD,
PRE_DELETE,
POST_DELETE;
}
private VetoListenerSupport<ItemAction, SpecimenWrapper> vetoListenerSupport =
new VetoListenerSupport<ItemAction, SpecimenWrapper>();
public void addVetoListener(ItemAction action,
VetoListener<ItemAction, SpecimenWrapper> listener) {
vetoListenerSupport.addListener(action, listener);
}
public void removeVetoListener(ItemAction action,
VetoListener<ItemAction, SpecimenWrapper> listener) {
vetoListenerSupport.removeListener(action, listener);
}
public SpecimenEntryWidget(Composite parent, int style,
FormToolkit toolkit, boolean editable) {
super(parent, style);
Assert.isNotNull(toolkit, "toolkit is null"); //$NON-NLS-1$
this.editable = editable;
setLayout(new GridLayout(2, false));
setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
toolkit.paintBordersFor(this);
if (editable) {
Label label = toolkit.createLabel(this,
Messages.SpecimenEntryWidget_inventoryid_label);
GridData gd = new GridData();
gd.horizontalSpan = 2;
label.setLayoutData(gd);
newSpecimenInventoryId = new BgcBaseText(this, SWT.NONE, toolkit);
newSpecimenInventoryId.addListener(SWT.DefaultSelection,
new Listener() {
@Override
public void handleEvent(Event e) {
addSpecimen();
newSpecimenInventoryId.setFocus();
newSpecimenInventoryId.setText(""); //$NON-NLS-1$
}
});
addButton = toolkit.createButton(this, "", SWT.PUSH); //$NON-NLS-1$
addButton.setImage(BgcPlugin.getDefault().getImageRegistry()
.get(BgcPlugin.IMG_ADD));
addButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
addSpecimen();
}
});
}
if (editable) {
specTable = new NewSpecimenEntryInfoTable(this, null,
ColumnsShown.PEVENT_SOURCE_SPECIMENS);
} else {
specTable = new NewSpecimenInfoTable(this, null,
ColumnsShown.PEVENT_SOURCE_SPECIMENS, 20);
}
specTable.adaptToToolkit(toolkit, true);
GridData gd = new GridData();
gd.horizontalSpan = 2;
gd.horizontalAlignment = SWT.FILL;
gd.grabExcessHorizontalSpace = true;
specTable.setLayoutData(gd);
addDeleteSupport();
}
public List<SpecimenInfo> getAddedSpecimens() {
return new ArrayList<SpecimenInfo>(addedSpecimens);
}
public List<SpecimenInfo> getRemovedSpecimens() {
return new ArrayList<SpecimenInfo>(removedSpecimens);
}
private void addSpecimen() {
BiobankApplicationService appService = SessionManager.getAppService();
String inventoryId = newSpecimenInventoryId.getText().trim();
if (!inventoryId.isEmpty()) {
SpecimenBriefInfo bspecimen = null;
try {
Integer specId = appService.doAction(
new SpecimenByInventorySearchAction(inventoryId,
SessionManager.getUser().getCurrentWorkingCenter()
.getId())).getList().get(0);
bspecimen =
appService.doAction(
new SpecimenGetInfoAction(specId));
// Need to convert to table type
SpecimenInfo ispecimen =
new SpecimenInfo();
ispecimen.specimen = bspecimen.getSpecimen();
ispecimen.parentLabel =
bspecimen.getParents().size() > 0 ? bspecimen.getParents()
.pop().getLabel() : ""; //$NON-NLS-1$
ispecimen.positionString =
bspecimen.getSpecimen().getSpecimenPosition() != null ?
bspecimen.getSpecimen().getSpecimenPosition()
.getPositionString() : null;
ispecimen.comment =
bspecimen.getSpecimen().getComments().size() == 0 ? Messages.SpecimenEntryWidget_no
: Messages.SpecimenEntryWidget_yes;
try {
addSpecimen(ispecimen);
} catch (VetoException e) {
BgcPlugin.openAsyncError(
Messages.SpecimenEntryWidget_error_title,
e.getMessage());
}
} catch (Exception e) {
BgcPlugin.openAsyncError(
Messages.SpecimenEntryWidget_retrieve_error_title,
Messages.SpecimenEntryWidget_notfound);
}
}
}
public void addSpecimen(SpecimenInfo specimen) throws VetoException {
if (specimen != null && specimens.contains(specimen)) {
BgcPlugin.openAsyncError(Messages.SpecimenEntryWidget_error_title,
NLS.bind(Messages.SpecimenEntryWidget_already_added_error_msg,
specimen.specimen.getInventoryId()));
return;
}
SpecimenWrapper wrap =
new SpecimenWrapper(SessionManager.getAppService(),
specimen.specimen);
VetoListenerSupport.Event<ItemAction, SpecimenWrapper> preAdd =
VetoListenerSupport.Event
.newEvent(ItemAction.PRE_ADD, wrap);
VetoListenerSupport.Event<ItemAction, SpecimenWrapper> postAdd =
VetoListenerSupport.Event
.newEvent(ItemAction.POST_ADD, wrap);
vetoListenerSupport.notifyListeners(preAdd);
specimens.add(specimen);
// FIXME: sorting? Collections.sort(specimens);
specTable.setList(specimens);
addedSpecimens.add(specimen);
removedSpecimens.remove(specimen);
notifyListeners();
hasSpecimens.setValue(true);
vetoListenerSupport.notifyListeners(postAdd);
}
private void addDeleteSupport() {
if (!editable)
return;
specTable
.addDeleteItemListener(new IInfoTableDeleteItemListener<SpecimenInfo>() {
@Override
public void deleteItem(InfoTableEvent<SpecimenInfo> event) {
SpecimenInfo specimen = specTable.getSelection();
if (specimen != null) {
if (!MessageDialog.openConfirm(
PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell(),
Messages.SpecimenEntryWidget_delete_question_title,
NLS.bind(
Messages.SpecimenEntryWidget_delete_question_msg,
specimen.specimen.getInventoryId()))) {
return;
}
try {
removeSpecimen(specimen);
} catch (VetoException e) {
BgcPlugin.openAsyncError(
Messages.SpecimenEntryWidget_error_title,
e.getMessage());
}
}
}
});
}
public void removeSpecimen(SpecimenInfo specimen) throws VetoException {
SpecimenWrapper wrap =
new SpecimenWrapper(SessionManager.getAppService(),
specimen.specimen);
VetoListenerSupport.Event<ItemAction, SpecimenWrapper> preDelete =
VetoListenerSupport.Event
.newEvent(ItemAction.PRE_DELETE, wrap);
VetoListenerSupport.Event<ItemAction, SpecimenWrapper> postDelete =
VetoListenerSupport.Event
.newEvent(ItemAction.POST_DELETE, wrap);
vetoListenerSupport.notifyListeners(preDelete);
if (preDelete.doit) {
specimens.remove(specimen);
// FIXME: sorting? Collections.sort(specimens);
specTable.setList(specimens);
removedSpecimens.add(specimen);
addedSpecimens.remove(specimen);
notifyListeners();
hasSpecimens.setValue(specimens.size() > 0);
vetoListenerSupport.notifyListeners(postDelete);
}
}
public void setSpecimens(List<SpecimenInfo> specimens) {
// don't want to work on exactly the same list. This will be the gui
// list only.
this.specimens = new ArrayList<SpecimenInfo>(specimens);
if (specimens != null)
specTable.setList(specimens);
else
specTable.setList(new ArrayList<SpecimenInfo>());
addedSpecimens.clear();
removedSpecimens.clear();
hasSpecimens.setValue(specimens != null && specimens.size() > 0);
}
public void addDoubleClickListener(
IInfoTableDoubleClickItemListener<SpecimenInfo> listener) {
specTable.addClickListener(listener);
}
public void addBinding(BgcWidgetCreator dbc, final String message) {
final ControlDecoration controlDecoration = createDecorator(addButton,
message);
WritableValue wv = new WritableValue(Boolean.FALSE, Boolean.class);
UpdateValueStrategy uvs = new UpdateValueStrategy();
uvs.setAfterGetValidator(new IValidator() {
@Override
public IStatus validate(Object value) {
if (value instanceof Boolean && !(Boolean) value) {
controlDecoration.show();
return ValidationStatus.error(message);
}
controlDecoration.hide();
return Status.OK_STATUS;
}
});
dbc.bindValue(wv, hasSpecimens, uvs, uvs);
}
}