package edu.ualberta.med.biobank.forms; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import edu.ualberta.med.biobank.SessionManager; import edu.ualberta.med.biobank.common.action.processingEvent.ProcessingEventGetInfoAction; import edu.ualberta.med.biobank.common.action.processingEvent.ProcessingEventGetInfoAction.PEventInfo; import edu.ualberta.med.biobank.common.action.processingEvent.ProcessingEventSaveAction; import edu.ualberta.med.biobank.common.action.specimen.SpecimenGetInfoAction; import edu.ualberta.med.biobank.common.action.specimen.SpecimenInfo; import edu.ualberta.med.biobank.common.formatters.DateFormatter; import edu.ualberta.med.biobank.common.peer.ProcessingEventPeer; import edu.ualberta.med.biobank.common.wrappers.CenterWrapper; import edu.ualberta.med.biobank.common.wrappers.CommentWrapper; import edu.ualberta.med.biobank.common.wrappers.ProcessingEventWrapper; import edu.ualberta.med.biobank.common.wrappers.SpecimenWrapper; import edu.ualberta.med.biobank.forms.input.FormInput; import edu.ualberta.med.biobank.gui.common.validators.NonEmptyStringValidator; import edu.ualberta.med.biobank.gui.common.widgets.BgcBaseText; import edu.ualberta.med.biobank.gui.common.widgets.BgcEntryFormWidgetListener; import edu.ualberta.med.biobank.gui.common.widgets.DateTimeWidget; 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.InfoTableSelection; import edu.ualberta.med.biobank.gui.common.widgets.MultiSelectEvent; import edu.ualberta.med.biobank.gui.common.widgets.utils.ComboSelectionUpdate; import edu.ualberta.med.biobank.model.ActivityStatus; import edu.ualberta.med.biobank.model.Comment; import edu.ualberta.med.biobank.model.ProcessingEvent; import edu.ualberta.med.biobank.model.Specimen; import edu.ualberta.med.biobank.model.Study; import edu.ualberta.med.biobank.treeview.AdapterBase; import edu.ualberta.med.biobank.treeview.SpecimenAdapter; import edu.ualberta.med.biobank.treeview.processing.ProcessingEventAdapter; import edu.ualberta.med.biobank.validators.NotNullValidator; import edu.ualberta.med.biobank.widgets.SpecimenEntryWidget; import edu.ualberta.med.biobank.widgets.SpecimenEntryWidget.ItemAction; import edu.ualberta.med.biobank.widgets.infotables.CommentsInfoTable; import edu.ualberta.med.biobank.widgets.listeners.VetoListenerSupport.Event; import edu.ualberta.med.biobank.widgets.listeners.VetoListenerSupport.VetoException; import edu.ualberta.med.biobank.widgets.listeners.VetoListenerSupport.VetoListener; import edu.ualberta.med.biobank.widgets.utils.GuiUtil; public class ProcessingEventEntryForm extends BiobankEntryForm { public static final String ID = "edu.ualberta.med.biobank.forms.ProcessingEventEntryForm"; private static final String MSG_NEW_PEVENT_OK = "Creating a new processing event"; private static final String MSG_PEVENT_OK = "Editing a processing event"; private ProcessingEventAdapter pEventAdapter; private ComboViewer activityStatusComboViewer; private DateTimeWidget dateWidget; private SpecimenEntryWidget specimenEntryWidget; private ActivityStatus closedActivityStatus; private CommentsInfoTable commentEntryTable; private final ProcessingEventWrapper pevent = new ProcessingEventWrapper( SessionManager.getAppService()); private final CommentWrapper comment = new CommentWrapper( SessionManager.getAppService()); private List<SpecimenInfo> specimens; protected Study study; @Override protected void init() throws Exception { Assert.isTrue(adapter instanceof ProcessingEventAdapter, "Invalid editor input: object of type " + adapter.getClass().getName()); pEventAdapter = (ProcessingEventAdapter) adapter; setPEventInfo(adapter.getId()); String tabName; if (pEventAdapter.getId() == null) { tabName = "New processing event"; } else { if (pevent.getWorksheet() == null) tabName = NLS.bind( "Processing event {0} on {1}", pevent.getWorksheet(), pevent.getFormattedCreatedAt()); else tabName = NLS.bind( "Processing event date {0}", DateFormatter.formatAsDateTime(pevent.getCreatedAt())); } closedActivityStatus = ActivityStatus.CLOSED; setPartName(tabName); } private void setPEventInfo(Integer id) throws Exception { if (id == null) { ProcessingEvent p = new ProcessingEvent(); p.setActivityStatus(ActivityStatus.ACTIVE); pevent.setWrappedObject(p); pevent .setCenter(SessionManager.getUser().getCurrentWorkingCenter()); specimens = new ArrayList<SpecimenInfo>(); } else { PEventInfo read = SessionManager.getAppService().doAction( new ProcessingEventGetInfoAction(adapter.getId())); pevent.setWrappedObject(read.pevent); specimens = read.sourceSpecimenInfos; SessionManager.logLookup(read.pevent); } comment.setWrappedObject(new Comment()); } @Override protected void createFormContent() throws Exception { form.setText("Processing event information"); form.setMessage(getOkMessage(), IMessageProvider.NONE); page.setLayout(new GridLayout(1, false)); createMainSection(); createSpecimensSection(); } private void createMainSection() { Composite client = toolkit.createComposite(page); GridLayout layout = new GridLayout(2, false); layout.horizontalSpacing = 10; client.setLayout(layout); client.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); toolkit.paintBordersFor(client); createReadOnlyLabelledField(client, SWT.NONE, "Center", pevent.getCenter() .getName()); dateWidget = createDateTimeWidget( client, "Start time", pevent.getCreatedAt(), pevent, ProcessingEventPeer.CREATED_AT.getName(), new NotNullValidator( "A creation date/time should be selected")); setFirstControl(dateWidget); createBoundWidgetWithLabel(client, BgcBaseText.class, SWT.NONE, "Worksheet", null, pevent, ProcessingEventPeer.WORKSHEET.getName(), (!pevent.isNew() && pevent.getWorksheet() == null) ? null : new NonEmptyStringValidator( "Worksheet cannot be null")); activityStatusComboViewer = createComboViewer( client, "Activity status", ActivityStatus.valuesList(), pevent.getActivityStatus(), "Processing event must have an activity status ", new ComboSelectionUpdate() { @Override public void doSelection(Object selectedObject) { setDirty(true); pevent .setActivityStatus((ActivityStatus) selectedObject); } }); if (pevent.getActivityStatus() != null) { activityStatusComboViewer.setSelection(new StructuredSelection( pevent.getActivityStatus())); setDirty(false); } createCommentSection(); } private void createCommentSection() { Composite client = createSectionWithClient("Comments"); GridLayout gl = new GridLayout(2, false); client.setLayout(gl); commentEntryTable = new CommentsInfoTable(client, pevent.getCommentCollection(false)); GridData gd = new GridData(); gd.horizontalSpan = 2; gd.grabExcessHorizontalSpace = true; gd.horizontalAlignment = SWT.FILL; commentEntryTable.setLayoutData(gd); createBoundWidgetWithLabel(client, BgcBaseText.class, SWT.MULTI, "Add a comment", null, comment, "message", null); } private void createSpecimensSection() { Assert.isNotNull(SessionManager.getUser().getCurrentWorkingCenter()); Composite client = createSectionWithClient("Source specimens"); GridLayout layout = new GridLayout(1, false); client.setLayout(layout); client.setLayoutData(new GridData(GridData.FILL, GridData.FILL)); toolkit.paintBordersFor(client); specimenEntryWidget = new SpecimenEntryWidget(client, SWT.NONE, toolkit, true); specimenEntryWidget .addSelectionChangedListener(new BgcEntryFormWidgetListener() { @Override public void selectionChanged(MultiSelectEvent event) { setDirty(true); } }); specimenEntryWidget .addDoubleClickListener(new IInfoTableDoubleClickItemListener<SpecimenInfo>() { @Override public void doubleClick(InfoTableEvent<SpecimenInfo> event) { Specimen s = ((SpecimenInfo) ((InfoTableSelection) event .getSelection()).getObject()).specimen; AdapterBase.openForm( new FormInput( new SpecimenAdapter(null, new SpecimenWrapper(SessionManager .getAppService(), s))), SpecimenViewForm.ID); } }); VetoListener<ItemAction, SpecimenWrapper> vetoListener = new VetoListener<ItemAction, SpecimenWrapper>() { @Override public void handleEvent(Event<ItemAction, SpecimenWrapper> event) throws VetoException { SpecimenWrapper specimen = event.getObject(); switch (event.getType()) { case PRE_ADD: if (specimen == null) throw new VetoException( "No specimen found for that inventory id."); else if (!SessionManager.getUser() .getCurrentWorkingCenter() .equals(specimen.getCurrentCenter())) { String centerName = "'none'"; if (specimen.getCurrentCenter() != null) centerName = specimen.getCurrentCenter().getNameShort(); throw new VetoException( NLS.bind( "Specimen is currently in center {0}. You can''t process it.", centerName)); } else if (specimen.getProcessingEvent() != null) { throw new VetoException( NLS.bind( "This specimen is already in processing event ''{0}'' ({1}). Remove it from the other processing event first.", specimen.getProcessingEvent() .getWorksheet(), specimen .getProcessingEvent() .getFormattedCreatedAt())); } else if (!specimen.isActive()) throw new VetoException( NLS.bind( "This specimen has status ''{0}''. Only ''Active'' specimens can be added to a processing event.", specimen.getActivityStatus().getName())); else if (specimen.isUsedInDispatch()) throw new VetoException( "Specimen is currently listed in a dispatch."); else if (specimen.getParentContainer() != null) throw new VetoException( "Specimen is currently listed as stored in a container."); else if (!SessionManager.getUser() .getCurrentWorkingCenter().getStudyCollection() .contains( specimen.getCollectionEvent().getPatient() .getStudy())) throw new VetoException( NLS.bind( "This specimen is from study ''{0}''. This study is not linked to your current working center. Processing is not allowed.", specimen.getCollectionEvent().getPatient() .getStudy().getNameShort())); else if (study == null) { if (specimens.size() == 0) study = specimen.getCollectionEvent().getPatient() .getStudy().getWrappedObject(); else { try { study = SessionManager .getAppService() .doAction( new SpecimenGetInfoAction(specimens .get(0).specimen.getId())) .getSpecimen().getCollectionEvent() .getPatient().getStudy(); } catch (Exception e) { throw new VetoException( "All Specimens must be part of the same study."); } } } if (!specimen.getCollectionEvent().getPatient() .getStudy().getWrappedObject().equals(study)) throw new VetoException( "In a processing event, all specimens must be part of the same study."); case POST_ADD: specimen.setProcessingEvent(pevent); specimen.setActivityStatus(closedActivityStatus); break; case PRE_DELETE: if (specimen.getChildSpecimenCollection(false).size() != 0) throw new VetoException( "Cannot remove processed specimens with children."); } } }; specimenEntryWidget.addBinding(widgetCreator, "Specimens should be added to a processing event"); specimenEntryWidget.addVetoListener(ItemAction.PRE_ADD, vetoListener); specimenEntryWidget.addVetoListener(ItemAction.POST_ADD, vetoListener); specimenEntryWidget .addVetoListener(ItemAction.PRE_DELETE, vetoListener); specimenEntryWidget.addVetoListener(ItemAction.POST_DELETE, vetoListener); specimenEntryWidget.setSpecimens(specimens); } @Override protected void saveForm() throws Exception { Set<Integer> added = new HashSet<Integer>(); Set<Integer> removed = new HashSet<Integer>(); for (SpecimenInfo spec : specimenEntryWidget.getAddedSpecimens()) added.add(spec.specimen.getId()); for (SpecimenInfo spec : specimenEntryWidget.getRemovedSpecimens()) removed.add(spec.specimen.getId()); Integer peventId = SessionManager .getAppService() .doAction( new ProcessingEventSaveAction(pevent.getId(), pevent .getCenter().getId(), pevent.getCreatedAt(), pevent .getWorksheet(), pevent.getActivityStatus(), comment .getMessage(), added, removed)).getId(); pevent.setId(peventId); ((AdapterBase) adapter).setModelObject(pevent); } @Override protected void doAfterSave() throws Exception { SessionManager.updateAllSimilarNodes(pEventAdapter, true); } @Override protected String getOkMessage() { return (pevent.isNew()) ? MSG_NEW_PEVENT_OK : MSG_PEVENT_OK; } @Override public String getNextOpenedFormId() { return ProcessingEventViewForm.ID; } @Override public void setValues() throws Exception { CenterWrapper<?> center = pevent.getCenter(); pevent.reset(); pevent.setCenter(center); if (pevent.isNew()) { pevent.setActivityStatus(ActivityStatus.ACTIVE); } GuiUtil.reset(activityStatusComboViewer, pevent.getActivityStatus()); specimenEntryWidget.setSpecimens(specimens); } }