/* * This file is part of ADDIS (Aggregate Data Drug Information System). * ADDIS is distributed from http://drugis.org/. * Copyright © 2009 Gert van Valkenhoef, Tommi Tervonen. * Copyright © 2010 Gert van Valkenhoef, Tommi Tervonen, Tijs Zwinkels, * Maarten Jacobs, Hanno Koeslag, Florin Schimbinschi, Ahmad Kamal, Daniel * Reid. * Copyright © 2011 Gert van Valkenhoef, Ahmad Kamal, Daniel Reid, Florin * Schimbinschi. * Copyright © 2012 Gert van Valkenhoef, Daniel Reid, Joël Kuiper, Wouter * Reckman. * Copyright © 2013 Gert van Valkenhoef, Joël Kuiper. * * 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 <http://www.gnu.org/licenses/>. */ package org.drugis.addis.gui; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.swing.JDialog; import org.drugis.addis.entities.FlexibleDose; import org.drugis.addis.gui.wizard.AbstractTreatmentCategorizationWizardStep; import org.drugis.addis.gui.wizard.AddTreatmentCategorizationWizardStep; import org.drugis.addis.gui.wizard.DoseRangeWizardStep; import org.drugis.addis.gui.wizard.TreatmentCategorizationOverviewWizardStep; import org.drugis.addis.gui.wizard.SpecifyDoseTypeWizardStep; import org.drugis.addis.presentation.UnmodifiableHolder; import org.drugis.addis.presentation.ValueHolder; import org.drugis.addis.presentation.ValueModelWrapper; import org.drugis.addis.presentation.wizard.TreatmentCategorizationWizardPresentation; import org.drugis.common.beans.AbstractObservable; import org.drugis.common.validation.BooleanAndModel; import org.drugis.common.validation.BooleanNotModel; import org.drugis.common.validation.BooleanOrModel; import org.pietschy.wizard.Wizard; import org.pietschy.wizard.WizardEvent; import org.pietschy.wizard.WizardListener; import org.pietschy.wizard.WizardModel; import org.pietschy.wizard.WizardStep; import org.pietschy.wizard.models.BranchingPath; import org.pietschy.wizard.models.Condition; import org.pietschy.wizard.models.MultiPathModel; import org.pietschy.wizard.models.Path; import org.pietschy.wizard.models.SimplePath; import com.jgoodies.binding.value.ValueModel; @SuppressWarnings("serial") public class AddDosedDrugTreatmentWizard extends Wizard { private static final List<Condition> s_conditions = new ArrayList<Condition>(); private static final class DynamicMultiPathModel extends MultiPathModel { public DynamicMultiPathModel(final Path firstPath) { super(firstPath); for(final Condition condition : s_conditions) { if(condition instanceof ValueHolderCondition) { final ValueHolderCondition wrapped = (ValueHolderCondition) condition; attachListener(wrapped); } } setLastVisible(false); } private void attachListener(final ValueHolderCondition wrapped) { wrapped.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(final PropertyChangeEvent evt) { refreshModelState(); } }); } } private static final class ValueHolderCondition extends AbstractObservable implements Condition { private final ValueHolder<Boolean> d_condition; private ValueHolderCondition(final ValueModel condition) { d_condition = new ValueModelWrapper<Boolean>(condition); d_condition.addValueChangeListener(new PropertyChangeListener() { @Override public void propertyChange(final PropertyChangeEvent evt) { firePropertyChange("value", evt.getOldValue(), evt.getNewValue()); } }); } @Override public boolean evaluate(final WizardModel model) { return d_condition.getValue(); } @Override public String toString() { return "condition[" + d_condition.getValue() + "]"; } } public AddDosedDrugTreatmentWizard( final TreatmentCategorizationWizardPresentation pm, final JDialog dialog) { super(buildModel(pm, dialog)); final AddisWindow mainWindow = Main.getMainWindow(); addWizardListener(new WizardListener() { @Override public void wizardClosed(final WizardEvent e) { mainWindow.leftTreeFocus(pm.commit()); } @Override public void wizardCancelled(final WizardEvent e) { } }); setDefaultExitMode(Wizard.EXIT_ON_FINISH); } private static WizardModel buildModel(final TreatmentCategorizationWizardPresentation pm, final JDialog dialog) { final AddTreatmentCategorizationWizardStep generalInfo = new AddTreatmentCategorizationWizardStep(pm, dialog); final SpecifyDoseTypeWizardStep type = new SpecifyDoseTypeWizardStep(pm, dialog); final TreatmentCategorizationOverviewWizardStep overview = new TreatmentCategorizationOverviewWizardStep(pm); final SimplePath lastPath = new SimplePath(overview); final BranchingPath typePath = new BranchingPath(type); final BranchingPath firstStep = new BranchingPath(generalInfo); final BranchingPath fixedAndFlexiblePath = new BranchingPath(createFixedDose(dialog, pm)); final ValueModel considerFixed = pm.getConsiderFixed(); buildFlexiblePath(pm, dialog, fixedAndFlexiblePath, type, lastPath, new UnmodifiableHolder<Boolean>(true)); buildFlexiblePath(pm, dialog, typePath, type, lastPath, new BooleanNotModel(considerFixed)); final ValueModel anyFlexibleDose = new BooleanOrModel(Arrays.<ValueModel>asList( pm.getConsiderFlexibleLowerFirst(), pm.getConsiderFlexibleUpperFirst())); addBranch(typePath, createSimplePath(lastPath, createFixedDose(dialog, pm)), new BooleanAndModel(new BooleanNotModel(anyFlexibleDose), considerFixed)); addBranch(typePath, lastPath, new BooleanAndModel(new BooleanNotModel(anyFlexibleDose), new BooleanNotModel(considerFixed))); addBranch(typePath, fixedAndFlexiblePath, new BooleanAndModel(considerFixed, anyFlexibleDose)); addBranch(firstStep, lastPath, new BooleanNotModel(new BooleanOrModel(pm.getConsiderDoseType(), pm.getIgnoreDoseType()))); addBranch(firstStep, typePath, pm.getConsiderDoseType()); addBranch(firstStep, createSimplePath(lastPath, createKnownDose(dialog, pm)), pm.getIgnoreDoseType()); return new DynamicMultiPathModel(firstStep); } private static void buildFlexiblePath(final TreatmentCategorizationWizardPresentation pm, final JDialog dialog, final BranchingPath flexiblePath, final SpecifyDoseTypeWizardStep type, final SimplePath lastPath, final ValueModel condition) { final DoseRangeWizardStep lowerFirst = createFlexibleLowerDose(dialog, pm); final DoseRangeWizardStep upperFirst = createFlexibleUpperDose(dialog, pm); final BranchingPath lowerFirstPath = new BranchingPath(lowerFirst); final BranchingPath upperFirstPath = new BranchingPath(upperFirst); addBranch(flexiblePath, lowerFirstPath, new BooleanAndModel(condition, pm.getConsiderFlexibleLowerFirst())); addBranch(flexiblePath, upperFirstPath, new BooleanAndModel(condition, pm.getConsiderFlexibleUpperFirst())); addBranch(lowerFirstPath, createSimplePath(lastPath, createFlexibleUpperRanges(dialog, pm)), lowerFirst.getConsiderNextProperty()); addBranch(upperFirstPath, createSimplePath(lastPath, createFlexibleLowerRanges(dialog, pm)), upperFirst.getConsiderNextProperty()); addBranch(lowerFirstPath, lastPath, new BooleanNotModel(lowerFirst.getConsiderNextProperty())); addBranch(upperFirstPath, lastPath, new BooleanNotModel(upperFirst.getConsiderNextProperty())); } private static WizardStep createFlexibleUpperRanges(final JDialog dialog, final TreatmentCategorizationWizardPresentation pm) { return DoseRangeWizardStep.createOnMultipleParentRanges( dialog, pm, pm.getFlexibleLowerRanges(), "Specify the ranges for upper bound of flexible doses", "For each of the categories, define a range in which the upper bound of the administered dose must lie. "); } private static WizardStep createFlexibleLowerRanges(final JDialog dialog, final TreatmentCategorizationWizardPresentation pm) { return DoseRangeWizardStep.createOnMultipleParentRanges( dialog, pm, pm.getFlexibleUpperRanges(), "Specify the ranges for lower bound of flexible doses", "For each of the categories, define a range in which the lower bound of the administered dose must lie."); } private static AbstractTreatmentCategorizationWizardStep createFixedDose(final JDialog dialog, final TreatmentCategorizationWizardPresentation pm) { return DoseRangeWizardStep.createOnBeanProperty( dialog, pm, pm.getFixedRangeNode(), null, "Specify ranges for fixed doses", "For each of the categories, define a range in which the administered dose must lie."); } private static DoseRangeWizardStep createFlexibleLowerDose(final JDialog dialog, final TreatmentCategorizationWizardPresentation pm) { return DoseRangeWizardStep.createOnBeanProperty( dialog, pm, pm.getFlexibleLowerRangeNode(), FlexibleDose.PROPERTY_MAX_DOSE, "Specify the ranges for lower bound of flexible doses", "For each of the categories, define a range in which the lower bound of the administered dose must lie."); } private static DoseRangeWizardStep createFlexibleUpperDose(final JDialog dialog, final TreatmentCategorizationWizardPresentation pm) { return DoseRangeWizardStep.createOnBeanProperty( dialog, pm, pm.getFlexibleUpperRangeNode(), FlexibleDose.PROPERTY_MIN_DOSE, "Specify the ranges for upper bound of flexible doses", "For each of the categories, define a range in which the upper bound of the administered dose must lie."); } private static WizardStep createKnownDose(final JDialog dialog, final TreatmentCategorizationWizardPresentation pm) { return DoseRangeWizardStep.createOnKnownDoses(dialog, pm, "Any dose type", "For each of the categories, define a range in which the dose must lie. For flexible dose the entire administered dose range must be within the specified range to be in the category."); } private static void addBranch(final BranchingPath origin, final Path destination, final ValueModel model) { final Condition condition = createCondition(model); addBranch(origin, destination, condition); } private static void addBranch(final BranchingPath origin, final Path destination, final Condition condition) { s_conditions.add(condition); origin.addBranch(destination, condition); } private static Condition createCondition(final ValueModel condition) { return new ValueHolderCondition(condition); } private static SimplePath createSimplePath(final SimplePath nextPath, final WizardStep ... steps) { final SimplePath path = new SimplePath(); for(final WizardStep step : steps) { path.addStep(step); } path.setNextPath(nextPath); return path; } }