Java tutorial
/* * Copyright 2016 Crown Copyright * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package stroom.widget.xsdbrowser.client.view; import java.util.HashMap; import java.util.List; import java.util.Map; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.user.client.ui.AbstractImagePrototype; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.MaxScrollPanel; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import stroom.widget.xsdbrowser.client.view.XSDNode.XSDAttribute; import stroom.widget.xsdbrowser.client.view.XSDNode.XSDType; public class XSDDisplay extends Composite { private final FlowPanel contentPanel = new FlowPanel(); XSDModel model; private final Map<XSDNode, Integer> rowMap = new HashMap<>(); SelectionMap selectionMap; private static final Resources resources = GWT.create(Resources.class); public XSDDisplay() { contentPanel.setStyleName("content"); final ScrollPanel scrollPanel = new MaxScrollPanel(contentPanel); scrollPanel.setStyleName("container"); initWidget(scrollPanel); } public void setModel(final XSDModel model) { this.model = model; setSelectedNode(model.getSelectedItem(), true); } public void setSelectedNode(final XSDNode node, final boolean change) { if (change) { showNode(node); } if (selectionMap != null) { selectionMap.setSelectedItem(node); } } void showNode(final XSDNode node) { if (node != null) { Widget display = null; final SelectionMap map = new SelectionMap(); final XSDType type = node.getType(); if (type == XSDType.SCHEMA) { display = getRootDisplay(map, node); } else if (type == XSDType.ELEMENT) { display = getElementDisplay(map, node); } else if (type == XSDType.COMPLEX_TYPE) { display = getTypeDisplay(map, node); } if (display != null) { contentPanel.clear(); contentPanel.add(display); selectionMap = map; } } else { contentPanel.clear(); if (model.getParseException() != null) { contentPanel.add(new Label(model.getParseException().getMessage())); } } } private XSDDisplayBox getRootDisplay(final SelectionMap map, final XSDNode node) { final HorizontalPanel midPanel = new HorizontalPanel(); midPanel.addStyleName("midPanel"); midPanel.setSpacing(5); midPanel.add(new XSDDisplayBox(resources.xsdTitleElements(), "Elements", getNodeListDisplay(null, map, node, false, true, false, false, false), map, model, null, "100%", "100%")); midPanel.add(new XSDDisplayBox(resources.xsdTitleTypes(), "Types", getNodeListDisplay(null, map, node, false, false, true, true, false), map, model, null, "100%", "100%")); final String targetNamespace = XMLUtil.getAttributeValue(node.getNode(), XSDAttribute.TARGET_NAMESPACE, false); String title = "Schema: "; if (targetNamespace != null) { title = title + targetNamespace; } final XSDDisplayBox box = new XSDDisplayBox(resources.xsdTitleSchema(), title, midPanel, map, model, node, null, null); return box; } private HorizontalPanel getElementDisplay(final SelectionMap map, final XSDNode node) { final XSDNode typeNode = node.getTypeNode(); if (typeNode == null) { return null; } final VerticalPanel left = new VerticalPanel(); final VerticalPanel right = new VerticalPanel(); left.add( new XSDDisplayBox(resources.xsdTitleElement(), node.getName(), null, map, model, node, null, null)); right.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); right.add(getTypeBox(right, map, typeNode)); final Label padding = new Label(); padding.setSize("40px", "1px"); final HorizontalPanel layout = new HorizontalPanel(); layout.add(left); layout.add(padding); layout.add(right); return layout; } private HorizontalPanel getTypeDisplay(final SelectionMap map, final XSDNode node) { final VerticalPanel left = new VerticalPanel(); final VerticalPanel right = new VerticalPanel(); left.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER); left.add(getTypeBox(left, map, node)); for (final XSDNode child : node.getChildTypes()) { final XSDDisplayBox typeBox = getTypeBox(null, map, child); typeBox.addStyleName("displayTypeBox"); right.add(typeBox); } final Label padding = new Label(); padding.setSize("40px", "1px"); final HorizontalPanel layout = new HorizontalPanel(); layout.add(left); layout.add(padding); layout.add(right); return layout; } private XSDDisplayBox getTypeBox(final VerticalPanel layoutColumn, final SelectionMap map, final XSDNode node) { if (node != null) { String title = node.getName(); if (title == null) { final XSDNode parent = node.getParent(); if (parent != null) { title = parent.getName(); title = "(" + title + "Type)"; } } if (title != null) { if (node.getType() == XSDType.SIMPLE_TYPE) { return new XSDDisplayBox(resources.xsdTitleSimpleType(), title, null, map, model, node, null, null); } return new XSDDisplayBox(resources.xsdTitleComplexType(), title, getNodeListDisplay(layoutColumn, map, node, true, true, false, false, true), map, model, node, null, null); } } return null; } private Grid getNodeListDisplay(final VerticalPanel layoutColumn, final SelectionMap map, final XSDNode node, final boolean showAttributes, final boolean showElements, final boolean showComplexTypes, final boolean showSimpleTypes, final boolean showOccurance) { Grid layout = null; if (node != null) { // Clear the row map. rowMap.clear(); // First find out what the maximum depth of nesting constructs is. int maxConstructDepth = getMaxConstructDepth(node); if (maxConstructDepth > 0) { // Each level has 2 images so double the construct depth. maxConstructDepth = maxConstructDepth * 2; } layout = new Grid(0, 6 + maxConstructDepth); layout.setCellPadding(0); layout.setCellSpacing(0); int row = 0; int col = 0; if (showAttributes) { row = addNode(layoutColumn, layout, map, node, showOccurance, true, row, col, XSDTypeFilter.ATTRIBUTE_FILTER); } if (showElements) { row = addNode(layoutColumn, layout, map, node, showOccurance, false, row, col, XSDTypeFilter.COMPLEX_CONTENT_FILTER); row = addNode(layoutColumn, layout, map, node, showOccurance, false, row, col, XSDTypeFilter.STRUCTURE_FILTER); } if (showComplexTypes) { row = addNode(layoutColumn, layout, map, node, showOccurance, false, row, col, XSDTypeFilter.COMPLEX_TYPE_FILTER); } if (showSimpleTypes) { row = addNode(layoutColumn, layout, map, node, showOccurance, false, row, col, XSDTypeFilter.SIMPLE_TYPE_FILTER); } // Apply some overall styles to surround the content. for (row = 0; row < layout.getRowCount(); row++) { layout.getCellFormatter().getElement(row, 0).getStyle().setProperty("paddingLeft", "5px"); layout.getCellFormatter().getElement(row, layout.getColumnCount() - 1).getStyle() .setProperty("paddingRight", "5px"); } // Align all cells to the middle. for (row = 0; row < layout.getRowCount(); row++) { for (col = 0; col < layout.getColumnCount(); col++) { layout.getCellFormatter().setVerticalAlignment(row, col, HasVerticalAlignment.ALIGN_MIDDLE); } } if (layout.getRowCount() > 0) { setRowStyle(layout, 0, "paddingTop", "3px"); setRowStyle(layout, layout.getRowCount() - 1, "paddingBottom", "3px"); } // If we didn't add any rows then set the layout to null. if (row == 0) { layout = null; } } return layout; } private int getMaxConstructDepth(final XSDNode node) { boolean hasConstruct = false; int maxDepth = 0; // Add complex content structures. final List<XSDNode> complexContentNodes = node.getChildNodes(XSDTypeFilter.COMPLEX_CONTENT_FILTER, true); for (final XSDNode complexContentNode : complexContentNodes) { maxDepth += getMaxConstructDepth(complexContentNode); } // Add extension node structures. final List<XSDNode> extensionNodes = node.getChildNodes(XSDTypeFilter.EXTENSION_FILTER, true); for (final XSDNode extensionNode : extensionNodes) { maxDepth += getMaxConstructDepth(extensionNode); } // Add structure nodes. final List<XSDNode> structureNodes = node.getChildNodes(XSDTypeFilter.STRUCTURE_FILTER, true); for (final XSDNode child : structureNodes) { final XSDType type = child.getType(); if (type.isStructural()) { hasConstruct = true; maxDepth += getMaxConstructDepth(child); } } if (hasConstruct) { maxDepth++; } return maxDepth; } private int addNode(final VerticalPanel layoutColumn, final Grid layout, final SelectionMap map, final XSDNode node, final boolean showOccurrence, final boolean addSeparator, final int initialRow, final int initialCol, final XSDTypeFilter typeFilter) { int row = initialRow; final int col = initialCol; final List<XSDNode> childNodes = node.getChildNodes(typeFilter, true); if (childNodes.size() == 0 && node.getType().isStructural()) { row++; } else { if (typeFilter == XSDTypeFilter.COMPLEX_CONTENT_FILTER) { // See if we have complex content. for (final XSDNode child : childNodes) { final List<XSDNode> extensionNodes = child.getChildNodes(XSDTypeFilter.EXTENSION_FILTER, true); for (final XSDNode extensionNode : extensionNodes) { // Add a type box for the super type above the extension // type. if (layoutColumn != null) { final XSDNode baseNode = extensionNode.getBaseNode(); final XSDDisplayBox typeBox = getTypeBox(layoutColumn, map, baseNode); layoutColumn.add(typeBox); final Image superArrow = AbstractImagePrototype.create(resources.superArrowSelect()) .createImage(); layoutColumn.add(superArrow); superArrow.getElement().getParentElement().setAttribute("textAlign", "center"); } row = addNode(layoutColumn, layout, map, extensionNode, showOccurrence, true, row, col, XSDTypeFilter.ATTRIBUTE_FILTER); row = addNode(layoutColumn, layout, map, extensionNode, showOccurrence, addSeparator, row, col, XSDTypeFilter.STRUCTURE_FILTER); } } } else { // Add child element nodes as normal. for (final XSDNode child : childNodes) { final XSDType type = child.getType(); if (type == XSDType.SEQUENCE || type == XSDType.CHOICE || type == XSDType.ALL) { addChild(layout, map, child, showOccurrence, row, col); row = addNode(layoutColumn, layout, map, child, true, false, row, col + 2, typeFilter); } else { addChild(layout, map, child, showOccurrence, row, col); row++; } } } } if (addSeparator) { addSeparator(layout); } return row; } private void addChild(final Grid layout, final SelectionMap map, final XSDNode node, final boolean showOccurance, final int row, final int col) { // Ensure layout size. if (layout.getRowCount() < row + 1) { layout.resizeRows(row + 1); } final XSDType type = node.getType(); rowMap.put(node, row); // Add the image for the structure element if this is one. if (type.isStructural()) { final String occurrence = node.getOccurance(); if (occurrence != null) { final SafeHtmlBuilder builder = new SafeHtmlBuilder(); builder.appendHtmlConstant("<div class=\"occuranceLabel\">"); builder.appendEscaped(occurrence); builder.appendHtmlConstant("</div>"); final HTML html = new HTML(builder.toSafeHtml()); final FlowPanel fp = new FlowPanel(); fp.add(getImage(type)); fp.add(html); fp.getElement().getStyle().setPosition(Position.RELATIVE); layout.setWidget(row, col, fp); } else { layout.setWidget(row, col, getImage(type)); } layout.setWidget(row, col + 1, AbstractImagePrototype.create(resources.xsdTree03()).createImage()); } else { // Otherwise add the element. XSDNode refNode = null; Image image = null; XSDNodeLabel lblName = null; Label lblOccurrence = null; Label lblType = null; String name = node.getName(); String valueType = null; if (type == XSDType.ELEMENT || type == XSDType.ATTRIBUTE) { if (name == null) { refNode = node.getRefNode(); if (refNode != null) { name = refNode.getName(); } } if (refNode != null) { valueType = refNode.getValueType(); if (valueType == null) { valueType = "(" + name + "Type)"; } } else { valueType = node.getValueType(); if (valueType == null) { valueType = "(" + name + "Type)"; } } if (showOccurance) { final String occurance = node.getOccurance(); if (occurance != null) { lblOccurrence = new Label(node.getOccurance(), false); } } } // Get the image to use. if (refNode != null) { image = getImage(XSDType.ELEMENT_REF); } else { image = getImage(type); } if (name != null) { lblName = new XSDNodeLabel(name, map, model, node, refNode); } if (valueType != null) { lblType = new Label(valueType, false); } final int colCount = layout.getColumnCount(); // Add line images to get back to the structure level. if (node.getParent() != null && node.getParent().getType().isStructural()) { for (int i = col; i < colCount - 6; i++) { layout.setWidget(row, i, AbstractImagePrototype.create(resources.xsdTree03()).createImage()); } } // Add other images to create the tree lines. int pos = col - 1; XSDNode parent = node; while (pos >= 0 && parent != null && parent.getType().isStructuralOrElement()) { if (node == parent || rowMap.get(parent) == row) { if (parent.isFirstChild() && parent.isLastChild()) { layout.setWidget(row, pos, AbstractImagePrototype.create(resources.xsdTree03()).createImage()); } else if (parent.isFirstChild()) { layout.setWidget(row, pos, AbstractImagePrototype.create(resources.xsdTree06()).createImage()); } else if (parent.isLastChild()) { layout.setWidget(row, pos, AbstractImagePrototype.create(resources.xsdTree09()).createImage()); } else { layout.setWidget(row, pos, AbstractImagePrototype.create(resources.xsdTree05()).createImage()); } } else if (!parent.isLastChild()) { layout.setWidget(row, pos, AbstractImagePrototype.create(resources.xsdTree02()).createImage()); } parent = parent.getParent(); pos -= 2; } if (image != null) { layout.setWidget(row, colCount - 6, image); image.addStyleName("marginRight"); } if (lblName != null) { layout.setWidget(row, colCount - 5, lblName); } if (lblOccurrence != null) { layout.setWidget(row, colCount - 4, new Label("[", false)); layout.setWidget(row, colCount - 3, lblOccurrence); layout.setWidget(row, colCount - 2, new Label("]", false)); } if (lblType != null) { layout.setWidget(row, colCount - 1, lblType); lblType.addStyleName("marginLeft"); } } } private void addSeparator(final Grid layout) { // Add a row with a black border at the bottom. setRowStyle(layout, layout.getRowCount() - 1, "borderBottom", "1px solid black"); } private void setRowStyle(final Grid layout, final int row, final String name, final String value) { if (row >= 0) { for (int col = 0; col < layout.getColumnCount(); col++) { layout.getCellFormatter().getElement(row, col).getStyle().setProperty(name, value); } } } private Image getImage(final XSDType type) { ImageResource resource = null; String title = null; switch (type) { case ALL: resource = resources.xsdAll(); title = "All"; break; case ANY: resource = resources.xsdAny(); break; case ATTRIBUTE: resource = resources.xsdAttribute(); break; case CHOICE: resource = resources.xsdChoice(); title = "Choice"; break; case COMPLEX_TYPE: resource = resources.xsdComplexType(); break; case ELEMENT: resource = resources.xsdElement(); break; case ELEMENT_REF: resource = resources.xsdElementRef(); break; case SCHEMA: resource = resources.xsdTitleSchema(); break; case SEQUENCE: resource = resources.xsdSequence(); title = "Sequence"; break; case SIMPLE_TYPE: resource = resources.xsdSimpleType(); break; default: break; } if (resource != null) { final Image img = new Image(resource); if (title != null) { img.setTitle(title); } return img; } return null; } public interface Resources extends ClientBundle { ImageResource superArrow(); ImageResource superArrowSelect(); ImageResource xsdAll(); ImageResource xsdAny(); ImageResource xsdAttribute(); ImageResource xsdChoice(); ImageResource xsdComplexType(); ImageResource xsdElement(); ImageResource xsdElementRef(); ImageResource xsdSequence(); ImageResource xsdSimpleType(); ImageResource xsdTitleAttributes(); ImageResource xsdTitleComplexType(); ImageResource xsdTitleDirectives(); ImageResource xsdTitleElement(); ImageResource xsdTitleElements(); ImageResource xsdTitleGroups(); ImageResource xsdTitleSchema(); ImageResource xsdTitleSimpleType(); ImageResource xsdTitleTypes(); ImageResource xsdTree01(); ImageResource xsdTree02(); ImageResource xsdTree03(); ImageResource xsdTree04(); ImageResource xsdTree05(); ImageResource xsdTree06(); ImageResource xsdTree07(); ImageResource xsdTree08(); ImageResource xsdTree09(); ImageResource xsdTree10(); ImageResource xsdTree11(); } }