Paints the given WDataTable.

@param component the WDataTable to paint.
@param renderContext the RenderContext to paint to.
191000
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {
		WDataTable table = (WDataTable) component;
		XmlStringBuilder xml = renderContext.getWriter();

		xml.appendTagOpen("ui:table");
		xml.appendAttribute("id", component.getId());
		xml.appendOptionalAttribute("track", component.isTracking(), "true");
		xml.appendOptionalAttribute("hidden", table.isHidden(), "true");
		xml.appendOptionalAttribute("caption", table.getCaption());

		switch (table.getType()) {
			case TABLE:
				xml.appendAttribute("type", "table");
				break;
			case HIERARCHIC:
				xml.appendAttribute("type", "hierarchic");
				break;
			default:
				throw new SystemException("Unknown table type: " + table.getType());
		}

		switch (table.getStripingType()) {
			case ROWS:
				xml.appendAttribute("striping", "rows");
				break;
			case COLUMNS:
				xml.appendAttribute("striping", "cols");
				break;
			case NONE:
				break;
			default:
				throw new SystemException("Unknown striping type: " + table.getStripingType());
		}

		switch (table.getSeparatorType()) {
			case HORIZONTAL:
				xml.appendAttribute("separators", "horizontal");
				break;
			case VERTICAL:
				xml.appendAttribute("separators", "vertical");
				break;
			case BOTH:
				xml.appendAttribute("separators", "both");
				break;
			case NONE:
				break;
			default:
				throw new SystemException("Unknown separator type: " + table.getSeparatorType());
		}

		xml.appendClose();

		if (table.getPaginationMode() != PaginationMode.NONE) {
			paintPaginationElement(table, xml);
		}

		if (table.getSelectMode() != SelectMode.NONE) {
			paintRowSelectionElement(table, xml);
		}

		if (table.getExpandMode() != ExpandMode.NONE) {
			paintRowExpansionElement(table, xml);
		}

		if (table.isSortable()) {
			paintSortElement(table, xml);
		}

		paintColumnHeadings(table, renderContext);
		paintRows(table, renderContext);
		paintTableActions(table, renderContext);

		xml.appendEndTag("ui:table");
	}
977725
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {
		WMessageBox messageBox = (WMessageBox) component;
		XmlStringBuilder xml = renderContext.getWriter();

		if (messageBox.hasMessages()) {
			xml.appendTagOpen("ui:messagebox");
			xml.appendAttribute("id", component.getId());
			xml.appendOptionalAttribute("class", component.getHtmlClass());
			xml.appendOptionalAttribute("track", component.isTracking(), "true");

			switch (messageBox.getType()) {
				case SUCCESS:
					xml.appendOptionalAttribute("type", "success");
					break;

				case INFO:
					xml.appendOptionalAttribute("type", "info");
					break;

				case WARN:
					xml.appendOptionalAttribute("type", "warn");
					break;

				case ERROR:
				default:
					xml.appendOptionalAttribute("type", "error");
					break;
			}

			xml.appendOptionalAttribute("title", messageBox.getTitleText());

			xml.appendClose();

			for (String message : messageBox.getMessages()) {
				xml.appendTag("ui:message");
				xml.print(message);
				xml.appendEndTag("ui:message");
			}

			xml.appendEndTag("ui:messagebox");
		}
	}
358594
public static void renderDiagnostics(final Diagnosable component, final WebXmlRenderContext renderContext) {
		List<Diagnostic> diags = component.getDiagnostics(Diagnostic.ERROR);
		if (diags != null) {
			renderHelper(renderContext, component, diags, Diagnostic.ERROR);
		}
		diags = component.getDiagnostics(Diagnostic.WARNING);
		if (diags != null) {
			renderHelper(renderContext, component, diags, Diagnostic.WARNING);
		}
		diags = component.getDiagnostics(Diagnostic.INFO);
		if (diags != null) {
			renderHelper(renderContext, component, diags, Diagnostic.INFO);
		}
		diags = component.getDiagnostics(Diagnostic.SUCCESS);
		if (diags != null) {
			renderHelper(renderContext, component, diags, Diagnostic.SUCCESS);
		}
	}
