/*
* 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.presentation;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import org.drugis.addis.entities.StudyOutcomeMeasure;
import org.drugis.addis.entities.Variable;
import org.drugis.addis.entities.WhenTaken;
import org.drugis.addis.gui.AddisWindow;
import org.drugis.addis.presentation.wizard.WhenTakenFactory;
import org.drugis.common.EqualsUtil;
import org.drugis.common.gui.GUIHelper;
import com.jgoodies.binding.beans.Model;
import com.jgoodies.binding.list.ObservableList;
import com.jgoodies.binding.value.AbstractValueModel;
import com.jgoodies.binding.value.ValueModel;
@SuppressWarnings("serial")
abstract public class SelectVariablesPresentation<T extends Variable> extends Model implements SelectFromFiniteListPresentation<T> {
protected List<StudyOutcomeMeasure<T>> d_slots;
protected ObservableList<T> d_options;
protected ValueModel d_addSlotsEnabled;
protected InputCompleteModel d_inputCompleteModel;
protected AddisWindow d_mainWindow;
public static final String PROPERTY_NSLOTS = "nSlots";
private String d_title;
private String d_description;
private PropertyChangeListener d_slotValueListener = new SlotsUniqueListener();
private PropertyChangeListener d_placeHolderListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
d_inputCompleteModel.evaluate();
}
};
private final WhenTakenFactory d_wtf;
private final Class<T> d_type;
public SelectVariablesPresentation(ObservableList<T> options, Class<T> type, String title, String description, WhenTakenFactory wtf, AddisWindow mainWindow) {
d_type = type;
d_title = title;
d_description = description;
d_wtf = wtf;
d_slots = new ArrayList<StudyOutcomeMeasure<T>>();
d_options = options;
d_addSlotsEnabled = new AddSlotsAlwaysEnabledModel();
d_inputCompleteModel = new InputCompleteModel();
d_mainWindow = mainWindow;
}
public ObservableList<T> getOptions() {
return d_options;
}
public void addSlot() {
StudyOutcomeMeasure<T> som = new StudyOutcomeMeasure<T>(d_type);
WhenTaken measurmentEpoch = d_wtf.buildDefault();
if(measurmentEpoch != null) {
som.getWhenTaken().add(measurmentEpoch);
}
d_slots.add(som);
bindSlot(som);
}
private void bindSlot(StudyOutcomeMeasure<T> slot) {
slot.addPropertyChangeListener("value", d_slotValueListener);
slot.addPropertyChangeListener(StudyOutcomeMeasure.PROPERTY_HAS_PLACEHOLDER, d_placeHolderListener);
firePropertyChange(PROPERTY_NSLOTS, d_slots.size() - 1, d_slots.size());
d_inputCompleteModel.addSlot(slot);
}
public int countSlots() {
return d_slots.size();
}
public void removeSlot(int idx) {
StudyOutcomeMeasure<T> s = d_slots.get(idx);
d_slots.remove(idx);
unbindSlot(s);
}
private void unbindSlot(StudyOutcomeMeasure<T> s) {
s.removePropertyChangeListener("value", d_slotValueListener);
s.removePropertyChangeListener(StudyOutcomeMeasure.PROPERTY_HAS_PLACEHOLDER, d_placeHolderListener);
firePropertyChange(PROPERTY_NSLOTS, d_slots.size() + 1, d_slots.size());
d_inputCompleteModel.removeSlot(s);
}
public StudyOutcomeMeasure<T> getSlot(int idx) {
return d_slots.get(idx);
}
public ValueModel getAddSlotsEnabledModel() {
return d_addSlotsEnabled;
}
public ValueModel getInputCompleteModel() {
return d_inputCompleteModel;
}
public boolean hasAddOptionDialog() {
return true;
}
public void showAddOptionDialog(int idx) {
throw new RuntimeException("AddOptionDialog not implemented");
}
public String getTypeName() {
return GUIHelper.humanize(d_type.getSimpleName());
}
public String getTitle() {
return d_title;
}
public String getDescription() {
return d_description;
}
public List<ModifiableHolder<T>> getSlots() {
List<ModifiableHolder<T>> slots = new ArrayList<ModifiableHolder<T>>();
for (StudyOutcomeMeasure<T> slot : d_slots) {
slots.add(slot);
}
return slots;
}
public void setSlots(List<StudyOutcomeMeasure<T>> slots) {
for (StudyOutcomeMeasure<T> slot : d_slots) {
unbindSlot(slot);
}
d_slots = slots;
for (StudyOutcomeMeasure<T> slot : slots) {
bindSlot(slot);
}
}
class Slot<E> extends ModifiableHolder<E> {
private List<ModifiableHolder<E>> d_slots;
public Slot(List<ModifiableHolder<E>> slots) {
d_slots = slots;
}
@Override
public void setValue(Object obj) {
super.setValue(obj);
// Make sure each option is selected only once
for (ModifiableHolder<E> s : d_slots) {
if (s.getValue() != null && s != this && EqualsUtil.equal(s.getValue(), getValue())) {
s.setValue(null);
}
}
}
}
class SlotsUniqueListener implements PropertyChangeListener {
@SuppressWarnings("unchecked")
public void propertyChange(PropertyChangeEvent evt) {
StudyOutcomeMeasure<T> holder = (StudyOutcomeMeasure<T>) evt.getSource();
if (holder.getValue() == null && holder.hasPlaceholder()) {
return;
}
for (StudyOutcomeMeasure<T> som : d_slots) {
if ((som.getValue() != null && !som.hasPlaceholder())
&& som != holder
&& EqualsUtil.equal(som.getValue(), holder.getValue())) {
som.setValue(null);
}
}
}
}
public class InputCompleteModel extends AbstractValueModel implements PropertyChangeListener {
private Boolean d_oldValue;
public InputCompleteModel() {
for (ModifiableHolder<T> s : d_slots) {
s.addValueChangeListener(this);
}
d_oldValue = getValue();
}
public void propertyChange(PropertyChangeEvent evt) {
evaluate();
}
private void evaluate() {
if (getValue() != d_oldValue) {
fireValueChange(d_oldValue, getValue());
d_oldValue = getValue();
}
}
public Boolean getValue() {
boolean r = true;
for (ModifiableHolder<T> s: d_slots) {
if (s instanceof StudyOutcomeMeasure) {
StudyOutcomeMeasure<T> som = (StudyOutcomeMeasure<T>) s;
if (s.getValue() != null && som.hasPlaceholder()) {
r = false;
break;
}
}
}
return r;
}
public void addSlot(ModifiableHolder<T> s) {
s.addValueChangeListener(this);
evaluate();
}
public void removeSlot(ModifiableHolder<T> s) {
s.removeValueChangeListener(this);
evaluate();
}
public void setValue(Object newValue) {
throw new RuntimeException("InputCompleteModel is read-only");
}
}
public class AddSlotsAlwaysEnabledModel extends AbstractValueModel {
public Object getValue() {
return true;
}
public void setValue(Object newValue) {
throw new RuntimeException("AddSlotsEnabledModel is read-only");
}
}
}