Java tutorial
/******************************************************************************* * SORMAS - Surveillance Outbreak Response Management & Analysis System * Copyright 2016-2018 Helmholtz-Zentrum fr Infektionsforschung GmbH (HZI) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. *******************************************************************************/ package de.symeda.sormas.ui.symptoms; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import com.vaadin.v7.data.Validator; import com.vaadin.v7.data.fieldgroup.FieldGroup; import com.vaadin.v7.data.util.converter.Converter.ConversionException; import com.vaadin.server.ThemeResource; import com.vaadin.shared.ui.ContentMode; import com.vaadin.v7.ui.AbstractField; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.v7.ui.ComboBox; import com.vaadin.v7.ui.DateField; import com.vaadin.v7.ui.Field; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Image; import com.vaadin.ui.Label; import com.vaadin.v7.ui.OptionGroup; import com.vaadin.ui.themes.ValoTheme; import de.symeda.sormas.api.Disease; import de.symeda.sormas.api.caze.CaseDataDto; import de.symeda.sormas.api.hospitalization.HospitalizationDto; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.i18n.Validations; import de.symeda.sormas.api.person.ApproximateAgeType; import de.symeda.sormas.api.person.PersonDto; import de.symeda.sormas.api.symptoms.CongenitalHeartDiseaseType; import de.symeda.sormas.api.symptoms.SymptomState; import de.symeda.sormas.api.symptoms.SymptomsContext; import de.symeda.sormas.api.symptoms.SymptomsDto; import de.symeda.sormas.api.symptoms.SymptomsHelper; import de.symeda.sormas.api.user.UserRight; import de.symeda.sormas.api.visit.VisitStatus; import de.symeda.sormas.ui.utils.AbstractEditForm; import de.symeda.sormas.ui.utils.CssStyles; import de.symeda.sormas.ui.utils.DateComparisonValidator; import de.symeda.sormas.ui.utils.FieldHelper; import de.symeda.sormas.ui.utils.LayoutUtil; import de.symeda.sormas.ui.utils.ViewMode; @SuppressWarnings("serial") public class SymptomsForm extends AbstractEditForm<SymptomsDto> { private static final String BUTTONS_LOC = "buttonsLoc"; private static final String LESIONS_LOCATIONS_LOC = "lesionsLocationsLoc"; private static final String MONKEYPOX_LESIONS_IMG1 = "monkeypoxLesionsImg1"; private static final String MONKEYPOX_LESIONS_IMG2 = "monkeypoxLesionsImg2"; private static final String MONKEYPOX_LESIONS_IMG3 = "monkeypoxLesionsImg3"; private static final String MONKEYPOX_LESIONS_IMG4 = "monkeypoxLesionsImg4"; private static final String SYMPTOMS_HINT_LOC = "symptomsHintLoc"; private static final String COMPLICATIONS_HEADING = "complicationsHeading"; private static final String HTML_LAYOUT = LayoutUtil .h3(I18nProperties.getString(Strings.headingClinicalMeasurements)) + LayoutUtil.fluidRowLocs(SymptomsDto.TEMPERATURE, SymptomsDto.TEMPERATURE_SOURCE) + LayoutUtil.fluidRowLocs(SymptomsDto.BLOOD_PRESSURE_SYSTOLIC, SymptomsDto.BLOOD_PRESSURE_DIASTOLIC, SymptomsDto.HEART_RATE, SymptomsDto.RESPIRATORY_RATE) + LayoutUtil.fluidRowLocs(SymptomsDto.GLASGOW_COMA_SCALE, SymptomsDto.WEIGHT, SymptomsDto.HEIGHT, SymptomsDto.MID_UPPER_ARM_CIRCUMFERENCE) + LayoutUtil.h3(I18nProperties.getString(Strings.headingSignsAndSymptoms)) + LayoutUtil.fluidRowLocsCss(CssStyles.VSPACE_3, SymptomsDto.ONSET_DATE, SymptomsDto.ONSET_SYMPTOM) + LayoutUtil.fluidRowCss(CssStyles.VSPACE_3, LayoutUtil.fluidColumn(8, 0, LayoutUtil.loc(SYMPTOMS_HINT_LOC)), LayoutUtil.fluidColumn(4, 0, LayoutUtil.locCss(CssStyles.ALIGN_RIGHT, BUTTONS_LOC))) + LayoutUtil.fluidRow(LayoutUtil.fluidColumn(6, 0, LayoutUtil.locsCss(CssStyles.VSPACE_3, SymptomsDto.ABDOMINAL_PAIN, SymptomsDto.HEARINGLOSS, SymptomsDto.ANOREXIA_APPETITE_LOSS, SymptomsDto.BACKACHE, SymptomsDto.BLACKENING_DEATH_OF_TISSUE, SymptomsDto.BLOOD_IN_STOOL, SymptomsDto.BUBOES_GROIN_ARMPIT_NECK, SymptomsDto.BULGING_FONTANELLE, SymptomsDto.BILATERAL_CATARACTS, SymptomsDto.UNILATERAL_CATARACTS, SymptomsDto.CHEST_PAIN, SymptomsDto.CHILLS_SWEATS, SymptomsDto.CONGENITAL_GLAUCOMA, SymptomsDto.CONGENITAL_HEART_DISEASE, SymptomsDto.CONGENITAL_HEART_DISEASE_TYPE, SymptomsDto.CONGENITAL_HEART_DISEASE_DETAILS, SymptomsDto.CONJUNCTIVITIS, SymptomsDto.COUGH, SymptomsDto.DARK_URINE, SymptomsDto.DEHYDRATION, SymptomsDto.DEVELOPMENTAL_DELAY, SymptomsDto.DIARRHEA, SymptomsDto.DIFFICULTY_BREATHING, SymptomsDto.LYMPHADENOPATHY_AXILLARY, SymptomsDto.LYMPHADENOPATHY_CERVICAL, SymptomsDto.LYMPHADENOPATHY_INGUINAL, SymptomsDto.FATIGUE_WEAKNESS, SymptomsDto.FEVER, SymptomsDto.FLUID_IN_LUNG_CAVITY, SymptomsDto.HEADACHE, SymptomsDto.HICCUPS, SymptomsDto.BEDRIDDEN, SymptomsDto.JAUNDICE, SymptomsDto.JAUNDICE_WITHIN_24_HOURS_OF_BIRTH, SymptomsDto.JOINT_PAIN, SymptomsDto.KOPLIKS_SPOTS, SymptomsDto.LOSS_SKIN_TURGOR, SymptomsDto.SKIN_RASH, SymptomsDto.MALAISE, SymptomsDto.MENINGOENCEPHALITIS, SymptomsDto.OTITIS_MEDIA, SymptomsDto.MICROCEPHALY, SymptomsDto.MUSCLE_PAIN, SymptomsDto.NAUSEA, SymptomsDto.NECK_STIFFNESS, SymptomsDto.OEDEMA_FACE_NECK, SymptomsDto.OEDEMA_LOWER_EXTREMITY, SymptomsDto.EYE_PAIN_LIGHT_SENSITIVE, SymptomsDto.PAINFUL_LYMPHADENITIS)), LayoutUtil.fluidColumn(6, 0, LayoutUtil.locsCss(CssStyles.VSPACE_3, SymptomsDto.PALPABLE_LIVER, SymptomsDto.PALPABLE_SPLEEN, SymptomsDto.PHARYNGEAL_ERYTHEMA, SymptomsDto.PHARYNGEAL_EXUDATE, SymptomsDto.PIGMENTARY_RETINOPATHY, SymptomsDto.PURPURIC_RASH, SymptomsDto.RADIOLUCENT_BONE_DISEASE, SymptomsDto.RAPID_BREATHING, SymptomsDto.REFUSAL_FEEDOR_DRINK, SymptomsDto.RUNNY_NOSE, SymptomsDto.ORAL_ULCERS, SymptomsDto.SIDE_PAIN, SymptomsDto.SORE_THROAT, SymptomsDto.SPLENOMEGALY, SymptomsDto.SUNKEN_EYES_FONTANELLE, SymptomsDto.SWOLLEN_GLANDS, SymptomsDto.THROBOCYTOPENIA, SymptomsDto.TREMOR, SymptomsDto.UNEXPLAINED_BLEEDING, SymptomsDto.EYES_BLEEDING, SymptomsDto.INJECTION_SITE_BLEEDING, SymptomsDto.BLEEDING_VAGINA, SymptomsDto.GUMS_BLEEDING, SymptomsDto.STOMACH_BLEEDING, SymptomsDto.BLOOD_URINE, SymptomsDto.BLOODY_BLACK_STOOL, SymptomsDto.SKIN_BRUISING, SymptomsDto.COUGHING_BLOOD, SymptomsDto.DIGESTED_BLOOD_VOMIT, SymptomsDto.RED_BLOOD_VOMIT, SymptomsDto.NOSE_BLEEDING, SymptomsDto.OTHER_HEMORRHAGIC_SYMPTOMS, SymptomsDto.OTHER_HEMORRHAGIC_SYMPTOMS_TEXT, SymptomsDto.LESIONS, SymptomsDto.LESIONS_THAT_ITCH, SymptomsDto.LESIONS_SAME_STATE, SymptomsDto.LESIONS_SAME_SIZE, SymptomsDto.LESIONS_DEEP_PROFOUND, LESIONS_LOCATIONS_LOC, SymptomsDto.LESIONS_FACE, SymptomsDto.LESIONS_LEGS, SymptomsDto.LESIONS_SOLES_FEET, SymptomsDto.LESIONS_PALMS_HANDS, SymptomsDto.LESIONS_THORAX, SymptomsDto.LESIONS_ARMS, SymptomsDto.LESIONS_GENITALS, SymptomsDto.LESIONS_ALL_OVER_BODY, SymptomsDto.LESIONS_RESEMBLE_IMG1, MONKEYPOX_LESIONS_IMG1, SymptomsDto.LESIONS_RESEMBLE_IMG2, MONKEYPOX_LESIONS_IMG2, SymptomsDto.LESIONS_RESEMBLE_IMG3, MONKEYPOX_LESIONS_IMG3, SymptomsDto.LESIONS_RESEMBLE_IMG4, MONKEYPOX_LESIONS_IMG4, SymptomsDto.LESIONS_ONSET_DATE, SymptomsDto.VOMITING, SymptomsDto.OTHER_NON_HEMORRHAGIC_SYMPTOMS, SymptomsDto.OTHER_NON_HEMORRHAGIC_SYMPTOMS_TEXT) + LayoutUtil.locsCss(CssStyles.VSPACE_3, SymptomsDto.PATIENT_ILL_LOCATION, SymptomsDto.SYMPTOMS_COMMENTS))) + LayoutUtil.loc(COMPLICATIONS_HEADING) + LayoutUtil.fluidRow( LayoutUtil.fluidColumn(6, 0, LayoutUtil.locsCss(CssStyles.VSPACE_3, SymptomsDto.ALTERED_CONSCIOUSNESS, SymptomsDto.CONFUSED_DISORIENTED, SymptomsDto.HEMORRHAGIC_SYNDROME, SymptomsDto.HYPERGLYCEMIA, SymptomsDto.HYPOGLYCEMIA)), LayoutUtil.fluidColumn(6, 0, LayoutUtil.locsCss(CssStyles.VSPACE_3, SymptomsDto.MENINGEAL_SIGNS, SymptomsDto.SEIZURES, SymptomsDto.SEPSIS, SymptomsDto.SHOCK))); private final CaseDataDto caze; private final Disease disease; private final PersonDto person; private final SymptomsContext symptomsContext; private final ViewMode viewMode; private transient List<String> unconditionalSymptomFieldIds; private List<String> conditionalBleedingSymptomFieldIds; private List<String> lesionsFieldIds; private List<String> lesionsLocationFieldIds; private List<String> monkeypoxImageFieldIds; public SymptomsForm(CaseDataDto caze, Disease disease, PersonDto person, SymptomsContext symptomsContext, UserRight editOrCreateUserRight, ViewMode viewMode) { // TODO add user right parameter super(SymptomsDto.class, SymptomsDto.I18N_PREFIX, editOrCreateUserRight); this.caze = caze; this.disease = disease; this.person = person; this.symptomsContext = symptomsContext; this.viewMode = viewMode; if (disease == null || symptomsContext == null) { throw new IllegalArgumentException("disease and symptoms context cannot be null"); } if (symptomsContext == SymptomsContext.CASE && caze == null) { throw new IllegalArgumentException("case cannot be null when symptoms context is case"); } addFields(); hideValidationUntilNextCommit(); } @Override protected void addFields() { if (disease == null || symptomsContext == null) { // workaround to stop initialization until disease is set return; } // Add fields DateField onsetDateField = addField(SymptomsDto.ONSET_DATE, DateField.class); ComboBox onsetSymptom = addField(SymptomsDto.ONSET_SYMPTOM, ComboBox.class); if (symptomsContext == SymptomsContext.CASE) { onsetDateField.addValidator(new DateComparisonValidator(onsetDateField, caze.getHospitalization().getAdmissionDate(), true, false, I18nProperties.getValidationError(Validations.beforeDateSoft, onsetDateField.getCaption(), I18nProperties.getPrefixCaption(HospitalizationDto.I18N_PREFIX, HospitalizationDto.ADMISSION_DATE)))); onsetDateField.setInvalidCommitted(true); } ComboBox temperature = addField(SymptomsDto.TEMPERATURE, ComboBox.class); for (Float temperatureValue : SymptomsHelper.getTemperatureValues()) { temperature.addItem(temperatureValue); temperature.setItemCaption(temperatureValue, SymptomsHelper.getTemperatureString(temperatureValue)); } if (symptomsContext == SymptomsContext.CASE) { temperature.setCaption(I18nProperties.getCaption(Captions.symptomsMaxTemperature)); } addField(SymptomsDto.TEMPERATURE_SOURCE); ComboBox bloodPressureSystolic = addField(SymptomsDto.BLOOD_PRESSURE_SYSTOLIC, ComboBox.class); bloodPressureSystolic.addItems(SymptomsHelper.getBloodPressureValues()); ComboBox bloodPressureDiastolic = addField(SymptomsDto.BLOOD_PRESSURE_DIASTOLIC, ComboBox.class); bloodPressureDiastolic.addItems(SymptomsHelper.getBloodPressureValues()); ComboBox heartRate = addField(SymptomsDto.HEART_RATE, ComboBox.class); heartRate.addItems(SymptomsHelper.getHeartRateValues()); ComboBox respiratoryRate = addField(SymptomsDto.RESPIRATORY_RATE, ComboBox.class); respiratoryRate.addItems(SymptomsHelper.getRespiratoryRateValues()); ComboBox weight = addField(SymptomsDto.WEIGHT, ComboBox.class); for (Integer weightValue : SymptomsHelper.getWeightValues()) { weight.addItem(weightValue); weight.setItemCaption(weightValue, SymptomsHelper.getDecimalString(weightValue)); } ComboBox height = addField(SymptomsDto.HEIGHT, ComboBox.class); height.addItems(SymptomsHelper.getHeightValues()); ComboBox midUpperArmCircumference = addField(SymptomsDto.MID_UPPER_ARM_CIRCUMFERENCE, ComboBox.class); for (Integer circumferenceValue : SymptomsHelper.getMidUpperArmCircumferenceValues()) { midUpperArmCircumference.addItem(circumferenceValue); midUpperArmCircumference.setItemCaption(circumferenceValue, SymptomsHelper.getDecimalString(circumferenceValue)); } ComboBox glasgowComaScale = addField(SymptomsDto.GLASGOW_COMA_SCALE, ComboBox.class); glasgowComaScale.addItems(SymptomsHelper.getGlasgowComaScaleValues()); addFields(SymptomsDto.FEVER, SymptomsDto.VOMITING, SymptomsDto.DIARRHEA, SymptomsDto.BLOOD_IN_STOOL, SymptomsDto.NAUSEA, SymptomsDto.ABDOMINAL_PAIN, SymptomsDto.HEADACHE, SymptomsDto.MUSCLE_PAIN, SymptomsDto.FATIGUE_WEAKNESS, SymptomsDto.SKIN_RASH, SymptomsDto.NECK_STIFFNESS, SymptomsDto.SORE_THROAT, SymptomsDto.COUGH, SymptomsDto.RUNNY_NOSE, SymptomsDto.DIFFICULTY_BREATHING, SymptomsDto.CHEST_PAIN, SymptomsDto.CONJUNCTIVITIS, SymptomsDto.EYE_PAIN_LIGHT_SENSITIVE, SymptomsDto.KOPLIKS_SPOTS, SymptomsDto.THROBOCYTOPENIA, SymptomsDto.OTITIS_MEDIA, SymptomsDto.HEARINGLOSS, SymptomsDto.DEHYDRATION, SymptomsDto.ANOREXIA_APPETITE_LOSS, SymptomsDto.REFUSAL_FEEDOR_DRINK, SymptomsDto.JOINT_PAIN, SymptomsDto.HICCUPS, SymptomsDto.BACKACHE, SymptomsDto.EYES_BLEEDING, SymptomsDto.JAUNDICE, SymptomsDto.DARK_URINE, SymptomsDto.STOMACH_BLEEDING, SymptomsDto.RAPID_BREATHING, SymptomsDto.SWOLLEN_GLANDS, SymptomsDto.SYMPTOMS_COMMENTS, SymptomsDto.UNEXPLAINED_BLEEDING, SymptomsDto.GUMS_BLEEDING, SymptomsDto.INJECTION_SITE_BLEEDING, SymptomsDto.NOSE_BLEEDING, SymptomsDto.BLOODY_BLACK_STOOL, SymptomsDto.RED_BLOOD_VOMIT, SymptomsDto.DIGESTED_BLOOD_VOMIT, SymptomsDto.COUGHING_BLOOD, SymptomsDto.BLEEDING_VAGINA, SymptomsDto.SKIN_BRUISING, SymptomsDto.BLOOD_URINE, SymptomsDto.OTHER_HEMORRHAGIC_SYMPTOMS, SymptomsDto.OTHER_HEMORRHAGIC_SYMPTOMS_TEXT, SymptomsDto.OTHER_NON_HEMORRHAGIC_SYMPTOMS, SymptomsDto.OTHER_NON_HEMORRHAGIC_SYMPTOMS_TEXT, SymptomsDto.LESIONS, SymptomsDto.LESIONS_THAT_ITCH, SymptomsDto.LESIONS_SAME_STATE, SymptomsDto.LESIONS_SAME_SIZE, SymptomsDto.LESIONS_DEEP_PROFOUND, SymptomsDto.LESIONS_FACE, SymptomsDto.LESIONS_LEGS, SymptomsDto.LESIONS_SOLES_FEET, SymptomsDto.LESIONS_PALMS_HANDS, SymptomsDto.LESIONS_THORAX, SymptomsDto.LESIONS_ARMS, SymptomsDto.LESIONS_GENITALS, SymptomsDto.LESIONS_ALL_OVER_BODY, SymptomsDto.LYMPHADENOPATHY_AXILLARY, SymptomsDto.LYMPHADENOPATHY_CERVICAL, SymptomsDto.LYMPHADENOPATHY_INGUINAL, SymptomsDto.CHILLS_SWEATS, SymptomsDto.BEDRIDDEN, SymptomsDto.ORAL_ULCERS, SymptomsDto.PAINFUL_LYMPHADENITIS, SymptomsDto.BLACKENING_DEATH_OF_TISSUE, SymptomsDto.BUBOES_GROIN_ARMPIT_NECK, SymptomsDto.BULGING_FONTANELLE, SymptomsDto.PHARYNGEAL_ERYTHEMA, SymptomsDto.PHARYNGEAL_EXUDATE, SymptomsDto.OEDEMA_FACE_NECK, SymptomsDto.OEDEMA_LOWER_EXTREMITY, SymptomsDto.LOSS_SKIN_TURGOR, SymptomsDto.PALPABLE_LIVER, SymptomsDto.PALPABLE_SPLEEN, SymptomsDto.MALAISE, SymptomsDto.SUNKEN_EYES_FONTANELLE, SymptomsDto.SIDE_PAIN, SymptomsDto.FLUID_IN_LUNG_CAVITY, SymptomsDto.TREMOR, SymptomsDto.BILATERAL_CATARACTS, SymptomsDto.UNILATERAL_CATARACTS, SymptomsDto.CONGENITAL_GLAUCOMA, SymptomsDto.CONGENITAL_HEART_DISEASE, SymptomsDto.PIGMENTARY_RETINOPATHY, SymptomsDto.RADIOLUCENT_BONE_DISEASE, SymptomsDto.SPLENOMEGALY, SymptomsDto.MICROCEPHALY, SymptomsDto.MENINGOENCEPHALITIS, SymptomsDto.PURPURIC_RASH, SymptomsDto.DEVELOPMENTAL_DELAY, SymptomsDto.CONGENITAL_HEART_DISEASE_TYPE, SymptomsDto.CONGENITAL_HEART_DISEASE_DETAILS, SymptomsDto.JAUNDICE_WITHIN_24_HOURS_OF_BIRTH, SymptomsDto.PATIENT_ILL_LOCATION); addField(SymptomsDto.LESIONS_ONSET_DATE, DateField.class); // complications addFields(SymptomsDto.ALTERED_CONSCIOUSNESS, SymptomsDto.CONFUSED_DISORIENTED, SymptomsDto.HEMORRHAGIC_SYNDROME, SymptomsDto.HYPERGLYCEMIA, SymptomsDto.HYPOGLYCEMIA, SymptomsDto.MENINGEAL_SIGNS, SymptomsDto.SEIZURES, SymptomsDto.SEPSIS, SymptomsDto.SHOCK); monkeypoxImageFieldIds = Arrays.asList(SymptomsDto.LESIONS_RESEMBLE_IMG1, SymptomsDto.LESIONS_RESEMBLE_IMG2, SymptomsDto.LESIONS_RESEMBLE_IMG3, SymptomsDto.LESIONS_RESEMBLE_IMG4); for (String propertyId : monkeypoxImageFieldIds) { @SuppressWarnings("rawtypes") Field monkeypoxImageField = addField(propertyId); CssStyles.style(monkeypoxImageField, CssStyles.VSPACE_NONE); } // Set initial visibilities initializeVisibilitiesAndAllowedVisibilities(disease, viewMode); if (symptomsContext != SymptomsContext.CLINICAL_VISIT) { setVisible(false, SymptomsDto.BLOOD_PRESSURE_SYSTOLIC, SymptomsDto.BLOOD_PRESSURE_DIASTOLIC, SymptomsDto.HEART_RATE, SymptomsDto.RESPIRATORY_RATE, SymptomsDto.WEIGHT, SymptomsDto.HEIGHT, SymptomsDto.MID_UPPER_ARM_CIRCUMFERENCE, SymptomsDto.GLASGOW_COMA_SCALE); } else { setVisible(false, SymptomsDto.ONSET_SYMPTOM, SymptomsDto.ONSET_DATE); } // Initialize lists conditionalBleedingSymptomFieldIds = Arrays.asList(SymptomsDto.GUMS_BLEEDING, SymptomsDto.INJECTION_SITE_BLEEDING, SymptomsDto.NOSE_BLEEDING, SymptomsDto.BLOODY_BLACK_STOOL, SymptomsDto.RED_BLOOD_VOMIT, SymptomsDto.DIGESTED_BLOOD_VOMIT, SymptomsDto.EYES_BLEEDING, SymptomsDto.COUGHING_BLOOD, SymptomsDto.BLEEDING_VAGINA, SymptomsDto.SKIN_BRUISING, SymptomsDto.STOMACH_BLEEDING, SymptomsDto.BLOOD_URINE, SymptomsDto.OTHER_HEMORRHAGIC_SYMPTOMS); lesionsFieldIds = Arrays.asList(SymptomsDto.LESIONS_SAME_STATE, SymptomsDto.LESIONS_SAME_SIZE, SymptomsDto.LESIONS_DEEP_PROFOUND, SymptomsDto.LESIONS_THAT_ITCH); lesionsLocationFieldIds = Arrays.asList(SymptomsDto.LESIONS_FACE, SymptomsDto.LESIONS_LEGS, SymptomsDto.LESIONS_SOLES_FEET, SymptomsDto.LESIONS_PALMS_HANDS, SymptomsDto.LESIONS_THORAX, SymptomsDto.LESIONS_ARMS, SymptomsDto.LESIONS_GENITALS, SymptomsDto.LESIONS_ALL_OVER_BODY); unconditionalSymptomFieldIds = Arrays.asList(SymptomsDto.FEVER, SymptomsDto.VOMITING, SymptomsDto.DIARRHEA, SymptomsDto.BLOOD_IN_STOOL, SymptomsDto.NAUSEA, SymptomsDto.ABDOMINAL_PAIN, SymptomsDto.HEADACHE, SymptomsDto.MUSCLE_PAIN, SymptomsDto.FATIGUE_WEAKNESS, SymptomsDto.SKIN_RASH, SymptomsDto.NECK_STIFFNESS, SymptomsDto.SORE_THROAT, SymptomsDto.COUGH, SymptomsDto.RUNNY_NOSE, SymptomsDto.DIFFICULTY_BREATHING, SymptomsDto.CHEST_PAIN, SymptomsDto.CONJUNCTIVITIS, SymptomsDto.EYE_PAIN_LIGHT_SENSITIVE, SymptomsDto.KOPLIKS_SPOTS, SymptomsDto.THROBOCYTOPENIA, SymptomsDto.OTITIS_MEDIA, SymptomsDto.HEARINGLOSS, SymptomsDto.DEHYDRATION, SymptomsDto.ANOREXIA_APPETITE_LOSS, SymptomsDto.REFUSAL_FEEDOR_DRINK, SymptomsDto.JOINT_PAIN, SymptomsDto.HICCUPS, SymptomsDto.BACKACHE, SymptomsDto.JAUNDICE, SymptomsDto.DARK_URINE, SymptomsDto.RAPID_BREATHING, SymptomsDto.SWOLLEN_GLANDS, SymptomsDto.UNEXPLAINED_BLEEDING, SymptomsDto.OTHER_NON_HEMORRHAGIC_SYMPTOMS, SymptomsDto.LESIONS, SymptomsDto.LYMPHADENOPATHY_AXILLARY, SymptomsDto.LYMPHADENOPATHY_CERVICAL, SymptomsDto.LYMPHADENOPATHY_INGUINAL, SymptomsDto.CHILLS_SWEATS, SymptomsDto.BEDRIDDEN, SymptomsDto.ORAL_ULCERS, SymptomsDto.PAINFUL_LYMPHADENITIS, SymptomsDto.BLACKENING_DEATH_OF_TISSUE, SymptomsDto.BUBOES_GROIN_ARMPIT_NECK, SymptomsDto.BULGING_FONTANELLE, SymptomsDto.PHARYNGEAL_ERYTHEMA, SymptomsDto.PHARYNGEAL_EXUDATE, SymptomsDto.OEDEMA_FACE_NECK, SymptomsDto.OEDEMA_LOWER_EXTREMITY, SymptomsDto.LOSS_SKIN_TURGOR, SymptomsDto.PALPABLE_LIVER, SymptomsDto.PALPABLE_SPLEEN, SymptomsDto.MALAISE, SymptomsDto.SUNKEN_EYES_FONTANELLE, SymptomsDto.SIDE_PAIN, SymptomsDto.FLUID_IN_LUNG_CAVITY, SymptomsDto.TREMOR, SymptomsDto.BILATERAL_CATARACTS, SymptomsDto.UNILATERAL_CATARACTS, SymptomsDto.CONGENITAL_GLAUCOMA, SymptomsDto.CONGENITAL_HEART_DISEASE, SymptomsDto.RADIOLUCENT_BONE_DISEASE, SymptomsDto.SPLENOMEGALY, SymptomsDto.MICROCEPHALY, SymptomsDto.MENINGOENCEPHALITIS, SymptomsDto.DEVELOPMENTAL_DELAY, SymptomsDto.PURPURIC_RASH, SymptomsDto.PIGMENTARY_RETINOPATHY, // complications SymptomsDto.ALTERED_CONSCIOUSNESS, SymptomsDto.CONFUSED_DISORIENTED, SymptomsDto.HEMORRHAGIC_SYNDROME, SymptomsDto.HYPERGLYCEMIA, SymptomsDto.HYPOGLYCEMIA, SymptomsDto.MENINGEAL_SIGNS, SymptomsDto.SEIZURES, SymptomsDto.SEPSIS, SymptomsDto.SHOCK); // Set visibilities FieldHelper.setVisibleWhen(getFieldGroup(), conditionalBleedingSymptomFieldIds, SymptomsDto.UNEXPLAINED_BLEEDING, Arrays.asList(SymptomState.YES), true, SymptomsDto.class, disease); FieldHelper.setVisibleWhen(getFieldGroup(), SymptomsDto.OTHER_HEMORRHAGIC_SYMPTOMS_TEXT, SymptomsDto.OTHER_HEMORRHAGIC_SYMPTOMS, Arrays.asList(SymptomState.YES), true); FieldHelper.setVisibleWhen(getFieldGroup(), SymptomsDto.OTHER_NON_HEMORRHAGIC_SYMPTOMS_TEXT, SymptomsDto.OTHER_NON_HEMORRHAGIC_SYMPTOMS, Arrays.asList(SymptomState.YES), true); FieldHelper.setVisibleWhen(getFieldGroup(), lesionsFieldIds, SymptomsDto.LESIONS, Arrays.asList(SymptomState.YES), true); FieldHelper.setVisibleWhen(getFieldGroup(), lesionsLocationFieldIds, SymptomsDto.LESIONS, Arrays.asList(SymptomState.YES), true); FieldHelper.setVisibleWhen(getFieldGroup(), SymptomsDto.LESIONS_ONSET_DATE, SymptomsDto.LESIONS, Arrays.asList(SymptomState.YES), true); FieldHelper.setVisibleWhen(getFieldGroup(), SymptomsDto.CONGENITAL_HEART_DISEASE_TYPE, SymptomsDto.CONGENITAL_HEART_DISEASE, Arrays.asList(SymptomState.YES), true); FieldHelper.setVisibleWhen(getFieldGroup(), SymptomsDto.CONGENITAL_HEART_DISEASE_DETAILS, SymptomsDto.CONGENITAL_HEART_DISEASE_TYPE, Arrays.asList(CongenitalHeartDiseaseType.OTHER), true); if (isVisibleAllowed(getFieldGroup().getField(SymptomsDto.JAUNDICE_WITHIN_24_HOURS_OF_BIRTH))) { FieldHelper.setVisibleWhen(getFieldGroup(), SymptomsDto.JAUNDICE_WITHIN_24_HOURS_OF_BIRTH, SymptomsDto.JAUNDICE, Arrays.asList(SymptomState.YES), true); } FieldHelper.addSoftRequiredStyle(getField(SymptomsDto.LESIONS_ONSET_DATE)); boolean isInfant = person != null && person.getApproximateAge() != null && ((person.getApproximateAge() <= 12 && person.getApproximateAgeType() == ApproximateAgeType.MONTHS) || person.getApproximateAge() <= 1); if (!isInfant) { getFieldGroup().getField(SymptomsDto.BULGING_FONTANELLE).setVisible(false); } // Handle visibility of lesions locations caption Label lesionsLocationsCaption = new Label(I18nProperties.getCaption(Captions.symptomsLesionsLocations)); CssStyles.style(lesionsLocationsCaption, CssStyles.VSPACE_3); getContent().addComponent(lesionsLocationsCaption, LESIONS_LOCATIONS_LOC); getContent().getComponent(LESIONS_LOCATIONS_LOC) .setVisible(getFieldGroup().getField(SymptomsDto.LESIONS).getValue() == SymptomState.YES); getFieldGroup().getField(SymptomsDto.LESIONS).addValueChangeListener(e -> { getContent().getComponent(LESIONS_LOCATIONS_LOC) .setVisible(e.getProperty().getValue() == SymptomState.YES); }); // Symptoms hint text Label symptomsHint = new Label( I18nProperties.getString(symptomsContext == SymptomsContext.CASE ? Strings.messageSymptomsHint : Strings.messageSymptomsVisitHint), ContentMode.HTML); getContent().addComponent(symptomsHint, SYMPTOMS_HINT_LOC); if (disease == Disease.MONKEYPOX) { setUpMonkeypoxVisibilities(); } if (symptomsContext != SymptomsContext.CASE) { getFieldGroup().getField(SymptomsDto.PATIENT_ILL_LOCATION).setVisible(false); } FieldHelper.setRequiredWhen(getFieldGroup(), getFieldGroup().getField(SymptomsDto.OTHER_HEMORRHAGIC_SYMPTOMS), Arrays.asList(SymptomsDto.OTHER_HEMORRHAGIC_SYMPTOMS_TEXT), Arrays.asList(SymptomState.YES), disease); FieldHelper.setRequiredWhen(getFieldGroup(), getFieldGroup().getField(SymptomsDto.OTHER_NON_HEMORRHAGIC_SYMPTOMS), Arrays.asList(SymptomsDto.OTHER_NON_HEMORRHAGIC_SYMPTOMS_TEXT), Arrays.asList(SymptomState.YES), disease); FieldHelper.setRequiredWhen(getFieldGroup(), getFieldGroup().getField(SymptomsDto.LESIONS), lesionsFieldIds, Arrays.asList(SymptomState.YES), disease); FieldHelper.setRequiredWhen(getFieldGroup(), getFieldGroup().getField(SymptomsDto.LESIONS), monkeypoxImageFieldIds, Arrays.asList(SymptomState.YES), disease); addListenerForOnsetFields(onsetSymptom, onsetDateField); Button clearAllButton = new Button(I18nProperties.getCaption(Captions.actionClearAll)); clearAllButton.addStyleName(ValoTheme.BUTTON_LINK); clearAllButton.addClickListener(new ClickListener() { @Override public void buttonClick(ClickEvent event) { for (Object symptomId : unconditionalSymptomFieldIds) { getFieldGroup().getField(symptomId).setValue(null); } for (Object symptomId : conditionalBleedingSymptomFieldIds) { getFieldGroup().getField(symptomId).setValue(null); } for (Object symptomId : lesionsFieldIds) { getFieldGroup().getField(symptomId).setValue(null); } for (Object symptomId : lesionsLocationFieldIds) { getFieldGroup().getField(symptomId).setValue(null); } for (Object symptomId : monkeypoxImageFieldIds) { getFieldGroup().getField(symptomId).setValue(null); } } }); Button setEmptyToNoButton = new Button(I18nProperties.getCaption(Captions.symptomsSetClearedToNo)); setEmptyToNoButton.addStyleName(ValoTheme.BUTTON_LINK); setEmptyToNoButton.addClickListener(new ClickListener() { @SuppressWarnings("unchecked") @Override public void buttonClick(ClickEvent event) { for (Object symptomId : unconditionalSymptomFieldIds) { Field<SymptomState> symptom = (Field<SymptomState>) getFieldGroup().getField(symptomId); if (symptom.isVisible() && symptom.getValue() == null) { symptom.setValue(SymptomState.NO); } } for (Object symptomId : conditionalBleedingSymptomFieldIds) { Field<SymptomState> symptom = (Field<SymptomState>) getFieldGroup().getField(symptomId); if (symptom.isVisible() && symptom.getValue() == null) { symptom.setValue(SymptomState.NO); } } for (Object symptomId : lesionsFieldIds) { Field<SymptomState> symptom = (Field<SymptomState>) getFieldGroup().getField(symptomId); if (symptom.isVisible() && symptom.getValue() == null) { symptom.setValue(SymptomState.NO); } } for (Object symptomId : monkeypoxImageFieldIds) { Field<SymptomState> symptom = (Field<SymptomState>) getFieldGroup().getField(symptomId); if (symptom.isVisible() && symptom.getValue() == null) { symptom.setValue(SymptomState.NO); } } } }); // Complications heading - not displayed for Rubella (dirty, should be made generic) Label complicationsHeading = new Label(I18nProperties.getString(Strings.headingComplications)); CssStyles.style(complicationsHeading, CssStyles.H3); if (disease != Disease.CONGENITAL_RUBELLA) { getContent().addComponent(complicationsHeading, COMPLICATIONS_HEADING); } HorizontalLayout buttonsLayout = new HorizontalLayout(); buttonsLayout.addComponent(clearAllButton); buttonsLayout.addComponent(setEmptyToNoButton); buttonsLayout.setDefaultComponentAlignment(Alignment.MIDDLE_RIGHT); getContent().addComponent(buttonsLayout, BUTTONS_LOC); } @Override protected String createHtmlLayout() { return HTML_LAYOUT; } public void initializeSymptomRequirementsForVisit(OptionGroup visitStatus) { FieldHelper.addSoftRequiredStyleWhen(getFieldGroup(), visitStatus, Arrays.asList(SymptomsDto.TEMPERATURE, SymptomsDto.TEMPERATURE_SOURCE), Arrays.asList(VisitStatus.COOPERATIVE), disease); addSoftRequiredStyleWhenSymptomaticAndCooperative(getFieldGroup(), SymptomsDto.ONSET_DATE, unconditionalSymptomFieldIds, Arrays.asList(SymptomState.YES), visitStatus); addSoftRequiredStyleWhenSymptomaticAndCooperative(getFieldGroup(), SymptomsDto.ONSET_SYMPTOM, unconditionalSymptomFieldIds, Arrays.asList(SymptomState.YES), visitStatus); getFieldGroup().getField(SymptomsDto.FEVER).addValidator(new Validator() { @Override public void validate(Object value) throws InvalidValueException { if (getFieldGroup().getField(SymptomsDto.TEMPERATURE).getValue() != null) { if ((Float) (getFieldGroup().getField(SymptomsDto.TEMPERATURE).getValue()) >= 38.0f) { if (value != SymptomState.YES) { throw new InvalidValueException( I18nProperties.getString(Strings.errorSetFeverRequired)); } } } } }); } @Override public void setValue(SymptomsDto newFieldValue) throws ReadOnlyException, ConversionException { super.setValue(newFieldValue); initializeSymptomRequirementsForCase(); if (symptomsContext == SymptomsContext.CLINICAL_VISIT) { initializeSymptomRequirementsForClinicalVisit(); } } private void initializeSymptomRequirementsForCase() { addSoftRequiredStyleWhenSymptomaticAndCooperative(getFieldGroup(), SymptomsDto.ONSET_DATE, unconditionalSymptomFieldIds, Arrays.asList(SymptomState.YES), null); addSoftRequiredStyleWhenSymptomaticAndCooperative(getFieldGroup(), SymptomsDto.ONSET_SYMPTOM, unconditionalSymptomFieldIds, Arrays.asList(SymptomState.YES), null); addSoftRequiredStyleWhenSymptomaticAndCooperative(getFieldGroup(), SymptomsDto.PATIENT_ILL_LOCATION, unconditionalSymptomFieldIds, Arrays.asList(SymptomState.YES), null); } private void initializeSymptomRequirementsForClinicalVisit() { getFieldGroup().getField(SymptomsDto.FEVER).addValidator(new Validator() { @Override public void validate(Object value) throws InvalidValueException { if (getFieldGroup().getField(SymptomsDto.TEMPERATURE).getValue() != null) { if ((Float) (getFieldGroup().getField(SymptomsDto.TEMPERATURE).getValue()) >= 38.0f) { if (value != SymptomState.YES) { throw new InvalidValueException( I18nProperties.getString(Strings.errorSetFeverRequired)); } } } } }); } /** * Sets the fields defined by the ids contained in sourceValues to required when the person is symptomatic * and - if a visit is processed - cooperative. When this method is called from within a case, it needs to * be called with visitStatusField set to null in order to ignore the visit status requirement. */ @SuppressWarnings("rawtypes") private void addSoftRequiredStyleWhenSymptomaticAndCooperative(FieldGroup fieldGroup, Object targetPropertyId, List<String> sourcePropertyIds, List<Object> sourceValues, OptionGroup visitStatusField) { for (Object sourcePropertyId : sourcePropertyIds) { Field sourceField = fieldGroup.getField(sourcePropertyId); if (sourceField instanceof AbstractField<?>) { ((AbstractField) sourceField).setImmediate(true); } } // Initialize final Field targetField = fieldGroup.getField(targetPropertyId); if (!targetField.isVisible()) { return; } if (visitStatusField != null) { if (isAnySymptomSetToYes(fieldGroup, sourcePropertyIds, sourceValues) && visitStatusField.getValue() == VisitStatus.COOPERATIVE) { FieldHelper.addSoftRequiredStyle(targetField); } else { FieldHelper.removeSoftRequiredStyle(targetField); } } else { if (isAnySymptomSetToYes(fieldGroup, sourcePropertyIds, sourceValues)) { FieldHelper.addSoftRequiredStyle(targetField); } else { FieldHelper.removeSoftRequiredStyle(targetField); } } // Add listeners for (Object sourcePropertyId : sourcePropertyIds) { Field sourceField = fieldGroup.getField(sourcePropertyId); sourceField.addValueChangeListener(event -> { if (visitStatusField != null) { if (isAnySymptomSetToYes(fieldGroup, sourcePropertyIds, sourceValues) && visitStatusField.getValue() == VisitStatus.COOPERATIVE) { FieldHelper.addSoftRequiredStyle(targetField); } else { FieldHelper.removeSoftRequiredStyle(targetField); } } else { if (isAnySymptomSetToYes(fieldGroup, sourcePropertyIds, sourceValues)) { FieldHelper.addSoftRequiredStyle(targetField); } else { FieldHelper.removeSoftRequiredStyle(targetField); } } }); } if (visitStatusField != null) { visitStatusField.addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { if (isAnySymptomSetToYes(fieldGroup, sourcePropertyIds, sourceValues) && visitStatusField.getValue() == VisitStatus.COOPERATIVE) { FieldHelper.addSoftRequiredStyle(targetField); } else { FieldHelper.removeSoftRequiredStyle(targetField); } } }); } } /** * Returns true if if the value of any field associated with the sourcePropertyIds * is set to one of the values contained in sourceValues. * * @param fieldGroup * @param sourcePropertyIds * @param sourceValues * @return */ @SuppressWarnings("rawtypes") public boolean isAnySymptomSetToYes(FieldGroup fieldGroup, List<String> sourcePropertyIds, List<Object> sourceValues) { for (Object sourcePropertyId : sourcePropertyIds) { Field sourceField = fieldGroup.getField(sourcePropertyId); if (sourceValues.contains(sourceField.getValue())) { return true; } } return false; } @SuppressWarnings("rawtypes") private void addListenerForOnsetFields(ComboBox onsetSymptom, DateField onsetDateField) { List<String> allPropertyIds = Stream .concat(unconditionalSymptomFieldIds.stream(), conditionalBleedingSymptomFieldIds.stream()) .collect(Collectors.toList()); allPropertyIds.add(SymptomsDto.LESIONS_THAT_ITCH); for (Object sourcePropertyId : allPropertyIds) { Field sourceField = getFieldGroup().getField(sourcePropertyId); sourceField.addValueChangeListener(event -> { if (sourceField.getValue() == SymptomState.YES) { onsetSymptom.addItem(sourceField.getCaption()); onsetDateField.setEnabled(true); } else { onsetSymptom.removeItem(sourceField.getCaption()); onsetDateField.setEnabled( isAnySymptomSetToYes(getFieldGroup(), allPropertyIds, Arrays.asList(SymptomState.YES))); } onsetSymptom.setEnabled(!onsetSymptom.getItemIds().isEmpty()); }); } onsetSymptom.setEnabled(false); // will be updated by listener if needed onsetDateField.setEnabled(false); // will be updated by listener if needed } private void setUpMonkeypoxVisibilities() { // Monkeypox picture resemblance fields FieldHelper.setVisibleWhen(getFieldGroup(), monkeypoxImageFieldIds, SymptomsDto.LESIONS, Arrays.asList(SymptomState.YES), true); // Set up images Image lesionsImg1 = new Image(null, new ThemeResource("img/monkeypox-lesions-1.png")); CssStyles.style(lesionsImg1, CssStyles.VSPACE_3); Image lesionsImg2 = new Image(null, new ThemeResource("img/monkeypox-lesions-2.png")); CssStyles.style(lesionsImg2, CssStyles.VSPACE_3); Image lesionsImg3 = new Image(null, new ThemeResource("img/monkeypox-lesions-3.png")); CssStyles.style(lesionsImg3, CssStyles.VSPACE_3); Image lesionsImg4 = new Image(null, new ThemeResource("img/monkeypox-lesions-4.png")); CssStyles.style(lesionsImg4, CssStyles.VSPACE_3); getContent().addComponent(lesionsImg1, MONKEYPOX_LESIONS_IMG1); getContent().addComponent(lesionsImg2, MONKEYPOX_LESIONS_IMG2); getContent().addComponent(lesionsImg3, MONKEYPOX_LESIONS_IMG3); getContent().addComponent(lesionsImg4, MONKEYPOX_LESIONS_IMG4); List<String> monkeypoxImages = Arrays.asList(MONKEYPOX_LESIONS_IMG1, MONKEYPOX_LESIONS_IMG2, MONKEYPOX_LESIONS_IMG3, MONKEYPOX_LESIONS_IMG4); // Set up initial visibility boolean lesionsSetToYes = getFieldGroup().getField(SymptomsDto.LESIONS).getValue() == SymptomState.YES; for (String monkeypoxImage : monkeypoxImages) { getContent().getComponent(monkeypoxImage).setVisible(lesionsSetToYes); } // Set up image visibility listener getFieldGroup().getField(SymptomsDto.LESIONS).addValueChangeListener(e -> { for (String monkeypoxImage : monkeypoxImages) { getContent().getComponent(monkeypoxImage) .setVisible(e.getProperty().getValue() == SymptomState.YES); } }); } public List<String> getUnconditionalSymptomFieldIds() { return unconditionalSymptomFieldIds; } }