350048
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {
		WImageEditor editorComponent = (WImageEditor) component;
		XmlStringBuilder xml = renderContext.getWriter();

		xml.appendTagOpen("wc-imageedit");
		xml.appendAttribute("id", editorComponent.getId());
		xml.appendOptionalAttribute("class", editorComponent.getHtmlClass());
		xml.appendOptionalUrlAttribute("overlay", editorComponent.getOverlayUrl());
		xml.appendOptionalAttribute("camera", editorComponent.getUseCamera());
		xml.appendOptionalAttribute("face", editorComponent.getIsFace());
		xml.appendOptionalAttribute("inline", editorComponent.getRenderInline());

		// Check for size information on the image
		Dimension size = editorComponent.getSize();
		if (size != null) {
			if (size.getHeight() >= 0) {
				xml.appendAttribute("height", size.height);
			}

			if (size.getWidth() >= 0) {
				xml.appendAttribute("width", size.width);
			}
		}

		xml.appendEnd();
	}
780038
@Override
	protected void afterPaint(final RenderContext renderContext) {
		super.afterPaint(renderContext);

		final int size = getChildCount();

		for (int i = 0; i < size; i++) {
			WComponent child = getChildAt(i);
			child.reset();
		}
	}
116133
private void paintRows(final WDataTable table, final WebXmlRenderContext renderContext) {
		XmlStringBuilder xml = renderContext.getWriter();
		TableDataModel model = table.getDataModel();

		xml.appendTagOpen("ui:tbody");
		xml.appendAttribute("id", table.getRepeater().getId());
		xml.appendClose();

		if (model.getRowCount() == 0) {
			xml.appendTag("ui:nodata");
			xml.appendEscaped(table.getNoDataMessage());
			xml.appendEndTag("ui:nodata");
		} else {
			// If has at least one visible col, paint the rows.
			final int columnCount = table.getColumnCount();

			for (int i = 0; i < columnCount; i++) {
				if (table.getColumn(i).isVisible()) {
					doPaintRows(table, renderContext);
					break;
				}
			}
		}

		xml.appendEndTag("ui:tbody");
	}
