package org.openrosa.client.widget.skiprule;
import java.util.List;
import org.openrosa.client.model.FormDef;
import org.openrosa.client.model.GroupDef;
import org.openrosa.client.model.IFormElement;
import org.openrosa.client.model.QuestionDef;
import org.openrosa.client.util.FormDesignerUtil;
import org.openrosa.client.util.Itext;
import org.openrosa.client.controller.ItemSelectionListener;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.TextBox;
/**
* This widget is used to let one select a field or question for a skip or validation
* rule condition. For validation rules, this can be used for the condition value. eg
* Weight less than Height. For skip rules, this can be used for both the condition
* question and value.
*
* @author daniel
*
*/
public class FieldWidget extends Composite{
/** The text to display when no value is specified for a condition. */
private static final String EMPTY_VALUE = "_____";
/** The form to which the question, represented by this widget, belongs. */
private FormDef formDef;
/** The main widget. */
private HorizontalPanel horizontalPanel;
/** The widget to do auto suggest for form questions as the user types. */
private SuggestBox sgstField = new SuggestBox();
/** The text field where to type the question name. */
private TextBox txtField = new TextBox();
/** The widget to display the selected question text when not in selection mode. */
private Hyperlink fieldHyperlink;
/** The listener for item selection events. */
private ItemSelectionListener itemSelectionListener;
/** A flag determining if the current field selection is for a single select dynamic.
* type of question.
*/
private boolean forDynamicOptions = false;
/** The single select dynamic question. */
private QuestionDef dynamicQuestionDef;
//TODO I think we need only one of questionDef or dynamicQuestionDef to serve the same purpose
/** The question that this field widget is handling. eg the skip logic question. */
private QuestionDef questionDef;
public FieldWidget(ItemSelectionListener itemSelectionListener){
this.itemSelectionListener = itemSelectionListener;
setupWidgets();
}
/**
* Sets the form to which the referenced question belongs.
*
* @param formDef the form definition object.
*/
public void setFormDef(FormDef formDef){
this.formDef = formDef;
setupPopup();
}
private void setupWidgets(){
fieldHyperlink = new Hyperlink("_",""); //Field 1
horizontalPanel = new HorizontalPanel();
horizontalPanel.add(fieldHyperlink);
fieldHyperlink.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event){
itemSelectionListener.onStartItemSelection(this);
horizontalPanel.remove(fieldHyperlink);
horizontalPanel.add(sgstField);
sgstField.setText(fieldHyperlink.getText());
sgstField.setFocus(true);
txtField.selectAll();
}
});
/*txtField.addFocusListener(new FocusListenerAdapter(){
public void onLostFocus(Widget sender){
stopSelection();
}
});
/*sgstField.addFocusListener(new FocusListenerAdapter(){
public void onLostFocus(Widget sender){
stopSelection();
}
});*/
sgstField.addSelectionHandler(new SelectionHandler(){
public void onSelection(SelectionEvent event){
stopSelection();
}
});
initWidget(horizontalPanel);
}
public void stopSelection(){
if(horizontalPanel.getWidgetIndex(fieldHyperlink) != -1)
return;
String val = sgstField.getText();
if(val.trim().length() == 0)
val = EMPTY_VALUE;
fieldHyperlink.setText(val);
horizontalPanel.remove(sgstField);
horizontalPanel.add(fieldHyperlink);
IFormElement qtn = formDef.getQuestionWithText(txtField.getText());
if(qtn != null)
itemSelectionListener.onItemSelected(this,qtn);
}
private void setupPopup(){
MultiWordSuggestOracle oracle = new MultiWordSuggestOracle();
//for(int i=0; i<formDef.getPageCount(); i++)
// FormDesignerUtil.loadQuestions(formDef.getPageAt(i).getQuestions(),dynamicQuestionDef,oracle,forDynamicOptions);
FormDesignerUtil.loadQuestions(formDef.getChildren(),(forDynamicOptions ? dynamicQuestionDef : questionDef),oracle,forDynamicOptions);
txtField = new TextBox(); //TODO New and hence could be buggy
sgstField = new SuggestBox(oracle,txtField);
selectFirstQuestion();
sgstField.addSelectionHandler(new SelectionHandler(){
public void onSelection(SelectionEvent event){
stopSelection();
}
});
/*sgstField.addFocusListener(new FocusListenerAdapter(){
public void onLostFocus(Widget sender){
stopSelection();
}
});*/
}
public void selectQuestion(IFormElement questionDef){
String dText = Itext.getDisplayText(questionDef);
fieldHyperlink.setText(dText);
itemSelectionListener.onItemSelected(this, questionDef);
}
private void selectFirstQuestion(){
/*for(int i=0; i<formDef.getPageCount(); i++){
if(selectFirstQuestion(formDef.getPageAt(i).getQuestions()))
return;
}*/
selectFirstQuestion(formDef.getChildren());
}
private boolean selectFirstQuestion(List<IFormElement> questions){
for(int i=0; i<questions.size(); i++){
IFormElement questionDef = questions.get(i);
//if(questionDef.getDataType() == QuestionDef.QTN_TYPE_REPEAT)
// selectFirstQuestion(questionDef.getRepeatQtnsDef().getQuestions());
if(questionDef instanceof GroupDef)
selectFirstQuestion(((GroupDef)questionDef).getChildren());
else{
if(forDynamicOptions){
if(questionDef == dynamicQuestionDef)
continue;
if(!(questionDef.getDataType() == QuestionDef.QTN_TYPE_LIST_EXCLUSIVE ||
questionDef.getDataType() == QuestionDef.QTN_TYPE_LIST_EXCLUSIVE_DYNAMIC))
continue;
}
selectQuestion(questionDef);
return true;
}
}
return false;
}
/**
* Sets the question for this widget.
*
* @param questionDef the question definition object.
*/
public void setQuestion(IFormElement questionDef){
if(questionDef instanceof QuestionDef)
this.questionDef = (QuestionDef)questionDef;
if(questionDef != null)
fieldHyperlink.setText(Itext.getDisplayText(questionDef));
else{
horizontalPanel.remove(fieldHyperlink);
horizontalPanel.remove(sgstField);
//Removing and adding of fieldHyperlink is to prevent a wiered bug from
//happening where focus is taken off, brought back and the hyperlink
//displays no more text.
horizontalPanel.add(fieldHyperlink);
fieldHyperlink.setText("");
}
}
public void setForDynamicOptions(boolean forDynamicOptions){
this.forDynamicOptions = forDynamicOptions;
}
public void setDynamicQuestionDef(QuestionDef dynamicQuestionDef){
this.dynamicQuestionDef = dynamicQuestionDef;
}
}