Java tutorial
/** * Exhibit A - UIRF Open-source Based Public Software License. * * The contents of this file are subject to the UIRF Open-source Based Public * Software License(the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * openelis.uhl.uiowa.edu * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * The Original Code is OpenELIS code. * * The Initial Developer of the Original Code is The University of Iowa. * Portions created by The University of Iowa are Copyright 2006-2008. All * Rights Reserved. * * Contributor(s): ______________________________________. * * Alternatively, the contents of this file marked "Separately-Licensed" may be * used under the terms of a UIRF Software license ("UIRF Software License"), in * which case the provisions of a UIRF Software License are applicable instead * of those above. */ package org.openelis.modules.secondDataEntry.client.field; import static org.openelis.modules.main.client.Logger.logger; import static org.openelis.ui.screen.State.UPDATE; import java.util.ArrayList; import java.util.HashMap; import java.util.logging.Level; import org.openelis.constants.Messages; import org.openelis.domain.AuxDataViewDO; import org.openelis.domain.Constants; import org.openelis.exception.ParseException; import org.openelis.manager.AuxFieldGroupManager1; import org.openelis.manager.SampleManager1; import org.openelis.modules.main.client.resources.OpenELISResources; import org.openelis.modules.sample1.client.ResultCell; import org.openelis.modules.sample1.client.ResultCell.Value; import org.openelis.modules.secondDataEntry.client.VerificationScreen; import org.openelis.ui.common.DataBaseUtil; import org.openelis.ui.event.DataChangeEvent; import org.openelis.ui.event.StateChangeEvent; import org.openelis.ui.screen.ScreenHandler; import org.openelis.ui.widget.Item; import org.openelis.ui.widget.TextBase; import org.openelis.ui.widget.TextBox; import org.openelis.ui.widget.table.Row; import org.openelis.ui.widget.table.Table; import org.openelis.ui.widget.table.event.BeforeCellEditedEvent; import org.openelis.ui.widget.table.event.BeforeCellEditedHandler; import org.openelis.ui.widget.table.event.CellEditedEvent; import org.openelis.ui.widget.table.event.CellEditedHandler; import org.openelis.utilcommon.ResultFormatter; import org.openelis.utilcommon.ResultFormatter.FormattedValue; import org.openelis.utilcommon.ResultHelper; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.TableRowElement; import com.google.gwt.event.dom.client.FocusEvent; import com.google.gwt.event.dom.client.FocusHandler; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Widget; /** * This class manages the widgets used for verifying aux data */ public class AuxData extends MultiField<Table> { protected HashMap<String, ArrayList<Item<Integer>>> dictionaryModel; protected int row; public AuxData(VerificationScreen parentScreen, TableRowElement tableRowElement, Table editableWidget, int rowIndex) { super(parentScreen, tableRowElement, editableWidget, rowIndex); init(); } /** * Makes the row in which the widgets are shown, visible and sets its style; * adds handlers to the widgets in the row */ protected void init() { ScheduledCommand cmd; setRowVisible(); /* * this is done so that the table gets resized to show the headers and * rows after it's made visible; it won't get resized otherwise because * it's in a LayoutPanel, and that panel is inside a <td> and not * another panel; so the browser's chain for resizing panels gets broken * and doesn't reach the table */ cmd = new ScheduledCommand() { @Override public void execute() { editableWidget.onResize(); } }; Scheduler.get().scheduleDeferred(cmd); parentScreen.addScreenHandler(editableWidget, "auxDataTable", new ScreenHandler<ArrayList<Row>>() { public void onDataChange(DataChangeEvent<ArrayList<Row>> event) { clear(); } public void onStateChange(StateChangeEvent event) { editableWidget.setEnabled(true); } public Widget onTab(boolean forward) { return forward ? nextTabWidget : prevTabWidget; } }); /* * overridden because the table by default doesn't show any special * style on getting the focus */ editableWidget.addDomHandler(new FocusHandler() { @Override public void onFocus(FocusEvent event) { if (editableWidget.getRowCount() > 0 && editableWidget.getSelectedRow() == -1) editableWidget.selectRowAt(0); } }, FocusEvent.getType()); editableWidget.addBeforeCellEditedHandler(new BeforeCellEditedHandler() { @Override public void onBeforeCellEdited(BeforeCellEditedEvent event) { AuxDataViewDO data; if (!parentScreen.isState(UPDATE) || event.getCol() != 1) { event.cancel(); return; } /* * set the editor, e.g. dropdown or text box, in the editable * cell and in the cell for showing the value in the manager for * this row's analyte */ data = parentScreen.getManager().auxData.get(event.getRow()); try { setCellEditor(1, data.getAuxFieldGroupId(), data.getAuxFieldId()); setCellEditor(4, data.getAuxFieldGroupId(), data.getAuxFieldId()); } catch (Exception e) { Window.alert(e.getMessage()); logger.log(Level.SEVERE, e.getMessage(), e); event.cancel(); } } }); editableWidget.addCellEditedHandler(new CellEditedHandler() { @Override public void onCellUpdated(CellEditedEvent event) { switch (event.getCol()) { case 1: valueChanged(event.getRow(), false); break; } } }); } /** * Copies the row's aux data DO's value to the editable cell */ public void copyFromSample() { int r; Value userVal, manVal; VerificationData vd; r = editableWidget.getEditingRow(); if (r < 0) return; /* * here the non-editable cell's value is used in the comparison instead * of getting the value from the DO because if the value has been * changed twice by the user, the DO's value would already be showing in * the non-editable cell */ userVal = (Value) editableWidget.getValueAt(r, 1); manVal = (Value) editableWidget.getValueAt(r, 4); vd = editableWidget.getRowAt(r).getData(); if (vd.numEdit > 1 && DataBaseUtil.isDifferent(userVal, manVal)) { editableWidget.setValueAt(r, 1, manVal); editableWidget.setValueAt(r, 2, OpenELISResources.INSTANCE.icon().CommitButtonImage()); editableWidget.setValueAt(r, 3, OpenELISResources.INSTANCE.icon().arrowLeftImage()); /* * set the focus back to the cell being edited because it loses * focus when setValueAt is called */ editableWidget.startEditing(r, 1); vd.isVerified = true; vd.operation = 1; } } /** * Copies the value in the row's editable cell to its aux data DO */ public void copyToSample() { int r; AuxDataViewDO data; AuxFieldGroupManager1 agm; ResultFormatter rf; Value userVal, manVal; VerificationData vd; r = editableWidget.getEditingRow(); if (r < 0) return; /* * validate the value entered by the user and copy it to the row's DO * and non-editable cell; set the type to null if the value is not * valid; here the non-editable cell's value is used in the comparison * instead of getting the value from the DO because if the value has * been changed twice by the user, the DO's value would already be * showing in the non-editable cell */ userVal = (Value) editableWidget.getValueAt(r, 1); manVal = (Value) editableWidget.getValueAt(r, 4); data = parentScreen.getManager().auxData.get(r); vd = editableWidget.getRowAt(r).getData(); if (vd.numEdit > 1 && DataBaseUtil.isDifferent(userVal, manVal)) { try { agm = parentScreen.getCacheProvider().get(data.getAuxFieldGroupId(), AuxFieldGroupManager1.class); rf = agm.getFormatter(); ResultHelper.formatValue(data, userVal.getDisplay(), rf); } catch (ParseException e) { data.setValue(userVal.getDisplay()); data.setTypeId(null); } catch (Exception e) { Window.alert(e.getMessage()); logger.log(Level.SEVERE, e.getMessage(), e); } editableWidget.setValueAt(r, 4, userVal); editableWidget.setValueAt(r, 2, OpenELISResources.INSTANCE.icon().CommitButtonImage()); editableWidget.setValueAt(r, 3, OpenELISResources.INSTANCE.icon().arrowRightImage()); /* * set the focus back to the editable cell because it loses focus * when setValueAt is called */ editableWidget.startEditing(r, 1); vd.isVerified = true; vd.operation = 2; } } /** * Verifies whether the value entered by the user in the row at the passed * index is the same as the value in the aux data DO at the same index; * increments the number of times the value has been changed; if the values * are different and the value has been changed more than once, shows the * DO's value to the user */ public void valueChanged() { valueChanged(editableWidget.getEditingRow(), true); } /** * Marks the aux data in the sample at the passed index as verified if its * value is the same as the value entered by the user; shows the image for * "match" or "no match" based on whether the two values are same or * different respectively */ protected void verify(int i) { boolean match; Value value; String userVal; AuxDataViewDO data; userVal = null; value = (Value) editableWidget.getValueAt(i, 1); if (value != null) userVal = value.getDictId() != null ? value.getDictId() : value.getDisplay(); data = parentScreen.getManager().auxData.get(i); match = !DataBaseUtil.isDifferent(userVal, data.getValue()); /* * set the icon for match/no match */ editableWidget.setValueAt(i, 2, match ? OpenELISResources.INSTANCE.icon().CommitButtonImage() : OpenELISResources.INSTANCE.icon().AbortButtonImage()); ((VerificationData) editableWidget.getRowAt(i).getData()).isVerified = match; } /** * Returns true if the aux data at the passed index is verified; */ protected boolean getIsVerified(int i) { return ((VerificationData) editableWidget.getRowAt(i).getData()).isVerified; } /** * Sets all the widgets and class fields to their default values */ protected void clear() { SampleManager1 sm; editableWidget.setModel(getTableModel()); sm = parentScreen.getManager(); setCount(sm != null ? sm.auxData.count() : 0); } protected Integer getOperation(int i) { return ((VerificationData) editableWidget.getRowAt(i).getData()).operation; } protected String getKey(int i) { return Messages.get().secondDataEntry_auxLogText(parentScreen.getManager().auxData.get(i).getId()); } /** * Creates and returns the model for the table */ private ArrayList<Row> getTableModel() { Row row; AuxDataViewDO data; ArrayList<Row> model; SampleManager1 sm; model = new ArrayList<Row>(); sm = parentScreen.getManager(); if (sm == null) return model; for (int i = 0; i < sm.auxData.count(); i++) { data = sm.auxData.get(i); row = new Row(data.getAnalyteName(), new ResultCell.Value(null, null), null, null, new ResultCell.Value(null, null)); row.setData(new VerificationData()); model.add(row); } return model; } /** * Sets the cell editor for the column at position "col" in aux data table; * the editor is a dropdown if all potential values for an aux field are * dictionary, otherwise the editor is a textbox; if the editor is a * dropdown, creates and sets its model from the values; if it's a textbox, * sets its case to upper or lower if all values for the aux field are of * type alpha lower or alpha upper; the aux field group and aux field are * specified by the two passed ids respectively */ private void setCellEditor(int col, Integer groupId, Integer fieldId) throws Exception { Integer caseFlag; String key; ResultCell rc; ResultFormatter rf; TextBox tb; Item<Integer> item; ArrayList<Item<Integer>> model; ArrayList<FormattedValue> values; AuxFieldGroupManager1 agm; if (dictionaryModel == null) dictionaryModel = new HashMap<String, ArrayList<Item<Integer>>>(); caseFlag = null; key = groupId + ":" + fieldId; model = dictionaryModel.get(key); if (model == null) { agm = parentScreen.getCacheProvider().get(groupId, AuxFieldGroupManager1.class); rf = agm.getFormatter(); /* * if all the values for this aux field are dictionary values, then * create a dropdown model from them */ if (rf.hasAllDictionary(fieldId, null)) { values = rf.getDictionaryValues(fieldId, null); if (values != null) { model = new ArrayList<Item<Integer>>(); for (FormattedValue v : values) { item = new Item<Integer>(v.getId(), v.getDisplay()); item.setEnabled(v.getIsActive()); model.add(item); } } } else if (rf.hasOnlyAlphaLower(fieldId, null)) { caseFlag = Constants.dictionary().TEST_RES_TYPE_ALPHA_LOWER; } else if (rf.hasOnlyAlphaUpper(fieldId, null)) { caseFlag = Constants.dictionary().TEST_RES_TYPE_ALPHA_UPPER; } } /* * this ensures that even if a model was not found above, it's not * looked up again */ dictionaryModel.put(key, model); rc = (ResultCell) editableWidget.getColumnAt(col).getCellEditor(); rc.setModel(model); /* * set the case if the editor is a textbox */ if (rc.getWidget() instanceof TextBox) { tb = (TextBox) rc.getWidget(); if (Constants.dictionary().TEST_RES_TYPE_ALPHA_LOWER.equals(caseFlag)) tb.setCase(TextBase.Case.LOWER); else if (Constants.dictionary().TEST_RES_TYPE_ALPHA_UPPER.equals(caseFlag)) tb.setCase(TextBase.Case.UPPER); else tb.setCase(TextBase.Case.MIXED); } } /** * Verifies whether the value entered by the user in the row at the passed * index is the same as the value in the aux data DO at the same index; if * the values are different and the value has been changed by the user more * than once, shows the DO's value to the user; increments the number of * times the value has been changed; if the boolean flag is true, the user * wants the entered value to be treated as changed even though it wasn't * actually changed; this could be to verify the entered value again and see * the DO's value without needing to the enter some other value */ private void valueChanged(int r, boolean isForced) { Value value; AuxDataViewDO data; VerificationData vd; if (r < 0) return; data = parentScreen.getManager().auxData.get(r); vd = editableWidget.getRowAt(r).getData(); /* * increment the number of times the value for this aux data has been * changed */ vd.numEdit++; /* * if there's no match and the value has been changed by the user more * than once, show the value in the manager to the user */ verify(r); if (!vd.isVerified) { /* * blank the icon for the direction of copy because the current * value was not copied to or from the manager */ editableWidget.setValueAt(r, 3, OpenELISResources.INSTANCE.icon().blankIcon()); if (vd.numEdit > 1) { if (Constants.dictionary().AUX_DICTIONARY.equals(data.getTypeId())) value = new ResultCell.Value(null, data.getValue()); else value = new ResultCell.Value(data.getValue(), null); editableWidget.setValueAt(r, 4, value); } } /* * reset the focus to the cell most recently edited, to allow the user * to change the value; this needs to be done because either that cell * didn't have focus when this method was called or it lost focus when * the icon for match/no match was set in verify() */ if (!vd.isVerified || isForced) refocus(r); } /** * Sets the focus to the editable cell in the row at the passed index */ private void refocus(int i) { /* * "row" is a class-level variable because if it's a simple local * variable it won't be in the scope of the ScheduledCommand below; it * can't be final either because then its value in the command won't * change after the command has been created */ row = i; if (focusCommand == null) { focusCommand = new ScheduledCommand() { @Override public void execute() { editableWidget.startEditing(row, 1); } }; } Scheduler.get().scheduleDeferred(focusCommand); } /** * This class is used to keep track of the data related to verifcation for * each analyte in the table e.g. the number of times its value has been * edited, whether the value is verified etc. */ private class VerificationData { int numEdit; boolean isVerified; Integer operation; } }