921788
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {
		WDataTableRowRenderer renderer = (WDataTableRowRenderer) component;
		XmlStringBuilder xml = renderContext.getWriter();
		WDataTable table = renderer.getTable();
		TableDataModel dataModel = table.getDataModel();
		UIContext uic = UIContextHolder.getCurrent();

		final int numCols = table.getColumnCount();
		int[] columnOrder = table.getColumnOrder();
		int rowIndex = getRowIndex(table, (SubUIContext) uic);
		boolean unselectable = table.getSelectMode() != SelectMode.NONE
				&& !dataModel.isSelectable(rowIndex);

		xml.appendTagOpen("ui:tr");
		xml.appendAttribute("rowIndex", rowIndex);
		xml.appendOptionalAttribute("unselectable", unselectable, "true");
		xml.appendOptionalAttribute("selected", table.getSelectedRows().contains(rowIndex), "true");
		xml.appendOptionalAttribute("filterValues", getFilterValues(dataModel, rowIndex));

		if (table.getExpandMode() != WDataTable.ExpandMode.NONE && dataModel instanceof TreeTableDataModel) {
			TableTreeNode node = ((TreeTableDataModel) dataModel).getNodeAtLine(rowIndex);
			boolean expandable = !node.isLeaf() && !node.isExpanded();
			xml.appendOptionalAttribute("expandable", expandable, "true");
		}

		xml.appendClose();

		if (table.isShowRowHeaders()) {
			xml.appendTag("ui:th");
			renderer.getRowHeader().paint(renderContext);
			xml.appendEndTag("ui:th");
		}

		for (int i = 0; i < numCols; i++) {
			int colIndex = columnOrder == null ? i : columnOrder[i];
			WTableColumn col = table.getColumn(colIndex);

			if (col.isVisible()) {
				xml.appendTag("ui:td");
				renderer.getRenderer(colIndex).paint(renderContext);
				xml.appendEndTag("ui:td");
			}
		}

		if (table.getExpandMode() != WDataTable.ExpandMode.NONE && dataModel instanceof TreeTableDataModel) {
			TreeTableDataModel treeModel = (TreeTableDataModel) dataModel;
			TableTreeNode node = treeModel.getNodeAtLine(rowIndex);

			if (!node.isLeaf()) {
				xml.appendTagOpen("ui:subtr");
				xml.appendOptionalAttribute("open", node.isExpanded(), "true");
				xml.appendClose();

				if (node.isExpanded() || table.getExpandMode() == ExpandMode.CLIENT) {
					WRepeater repeater = table.getRepeater();

					// If there a renderer specified by any child, we only paint content that has a specified renderer
					boolean rendererPresent = false;

					for (Iterator<TreeNode> i = node.children(); !rendererPresent && i.hasNext();) {
						TableTreeNode child = (TableTreeNode) i.next();

						if (child.getRendererClass() != null) {
							rendererPresent = true;
						}
					}

					// Paint immediate children only.
					if (rendererPresent) {
						xml.appendTagOpen("ui:content");
						xml.appendOptionalAttribute("spanAllCols", node.isRendererSpansAllCols(),
								"true");
						xml.appendClose();

						for (Iterator<TreeNode> i = node.children(); i.hasNext();) {
							TableTreeNode child = (TableTreeNode) i.next();
							Integer rowId = child.getRowIndex() - 1;
							UIContext nodeContext = repeater.getRowContext(rowId);

							WComponent expandedRenderer = renderer.getExpandedTreeNodeRenderer(
									child.getRendererClass());

							if (expandedRenderer != null) {
								UIContextHolder.pushContext(nodeContext);

								try {
									expandedRenderer.paint(renderContext);
								} finally {
									UIContextHolder.popContext();
								}
							}
						}

						xml.appendEndTag("ui:content");
					} else {
						for (Iterator<TreeNode> i = node.children(); i.hasNext();) {
							TableTreeNode child = (TableTreeNode) i.next();
							Integer rowId = child.getRowIndex() - 1;
							UIContext nodeContext = repeater.getRowContext(rowId);

							UIContextHolder.pushContext(nodeContext);

							try {
								render(component, renderContext);
							} finally {
								UIContextHolder.popContext();
							}
						}
					}
				}

				xml.appendEndTag("ui:subtr");
			}
		}

		xml.appendEndTag("ui:tr");
	}
1001255
@Override
	public void paint(final RenderContext renderContext) {
		if (windowId == null) {
			super.paint(renderContext);
		} else {
			// Get the window component
			ComponentWithContext target = WebUtilities.getComponentById(windowId, true);
			if (target == null) {
				throw new SystemException("No window component for id " + windowId);
			}

			UIContext uic = UIContextHolder.getCurrentPrimaryUIContext();
			Environment originalEnvironment = uic.getEnvironment();
			uic.setEnvironment(new EnvironmentDelegate(originalEnvironment, windowId, target));

			UIContextHolder.pushContext(target.getContext());
			try {
				super.paint(renderContext);
			} finally {
				uic.setEnvironment(originalEnvironment);
				UIContextHolder.popContext();
			}
		}
	}
