package waelti.statistics.views; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Map; import java.util.TreeMap; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import waelti.statistics.queries.AbstractQuery; import waelti.statistics.queries.SetDataException; import waelti.statistics.queries.annotations.GetProperty; import waelti.statistics.queries.annotations.SetProperty; import ch.elexis.core.ui.util.SWTHelper; /** * View of the meta model. All label - text field pairs are obtained by reflecting on the given * AbtractQuery object. At the moment, all query classes are represented in a map containing an * object of each query class. Might be changed in the future and done by reflecting on the whole * query package. * * @author michael waelti * @see SetProperty * @see GetProperty * @see AbstractQuery */ public class OptionPanel extends Composite { /** * Map containing all text fields an their name. Used to feed the query with the user input. */ private Map<String, Text> fieldMap; /** * The query which is selected at the moment and will be configured by the user input. */ private AbstractQuery query; /** Background color for this composite */ private Color background;; /** Standard constructor. */ public OptionPanel(Composite parent){ super(parent, SWT.BORDER); this.fieldMap = new TreeMap<String, Text>(); GridLayout layout = new GridLayout(); layout.numColumns = 2; this.setLayout(layout); this.background = parent.getBackground(); } public OptionPanel(Composite parent, Color background){ this(parent); this.background = background; this.setBackground(background); } /** {@inheritDoc} */ public void updateContent(AbstractQuery selectedQuery){ this.query = selectedQuery; // the query which was selected. // clear this composite for (Control child : this.getChildren()) { child.dispose(); } this.fieldMap = new TreeMap<String, Text>(); // populate again createQueryField(); this.layout(); } /** * Populates this composite via reflection using the getProperty annotation. */ private void createQueryField(){ ArrayList<Method> getterMethodList = new ArrayList<Method>(); for (Method method : query.getClass().getMethods()) { if (method.isAnnotationPresent(GetProperty.class)) { getterMethodList.add(method); } } this.sortMethodList(getterMethodList); this.createFields(getterMethodList); } /** * Sorts the methods according to the index of the getProperty annotation. * * @param methodList * a list containing only methods having a Set/GetProperty annotation. */ private void sortMethodList(ArrayList<Method> methodList){ Collections.sort(methodList, new Comparator<Method>() { public int compare(Method o1, Method o2){ int index1 = 0; int index2 = 0; if (o1.isAnnotationPresent(GetProperty.class)) { GetProperty anno1 = o1.getAnnotation(GetProperty.class); GetProperty anno2 = o2.getAnnotation(GetProperty.class); index1 = anno1.index(); index2 = anno2.index(); } else { // has to have a SetProperty annotation SetProperty anno1 = o1.getAnnotation(SetProperty.class); SetProperty anno2 = o2.getAnnotation(SetProperty.class); index1 = anno1.index(); index2 = anno2.index(); } return index1 - index2; } }); } private void createFields(ArrayList<Method> getterList){ for (Method method : getterList) { GetProperty getter = method.getAnnotation(GetProperty.class); this.createLabel(getter.value()); String value = this.getValue(method); Text field = this.createTextField(value); fieldMap.put(getter.value(), field); } } /** * Normally, a getter should not throw an exception, just return an empty string. Still, since * it is not clear, what the query is, any exception is caught and just logged. */ private String getValue(Method method){ try { return (String) method.invoke(query); } catch (Exception e) { // TODO: log } return "error"; } private Text createTextField(String value){ Text text = new Text(this, SWT.BORDER); text.setLayoutData(SWTHelper.getFillGridData(1, true, 1, true)); text.setText(value); return text; } private Label createLabel(String text){ Label lab = new Label(this, SWT.WRAP); lab.setLayoutData(SWTHelper.getFillGridData(1, false, 1, false)); lab.setBackground(this.background); lab.setText(text); return lab; } /** * Reads all fields, sets them via the meta model and returns the configured query. */ public AbstractQuery getQuery() throws SetDataException{ this.setQueryData(); return this.query; } /** Sets all fields via the meta model in the given query. */ private void setQueryData() throws SetDataException{ assert (this.query != null); ArrayList<Method> setterMethodList = new ArrayList<Method>(); for (Method method : query.getClass().getMethods()) { if (method.isAnnotationPresent(SetProperty.class)) { setterMethodList.add(method); } } this.sortMethodList(setterMethodList); this.setData(setterMethodList); } private void setData(ArrayList<Method> setterList) throws SetDataException{ for (Method method : setterList) { SetProperty setter = method.getAnnotation(SetProperty.class); Text field = this.fieldMap.get(setter.value()); String value = field.getText(); this.setValue(query, method, value); } } private void setValue(AbstractQuery query, Method method, String value) throws SetDataException{ try { method.invoke(query, value); } catch (Exception e) { throw (SetDataException) e.getCause(); } } }