Java tutorial
package org.openxdata.designer.client.view; import org.openxdata.designer.client.Context; import org.openxdata.designer.client.DesignerMessages; import org.openxdata.designer.client.controller.IFormActionListener; import org.openxdata.designer.client.controller.IFormChangeListener; import org.openxdata.designer.client.controller.IFormSelectionListener; import org.openxdata.designer.client.controller.ItemSelectionListener; import org.openxdata.designer.client.util.FormDesignerUtil; import org.openxdata.designer.client.view.helper.PropertiesViewHelper; import org.openxdata.designer.client.widget.DescTemplateWidget; import org.openxdata.sharedlib.client.locale.FormsConstants; import org.openxdata.sharedlib.client.model.Calculation; import org.openxdata.sharedlib.client.model.FormDef; import org.openxdata.sharedlib.client.model.OptionDef; import org.openxdata.sharedlib.client.model.PageDef; import org.openxdata.sharedlib.client.model.QuestionDef; import org.openxdata.sharedlib.client.model.RepeatQtnsDef; import org.openxdata.sharedlib.client.util.FormUtil; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyDownHandler; import com.google.gwt.event.dom.client.KeyPressEvent; import com.google.gwt.event.dom.client.KeyPressHandler; import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.DecoratedTabPanel; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import org.openxdata.sharedlib.client.model.QuestionType; /** * View responsible for displaying and hence allow editing of * form, page, question, or question option properties. * * www.openxdata.org - Licensed as written in license.txt and original sources of this file and its authors are found in sources.txt. * */ public class PropertiesView extends Composite implements IFormSelectionListener, ItemSelectionListener { final DesignerMessages designerMessages = GWT.create(DesignerMessages.class); final FormsConstants formsConstants = GWT.create(FormsConstants.class); /** List box index for no selected data type. */ private static final byte DT_INDEX_NONE = -1; /** List box index for text data type. */ private static final byte DT_INDEX_TEXT = 0; /** List box index for number data type. */ private static final byte DT_INDEX_NUMBER = 1; /** List box index for decimal data type. */ private static final byte DT_INDEX_DECIMAL = 2; /** List box index for date data type. */ private static final byte DT_INDEX_DATE = 3; /** List box index for time data type. */ private static final byte DT_INDEX_TIME = 4; /** List box index for dateTime data type. */ private static final byte DT_INDEX_DATE_TIME = 5; /** List box index for boolean data type. */ private static final byte DT_INDEX_BOOLEAN = 6; /** List box index for single select data type. */ private static final byte DT_INDEX_SINGLE_SELECT = 7; /** List box index for multiple select data type. */ private static final byte DT_INDEX_MULTIPLE_SELECT = 8; /** List box index for repeat data type. */ private static final byte DT_INDEX_REPEAT = 9; /** List box index for image data type. */ private static final byte DT_INDEX_IMAGE = 10; /** List box index for video data type. */ private static final byte DT_INDEX_VIDEO = 11; /** List box index for audio data type. */ private static final byte DT_INDEX_AUDIO = 12; /** List box index for single select dynamic data type. */ private static final byte DT_INDEX_SINGLE_SELECT_DYNAMIC = 13; /** List box index for gps data type. */ private static final byte DT_INDEX_GPS = 14; /** List box index for barcode data type. */ private static final byte DT_INDEX_BARCODE = 15; /** Table used for organising widgets in a table format. */ private FlexTable table = new FlexTable(); /** Widget for displaying the list of data types. */ private ListBox cbDataType = new ListBox(false); /** Widget for setting the visibility property. */ private CheckBox chkVisible = new CheckBox(); /** Widget for setting the enabled property. */ private CheckBox chkEnabled = new CheckBox(); /** Widget for setting the locked property. */ private CheckBox chkLocked = new CheckBox(); /** Widget for setting the required property. */ private CheckBox chkRequired = new CheckBox(); /** Widget for setting the text property. */ private TextBox txtText = new TextBox(); /** Widget for setting the help text property. */ private TextBox txtHelpText = new TextBox(); /** Widget for setting the binding property. */ private TextBox txtBinding = new TextBox(); /** Widget for setting the default value property. */ private TextBox txtDefaultValue = new TextBox(); /** Widget for setting the description template property. */ private TextBox txtDescTemplate = new TextBox(); private Label lblDescTemplate; private TextBox txtCalculation = new TextBox(); /** Widget for selecting fields which define the description template. */ private DescTemplateWidget btnDescTemplate; private DescTemplateWidget btnCalculation; /** Widget for setting the form key property. */ private TextBox txtFormKey = new TextBox(); /** The selected object which could be FormDef, PageDef, QuestionDef or OptionDef */ private Object propertiesObj; /** Listener to form change events. */ private IFormChangeListener formChangeListener; /** Widget for defining skip rules. */ private SkipRulesView skipRulesView = new SkipRulesView(); /** Widget for defining validation rules. */ private ValidationRulesView validationRulesView = new ValidationRulesView(); /** Widget for defining dynamic selection lists. */ private DynamicListsView dynamicListsView = new DynamicListsView(); /** Widget for defining edvanced validation Rules*/ private AdvancedValidationRulesView advancedValidationRulesView = new AdvancedValidationRulesView(); /** Listener to form action events. */ private IFormActionListener formActionListener; /** * Creates a new instance of the properties view widget. */ public PropertiesView() { btnDescTemplate = new DescTemplateWidget(this); btnCalculation = new DescTemplateWidget(this); table.setWidget(0, 0, new Label(designerMessages.text())); table.setWidget(1, 0, new Label(formsConstants.helpText())); table.setWidget(2, 0, new Label(formsConstants.type())); table.setWidget(3, 0, new Label(designerMessages.binding())); table.setWidget(4, 0, new Label(designerMessages.visible())); table.setWidget(5, 0, new Label(formsConstants.enable())); table.setWidget(6, 0, new Label(formsConstants.locked())); table.setWidget(7, 0, new Label(formsConstants.required())); table.setWidget(8, 0, new Label(formsConstants.defaultValue())); table.setWidget(9, 0, new Label(designerMessages.calculation())); lblDescTemplate = new Label(formsConstants.descriptionTemplate()); table.setWidget(10, 0, lblDescTemplate); table.setWidget(11, 0, new Label(designerMessages.formKey())); table.setWidget(0, 1, txtText); table.setWidget(1, 1, txtHelpText); table.setWidget(2, 1, cbDataType); table.setWidget(3, 1, txtBinding); table.setWidget(4, 1, chkVisible); table.setWidget(5, 1, chkEnabled); table.setWidget(6, 1, chkLocked); table.setWidget(7, 1, chkRequired); table.setWidget(8, 1, txtDefaultValue); HorizontalPanel panel = new HorizontalPanel(); panel.add(txtCalculation); panel.add(btnCalculation); panel.setCellWidth(btnCalculation, "20%"); FormUtil.maximizeWidget(txtCalculation); FormUtil.maximizeWidget(panel); table.setWidget(9, 1, panel); panel = new HorizontalPanel(); panel.add(txtDescTemplate); panel.add(btnDescTemplate); panel.setCellWidth(btnDescTemplate, "20%"); FormUtil.maximizeWidget(txtDescTemplate); FormUtil.maximizeWidget(panel); table.setWidget(10, 1, panel); table.setWidget(11, 1, txtFormKey); table.setStyleName("cw-FlexTable"); cbDataType.addItem(designerMessages.qtnTypeText()); cbDataType.addItem(designerMessages.qtnTypeNumber()); cbDataType.addItem(designerMessages.qtnTypeDecimal()); cbDataType.addItem(designerMessages.qtnTypeDate()); cbDataType.addItem(designerMessages.qtnTypeTime()); cbDataType.addItem(designerMessages.qtnTypeDateTime()); cbDataType.addItem(designerMessages.qtnTypeBoolean()); cbDataType.addItem(designerMessages.qtnTypeSingleSelect()); cbDataType.addItem(designerMessages.qtnTypeMultSelect()); cbDataType.addItem(designerMessages.qtnTypeRepeat()); cbDataType.addItem(designerMessages.qtnTypePicture()); cbDataType.addItem(designerMessages.qtnTypeVideo()); cbDataType.addItem(designerMessages.qtnTypeAudio()); cbDataType.addItem(designerMessages.qtnTypeSingleSelectDynamic()); cbDataType.addItem(designerMessages.qtnTypeGPS()); cbDataType.addItem(designerMessages.qtnTypeBarcode()); FlexCellFormatter cellFormatter = table.getFlexCellFormatter(); cellFormatter.setHorizontalAlignment(15, 1, HasHorizontalAlignment.ALIGN_CENTER); table.setWidth("100%"); cellFormatter.setWidth(0, 0, "20%"); txtText.setWidth("100%"); txtHelpText.setWidth("100%"); txtBinding.setWidth("100%"); txtDefaultValue.setWidth("100%"); cbDataType.setWidth("100%"); txtFormKey.setWidth("100%"); VerticalPanel verticalPanel = new VerticalPanel(); verticalPanel.setSpacing(5); verticalPanel.add(table); DecoratedTabPanel tabs = new DecoratedTabPanel(); tabs.add(skipRulesView, designerMessages.skipLogic()); tabs.add(validationRulesView, designerMessages.validationLogic()); tabs.add(dynamicListsView, designerMessages.dynamicLists()); tabs.add(advancedValidationRulesView, designerMessages.advancedValidationLogic()); tabs.selectTab(0); verticalPanel.add(tabs); FormUtil.maximizeWidget(tabs); FormUtil.maximizeWidget(verticalPanel); initWidget(verticalPanel); setupEventListeners(); cbDataType.setSelectedIndex(-1); enableQuestionOnlyProperties(false); txtText.setEnabled(false); enableDescriptionTemplate(false); txtCalculation.setEnabled(false); btnCalculation.setEnabled(false); txtBinding.setEnabled(false); txtText.setTitle(designerMessages.questionTextDesc()); txtHelpText.setTitle(designerMessages.questionDescDesc()); txtBinding.setTitle(designerMessages.questionIdDesc()); txtDefaultValue.setTitle(designerMessages.defaultValDesc()); cbDataType.setTitle(designerMessages.questionTypeDesc()); DOM.sinkEvents(getElement(), Event.ONKEYDOWN | DOM.getEventsSunk(getElement())); } /** * Sets up event listeners. */ private void setupEventListeners() { //Check boxes.k chkVisible.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { ((QuestionDef) propertiesObj).setVisible(chkVisible.getValue() == true); formChangeListener.onFormItemChanged(propertiesObj); } }); chkEnabled.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { ((QuestionDef) propertiesObj).setEnabled(chkEnabled.getValue() == true); formChangeListener.onFormItemChanged(propertiesObj); } }); chkLocked.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { ((QuestionDef) propertiesObj).setLocked(chkLocked.getValue() == true); formChangeListener.onFormItemChanged(propertiesObj); } }); chkRequired.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { ((QuestionDef) propertiesObj).setRequired(chkRequired.getValue() == true); formChangeListener.onFormItemChanged(propertiesObj); } }); //Text boxes. txtDefaultValue.addChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { if (checkDefaultValueAgainstQuestionType()) { updateDefaultValue(); } } }); txtDefaultValue.addKeyUpHandler(new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { if (checkDefaultValueAgainstQuestionType()) { updateDefaultValue(); } else { Window.alert(designerMessages.invalidDefaultValueForQuestionType()); } } }); txtHelpText.addChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { updateHelpText(); } }); txtHelpText.addKeyUpHandler(new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { updateHelpText(); } }); txtHelpText.addKeyDownHandler(new KeyDownHandler() { public void onKeyDown(KeyDownEvent event) { int keyCode = event.getNativeKeyCode(); if (keyCode == KeyCodes.KEY_ENTER || keyCode == KeyCodes.KEY_DOWN) cbDataType.setFocus(true); else if (keyCode == KeyCodes.KEY_UP) { txtText.setFocus(true); txtText.selectAll(); } } }); txtBinding.addChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { updateBinding(); } }); txtBinding.addKeyUpHandler(new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { String s = txtBinding.getText(); s = s.replace("%", ""); s = s.replace("(", ""); s = s.replace("!", ""); s = s.replace("&", ""); s = s.replace("'", ""); s = s.replace("\"", ""); s = s.replace("$", ""); s = s.replace("#", ""); txtBinding.setText(s); updateBinding(); } }); txtBinding.addKeyDownHandler(new KeyDownHandler() { public void onKeyDown(KeyDownEvent event) { if (event.getNativeKeyCode() == KeyCodes.KEY_UP) { if (cbDataType.isEnabled()) cbDataType.setFocus(true); else { txtText.setFocus(true); txtText.selectAll(); } } } }); txtBinding.addKeyPressHandler(new KeyPressHandler() { public void onKeyPress(KeyPressEvent event) { if (propertiesObj instanceof PageDef) { if (!Character.isDigit(event.getCharCode())) { ((TextBox) event.getSource()).cancelKey(); return; } } else if (propertiesObj instanceof FormDef || propertiesObj instanceof QuestionDef) { if (((TextBox) event.getSource()).getCursorPos() == 0) { if (!isAllowedXmlNodeNameStartChar(event.getCharCode())) { ((TextBox) event.getSource()).cancelKey(); return; } } else if (!isAllowedXmlNodeNameChar(event.getCharCode())) { ((TextBox) event.getSource()).cancelKey(); return; } } //else OptionDef varname can be anything } }); txtText.addChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { String orgText = getSelObjetOriginalText(); updateText(); updateSelObjBinding(orgText); } }); txtText.addKeyUpHandler(new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { String orgText = getSelObjetOriginalText(); updateText(); updateSelObjBinding(orgText); } }); txtText.addKeyDownHandler(new KeyDownHandler() { public void onKeyDown(KeyDownEvent event) { if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER || event.getNativeKeyCode() == KeyCodes.KEY_DOWN) { if (txtHelpText.isEnabled()) txtHelpText.setFocus(true); else { txtBinding.setFocus(true); txtBinding.selectAll(); } } } }); txtDescTemplate.addChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { updateDescTemplate(); } }); txtDescTemplate.addKeyUpHandler(new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { updateDescTemplate(); } }); txtCalculation.addChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { updateCalculation(); } }); txtCalculation.addKeyUpHandler(new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { updateCalculation(); } }); //Combo boxes cbDataType.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { updateDataType(); } }); cbDataType.addChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { updateDataType(); } }); cbDataType.addKeyDownHandler(new KeyDownHandler() { public void onKeyDown(KeyDownEvent event) { int keyCode = event.getNativeEvent().getKeyCode(); if (keyCode == KeyCodes.KEY_ENTER || keyCode == KeyCodes.KEY_DOWN) { txtBinding.setFocus(true); txtBinding.selectAll(); } else if (keyCode == KeyCodes.KEY_UP) { txtHelpText.setFocus(true); txtHelpText.selectAll(); } } }); txtFormKey.addChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { updateFormKey(); } }); txtFormKey.addKeyUpHandler(new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { updateFormKey(); } }); } private String getSelObjetOriginalText() { if (propertiesObj instanceof FormDef) return ((FormDef) propertiesObj).getName(); else if (propertiesObj instanceof QuestionDef) return ((QuestionDef) propertiesObj).getText(); else if (propertiesObj instanceof OptionDef) return ((OptionDef) propertiesObj).getText(); return null; } private void updateSelObjBinding(String orgText) { if (orgText == null) return; String orgTextDefBinding = FormDesignerUtil.getXmlTagName(getTextWithoutDecTemplate(orgText)); if (propertiesObj != null && Context.allowBindEdit() && !Context.isStructureReadOnly()) { String text = getTextWithoutDecTemplate(txtText.getText().trim()); String name = FormDesignerUtil.getXmlTagName(text); if (propertiesObj instanceof FormDef && ((FormDef) propertiesObj).getBinding().equals(orgTextDefBinding)) { ((FormDef) propertiesObj).setVariableName(name); txtBinding.setText(name); } else if (propertiesObj instanceof QuestionDef && ((QuestionDef) propertiesObj).getBinding().equals(orgTextDefBinding)) { ((QuestionDef) propertiesObj).setVariableName(name); txtBinding.setText(name); } else if (propertiesObj instanceof OptionDef && ((OptionDef) propertiesObj).getVariableName().equals(orgTextDefBinding)) { ((OptionDef) propertiesObj).setVariableName(name); txtBinding.setText(name); } } } /** * Gets text without the description template, for a given text. * * @param text the text to parse. * @return the text without the description template. */ private String getTextWithoutDecTemplate(String text) { if (text.contains("${")) { if (text.indexOf("}$") < text.length() - 2) text = text.substring(0, text.indexOf("${")) + text.substring(text.indexOf("}$") + 2); else text = text.substring(0, text.indexOf("${")); } return text; } /** * Checks if a given character is allowed to begin an xml node name. * * @param keyCode the character code. * @return true if is allowed, else false. */ private boolean isAllowedXmlNodeNameStartChar(char keyCode) { return ((keyCode >= 'a' && keyCode <= 'z') || (keyCode >= 'A' && keyCode <= 'Z') || isControlChar(keyCode)); } /** * Checks if a character is allowed in an xml node name. * * @param keyCode the character code. * @return true if allowed, else false. */ private boolean isAllowedXmlNodeNameChar(char keyCode) { return isAllowedXmlNodeNameStartChar(keyCode) || Character.isDigit(keyCode) || keyCode == '-' || keyCode == '_' || keyCode == '.'; } /** * Check if a character is a control character. Examples of control characters are * ALT, CTRL, ESCAPE, DELETE, SHIFT, HOME, PAGE_UP, BACKSPACE, ENTER, TAB, LEFT, and more. * * @param keyCode the character code. * @return true if yes, else false. */ private boolean isControlChar(char keyCode) { int code = keyCode; return (code == KeyCodes.KEY_ALT || code == KeyCodes.KEY_BACKSPACE || code == KeyCodes.KEY_CTRL || code == KeyCodes.KEY_DELETE || code == KeyCodes.KEY_DOWN || code == KeyCodes.KEY_END || code == KeyCodes.KEY_ENTER || code == KeyCodes.KEY_ESCAPE || code == KeyCodes.KEY_HOME || code == KeyCodes.KEY_LEFT || code == KeyCodes.KEY_PAGEDOWN || code == KeyCodes.KEY_PAGEUP || code == KeyCodes.KEY_RIGHT || code == KeyCodes.KEY_SHIFT || code == KeyCodes.KEY_TAB || code == KeyCodes.KEY_UP); } /** * Updates the selected object with the new text as typed by the user. */ private void updateText() { if (propertiesObj == null) return; if (propertiesObj instanceof QuestionDef) ((QuestionDef) propertiesObj).setText(txtText.getText()); else if (propertiesObj instanceof OptionDef) ((OptionDef) propertiesObj).setText(txtText.getText()); else if (propertiesObj instanceof PageDef) ((PageDef) propertiesObj).setName(txtText.getText()); else if (propertiesObj instanceof FormDef) ((FormDef) propertiesObj).setName(txtText.getText()); formChangeListener.onFormItemChanged(propertiesObj); } private void updateFormKey() { if (propertiesObj == null) return; if (propertiesObj instanceof FormDef) ((FormDef) propertiesObj).setFormKey(txtFormKey.getText()); formChangeListener.onFormItemChanged(propertiesObj); } /** * Updates the selected object with the new description template as typed by the user. */ private void updateDescTemplate() { if (propertiesObj == null) return; else if (propertiesObj instanceof FormDef) { ((FormDef) propertiesObj).setDescriptionTemplate(txtDescTemplate.getText()); formChangeListener.onFormItemChanged(propertiesObj); } } private void updateCalculation() { if (propertiesObj == null) return; assert (propertiesObj instanceof QuestionDef); Context.getFormDef().updateCalculation((QuestionDef) propertiesObj, txtCalculation.getText()); } /** * Updates the selected object with the new binding as typed by the user. */ private void updateBinding() { if (propertiesObj == null) return; if (txtBinding.getText().trim().length() == 0) return; if (propertiesObj instanceof QuestionDef) ((QuestionDef) propertiesObj).setVariableName(txtBinding.getText()); else if (propertiesObj instanceof OptionDef) ((OptionDef) propertiesObj).setVariableName(txtBinding.getText()); else if (propertiesObj instanceof FormDef) ((FormDef) propertiesObj).setVariableName(txtBinding.getText()); else if (propertiesObj instanceof PageDef) { try { ((PageDef) propertiesObj).setPageNo(Integer.parseInt(txtBinding.getText())); } catch (Exception ex) { return; } } formChangeListener.onFormItemChanged(propertiesObj); } /** * Updates the selected object with the new help text as typed by the user. */ private void updateHelpText() { if (propertiesObj == null) return; ((QuestionDef) propertiesObj).setHelpText(txtHelpText.getText()); formChangeListener.onFormItemChanged(propertiesObj); } /** * Updates the selected object with the new default value as typed by the user. */ private void updateDefaultValue() { if (propertiesObj == null) return; ((QuestionDef) propertiesObj).setDefaultValue(txtDefaultValue.getText()); formChangeListener.onFormItemChanged(propertiesObj); } /** * Checks if the value entered for Default Value matches the selected Question Data Type. * * @return True if and only if the entered value is in sync with the Question Data Type. */ private boolean checkDefaultValueAgainstQuestionType() { String defaultValue = txtDefaultValue.getText(); QuestionDef questionDef = (QuestionDef) propertiesObj; if (questionDef.getDataType() == QuestionType.NUMERIC && !PropertiesViewHelper.isDefaultValueNumeric(defaultValue)) { txtDefaultValue.setText(""); return false; } else if (questionDef.getDataType() == QuestionType.DECIMAL && !PropertiesViewHelper.isDefaultValueDecimal(defaultValue)) { txtDefaultValue.setText(""); return false; } else if (questionDef.getDataType() == QuestionType.BOOLEAN && !PropertiesViewHelper.isDefaultValueBoolean(defaultValue)) { txtDefaultValue.setText(""); return false; } return true; } /** * Updates the selected object with the new data type as typed by the user. */ private void updateDataType() { if (propertiesObj == null) return; boolean deleteKids = false; int index = cbDataType.getSelectedIndex(); QuestionDef questionDef = (QuestionDef) propertiesObj; if ((questionDef.getDataType() == QuestionType.LIST_EXCLUSIVE || questionDef.getDataType() == QuestionType.LIST_MULTIPLE) && !(index == DT_INDEX_SINGLE_SELECT || index == DT_INDEX_MULTIPLE_SELECT)) { if (questionDef.getOptionCount() > 0 && !Window.confirm(designerMessages.changeWidgetTypePrompt())) { index = (questionDef.getDataType() == QuestionType.LIST_EXCLUSIVE) ? DT_INDEX_SINGLE_SELECT : DT_INDEX_MULTIPLE_SELECT; cbDataType.setSelectedIndex(index); return; } deleteKids = true; } else if ((questionDef.getDataType() == QuestionType.REPEAT) && !(index == DT_INDEX_REPEAT)) { if (!Window.confirm(designerMessages.changeWidgetTypePrompt())) { index = DT_INDEX_REPEAT; cbDataType.setSelectedIndex(index); return; } deleteKids = true; } setQuestionDataType((QuestionDef) propertiesObj); formChangeListener.onFormItemChanged(propertiesObj); if (deleteKids) formChangeListener.onDeleteChildren(propertiesObj); } /** * Sets the data type of a question definition object basing on selection * in the type selection list box widget. * * @param questionDef the question definition object. */ private void setQuestionDataType(QuestionDef questionDef) { QuestionType dataType = QuestionType.TEXT; switch (cbDataType.getSelectedIndex()) { case DT_INDEX_NUMBER: txtDefaultValue.setEnabled(true); dataType = QuestionType.NUMERIC; break; case DT_INDEX_DECIMAL: txtDefaultValue.setEnabled(true); dataType = QuestionType.DECIMAL; break; case DT_INDEX_DATE: txtDefaultValue.setEnabled(true); dataType = QuestionType.DATE; break; case DT_INDEX_TIME: txtDefaultValue.setEnabled(true); dataType = QuestionType.TIME; break; case DT_INDEX_DATE_TIME: txtDefaultValue.setEnabled(true); dataType = QuestionType.DATE_TIME; break; case DT_INDEX_BOOLEAN: txtDefaultValue.setEnabled(true); dataType = QuestionType.BOOLEAN; break; case DT_INDEX_SINGLE_SELECT: txtDefaultValue.setEnabled(false); dataType = QuestionType.LIST_EXCLUSIVE; break; case DT_INDEX_MULTIPLE_SELECT: txtDefaultValue.setEnabled(false); dataType = QuestionType.LIST_MULTIPLE; break; case DT_INDEX_REPEAT: txtDefaultValue.setEnabled(false); dataType = QuestionType.REPEAT; break; case DT_INDEX_IMAGE: txtDefaultValue.setEnabled(false); dataType = QuestionType.IMAGE; break; case DT_INDEX_VIDEO: txtDefaultValue.setEnabled(false); dataType = QuestionType.VIDEO; break; case DT_INDEX_AUDIO: txtDefaultValue.setEnabled(false); dataType = QuestionType.AUDIO; break; case DT_INDEX_SINGLE_SELECT_DYNAMIC: txtDefaultValue.setEnabled(false); dataType = QuestionType.LIST_EXCLUSIVE_DYNAMIC; break; case DT_INDEX_GPS: txtDefaultValue.setEnabled(true); dataType = QuestionType.GPS; break; case DT_INDEX_BARCODE: txtDefaultValue.setEnabled(false); dataType = QuestionType.BARCODE; break; } if (dataType == QuestionType.REPEAT && questionDef.getDataType() != QuestionType.REPEAT) questionDef.setRepeatQtnsDef(new RepeatQtnsDef(questionDef)); questionDef.setDataType(dataType); if (questionDef.getDataType() != QuestionType.LIST_EXCLUSIVE_DYNAMIC) dynamicListsView.setEnabled(false); else if (!dynamicListsView.isEnabled()) dynamicListsView.setQuestionDef(questionDef); } /** * Sets the listener for form change events. * * @param formChangeListener the listener. */ public void setFormChangeListener(IFormChangeListener formChangeListener) { this.formChangeListener = formChangeListener; } /** * Sets values for widgets which deal with form definition properties. * * @param formDef the form definition object. */ private void setFormProperties(FormDef formDef) { enableQuestionOnlyProperties(false); txtText.setEnabled(true); enableDescriptionTemplate(Context.isStructureReadOnly() ? false : true); txtText.setText(formDef.getName()); txtBinding.setText(formDef.getBinding()); txtFormKey.setText(formDef.getFormKey()); txtDescTemplate.setText(formDef.getDescriptionTemplate()); btnDescTemplate.setFormDef(formDef); btnCalculation.setFormDef(formDef); } /** * Sets values for widgets which deal with page definition properties. * * @param pageDef the page definition object. */ private void setPageProperties(PageDef pageDef) { enableQuestionOnlyProperties(false); txtText.setEnabled(true); enableDescriptionTemplate(false); txtCalculation.setEnabled(false); btnCalculation.setEnabled(false); txtText.setText(pageDef.getName()); txtBinding.setText(String.valueOf(pageDef.getPageNo())); } /** * Sets values for widgets which deal with question definition properties. * * @param questionDef the question definition object. */ private void setQuestionProperties(QuestionDef questionDef) { enableQuestionOnlyProperties(true); enableDescriptionTemplate(false); txtText.setText(questionDef.getText()); txtBinding.setText(questionDef.getBinding()); txtHelpText.setText(questionDef.getHelpText()); txtDefaultValue.setText(questionDef.getDefaultValue()); chkVisible.setValue(questionDef.isVisible()); chkEnabled.setValue(questionDef.isEnabled()); chkLocked.setValue(questionDef.isLocked()); chkRequired.setValue(questionDef.isRequired()); setDataType(questionDef.getDataType()); String calculationExpression = null; Calculation calculation = Context.getFormDef().getCalculation(questionDef); if (calculation != null) calculationExpression = calculation.getCalculateExpression(); txtCalculation.setText(calculationExpression); //Skip logic processing is a bit slow and hence we wanna update the //UI with the rest of simple quick properties as we process skip logic Scheduler.get().scheduleDeferred(new ScheduledCommand() { public void execute() { skipRulesView.setQuestionDef((QuestionDef) propertiesObj); validationRulesView.setQuestionDef((QuestionDef) propertiesObj); dynamicListsView.setQuestionDef((QuestionDef) propertiesObj); } }); } /** * Sets values for widgets which deal with question option definition properties. * * @param optionDef the option definition object. */ private void setQuestionOptionProperties(OptionDef optionDef) { enableQuestionOnlyProperties(false); enableDescriptionTemplate(false); txtCalculation.setEnabled(false); btnCalculation.setEnabled(false); txtText.setText(optionDef.getText()); txtBinding.setText(optionDef.getVariableName()); } /** * Sets whether to enable question property widgets. * * @param enabled true to enable them, false to disable them. */ private void enableQuestionOnlyProperties(boolean enabled) { boolean enable2 = (enabled && !Context.inLocalizationMode()) ? true : false; cbDataType.setEnabled(enable2); chkVisible.setEnabled(enable2); chkEnabled.setEnabled(enable2); chkLocked.setEnabled(enable2); chkRequired.setEnabled(enable2); txtDefaultValue.setEnabled(enable2); txtHelpText.setEnabled(enabled); //We allow localisation of help text. skipRulesView.setEnabled(enable2); validationRulesView.setEnabled(enable2); dynamicListsView.setEnabled(enable2); txtCalculation.setEnabled(enable2); btnCalculation.setEnabled(enable2); clearProperties(); } /** * Selects the current question's data type in the data types drop down listbox. * * @param type the current question's data type. */ private void setDataType(QuestionType type) { int index = DT_INDEX_NONE; if (type == QuestionType.DATE) { index = DT_INDEX_DATE; } else if (type == QuestionType.BOOLEAN) { index = DT_INDEX_BOOLEAN; } else if (type == QuestionType.DATE_TIME) { index = DT_INDEX_DATE_TIME; } else if (type == QuestionType.DECIMAL) { index = DT_INDEX_DECIMAL; } else if (type == QuestionType.LIST_EXCLUSIVE) { index = DT_INDEX_SINGLE_SELECT; } else if (type == QuestionType.LIST_MULTIPLE) { index = DT_INDEX_MULTIPLE_SELECT; } else if (type == QuestionType.NUMERIC) { index = DT_INDEX_NUMBER; } else if (type == QuestionType.REPEAT) { index = DT_INDEX_REPEAT; } else if (type == QuestionType.TEXT) { index = DT_INDEX_TEXT; } else if (type == QuestionType.TIME) { index = DT_INDEX_TIME; } else if (type == QuestionType.IMAGE) { index = DT_INDEX_IMAGE; txtDefaultValue.setEnabled(false); } else if (type == QuestionType.VIDEO) { index = DT_INDEX_VIDEO; txtDefaultValue.setEnabled(false); } else if (type == QuestionType.AUDIO) { index = DT_INDEX_AUDIO; txtDefaultValue.setEnabled(false); } else if (type == QuestionType.LIST_EXCLUSIVE_DYNAMIC) { index = DT_INDEX_SINGLE_SELECT_DYNAMIC; txtDefaultValue.setEnabled(false); } else if (type == QuestionType.GPS) { index = DT_INDEX_GPS; txtDefaultValue.setEnabled(false); } else if (type == QuestionType.BARCODE) { index = DT_INDEX_BARCODE; txtDefaultValue.setEnabled(false); } cbDataType.setSelectedIndex(index); } /** * Clears values from all widgets. */ public void clearProperties() { cbDataType.setSelectedIndex(DT_INDEX_NONE); chkVisible.setValue(false); chkEnabled.setValue(false); chkLocked.setValue(false); chkRequired.setValue(false); txtDefaultValue.setText(null); txtHelpText.setText(null); txtText.setText(null); txtBinding.setText(null); txtDescTemplate.setText(null); txtCalculation.setText(null); txtFormKey.setText(null); } /** * @see org.openxdata.designer.client.controller.IFormSelectionListener#onFormItemSelected(java.lang.Object) */ public void onFormItemSelected(Object formItem) { propertiesObj = formItem; clearProperties(); //For now these may be options for boolean question types (Yes & No) if (formItem == null) { enableQuestionOnlyProperties(false); txtText.setEnabled(false); enableDescriptionTemplate(false); txtBinding.setEnabled(false); return; } txtBinding.setEnabled(Context.allowBindEdit() && !Context.isStructureReadOnly()); if (formItem instanceof FormDef) setFormProperties((FormDef) formItem); else if (formItem instanceof PageDef) { setPageProperties((PageDef) formItem); advancedValidationRulesView.addQuestions((PageDef) formItem); } else if (formItem instanceof QuestionDef) setQuestionProperties((QuestionDef) formItem); else if (formItem instanceof OptionDef) { setQuestionOptionProperties((OptionDef) formItem); //Since option bindings are not xml node names, we may allow their //edits as they are not structure breaking. txtBinding.setEnabled(!Context.isStructureReadOnly()); } } /** * Sets focus to the first input widget. */ public void setFocus() { txtText.setFocus(true); txtText.selectAll(); } /** * @see com.google.gwt.user.client.WindowResizeListener#onWindowResized(int, int) */ public void onWindowResized(int width, int height) { setWidth("100%"); setHeight("100%"); validationRulesView.onWindowResized(width, height); } /** * Retrieves changes from all widgets and updates the selected object. */ public void commitChanges() { skipRulesView.updateSkipRule(); validationRulesView.updateValidationRule(); dynamicListsView.updateDynamicLists(); advancedValidationRulesView.updateValidationRule(); } /** * @see org.openxdata.designer.client.controller.ItemSelectionListener#onItemSelected(Object, Object) */ public void onItemSelected(Object sender, Object item) { if (sender == btnDescTemplate) { item = "${" + item + "}$"; if (propertiesObj instanceof QuestionDef) { txtText.setText(txtText.getText() + " " + txtDescTemplate.getText() + item); updateText(); txtText.setFocus(true); } else { txtDescTemplate.setText(txtDescTemplate.getText() + item); updateDescTemplate(); //Added for IE which does not properly throw change events for the desc template textbox txtDescTemplate.setFocus(true); } } else if (sender == btnCalculation) { assert (propertiesObj instanceof QuestionDef); txtCalculation.setText(txtCalculation.getText() + item); updateCalculation(); //Added for IE which does not properly throw change events for the desc template textbox txtCalculation.setFocus(true); } } /** * @see org.openxdata.designer.client.controller.ItemSelectionListener#onStartItemSelection(Object) */ public void onStartItemSelection(Object sender) { } /** * Sets the listener to form action events. * * @param formActionListener the listener. */ public void setFormActionListener(IFormActionListener formActionListener) { this.formActionListener = formActionListener; } @Override public void onBrowserEvent(Event event) { switch (DOM.eventGetType(event)) { case Event.ONKEYDOWN: if (!isVisible()) return; int keyCode = event.getKeyCode(); if (event.getCtrlKey()) { if (keyCode == 'N' || keyCode == 'n') { formActionListener.addNewItem(); DOM.eventPreventDefault(event); } else if (keyCode == KeyCodes.KEY_RIGHT) { formActionListener.moveToChild(); DOM.eventPreventDefault(event); } else if (keyCode == KeyCodes.KEY_LEFT) { formActionListener.moveToParent(); DOM.eventPreventDefault(event); } else if (keyCode == KeyCodes.KEY_UP) { formActionListener.moveUp(); DOM.eventPreventDefault(event); } else if (keyCode == KeyCodes.KEY_DOWN) { formActionListener.moveDown(); DOM.eventPreventDefault(event); } } } } private void enableDescriptionTemplate(boolean enable) { btnDescTemplate.setEnabled(enable); FlexCellFormatter cellFormatter = table.getFlexCellFormatter(); cellFormatter.setVisible(10, 0, enable); cellFormatter.setVisible(10, 1, enable); //form key cellFormatter.setVisible(11, 0, enable); cellFormatter.setVisible(11, 1, enable); } }