346604
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {
		WMultiTextField textField = (WMultiTextField) component;
		XmlStringBuilder xml = renderContext.getWriter();

		boolean readOnly = textField.isReadOnly();

		String[] values = textField.getTextInputs();

		xml.appendTagOpen("ui:multitextfield");
		xml.appendAttribute("id", component.getId());
		xml.appendOptionalAttribute("class", component.getHtmlClass());
		xml.appendOptionalAttribute("track", component.isTracking(), "true");
		xml.appendOptionalAttribute("hidden", textField.isHidden(), "true");

		if (readOnly) {
			xml.appendAttribute("readOnly", "true");
		} else {
			int cols = textField.getColumns();
			int minLength = textField.getMinLength();
			int maxLength = textField.getMaxLength();
			int maxInputs = textField.getMaxInputs();
			String pattern = textField.getPattern();
			xml.appendOptionalAttribute("disabled", textField.isDisabled(), "true");
			xml.appendOptionalAttribute("required", textField.isMandatory(), "true");
			xml.appendOptionalAttribute("toolTip", textField.getToolTip());
			xml.appendOptionalAttribute("accessibleText", textField.getAccessibleText());
			xml.appendOptionalAttribute("size", cols > 0, cols);
			xml.appendOptionalAttribute("minLength", minLength > 0, minLength);
			xml.appendOptionalAttribute("maxLength", maxLength > 0, maxLength);
			xml.appendOptionalAttribute("max", maxInputs > 0, maxInputs);
			xml.appendOptionalAttribute("pattern", !Util.empty(pattern), pattern);
			// NOTE: do not use HtmlRenderUtil.getEffectivePlaceholder for placeholder - we do not want to echo "required" in every field.
			String placeholder = textField.getPlaceholder();
			xml.appendOptionalAttribute("placeholder", !Util.empty(placeholder), placeholder);
			xml.appendOptionalAttribute("title", I18nUtilities.format(null, InternalMessages.DEFAULT_MULTITEXTFIELD_TIP));
		}
		xml.appendClose();

		if (values != null) {
			for (String value : values) {
				xml.appendTag("ui:value");
				xml.appendEscaped(value);
				xml.appendEndTag("ui:value");
			}
		}

		if (!readOnly) {
			DiagnosticRenderUtil.renderDiagnostics(textField, renderContext);
		}
		xml.appendEndTag("ui:multitextfield");
	}
738963
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {
		WMultiDropdown dropdown = (WMultiDropdown) component;
		XmlStringBuilder xml = renderContext.getWriter();
		String dataKey = dropdown.getListCacheKey();
		boolean readOnly = dropdown.isReadOnly();

		xml.appendTagOpen("ui:multidropdown");
		xml.appendAttribute("id", component.getId());
		xml.appendOptionalAttribute("class", component.getHtmlClass());
		xml.appendOptionalAttribute("track", component.isTracking(), "true");
		xml.appendOptionalAttribute("hidden", dropdown.isHidden(), "true");
		if (readOnly) {
			xml.appendAttribute("readOnly", "true");
		} else {
			xml.appendOptionalAttribute("data", dataKey != null && !readOnly, dataKey);
			xml.appendOptionalAttribute("disabled", dropdown.isDisabled(), "true");
			xml.appendOptionalAttribute("required", dropdown.isMandatory(), "true");
			xml.appendOptionalAttribute("submitOnChange", dropdown.isSubmitOnChange(), "true");
			xml.appendOptionalAttribute("toolTip", component.getToolTip());
			xml.appendOptionalAttribute("accessibleText", component.getAccessibleText());
			int min = dropdown.getMinSelect();
			int max = dropdown.getMaxSelect();
			xml.appendOptionalAttribute("min", min > 0, min);
			xml.appendOptionalAttribute("max", max > 0, max);
			xml.appendOptionalAttribute("title", I18nUtilities.format(null, InternalMessages.DEFAULT_MULTIDROPDOWN_TIP));
		}

		xml.appendClose();

		// Options
		List<?> options = dropdown.getOptions();
		boolean renderSelectionsOnly = dropdown.isReadOnly() || dataKey != null;

		if (options != null) {
			int optionIndex = 0;
			List<?> selections = dropdown.getSelected();

			for (Object option : options) {
				if (option instanceof OptionGroup) {
					xml.appendTagOpen("ui:optgroup");
					xml.appendAttribute("label", ((OptionGroup) option).getDesc());
					xml.appendClose();

					for (Object nestedOption : ((OptionGroup) option).getOptions()) {
						renderOption(dropdown, nestedOption, optionIndex++, xml, selections,
								renderSelectionsOnly);
					}

					xml.appendEndTag("ui:optgroup");
				} else {
					renderOption(dropdown, option, optionIndex++, xml, selections,
							renderSelectionsOnly);
				}
			}
		}

		if (!readOnly) {
			DiagnosticRenderUtil.renderDiagnostics(dropdown, renderContext);
		}
		// End tag
		xml.appendEndTag("ui:multidropdown");
	}
