/* * 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.wizard; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.text.DefaultFormatter; import org.drugis.addis.FileNames; import org.drugis.addis.entities.StudyOutcomeMeasure; import org.drugis.addis.entities.TypeWithNotes; import org.drugis.addis.entities.Variable; import org.drugis.addis.entities.WhenTaken; import org.drugis.addis.entities.WhenTaken.RelativeTo; import org.drugis.addis.gui.AuxComponentFactory; import org.drugis.addis.gui.GUIFactory; import org.drugis.addis.gui.Main; import org.drugis.addis.gui.components.NotesView; import org.drugis.addis.presentation.DurationPresentation; import org.drugis.addis.presentation.ModifiableHolder; import org.drugis.addis.presentation.SelectFromFiniteListPresentation; import org.drugis.addis.presentation.ValueHolder; import org.drugis.addis.presentation.WhenTakenPresentation; import org.drugis.addis.presentation.wizard.AddEpochsPresentation; import org.drugis.addis.util.EntityUtil; import org.drugis.common.gui.LayoutUtil; import org.drugis.common.gui.OkCancelDialog; import org.drugis.mtc.gui.MainWindow; import org.pietschy.wizard.PanelWizardStep; import com.jgoodies.binding.adapter.BasicComponentFactory; import com.jgoodies.binding.adapter.Bindings; import com.jgoodies.binding.beans.PropertyAdapter; import com.jgoodies.binding.beans.PropertyConnector; import com.jgoodies.forms.builder.PanelBuilder; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; @SuppressWarnings("serial") public class SelectFromOutcomeMeasureListWizardStep<T extends Variable> extends PanelWizardStep { private SelectFromFiniteListPresentation<T> d_pm; private class RemoveSlotListener extends AbstractAction { int d_index; public RemoveSlotListener(final int index) { d_index = index; } public void actionPerformed(final ActionEvent e) { d_pm.removeSlot(d_index); prepare(); } } private class newOptionButtonListener extends AbstractAction { int d_index; public newOptionButtonListener(final int index) { d_index = index; } public void actionPerformed(final ActionEvent e) { d_pm.showAddOptionDialog(d_index); } } private PanelBuilder d_builder; private JScrollPane d_scrollPane; private final AddEpochsPresentation d_epm; private final JDialog d_parent; public SelectFromOutcomeMeasureListWizardStep(final JDialog parent, final SelectFromFiniteListPresentation<T> pm, final AddEpochsPresentation epm) { super(pm.getTitle(), pm.getDescription()); d_parent = parent; d_epm = epm; setLayout(new BorderLayout()); d_pm = pm; setComplete((Boolean)d_pm.getInputCompleteModel().getValue()); PropertyConnector.connectAndUpdate(d_pm.getInputCompleteModel(), this, "complete"); } @Override public void prepare() { this.setVisible(false); if (d_scrollPane != null) remove(d_scrollPane); buildWizardStep(); this.setVisible(true); repaint(); } private void buildWizardStep() { FormLayout layout = new FormLayout( "max(30dlu;pref), 3dlu, right:pref, 3dlu, fill:pref:grow, 3dlu, left:pref", "p, 3dlu, p" ); d_builder = new PanelBuilder(layout); d_builder.setDefaultDialogBorder(); CellConstraints cc = new CellConstraints(); d_builder.addLabel(d_pm.getTypeName() + "s: ", cc.xy(5, 1)); int row = buildSlotsPart(7, cc, 1, layout); // Add slot button row += 2; JButton btn = new JButton("Add"); d_builder.add(btn, cc.xy(1, row)); Bindings.bind(btn, "enabled", d_pm.getAddSlotsEnabledModel()); btn.addActionListener(new AbstractAction() { public void actionPerformed(final ActionEvent e) { d_pm.addSlot(); prepare(); } }); d_builder.addSeparator("", cc.xy(5, row)); JPanel panel = d_builder.getPanel(); d_scrollPane = new JScrollPane(panel); d_scrollPane.getVerticalScrollBar().setUnitIncrement(16); add(d_scrollPane, BorderLayout.CENTER); } private int buildSlotsPart(final int fullWidth, final CellConstraints cc, int row, final FormLayout layout) { for(int i = 0; i < d_pm.countSlots(); ++i) { row = LayoutUtil.addRow(layout, row); // add 'remove' button JButton btn = new JButton("Remove"); d_builder.add(btn, cc.xy(1, row)); btn.addActionListener(new RemoveSlotListener(i)); // dropdown ModifiableHolder<T> slot = d_pm.getSlot(i); d_builder.add(AuxComponentFactory.createBoundComboBox(d_pm.getOptions(), slot, true), cc.xy(5, row)); // (new) + button if (d_pm.hasAddOptionDialog()) { JButton addOptionButton = GUIFactory.createPlusButton("Create " + d_pm.getTypeName()); addOptionButton.addActionListener(new newOptionButtonListener(i)); d_builder.add(addOptionButton, cc.xy(7, row)); } row = createAdditionalComponents(slot, d_builder, layout, row); row = createMeasurementMomentsRow(slot, d_builder, layout, row); if (slot instanceof TypeWithNotes) { row = LayoutUtil.addRow(layout, row); d_builder.add(new NotesView(((TypeWithNotes)slot).getNotes(), true), cc.xy(5, row)); } row = LayoutUtil.addRow(layout, row); } return row; } private int createMeasurementMomentsRow(final ModifiableHolder<T> slot, final PanelBuilder builder, final FormLayout layout, int row) { CellConstraints cc = new CellConstraints(); row = LayoutUtil.addRow(layout, row); builder.add(new MeasurementMomentsPanel<T>(d_parent, (StudyOutcomeMeasure<T>) slot, d_epm), cc.xyw(3, row, 5)); return row; } private static class MeasurementMomentsPanel<T extends Variable> extends JPanel { private final JDialog d_parent; private final StudyOutcomeMeasure<T> d_slot; private final AddEpochsPresentation d_epm; public MeasurementMomentsPanel(final JDialog parent, final StudyOutcomeMeasure<T> slot, final AddEpochsPresentation epm) { d_parent = parent; d_slot = slot; d_epm = epm; setLayout(new FlowLayout(FlowLayout.LEFT)); add(buildPanel()); } private void rebuild() { setVisible(false); removeAll(); add(buildPanel()); setVisible(true); } private JComponent buildPanel() { FormLayout momentLayout = new FormLayout( "right:pref, 3dlu, left:pref, 3dlu, left:pref, 3dlu, left:pref", "p, 3dlu, p" ); final PanelBuilder momentPanelBuilder = new PanelBuilder(momentLayout); CellConstraints cc = new CellConstraints(); int row = 1; final StudyOutcomeMeasure<T> som = ((StudyOutcomeMeasure<T>)d_slot); for (final WhenTaken wt : som.getWhenTaken()) { row = LayoutUtil.addRow(momentLayout, row); momentPanelBuilder.addLabel("Measurement moment: ", cc.xy(1, row)); momentPanelBuilder.addLabel(wt.toString(), cc.xy(3, row)); JButton editButton = new JButton(Main.IMAGELOADER.getIcon(FileNames.ICON_EDIT)); editButton.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { AddWhenTakenDialog<T> dialog = new AddWhenTakenDialog<T>(d_parent, wt, (StudyOutcomeMeasure<T>) d_slot, d_epm); dialog.setVisible(true); rebuild(); } }); momentPanelBuilder.add(editButton, cc.xy(5, row)); JButton deleteButton = new JButton(MainWindow.IMAGELOADER.getIcon(org.drugis.mtc.gui.FileNames.ICON_DELETE)); deleteButton.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { d_slot.getWhenTaken().remove(wt); rebuild(); } }); momentPanelBuilder.add(deleteButton, cc.xy(7, row)); } row = LayoutUtil.addRow(momentLayout, row); JButton addWhenTakenButton = new JButton("Add measurement moment"); addWhenTakenButton.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { AddWhenTakenDialog<T> dialog = new AddWhenTakenDialog<T>(d_parent, (StudyOutcomeMeasure<T>) d_slot, d_epm); dialog.setVisible(true); rebuild(); } }); momentPanelBuilder.add(addWhenTakenButton, cc.xy(1, row)); return momentPanelBuilder.getPanel(); } } private static class AddWhenTakenDialog<T extends Variable> extends OkCancelDialog { private final StudyOutcomeMeasure<T> d_som; private final WhenTaken d_old; private final WhenTaken d_wt; private final ValueHolder<Boolean> d_validModel = new ModifiableHolder<Boolean>(); private final AddEpochsPresentation d_epm; public AddWhenTakenDialog(final JDialog parent, final WhenTaken wt, final StudyOutcomeMeasure<T> som, final AddEpochsPresentation epm) { super(parent, true); setLocationByPlatform(true); d_old = wt; d_som = som; d_epm = epm; if (d_old == null) { d_wt = new WhenTaken(EntityUtil.createDuration("P0D"), RelativeTo.BEFORE_EPOCH_END, d_epm.getStudy().findTreatmentEpoch()); } else { d_wt = wt.clone(); } d_wt.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(final PropertyChangeEvent evt) { d_validModel.setValue(isUnique()); } }); d_validModel.setValue(isUnique()); Bindings.bind(d_okButton, "enabled", d_validModel); getUserPanel().add(new MeasurementMomentsEditorPanel<T>(d_wt, epm)); getUserPanel().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "submit"); getUserPanel().getActionMap().put("submit", new AbstractAction() { public void actionPerformed(final ActionEvent e) { commit(); } }); pack(); } public AddWhenTakenDialog(final JDialog parent, final StudyOutcomeMeasure<T> som, final AddEpochsPresentation epm) { this(parent, null, som, epm); } private boolean isUnique() { if (!d_som.getWhenTaken().contains(d_wt)) { return true; } else { return d_wt.equals(d_old); } } @Override protected void cancel() { dispose(); } @Override protected void commit() { if (isUnique()) { d_wt.commit(); if (d_old == null) { d_som.getWhenTaken().add(d_wt); } else { d_epm.getStudy().replaceWhenTaken(d_som, d_old, d_wt); } dispose(); } } } private static class MeasurementMomentsEditorPanel<T extends Variable> extends JPanel { private final AddEpochsPresentation d_epm; private final WhenTaken d_wt; public MeasurementMomentsEditorPanel(final WhenTaken wt, final AddEpochsPresentation epm) { d_wt = wt; d_epm = epm; add(buildPanel()); } private JComponent buildPanel() { FormLayout momentLayout = new FormLayout( "max(30dlu;pref), 3dlu, right:pref, 3dlu, fill:pref:grow, 3dlu, left:pref, 3dlu, left:pref", "p" ); final PanelBuilder momentPanelBuilder = new PanelBuilder(momentLayout); CellConstraints cc = new CellConstraints(); int row2 = 1; WhenTakenPresentation wtp = new WhenTakenPresentation(d_wt, d_epm.getList()); row2 = LayoutUtil.addRow(momentLayout, row2); momentPanelBuilder.add(new JLabel("Measurement moment: "), cc.xy(1, row2)); DurationPresentation<WhenTaken> durationModel = wtp.getOffsetPresentation(); // duration quantity input final JTextField quantityField = BasicComponentFactory.createFormattedTextField( new PropertyAdapter<DurationPresentation<WhenTaken>>(durationModel, DurationPresentation.PROPERTY_DURATION_QUANTITY, true), new DefaultFormatter()); quantityField.setColumns(4); momentPanelBuilder.add(quantityField, cc.xy(3, row2)); // duration units input final JComboBox unitsField = AuxComponentFactory.createBoundComboBox( DurationPresentation.DateUnits.values(), new PropertyAdapter<DurationPresentation<WhenTaken>>(durationModel, DurationPresentation.PROPERTY_DURATION_UNITS, true)); momentPanelBuilder.add(unitsField, cc.xy(5, row2)); final JComboBox relativeTofield = AuxComponentFactory.createBoundComboBox( RelativeTo.values(), new PropertyAdapter<WhenTaken>(d_wt, WhenTaken.PROPERTY_RELATIVE_TO, true)); momentPanelBuilder.add(relativeTofield, cc.xy(7, row2)); final JComboBox epochField = AuxComponentFactory.createBoundComboBox(d_epm.getList().toArray(), new PropertyAdapter<WhenTaken>(d_wt, WhenTaken.PROPERTY_EPOCH), true); momentPanelBuilder.add(epochField, cc.xy(9, row2)); return momentPanelBuilder.getPanel(); } } protected int createAdditionalComponents(final ModifiableHolder<T> slot, final PanelBuilder builder, final FormLayout layout, final int row) { return row; } }