Java tutorial
package org.openxdata.designer.client.view; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Vector; import org.openxdata.designer.client.DesignerMessages; import org.openxdata.designer.client.controller.DragDropListener; import org.openxdata.designer.client.controller.FormDesignerDragController; import org.openxdata.designer.client.controller.IWidgetPopupMenuListener; import org.openxdata.designer.client.controller.LayoutChangeListener; import org.openxdata.designer.client.controller.WidgetSelectionListener; import org.openxdata.designer.client.util.FormDesignerUtil; import org.openxdata.designer.client.vew.widget.images.FormDesignerImages; import org.openxdata.designer.client.widget.DesignGroupWidget; import org.openxdata.designer.client.widget.DesignWidgetWrapper; import org.openxdata.sharedlib.client.OpenXdataConstants; import org.openxdata.sharedlib.client.locale.FormsConstants; 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.util.FormUtil; import org.openxdata.sharedlib.client.widget.DatePickerWidget; import org.openxdata.sharedlib.client.widget.DateTimeWidget; import org.openxdata.sharedlib.client.widget.RadioButtonWidget; import org.openxdata.sharedlib.client.widget.TimeWidget; import org.openxdata.sharedlib.client.widget.WidgetEx; import org.openxdata.sharedlib.client.xforms.XformConstants; 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.logical.shared.SelectionEvent; import com.google.gwt.event.logical.shared.SelectionHandler; import com.google.gwt.user.client.Command; 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.AbsolutePanel; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Hyperlink; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.MenuBar; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.TabBar; import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.xml.client.Document; import com.google.gwt.xml.client.Element; import com.google.gwt.xml.client.Node; import com.google.gwt.xml.client.NodeList; import com.google.gwt.xml.client.XMLParser; import org.openxdata.sharedlib.client.model.QuestionType; /** * The surface onto which to drag and drop widgets. * * 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 DesignSurfaceView extends DesignGroupView implements SelectionHandler<Integer>, DragDropListener, IWidgetPopupMenuListener { final FormsConstants formsConstants = GWT.create(FormsConstants.class); final DesignerMessages designerMessages = GWT.create(DesignerMessages.class); /** Height in pixels of the selected page. */ private String sHeight = "100%"; /** Width in pixels of the selected page. */ private String sWidth = "100%"; /** Listener to layout change events. */ private LayoutChangeListener layoutChangeListener; /** List of drag controllers. */ Vector<FormDesignerDragController> dragControllers = new Vector<FormDesignerDragController>(); /** The form being designed. */ FormDef formDef; /** The layout xml document object. */ Document doc; public DesignSurfaceView() { super(null); } /** * Creates a new instance of the design surface. * * @param images the images used by the design surface. */ public DesignSurfaceView(FormDesignerImages images) { super(images); FormUtil.maximizeWidget(tabs); initPanel(); tabs.selectTab(0); initWidget(tabs); tabs.addSelectionHandler(this); DOM.sinkEvents(getElement(), DOM.getEventsSunk(getElement()) | Event.MOUSEEVENTS | Event.KEYEVENTS); setupPopup(); widgetPopup = new PopupPanel(true, true); MenuBar menuBar = new MenuBar(true); menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.cut(), formsConstants.cut()), true, new Command() { public void execute() { widgetPopup.hide(); cutWidgets(); } }); menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.copy(), formsConstants.copy()), true, new Command() { public void execute() { widgetPopup.hide(); copyWidgets(false); } }); menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.delete(), formsConstants.deleteItem()), true, new Command() { public void execute() { widgetPopup.hide(); deleteWidgets(); } }); menuBar.addSeparator(); menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.add(), designerMessages.changeWidgetH()), true, new Command() { public void execute() { widgetPopup.hide(); changeWidget(false); } }); menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.add(), designerMessages.changeWidgetV()), true, new Command() { public void execute() { widgetPopup.hide(); changeWidget(true); } }); widgetPopup.setWidget(menuBar); rubberBand.addStyleName("rubberBand"); currentWidgetSelectionListener = this; } /** * Processes keyboard events for the design surface. * * @param event the event object. * @return true if processed, else false. */ public boolean handleKeyBoardEvent(Event event) { if (!childHandleKeyDownEvent(event)) handleKeyDownEvent(event); return true; } /** * Gives a chance to child widgets to process keyboard events. * * @param event the event object. * @return true if any child has handled the event, else false. */ private boolean childHandleKeyDownEvent(Event event) { for (int index = 0; index < selectedPanel.getWidgetCount(); index++) { Widget widget = selectedPanel.getWidget(index); if (!(widget instanceof DesignWidgetWrapper)) continue; if (!(((DesignWidgetWrapper) widget).getWrappedWidget() instanceof DesignGroupWidget)) continue; if (((DesignGroupWidget) ((DesignWidgetWrapper) widget).getWrappedWidget()).handleKeyDownEvent(event)) return true; } return false; } /** * Sets up the design surface panel for the first page. */ protected void initPanel() { AbsolutePanel panel = new AbsolutePanel(); FormUtil.maximizeWidget(panel); tabs.add(panel, formsConstants.page() + "1"); selectedPanel = panel; super.initPanel(); dragControllers.add(tabs.getWidgetCount() - 1, selectedDragController); panel.setHeight(sHeight); //This is needed for IE Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { setHeight(getHeight()); } }); } /** * Sets up up the context menu popup for the design surface. */ private void setupPopup() { popup = new PopupPanel(true, true); MenuBar menuBar = new MenuBar(true); MenuBar addControlMenu = new MenuBar(true); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), formsConstants.label()), true, new Command() { public void execute() { popup.hide(); addNewLabel(formsConstants.label(), true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), formsConstants.textBox()), true, new Command() { public void execute() { popup.hide(); addNewTextBox(true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), formsConstants.checkBox()), true, new Command() { public void execute() { popup.hide(); addNewCheckBox(true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), formsConstants.radioButton()), true, new Command() { public void execute() { popup.hide(); addNewRadioButton(true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), formsConstants.listBox()), true, new Command() { public void execute() { popup.hide(); addNewDropdownList(true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), formsConstants.textArea()), true, new Command() { public void execute() { popup.hide(); addNewTextArea(true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), formsConstants.button()), true, new Command() { public void execute() { popup.hide(); addNewButton(formsConstants.button(), null, true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), formsConstants.datePicker()), true, new Command() { public void execute() { popup.hide(); addNewDatePicker(true); } }); addControlMenu.addItem( FormDesignerUtil.createHeaderHTML(images.addchild(), designerMessages.dateTimeWidget()), true, new Command() { public void execute() { popup.hide(); addNewDateTimeWidget(true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), designerMessages.timeWidget()), true, new Command() { public void execute() { popup.hide(); addNewTimeWidget(true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), designerMessages.groupBox()), true, new Command() { public void execute() { popup.hide(); addNewGroupBox(true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), designerMessages.repeat()), true, new Command() { public void execute() { popup.hide(); addNewRepeatSection(true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), designerMessages.picture()), true, new Command() { public void execute() { popup.hide(); addNewPictureSection(null, null, true); } }); addControlMenu.addItem(FormDesignerUtil.createHeaderHTML(images.addchild(), designerMessages.videoAudio()), true, new Command() { public void execute() { popup.hide(); addNewVideoAudioSection(null, null, true); } }); menuBar.addItem(" " + designerMessages.addWidget(), addControlMenu); deleteWidgetsSeparator = menuBar.addSeparator(); deleteWidgetsMenu = menuBar.addItem( FormDesignerUtil.createHeaderHTML(images.delete(), designerMessages.deleteSelected()), true, new Command() { public void execute() { popup.hide(); deleteWidgets(); } }); groupWidgetsSeparator = menuBar.addSeparator(); groupWidgetsMenu = menuBar.addItem( FormDesignerUtil.createHeaderHTML(images.addchild(), designerMessages.groupWidgets()), true, new Command() { public void execute() { popup.hide(); groupWidgets(); } }); menuBar.addSeparator(); menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.add(), designerMessages.newTab()), true, new Command() { public void execute() { popup.hide(); addNewTab(null); } }); menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.delete(), designerMessages.deleteTab()), true, new Command() { public void execute() { popup.hide(); deleteTab(); } }); cutCopySeparator = menuBar.addSeparator(); cutMenu = menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.cut(), designerMessages.cut()), true, new Command() { public void execute() { popup.hide(); cutWidgets(); } }); copyMenu = menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.copy(), formsConstants.copy()), true, new Command() { public void execute() { popup.hide(); copyWidgets(false); } }); pasteSeparator = menuBar.addSeparator(); pasteMenu = menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.paste(), formsConstants.paste()), true, new Command() { public void execute() { popup.hide(); pasteWidgets(true); } }); menuBar.addSeparator(); lockWidgetsMenu = menuBar.addItem( FormDesignerUtil.createHeaderHTML(images.add(), designerMessages.lockWidgets()), true, new Command() { public void execute() { popup.hide(); lockWidgets(); } }); menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.add(), formsConstants.selectAll()), true, new Command() { public void execute() { popup.hide(); selectAll(); } }); menuBar.addSeparator(); menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.refresh(), formsConstants.refresh()), true, new Command() { public void execute() { popup.hide(); refresh(); } }); menuBar.addSeparator(); menuBar.addItem(FormDesignerUtil.createHeaderHTML(images.open(), formsConstants.load()), true, new Command() { public void execute() { popup.hide(); load(); } }); popup.setWidget(menuBar); } /** * Adds a new tab with a given name and selects it. * * @param name the tab name. */ private DesignWidgetWrapper addNewTab(String name) { initPanel(); if (name == null) name = formsConstants.page() + (tabs.getWidgetCount()); tabs.add(selectedPanel, name); selectedTabIndex = tabs.getWidgetCount() - 1; tabs.selectTab(selectedTabIndex); DesignWidgetWrapper widget = new DesignWidgetWrapper(tabs.getTabBar(), widgetPopup, this); widget.setBinding(name); widget.setFontFamily(FormUtil.getDefaultFontFamily()); widget.setFontSize(FormUtil.getDefaultFontSize()); widget.setFontWeight("normal"); pageWidgets.put(tabs.getTabBar().getTabCount() - 1, widget); Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { setHeight(getHeight()); } }); return widget; } /** * @see com.google.gwt.event.logical.shared.SelectionHandler#onSelection(SelectionEvent) */ public void onSelection(SelectionEvent<Integer> event) { selectedTabIndex = event.getSelectedItem(); selectedDragController = dragControllers.elementAt(selectedTabIndex); selectedPanel = selectedDragController.getBoundaryPanel(); widgetSelectionListener.onWidgetSelected(getSelPageDesignWidget(), false); } /** * Sets the listener to widget selection events. * * @param widgetSelectionListener the listener. */ public void setWidgetSelectionListener(WidgetSelectionListener widgetSelectionListener) { this.widgetSelectionListener = widgetSelectionListener; } /** * Gets the widgets layout xml. * * @return the xml. */ public String getLayoutXml() { if (tabs.getWidgetCount() == 0) return null; com.google.gwt.xml.client.Document doc = XMLParser.createDocument(); doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"")); Element rootNode = doc.createElement("Form"); if (formDef != null) rootNode.setAttribute(XformConstants.ATTRIBUTE_NAME_ID, formDef.getId() + ""); doc.appendChild(rootNode); this.doc = doc; boolean hasWidgets = false; AbsolutePanel prevSelPanel = selectedPanel; for (int i = 0; i < tabs.getWidgetCount(); i++) { Element node = doc.createElement("Page"); node.setAttribute(WidgetEx.WIDGET_PROPERTY_TEXT, DesignWidgetWrapper.getTabDisplayText(tabs.getTabBar().getTabHTML(i))); pageWidgets.get(i).buildLabelProperties(node); if (pageWidgets.get(i) != null) node.setAttribute(WidgetEx.WIDGET_PROPERTY_BINDING, pageWidgets.get(i).getBinding()); rootNode.appendChild(node); AbsolutePanel panel = (AbsolutePanel) tabs.getWidget(i); selectedPanel = panel; node.setAttribute(WidgetEx.WIDGET_PROPERTY_WIDTH, getWidth()); node.setAttribute(WidgetEx.WIDGET_PROPERTY_HEIGHT, getHeight()); node.setAttribute(WidgetEx.WIDGET_PROPERTY_BACKGROUND_COLOR, getBackgroundColor()); boolean b = buildLayoutXml(node, panel, doc); if (b) hasWidgets = true; } selectedPanel = prevSelPanel; if (hasWidgets) return FormDesignerUtil.formatXml(doc.toString()); return null; } /** * Gets the root node of the language or locale translation document for the widgets * layout on the design surface. * * @return the root node. */ public Element getLanguageNode() { if (tabs.getWidgetCount() == 0) return null; com.google.gwt.xml.client.Document doc = XMLParser.createDocument(); doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"")); Element rootNode = doc.createElement("Form"); if (formDef != null) rootNode.setAttribute(XformConstants.ATTRIBUTE_NAME_ID, formDef.getId() + ""); doc.appendChild(rootNode); for (int i = 0; i < tabs.getWidgetCount(); i++) { if (pageWidgets.get(i) == null) continue; //TODO Need to deal with this case where all widgets are deleted but layout and locale text remains String xpath = "Form/Page[@Binding='" + pageWidgets.get(i).getBinding() + "']/Item[@"; String text = DesignWidgetWrapper.getTabDisplayText(tabs.getTabBar().getTabHTML(i)); Element node = doc.createElement(XformConstants.NODE_NAME_TEXT); node.setAttribute(XformConstants.ATTRIBUTE_NAME_XPATH, "Form/Page[@Binding='" + pageWidgets.get(i).getBinding() + "'][@Text]"); node.setAttribute(XformConstants.ATTRIBUTE_NAME_VALUE, text); rootNode.appendChild(node); buildLanguageNode((AbsolutePanel) tabs.getWidget(i), doc, rootNode, xpath); } return rootNode; } private void buildLanguageNode(AbsolutePanel panel, com.google.gwt.xml.client.Document doc, Element parentNode, String xpath) { for (int i = 0; i < panel.getWidgetCount(); i++) { Widget widget = panel.getWidget(i); if (!(widget instanceof DesignWidgetWrapper)) continue; ((DesignWidgetWrapper) widget).buildLanguageXml(doc, parentNode, xpath); } } private boolean buildLayoutXml(Element parent, AbsolutePanel panel, com.google.gwt.xml.client.Document doc) { for (int i = 0; i < panel.getWidgetCount(); i++) { Widget widget = panel.getWidget(i); if (!(widget instanceof DesignWidgetWrapper)) continue; ((DesignWidgetWrapper) widget).buildLayoutXml(parent, doc); } return panel.getWidgetCount() > 0; } /** * Sets the layout xml for the design surface. * * @param xml the layout xml. * @param formDef the form whose layout xml is given. * @return true if the layout xml has been loaded successfully, else false. */ public boolean setLayoutXml(String xml, FormDef formDef) { this.formDef = formDef; PaletteView.unRegisterAllDropControllers(); tabs.clear(); pageWidgets.clear(); if (xml == null || xml.trim().length() == 0) { addNewTab(null); return false; } com.google.gwt.xml.client.Document doc = XMLParser.parse(xml); Element root = doc.getDocumentElement(); NodeList pages = root.getChildNodes(); for (int i = 0; i < pages.getLength(); i++) { if (pages.item(i).getNodeType() != Node.ELEMENT_NODE) continue; Element node = (Element) pages.item(i); DesignWidgetWrapper widget = addNewTab(node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT)); WidgetEx.loadLabelProperties(node, widget); ((DesignGroupView) this).setWidth(node.getAttribute(WidgetEx.WIDGET_PROPERTY_WIDTH)); ((DesignGroupView) this).setHeight(node.getAttribute(WidgetEx.WIDGET_PROPERTY_HEIGHT)); ((DesignGroupView) this) .setBackgroundColor(node.getAttribute(WidgetEx.WIDGET_PROPERTY_BACKGROUND_COLOR)); loadPage(node.getChildNodes()); } this.doc = doc; if (tabs.getWidgetCount() > 0) { selectedTabIndex = 0; tabs.selectTab(selectedTabIndex); } return true; } /** * Loads a list of layout xml nodes for a given page on the design surface. * * @param nodes the node list. */ private void loadPage(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE) continue; try { Element node = (Element) nodes.item(i); DesignWidgetWrapper widget = loadWidget(node, selectedDragController, selectedPanel, images, widgetPopup, this, currentWidgetSelectionListener, formDef); if (widget != null && (widget.getWrappedWidget() instanceof DesignGroupWidget)) { ((DesignGroupWidget) widget.getWrappedWidget()).loadWidgets(node, formDef); ((DesignGroupWidget) widget.getWrappedWidget()) .setWidgetSelectionListener(currentWidgetSelectionListener); if (!widget.isRepeated()) selectedDragController.makeDraggable(widget, ((DesignGroupWidget) widget.getWrappedWidget()).getHeaderLabel()); } } catch (Exception ex) { ex.printStackTrace(); } } } /** * Loads a widget on the design surface. * * @param node * @param dragController * @param panel * @param images * @param widgetPopup * @param widgetPopupMenuListener * @param widgetSelectionListener * @param formDef * @return */ public static DesignWidgetWrapper loadWidget(Element node, FormDesignerDragController dragController, AbsolutePanel panel, FormDesignerImages images, PopupPanel widgetPopup, IWidgetPopupMenuListener widgetPopupMenuListener, WidgetSelectionListener widgetSelectionListener, FormDef formDef) { String left = node.getAttribute(WidgetEx.WIDGET_PROPERTY_LEFT); String top = node.getAttribute(WidgetEx.WIDGET_PROPERTY_TOP); String s = node.getAttribute(WidgetEx.WIDGET_PROPERTY_WIDGETTYPE); Widget widget = null; if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_RADIOBUTTON)) widget = new RadioButtonWidget(node.getAttribute(WidgetEx.WIDGET_PROPERTY_PARENTBINDING), node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT)); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_CHECKBOX)) widget = new CheckBox(node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT)); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_BUTTON)) widget = new Button(node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT)); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_LISTBOX)) widget = new ListBox(false); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_TEXTAREA)) widget = new TextArea(); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_IMAGE)) widget = FormUtil.createImage(images.picture()); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_VIDEO_AUDIO)) widget = new Hyperlink(node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT), ""); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_DATEPICKER)) widget = new DatePickerWidget(); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_TIME)) widget = new TimeWidget(); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_DATETIME)) widget = new DateTimeWidget(); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_TEXTBOX)) widget = new TextBox(); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_LABEL)) widget = new Label(node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT)); else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_GROUPBOX) || s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_REPEATSECTION)) widget = new DesignGroupWidget(images, widgetPopupMenuListener); else return null; DesignWidgetWrapper wrapper = new DesignWidgetWrapper(widget, widgetPopup, widgetSelectionListener); wrapper.setLayoutNode(node); String value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_HELPTEXT); if (value != null && value.trim().length() > 0) wrapper.setTitle(value); value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_EXTERNALSOURCE); if (value != null && value.trim().length() > 0) wrapper.setExternalSource(value); value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_DISPLAYFIELD); if (value != null && value.trim().length() > 0) wrapper.setDisplayField(value); value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_VALUEFIELD); if (value != null && value.trim().length() > 0) wrapper.setValueField(value); value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_FILTERFIELD); if (value != null && value.trim().length() > 0) wrapper.setFilterField(value); value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_WIDTH); if (value != null && value.trim().length() > 0) wrapper.setWidth(value); value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_HEIGHT); if (value != null && value.trim().length() > 0) wrapper.setHeight(value); value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_REPEATED); if (value != null && value.trim().length() > 0) wrapper.setRepeated(value.equals(WidgetEx.REPEATED_TRUE_VALUE)); value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_ID); if (value != null && value.trim().length() > 0) wrapper.setId(value); String binding = node.getAttribute(WidgetEx.WIDGET_PROPERTY_BINDING); if (binding != null && binding.trim().length() > 0) wrapper.setBinding(binding); else binding = null; String parentBinding = node.getAttribute(WidgetEx.WIDGET_PROPERTY_PARENTBINDING); if (parentBinding != null && parentBinding.trim().length() > 0) wrapper.setParentBinding(parentBinding); else parentBinding = null; value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_TABINDEX); if (value != null && value.trim().length() > 0) wrapper.setTabIndex(Integer.parseInt(value)); WidgetEx.loadLabelProperties(node, wrapper); if (formDef != null && binding != null && parentBinding == null) { QuestionDef questionDef = formDef.getQuestion(binding); if (questionDef != null) wrapper.setQuestionDef(questionDef); } if (!"true".equals(node.getAttribute(WidgetEx.WIDGET_PROPERTY_HEADER_LABEL))) { dragController.makeDraggable(wrapper); //Without this, widgets in this box cant use Ctrl + A in edit mode and also //edited text is not automatically selected. wrapper.removeStyleName("dragdrop-handle"); } panel.add(wrapper); FormDesignerUtil.setWidgetPosition(wrapper, left, top); return wrapper; } /** * Deletes the selected widgets. */ public boolean deleteWidgets() { if (super.deleteWidgets() && doc != null) { String layout = null; if (!(tabs.getTabBar().getTabCount() == 1 && (selectedPanel == null || (selectedPanel != null && selectedPanel.getWidgetCount() == 0)))) layout = FormUtil.formatXml(doc.toString()); layoutChangeListener.onLayoutChanged(layout); return true; } if (tabs.getTabBar().getTabCount() == 1 && selectedPanel != null && selectedPanel.getWidgetCount() == 0) layoutChangeListener.onLayoutChanged(null); return true; } /** * Deletes the selected page tab. */ private void deleteTab() { if (tabs.getWidgetCount() == 1) { if (formDef != null) formDef.setLayoutXml(null); //TODO Check if this does not bring bugs Window.alert(formsConstants.cantDeleteAllTabs()); return; } if (selectedPanel.getWidgetCount() > 0) { Window.alert(formsConstants.deleteAllTabWidgetsFirst()); return; } if (!Window.confirm(formsConstants.deleteTabPrompt())) return; FormDesignerDragController dragController = dragControllers.remove(selectedTabIndex); PaletteView.unRegisterDropController(dragController.getFormDesignerDropController()); tabs.remove(selectedTabIndex); pageWidgets.remove(selectedTabIndex); if (selectedTabIndex > 0) selectedTabIndex -= 1; tabs.selectTab(selectedTabIndex); } /** * Loads the default widget layout for a given form. * * @param formDef the form definition object. */ public void setLayout(FormDef formDef) { this.formDef = formDef; PaletteView.unRegisterAllDropControllers(); tabs.clear(); pageWidgets.clear(); Vector<PageDef> pages = formDef.getPages(); if (pages != null) { for (int i = 0; i < pages.size(); i++) { PageDef pageDef = (PageDef) pages.get(i); addNewTab(pageDef.getName()); loadPage(pageDef); selectAll(); format(); clearSelection(); } layoutChangeListener.onLayoutChanged(getLayoutXml()); } if (tabs.getWidgetCount() > 0) { selectedTabIndex = 0; tabs.selectTab(selectedTabIndex); } } /** * Loads the default widget layout for a given page. * * @param pageDef the page definition object. */ private void loadPage(PageDef pageDef) { loadQuestions(pageDef.getQuestions()); } /** * Does automatic loading of question widgets onto the design surface for a given page. * * @param questions the list of questions. */ private void loadQuestions(List<QuestionDef> questions) { loadQuestions(questions, 20, 0, tabs.getTabBar().getTabCount() == 1, false); } /** * Does automatic loading of question widgets onto the design surface for a given page * and starting at a given y coordinate. * * @param questions the list of questions. * @param pageName the name of the page. * @param startY the y coordinate to start at. * @param tabIndex the tabIndex to start from. * @param submitCancelBtns set to true to add the submit and cancel buttons * @param select set to true to select all the created widgets. */ private void loadQuestions(List<QuestionDef> questions, int startY, int tabIndex, boolean submitCancelBtns, boolean select) { int maxX = 0, max = 999999; x = 20; y = startY; x += selectedPanel.getAbsoluteLeft(); y += selectedPanel.getAbsoluteTop(); DesignWidgetWrapper widgetWrapper = null; for (int i = 0; i < questions.size(); i++) { QuestionDef questionDef = (QuestionDef) questions.get(i); if (!questionDef.isVisible() || (questionDef.isRequired() && (questionDef.isLocked() || !questionDef.isEnabled()))) continue; QuestionType type = questionDef.getDataType(); if (type == QuestionType.REPEAT && questionDef.getRepeatQtnsDef().getQuestions() == null) continue; if (!(type == QuestionType.VIDEO || type == QuestionType.AUDIO || type == QuestionType.IMAGE)) { widgetWrapper = addNewLabel(questionDef.getText(), false); widgetWrapper.setBinding(questionDef.getBinding()); widgetWrapper.setTitle(questionDef.getText()); if (select) selectedDragController.selectWidget(widgetWrapper); } if (questionDef.getDataType() == QuestionType.REPEAT) { widgetWrapper.setFontWeight("bold"); widgetWrapper.setFontStyle("italic"); } widgetWrapper = null; if (!(type == QuestionType.VIDEO || type == QuestionType.AUDIO || type == QuestionType.IMAGE)) x += (questionDef.getText().length() * 10); if (type == QuestionType.LIST_EXCLUSIVE || type == QuestionType.LIST_EXCLUSIVE_DYNAMIC) widgetWrapper = addNewDropdownList(false); else if (type == QuestionType.DATE) widgetWrapper = addNewDatePicker(false); else if (type == QuestionType.DATE_TIME) widgetWrapper = addNewDateTimeWidget(false); else if (type == QuestionType.TIME) widgetWrapper = addNewTimeWidget(false); else if (type == QuestionType.LIST_MULTIPLE) { widgetWrapper = addNewCheckBoxSet(questionDef, true, tabIndex); tabIndex += questionDef.getOptions().size(); } else if (type == QuestionType.BOOLEAN) widgetWrapper = addNewDropdownList(false); else if (type == QuestionType.REPEAT) widgetWrapper = addNewRepeatSet(questionDef, false); else if (type == QuestionType.IMAGE) widgetWrapper = addNewPictureSection(questionDef.getBinding(), questionDef.getText(), false); else if (type == QuestionType.VIDEO || type == QuestionType.AUDIO) widgetWrapper = addNewVideoAudioSection(questionDef.getBinding(), questionDef.getText(), false); else widgetWrapper = addNewTextBox(false); if (widgetWrapper != null) { if (!(type == QuestionType.IMAGE || type == QuestionType.VIDEO || type == QuestionType.AUDIO)) widgetWrapper.setBinding(questionDef.getBinding()); widgetWrapper.setQuestionDef(questionDef); String helpText = questionDef.getHelpText(); if (helpText != null && helpText.trim().length() > 0) helpText = questionDef.getHelpText(); else helpText = questionDef.getText(); widgetWrapper.setTitle(helpText); widgetWrapper.setTabIndex(++tabIndex); if (select) selectedDragController.selectWidget(widgetWrapper); } if (x > maxX) maxX = x; x = 20 + selectedPanel.getAbsoluteLeft(); y += 40; if (questionDef.getDataType() == QuestionType.IMAGE) y += 195 + 30; if (questionDef.getDataType() == QuestionType.VIDEO || questionDef.getDataType() == QuestionType.AUDIO) y += 75 + 30; int rptIncr = 0; if (i < questions.size() - 1) { QuestionType dataType = ((QuestionDef) questions.get(i + 1)).getDataType(); if (dataType == QuestionType.REPEAT) rptIncr = 90 + 50; else if (dataType == QuestionType.IMAGE) rptIncr = 195 + 30; else if (dataType == QuestionType.VIDEO || dataType == QuestionType.AUDIO) rptIncr = 75 + 30; } //TODO Looks like this is not longer necessary as we can have a page as long as the user wants if ((y + 40 + rptIncr) > max) { y += 10; addNewTab(formsConstants.page()); y = 20 + selectedPanel.getAbsoluteTop(); } } y += 10; //The submit button is added only to the first tab such that we don't keep //adding multiple submit buttons every time one refreshes the design surface if (submitCancelBtns) { addSubmitButton(false); x += 200; addCancelButton(false); } y += ((ScrollPanel) getParent()).getScrollPosition(); setHeight(y + 40 + OpenXdataConstants.UNITS); if (maxX < 900) maxX = 900; if (FormUtil.convertDimensionToInt(getWidth()) < maxX) setWidth(maxX + OpenXdataConstants.UNITS); } /** * Adds a new set of check boxes. * * @param questionDef the multiple select question whose check boxes we are adding. * @param vertically set to true if you want to add the check boxes vertically. * @param tabIndex the current tab index. * @return this is always null. */ protected DesignWidgetWrapper addNewCheckBoxSet(QuestionDef questionDef, boolean vertically, int tabIndex) { List<OptionDef> options = questionDef.getOptions(); for (int i = 0; i < options.size(); i++) { OptionDef optionDef = (OptionDef) options.get(i); DesignWidgetWrapper wrapper = addNewWidget(new CheckBox(optionDef.getText()), false); wrapper.setFontFamily(FormUtil.getDefaultFontFamily()); wrapper.setFontSize(FormUtil.getDefaultFontSize()); wrapper.setBinding(optionDef.getVariableName()); wrapper.setParentBinding(questionDef.getBinding()); wrapper.setText(optionDef.getText()); wrapper.setTitle(optionDef.getText()); wrapper.setTabIndex(++tabIndex); if (i < (options.size() - 1)) { if (vertically) y += 40; else x += (optionDef.getText().length() * 12); } } return null; } /** * Adds a new repeat set of widgets. * * @param questionDef the repeat question whose widgets we are adding. * @param select set to true to select the repeat widget after adding it. * @return the added repeat widget. */ protected DesignWidgetWrapper addNewRepeatSet(QuestionDef questionDef, boolean select) { x = 35 + selectedPanel.getAbsoluteLeft(); y += 25; Vector<QuestionDef> questions = questionDef.getRepeatQtnsDef().getQuestions(); if (questions == null) return addNewTextBox(select); //TODO Bug here for (int index = 0; index < questions.size(); index++) { QuestionDef qtn = (QuestionDef) questions.get(index); if (index > 0) x += 210; DesignWidgetWrapper label = addNewLabel(qtn.getText(), select); label.setBinding(qtn.getBinding()); label.setTitle(qtn.getText()); label.setTextDecoration("underline"); } x = 20 + selectedPanel.getAbsoluteLeft(); y += 25; DesignWidgetWrapper widget = addNewRepeatSection(select); FormDesignerDragController selDragController = selectedDragController; AbsolutePanel absPanel = selectedPanel; PopupPanel wgpopup = widgetPopup; WidgetSelectionListener wgSelectionListener = currentWidgetSelectionListener; currentWidgetSelectionListener = (DesignGroupWidget) widget.getWrappedWidget(); int oldY = y; y = x = 10; selectedDragController = widget.getDragController(); selectedPanel = widget.getPanel(); widgetPopup = widget.getWidgetPopup(); x += selectedPanel.getAbsoluteLeft(); y += selectedPanel.getAbsoluteTop(); DesignWidgetWrapper widgetWrapper = null; for (int index = 0; index < questions.size(); index++) { QuestionDef qtn = (QuestionDef) questions.get(index); if (index > 0) x += 205; if (qtn.getDataType() == QuestionType.LIST_EXCLUSIVE || qtn.getDataType() == QuestionType.LIST_EXCLUSIVE_DYNAMIC) widgetWrapper = addNewDropdownList(false); else if (qtn.getDataType() == QuestionType.DATE) widgetWrapper = addNewDatePicker(false); else if (qtn.getDataType() == QuestionType.DATE_TIME) widgetWrapper = addNewDateTimeWidget(false); else if (qtn.getDataType() == QuestionType.TIME) widgetWrapper = addNewTimeWidget(false); else if (qtn.getDataType() == QuestionType.LIST_MULTIPLE) { widgetWrapper = addNewCheckBoxSet(qtn, false, index); index += qtn.getOptions().size(); } else if (qtn.getDataType() == QuestionType.BOOLEAN) widgetWrapper = addNewDropdownList(false); else if (qtn.getDataType() == QuestionType.IMAGE) widgetWrapper = addNewPicture(select); else if (qtn.getDataType() == QuestionType.VIDEO || qtn.getDataType() == QuestionType.AUDIO) widgetWrapper = addNewVideoAudioSection(null, qtn.getText(), select); else widgetWrapper = addNewTextBox(select); if (widgetWrapper != null) { widgetWrapper.setBinding(qtn.getBinding()); widgetWrapper.setQuestionDef(qtn); widgetWrapper.setTitle(qtn.getText()); widgetWrapper.setTabIndex(index + 1); } } selectedDragController.clearSelection(); selectedDragController = selDragController; selectedPanel = absPanel; widgetPopup = wgpopup; currentWidgetSelectionListener = wgSelectionListener; y = oldY; y += 90; if (questions.size() == 1) widget.setWidthInt(265); else widget.setWidthInt((questions.size() * 205) + 15); return widget; } /** * Sets the current form beign designed. * * @param formDef the form definition object. */ public void setFormDef(FormDef formDef) { if (this.formDef != formDef) { PaletteView.unRegisterAllDropControllers(); tabs.clear(); pageWidgets.clear(); addNewTab(null); } this.formDef = formDef; } /** * Loads widgets for questions that are not loaded on the design surface. */ public void refresh() { if (formDef == null) return; FormUtil.dlg.setText(formsConstants.refreshingDesignSurface()); FormUtil.dlg.center(); Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { try { boolean loading = false; if (!(tabs.getTabBar().getTabCount() == 1 && (selectedPanel == null || (selectedPanel != null && selectedPanel.getWidgetCount() == 0)))) loadNewWidgets(); else { if (formDef.getLayoutXml() != null && formDef.getLayoutXml().trim().length() > 0 && selectedPanel != null && selectedPanel.getWidgetCount() == 0) { loading = true; load(); } else setLayout(formDef); } if (!loading) FormUtil.dlg.hide(); } catch (Exception ex) { FormUtil.displayException(ex); } } }); } /** * Checks if the design surface has any widgets. * * @return true if it has, else false. */ public boolean hasWidgets() { return (tabs.getTabBar().getTabCount() > 0 && selectedPanel != null && selectedPanel.getWidgetCount() > 0); } /** * Loads design surface widgets from layout xml of the current form. */ public void load() { if (formDef == null) return; if ((selectedPanel != null && selectedPanel.getWidgetCount() > 0) || tabs.getTabBar().getTabCount() > 1) { Window.alert(formsConstants.deleteAllWidgetsFirst()); return; } FormUtil.dlg.setText(formsConstants.loadingDesignSurface()); FormUtil.dlg.center(); Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { try { if (!setLayoutXml(formDef.getLayoutXml(), formDef)) refresh(); else FormUtil.dlg.hide(); } catch (Exception ex) { FormUtil.displayException(ex); } } }); } /** * Gets the y coordinate of the lowest widget on the currently selected page. * * @return the y coordinate in pixels. */ private int getLowestWidgetYPos() { int lowestYPos = 0; for (int index = 0; index < selectedPanel.getWidgetCount(); index++) { Widget widget = selectedPanel.getWidget(index); int y = widget.getAbsoluteTop() + widget.getOffsetHeight(); if (y > lowestYPos) lowestYPos = y; } if (lowestYPos > 0) lowestYPos -= selectedPanel.getAbsoluteTop(); return lowestYPos; } /** * Loads widgets that have not yet been loaded on the design surface. If if they were once * loaded, have been deleted. */ private void loadNewWidgets() { //Create list of bindings for widgets that are already loaded on the design surface. HashMap<String, String> bindings = new HashMap<String, String>(); for (int i = 0; i < dragControllers.size(); i++) { AbsolutePanel panel = dragControllers.elementAt(i).getBoundaryPanel(); fillBindings(panel, bindings); } //Load the new questions onto the design surface for all pages. for (int index = 0; index < formDef.getPageCount(); index++) { List<QuestionDef> newQuestions = new ArrayList<QuestionDef>(); //Create a list of questions that have not yet been loaded on the design surface //for the current page. fillNewQuestions(formDef.getPageAt(index), newQuestions, bindings); //Check if this is a new page whose tab has not yet been added, and then add it if (tabs.getTabBar().getTabCount() < index + 1) addNewTab(formsConstants.page() + (index + 1)); else tabs.getTabBar().selectTab(index); //Load the new questions onto the design surface for the current page. if (newQuestions.size() > 0) { loadQuestions(newQuestions, getLowestWidgetYPos() + 20, selectedPanel.getWidgetCount(), false, true); format(); clearSelection(); } } } /** * Fills bindings for loaded widgets in a given panel. * * @param panel the panel. * @param bindings the map of bindings. Made a map instead of list for only easy of search with key. */ private void fillBindings(AbsolutePanel panel, HashMap<String, String> bindings) { if (panel.getWidgetIndex(rubberBand) > -1) panel.remove(rubberBand); for (int index = 0; index < panel.getWidgetCount(); index++) { DesignWidgetWrapper widget = (DesignWidgetWrapper) panel.getWidget(index); //When a widget is deleted, it is reloaded on refresh even if its label still exists. if (widget.getWrappedWidget() instanceof Label) continue; String binding = widget.getParentBinding(); if (binding == null) binding = widget.getBinding(); bindings.put(binding, binding); //Could possibly put widget as value. if (widget.getWrappedWidget() instanceof DesignGroupWidget) fillBindings(((DesignGroupWidget) widget.getWrappedWidget()).getPanel(), bindings); } } /** * Fills questions, in a page, that are not loaded on the design surface. * * @param pageDef the page. * @param newQuestions a list of the new questions. * @param bindings a map of bindings for questions that are aleady loaded on the design surface. */ private void fillNewQuestions(PageDef pageDef, List<QuestionDef> newQuestions, HashMap<String, String> bindings) { for (int index = 0; index < pageDef.getQuestionCount(); index++) { QuestionDef questionDef = pageDef.getQuestionAt(index); if (!bindings.containsKey(questionDef.getBinding())) newQuestions.add(questionDef); } } /** * Sets the height offset to be used when the form designer is used as widget embedded * in a GWT application. * * @param offset the height offset in pixels. */ public void setEmbeddedHeightOffset(int offset) { } /** * Sets the listener to widget layout change events. * * @param layoutChangeListener the listener. */ public void setLayoutChangeListener(LayoutChangeListener layoutChangeListener) { this.layoutChangeListener = layoutChangeListener; } /** * @see org.openxdata.designer.client.controller.WidgetSelectionListener#onWidgetSelected(Widget, boolean) */ public void onWidgetSelected(DesignWidgetWrapper widget, boolean multipleSel) { boolean ctrlKey = FormDesignerUtil.getCtrlKey(); if (!ctrlKey) stopLabelEdit(false); if (widget == null) { selectedDragController.clearSelection(); return; } if (!(widget.getWrappedWidget() instanceof TabBar)) { if (selectedPanel.getWidgetIndex(widget) > -1) { if (!ctrlKey) { if (!selectedDragController.isWidgetSelected(widget)) selectedDragController.clearSelection(); selectedDragController.selectWidget(widget); } clearGroupBoxSelection(); } else { if (!(widget.getWrappedWidget() instanceof Label && "100%".equals(widget.getWidth()))) selectedDragController.clearSelection(); for (int index = 0; index < selectedPanel.getWidgetCount(); index++) { Widget wid = selectedPanel.getWidget(index); if (!(wid instanceof DesignWidgetWrapper)) continue; if (!(((DesignWidgetWrapper) wid).getWrappedWidget() instanceof DesignGroupWidget)) continue; DesignGroupWidget designGroupWidget = (DesignGroupWidget) ((DesignWidgetWrapper) wid) .getWrappedWidget(); if (!designGroupWidget.containsWidget(widget)) designGroupWidget.clearGroupBoxSelection(); } } } widgetSelectionListener.onWidgetSelected(widget, multipleSel); } @Override protected void selectAll() { if (editWidget != null) { txtEdit.selectAll(); return; //let label editor do select all } List<Widget> widgets = selectedDragController.getSelectedWidgets(); if (widgets != null) { for (int index = 0; index < widgets.size(); index++) { DesignWidgetWrapper widget = (DesignWidgetWrapper) widgets.get(index); if (widget.getWrappedWidget() instanceof DesignGroupWidget) { selectedDragController.clearSelection(); ((DesignGroupWidget) widget.getWrappedWidget()).selectAll(); } } } super.selectAll(); } @Override public void setHeight(String height) { if (height != null && height.trim().length() > 0 && !height.equals("100%")) sHeight = height; super.setHeight(sHeight); } @Override public void setWidth(String width) { if (width != null && width.trim().length() > 0 && !width.equals("100%")) sWidth = width; super.setWidth(sWidth); } /** * Gets the html for the selected page. * * @return the html text. */ public String getSelectedPageHtml() { if (selectedPanel == null) return ""; return selectedPanel.getElement().getInnerHTML(); } }