316654
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {
		WEditableImage editableImage = (WEditableImage) component;
		XmlStringBuilder xml = renderContext.getWriter();

		// No image set
		if (editableImage.getImage() == null && editableImage.getImageUrl() == null) {
			return;
		}

		WImageRenderer.renderTagOpen(editableImage, xml);
		WComponent uploader = editableImage.getEditUploader();
		if (uploader != null) {
			xml.appendAttribute("data-wc-editor", uploader.getId());
		}
		xml.appendEnd();
	}
80989
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {
		WTabGroup group = (WTabGroup) component;
		paintChildren(group, renderContext);
	}
624540
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {
		WNumberField field = (WNumberField) component;
		XmlStringBuilder xml = renderContext.getWriter();
		boolean readOnly = field.isReadOnly();

		BigDecimal value = field.getValue();
		String userText = field.getText();

		xml.appendTagOpen("ui:numberfield");
		xml.appendAttribute("id", component.getId());
		xml.appendOptionalAttribute("class", component.getHtmlClass());
		xml.appendOptionalAttribute("track", component.isTracking(), "true");
		xml.appendOptionalAttribute("hidden", component.isHidden(), "true");
		if (readOnly) {
			xml.appendAttribute("readOnly", "true");
		} else {
			WComponent submitControl = field.getDefaultSubmitButton();
			String submitControlId = submitControl == null ? null : submitControl.getId();
			BigDecimal min = field.getMinValue();
			BigDecimal max = field.getMaxValue();
			BigDecimal step = field.getStep();
			int decimals = field.getDecimalPlaces();
			xml.appendOptionalAttribute("disabled", field.isDisabled(), "true");
			xml.appendOptionalAttribute("required", field.isMandatory(), "true");
			xml.appendOptionalAttribute("toolTip", field.getToolTip());
			xml.appendOptionalAttribute("accessibleText", field.getAccessibleText());
			xml.appendOptionalAttribute("min", min != null, String.valueOf(min));
			xml.appendOptionalAttribute("max", max != null, String.valueOf(max));
			xml.appendOptionalAttribute("step", step != null, String.valueOf(step));
			xml.appendOptionalAttribute("decimals", decimals > 0, decimals);
			xml.appendOptionalAttribute("buttonId", submitControlId);

			String autocomplete = field.getAutocomplete();
			xml.appendOptionalAttribute("autocomplete", !Util.empty(autocomplete), autocomplete);
		}

		xml.appendClose();

		xml.appendEscaped(value == null ? userText : value.toString());
		if (!readOnly) {
			DiagnosticRenderUtil.renderDiagnostics(field, renderContext);
		}
		xml.appendEndTag("ui:numberfield");
	}
754334
private void paintColumnHeadings(final WDataTable table, final WebXmlRenderContext renderContext) {
		XmlStringBuilder xml = renderContext.getWriter();
		int[] columnOrder = table.getColumnOrder();
		TableDataModel model = table.getDataModel();
		final int columnCount = table.getColumnCount();

		xml.appendTagOpen("ui:thead");
		xml.appendOptionalAttribute("hidden", !table.isShowColumnHeaders(), "true");
		xml.appendClose();

		if (table.isShowRowHeaders()) {
			paintColumnHeading(table.getRowHeaderColumn(), false, renderContext);
		}

		for (int i = 0; i < columnCount; i++) {
			int colIndex = columnOrder == null ? i : columnOrder[i];
			WTableColumn col = table.getColumn(colIndex);

			if (col.isVisible()) {
				boolean sortable = model.isSortable(colIndex);
				paintColumnHeading(col, sortable, renderContext);
			}
		}

		xml.appendEndTag("ui:thead");
	}
870125
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {

		WTree tree = (WTree) component;
		XmlStringBuilder xml = renderContext.getWriter();

		// Check if rendering an open item request
		String openId = tree.getOpenRequestItemId();
		if (openId != null) {
			handleOpenItemRequest(tree, xml, openId);
			return;
		}

		// Check the tree has tree items (WCAG requirement)
		TreeItemModel model = tree.getTreeModel();
		if (model == null || model.getRowCount() <= 0) {
			LOG.warn("Tree not rendered as it has no items.");
			return;
		}

		xml.appendTagOpen("ui:tree");
		xml.appendAttribute("id", component.getId());
		xml.appendOptionalAttribute("class", component.getHtmlClass());
		xml.appendOptionalAttribute("track", component.isTracking(), "true");
		xml.appendOptionalAttribute("htree", WTree.Type.HORIZONTAL == tree.getType(), "true");
		xml.appendOptionalAttribute("multiple", WTree.SelectMode.MULTIPLE == tree.getSelectMode(), "true");
		xml.appendOptionalAttribute("disabled", tree.isDisabled(), "true");
		xml.appendOptionalAttribute("hidden", tree.isHidden(), "true");
		xml.appendOptionalAttribute("required", tree.isMandatory(), "true");

		switch (tree.getExpandMode()) {
			case CLIENT:
				xml.appendAttribute("mode", "client");
				break;

			case DYNAMIC:
				xml.appendAttribute("mode", "dynamic");
				break;

			case LAZY:
				xml.appendAttribute("mode", "lazy");
				break;

			default:
				throw new IllegalStateException("Invalid expand mode: " + tree.getType());
		}
		xml.appendClose();

		// Render margin
		MarginRendererUtil.renderMargin(tree, renderContext);

		if (tree.getCustomTree() == null) {
			handlePaintItems(tree, xml);
		} else {
			handlePaintCustom(tree, xml);
		}

		DiagnosticRenderUtil.renderDiagnostics(tree, renderContext);
		xml.appendEndTag("ui:tree");
	}
644282
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {
		WTimeoutWarning warning = (WTimeoutWarning) component;

		XmlStringBuilder xml = renderContext.getWriter();
		final int timoutPeriod = warning.getTimeoutPeriod();
		if (timoutPeriod > 0) {
			xml.appendTagOpen("ui:session");
			xml.appendAttribute("timeout", String.valueOf(timoutPeriod));
			int warningPeriod = warning.getWarningPeriod();
			xml.appendOptionalAttribute("warn", warningPeriod > 0, warningPeriod);
			xml.appendEnd();
		}

	}
700989
@Override
	public void doRender(final WComponent component, final WebXmlRenderContext renderContext) {
		WFileWidget fileWidget = (WFileWidget) component;
		XmlStringBuilder xml = renderContext.getWriter();
		boolean readOnly = fileWidget.isReadOnly();

		xml.appendTagOpen(TAG_NAME);
		xml.appendAttribute("id", component.getId());
		xml.appendOptionalAttribute("class", component.getHtmlClass());
		xml.appendOptionalAttribute("track", component.isTracking(), "true");
		xml.appendOptionalAttribute("hidden", component.isHidden(), "true");
		if (readOnly) {
			xml.appendAttribute("readOnly", "true");
			xml.appendEnd();
			return;
		}
		xml.appendOptionalAttribute("disabled", fileWidget.isDisabled(), "true");
		xml.appendOptionalAttribute("required", fileWidget.isMandatory(), "true");
		xml.appendOptionalAttribute("toolTip", fileWidget.getToolTip());
		xml.appendOptionalAttribute("accessibleText", fileWidget.getAccessibleText());
		xml.appendOptionalAttribute("acceptedMimeTypes", typesToString(fileWidget.getFileTypes()));
		long maxFileSize = fileWidget.getMaxFileSize();
		xml.appendOptionalAttribute("maxFileSize", maxFileSize > 0, maxFileSize);

		List<Diagnostic> diags = fileWidget.getDiagnostics(Diagnostic.ERROR);
		if (diags == null || diags.isEmpty()) {
			xml.appendEnd();
			return;
		}
		xml.appendClose();
		DiagnosticRenderUtil.renderDiagnostics(fileWidget, renderContext);
		xml.appendEndTag(TAG_NAME);
	}