diff options
author | Henri Sara <hesara@vaadin.com> | 2013-08-30 08:37:27 +0300 |
---|---|---|
committer | Henri Sara <hesara@vaadin.com> | 2013-08-30 08:37:27 +0300 |
commit | 277e697f7d9258983e52042757baac09b4fe1908 (patch) | |
tree | 8ec57e33a8b9505932a6279123924e3b53fcb759 | |
parent | 6dc46c5cfc66defaa7ed2350f20bf2224b419d82 (diff) | |
download | vaadin-framework-277e697f7d9258983e52042757baac09b4fe1908.tar.gz vaadin-framework-277e697f7d9258983e52042757baac09b4fe1908.zip |
Refactor the debug window hierarchy section (#12471)
Various parts of the hierarchy section are split out to separate classes
to permit reusing some of them in other parts of the debug window.
Change-Id: I32ed562bc9d95df2d3c899d9a17a60d45aa703fd
7 files changed, 728 insertions, 447 deletions
diff --git a/client/src/com/vaadin/client/debug/internal/AnalyzeLayoutsPanel.java b/client/src/com/vaadin/client/debug/internal/AnalyzeLayoutsPanel.java new file mode 100644 index 0000000000..7561bc2c03 --- /dev/null +++ b/client/src/com/vaadin/client/debug/internal/AnalyzeLayoutsPanel.java @@ -0,0 +1,267 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * 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 com.vaadin.client.debug.internal; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.google.gwt.core.client.JsArray; +import com.google.gwt.dom.client.Style.TextDecoration; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.MouseOutEvent; +import com.google.gwt.event.dom.client.MouseOutHandler; +import com.google.gwt.event.dom.client.MouseOverEvent; +import com.google.gwt.event.dom.client.MouseOverHandler; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.ApplicationConfiguration; +import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.ComponentConnector; +import com.vaadin.client.ComputedStyle; +import com.vaadin.client.ConnectorMap; +import com.vaadin.client.ServerConnector; +import com.vaadin.client.SimpleTree; +import com.vaadin.client.Util; +import com.vaadin.client.ValueMap; + +/** + * Analyze layouts view panel of the debug window. + * + * @since 7.1.4 + */ +public class AnalyzeLayoutsPanel extends FlowPanel { + + private List<SelectConnectorListener> listeners = new ArrayList<SelectConnectorListener>(); + + public void update() { + clear(); + add(new Label("Analyzing layouts...")); + List<ApplicationConnection> runningApplications = ApplicationConfiguration + .getRunningApplications(); + for (ApplicationConnection applicationConnection : runningApplications) { + applicationConnection.analyzeLayouts(); + } + } + + public void meta(ApplicationConnection ac, ValueMap meta) { + clear(); + JsArray<ValueMap> valueMapArray = meta + .getJSValueMapArray("invalidLayouts"); + int size = valueMapArray.length(); + + if (size > 0) { + SimpleTree root = new SimpleTree("Layouts analyzed, " + size + + " top level problems"); + for (int i = 0; i < size; i++) { + printLayoutError(ac, valueMapArray.get(i), root); + } + root.open(false); + add(root); + } else { + add(new Label("Layouts analyzed, no top level problems")); + } + + Set<ComponentConnector> zeroHeightComponents = new HashSet<ComponentConnector>(); + Set<ComponentConnector> zeroWidthComponents = new HashSet<ComponentConnector>(); + findZeroSizeComponents(zeroHeightComponents, zeroWidthComponents, + ac.getUIConnector()); + if (zeroHeightComponents.size() > 0 || zeroWidthComponents.size() > 0) { + add(new HTML("<h4> Client side notifications</h4>" + + " <em>The following relative sized components were " + + "rendered to a zero size container on the client side." + + " Note that these are not necessarily invalid " + + "states, but reported here as they might be.</em>")); + if (zeroHeightComponents.size() > 0) { + add(new HTML("<p><strong>Vertically zero size:</strong></p>")); + printClientSideDetectedIssues(zeroHeightComponents, ac); + } + if (zeroWidthComponents.size() > 0) { + add(new HTML("<p><strong>Horizontally zero size:</strong></p>")); + printClientSideDetectedIssues(zeroWidthComponents, ac); + } + } + + } + + private void printClientSideDetectedIssues( + Set<ComponentConnector> zeroSized, ApplicationConnection ac) { + + // keep track of already highlighted parents + HashSet<String> parents = new HashSet<String>(); + + for (final ComponentConnector connector : zeroSized) { + final ServerConnector parent = connector.getParent(); + final String parentId = parent.getConnectorId(); + + final Label errorDetails = new Label(Util.getSimpleName(connector) + + "[" + connector.getConnectorId() + "]" + " inside " + + Util.getSimpleName(parent)); + + if (parent instanceof ComponentConnector) { + final ComponentConnector parentConnector = (ComponentConnector) parent; + if (!parents.contains(parentId)) { + parents.add(parentId); + Highlight.show(parentConnector, "yellow"); + } + + errorDetails.addMouseOverHandler(new MouseOverHandler() { + @Override + public void onMouseOver(MouseOverEvent event) { + Highlight.hideAll(); + Highlight.show(parentConnector, "yellow"); + Highlight.show(connector); + errorDetails.getElement().getStyle() + .setTextDecoration(TextDecoration.UNDERLINE); + } + }); + errorDetails.addMouseOutHandler(new MouseOutHandler() { + @Override + public void onMouseOut(MouseOutEvent event) { + Highlight.hideAll(); + errorDetails.getElement().getStyle() + .setTextDecoration(TextDecoration.NONE); + } + }); + errorDetails.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + fireSelectEvent(connector); + } + }); + + } + + Highlight.show(connector); + add(errorDetails); + + } + } + + private void printLayoutError(ApplicationConnection ac, ValueMap valueMap, + SimpleTree root) { + final String pid = valueMap.getString("id"); + + // find connector + final ComponentConnector connector = (ComponentConnector) ConnectorMap + .get(ac).getConnector(pid); + + if (connector == null) { + root.add(new SimpleTree("[" + pid + "] NOT FOUND")); + return; + } + + Highlight.show(connector); + + final SimpleTree errorNode = new SimpleTree( + Util.getSimpleName(connector) + " id: " + pid); + errorNode.addDomHandler(new MouseOverHandler() { + @Override + public void onMouseOver(MouseOverEvent event) { + Highlight.showOnly(connector); + ((Widget) event.getSource()).getElement().getStyle() + .setTextDecoration(TextDecoration.UNDERLINE); + } + }, MouseOverEvent.getType()); + errorNode.addDomHandler(new MouseOutHandler() { + @Override + public void onMouseOut(MouseOutEvent event) { + Highlight.hideAll(); + ((Widget) event.getSource()).getElement().getStyle() + .setTextDecoration(TextDecoration.NONE); + } + }, MouseOutEvent.getType()); + + errorNode.addDomHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + if (event.getNativeEvent().getEventTarget().cast() == errorNode + .getElement().getChild(1).cast()) { + fireSelectEvent(connector); + } + } + }, ClickEvent.getType()); + + VerticalPanel errorDetails = new VerticalPanel(); + + if (valueMap.containsKey("heightMsg")) { + errorDetails.add(new Label("Height problem: " + + valueMap.getString("heightMsg"))); + } + if (valueMap.containsKey("widthMsg")) { + errorDetails.add(new Label("Width problem: " + + valueMap.getString("widthMsg"))); + } + if (errorDetails.getWidgetCount() > 0) { + errorNode.add(errorDetails); + } + if (valueMap.containsKey("subErrors")) { + HTML l = new HTML( + "<em>Expand this node to show problems that may be dependent on this problem.</em>"); + errorDetails.add(l); + JsArray<ValueMap> suberrors = valueMap + .getJSValueMapArray("subErrors"); + for (int i = 0; i < suberrors.length(); i++) { + ValueMap value = suberrors.get(i); + printLayoutError(ac, value, errorNode); + } + + } + root.add(errorNode); + } + + private void findZeroSizeComponents( + Set<ComponentConnector> zeroHeightComponents, + Set<ComponentConnector> zeroWidthComponents, + ComponentConnector connector) { + Widget widget = connector.getWidget(); + ComputedStyle computedStyle = new ComputedStyle(widget.getElement()); + if (computedStyle.getIntProperty("height") == 0) { + zeroHeightComponents.add(connector); + } + if (computedStyle.getIntProperty("width") == 0) { + zeroWidthComponents.add(connector); + } + List<ServerConnector> children = connector.getChildren(); + for (ServerConnector serverConnector : children) { + if (serverConnector instanceof ComponentConnector) { + findZeroSizeComponents(zeroHeightComponents, + zeroWidthComponents, + (ComponentConnector) serverConnector); + } + } + } + + public void addListener(SelectConnectorListener listener) { + listeners.add(listener); + } + + public void removeListener(SelectConnectorListener listener) { + listeners.remove(listener); + } + + private void fireSelectEvent(ServerConnector connector) { + for (SelectConnectorListener listener : listeners) { + listener.select(connector, null); + } + } + +} diff --git a/client/src/com/vaadin/client/debug/internal/ConnectorInfoPanel.java b/client/src/com/vaadin/client/debug/internal/ConnectorInfoPanel.java new file mode 100644 index 0000000000..fc7b55497e --- /dev/null +++ b/client/src/com/vaadin/client/debug/internal/ConnectorInfoPanel.java @@ -0,0 +1,107 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * 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 com.vaadin.client.debug.internal; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.HTML; +import com.vaadin.client.ComponentConnector; +import com.vaadin.client.JsArrayObject; +import com.vaadin.client.ServerConnector; +import com.vaadin.client.Util; +import com.vaadin.client.VConsole; +import com.vaadin.client.metadata.NoDataException; +import com.vaadin.client.metadata.Property; +import com.vaadin.client.ui.AbstractConnector; +import com.vaadin.shared.AbstractComponentState; +import com.vaadin.shared.communication.SharedState; + +/** + * Connector information view panel of the debug window. + * + * @since 7.1.4 + */ +public class ConnectorInfoPanel extends FlowPanel { + + /** + * Update the panel to show information about a connector. + * + * @param connector + */ + public void update(ServerConnector connector) { + SharedState state = connector.getState(); + + Set<String> ignoreProperties = new HashSet<String>(); + ignoreProperties.add("id"); + + String html = getRowHTML("Id", connector.getConnectorId()); + html += getRowHTML("Connector", Util.getSimpleName(connector)); + + if (connector instanceof ComponentConnector) { + ComponentConnector component = (ComponentConnector) connector; + + ignoreProperties.addAll(Arrays.asList("caption", "description", + "width", "height")); + + AbstractComponentState componentState = component.getState(); + + html += getRowHTML("Widget", + Util.getSimpleName(component.getWidget())); + html += getRowHTML("Caption", componentState.caption); + html += getRowHTML("Description", componentState.description); + html += getRowHTML("Width", componentState.width + " (actual: " + + component.getWidget().getOffsetWidth() + "px)"); + html += getRowHTML("Height", componentState.height + " (actual: " + + component.getWidget().getOffsetHeight() + "px)"); + } + + try { + JsArrayObject<Property> properties = AbstractConnector + .getStateType(connector).getPropertiesAsArray(); + for (int i = 0; i < properties.size(); i++) { + Property property = properties.get(i); + String name = property.getName(); + if (!ignoreProperties.contains(name)) { + html += getRowHTML(property.getDisplayName(), + property.getValue(state)); + } + } + } catch (NoDataException e) { + html += "<div>Could not read state, error has been logged to the console</div>"; + VConsole.error(e); + } + + clear(); + add(new HTML(html)); + } + + private String getRowHTML(String caption, Object value) { + return "<div class=\"" + VDebugWindow.STYLENAME + + "-row\"><span class=\"caption\">" + caption + + "</span><span class=\"value\">" + + Util.escapeHTML(String.valueOf(value)) + "</span></div>"; + } + + /** + * Clear the contents of the panel. + */ + public void clearContents() { + clear(); + } +} diff --git a/client/src/com/vaadin/client/debug/internal/HierarchyPanel.java b/client/src/com/vaadin/client/debug/internal/HierarchyPanel.java new file mode 100644 index 0000000000..759dbf00dd --- /dev/null +++ b/client/src/com/vaadin/client/debug/internal/HierarchyPanel.java @@ -0,0 +1,138 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * 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 com.vaadin.client.debug.internal; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.DoubleClickEvent; +import com.google.gwt.event.dom.client.DoubleClickHandler; +import com.google.gwt.event.dom.client.HasDoubleClickHandlers; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.ApplicationConfiguration; +import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.ServerConnector; +import com.vaadin.client.SimpleTree; +import com.vaadin.client.Util; + +/** + * Hierarchy view panel of the debug window. This class can be used in various + * debug window sections to show the current connector hierarchy. + * + * @since 7.1.4 + */ +public class HierarchyPanel extends FlowPanel { + + // TODO separate click listeners for simple selection and doubleclick + private List<SelectConnectorListener> listeners = new ArrayList<SelectConnectorListener>(); + + public void update() { + clear(); + // TODO Clearing and rebuilding the contents is not optimal for UX as + // any previous expansions are lost. + SimplePanel trees = new SimplePanel(); + + for (ApplicationConnection application : ApplicationConfiguration + .getRunningApplications()) { + ServerConnector uiConnector = application.getUIConnector(); + Widget connectorTree = buildConnectorTree(uiConnector); + + trees.add(connectorTree); + } + + add(trees); + } + + private Widget buildConnectorTree(final ServerConnector connector) { + String connectorString = Util.getConnectorString(connector); + + List<ServerConnector> children = connector.getChildren(); + + Widget widget; + if (children == null || children.isEmpty()) { + // Leaf node, just add a label + Label label = new Label(connectorString); + label.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + Highlight.showOnly(connector); + showServerDebugInfo(connector); + } + }); + widget = label; + } else { + SimpleTree tree = new SimpleTree(connectorString) { + @Override + protected void select(ClickEvent event) { + super.select(event); + Highlight.showOnly(connector); + showServerDebugInfo(connector); + } + }; + for (ServerConnector child : children) { + tree.add(buildConnectorTree(child)); + } + widget = tree; + } + + if (widget instanceof HasDoubleClickHandlers) { + HasDoubleClickHandlers has = (HasDoubleClickHandlers) widget; + has.addDoubleClickHandler(new DoubleClickHandler() { + @Override + public void onDoubleClick(DoubleClickEvent event) { + fireSelectEvent(connector); + } + }); + } + + return widget; + } + + public void addListener(SelectConnectorListener listener) { + listeners.add(listener); + } + + public void removeListener(SelectConnectorListener listener) { + listeners.remove(listener); + } + + private void fireSelectEvent(ServerConnector connector) { + for (SelectConnectorListener listener : listeners) { + listener.select(connector, null); + } + } + + /** + * Outputs debug information on the server - usually in the console of an + * IDE, with a clickable reference to the relevant code location. + * + * @since 7.1 + * @param connector + * show debug info for this connector + */ + static void showServerDebugInfo(ServerConnector connector) { + if (connector != null) { + connector.getConnection().getUIConnector() + .showServerDebugInfo(connector); + } + } + +} diff --git a/client/src/com/vaadin/client/debug/internal/HierarchySection.java b/client/src/com/vaadin/client/debug/internal/HierarchySection.java index 90c9086d7d..616bf70c38 100644 --- a/client/src/com/vaadin/client/debug/internal/HierarchySection.java +++ b/client/src/com/vaadin/client/debug/internal/HierarchySection.java @@ -15,23 +15,9 @@ */ package com.vaadin.client.debug.internal; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import com.google.gwt.core.client.JsArray; -import com.google.gwt.dom.client.Style.TextDecoration; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.DoubleClickEvent; -import com.google.gwt.event.dom.client.DoubleClickHandler; -import com.google.gwt.event.dom.client.HasDoubleClickHandlers; import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.event.dom.client.MouseOutEvent; -import com.google.gwt.event.dom.client.MouseOutHandler; -import com.google.gwt.event.dom.client.MouseOverEvent; -import com.google.gwt.event.dom.client.MouseOverHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; @@ -40,28 +26,15 @@ import com.google.gwt.user.client.Event.NativePreviewHandler; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; -import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.SimplePanel; -import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConfiguration; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ComponentConnector; -import com.vaadin.client.ComputedStyle; -import com.vaadin.client.ConnectorMap; -import com.vaadin.client.JsArrayObject; import com.vaadin.client.ServerConnector; -import com.vaadin.client.SimpleTree; import com.vaadin.client.Util; -import com.vaadin.client.VConsole; import com.vaadin.client.ValueMap; -import com.vaadin.client.metadata.NoDataException; -import com.vaadin.client.metadata.Property; -import com.vaadin.client.ui.AbstractConnector; -import com.vaadin.client.ui.UnknownComponentConnector; -import com.vaadin.shared.AbstractComponentState; -import com.vaadin.shared.communication.SharedState; /** * Provides functionality for examining the UI component hierarchy. @@ -73,7 +46,15 @@ public class HierarchySection implements Section { private final DebugButton tabButton = new DebugButton(Icon.HIERARCHY, "Examine component hierarchy"); - private final FlowPanel content = new FlowPanel(); + private final SimplePanel content = new SimplePanel(); + + // TODO highlighting logic is split between these, should be refactored + private final FlowPanel helpPanel = new FlowPanel(); + private final ConnectorInfoPanel infoPanel = new ConnectorInfoPanel(); + private final HierarchyPanel hierarchyPanel = new HierarchyPanel(); + private final OptimizedWidgetsetPanel widgetsetPanel = new OptimizedWidgetsetPanel(); + private final AnalyzeLayoutsPanel analyzeLayoutsPanel = new AnalyzeLayoutsPanel(); + private final FlowPanel controls = new FlowPanel(); private final Button find = new DebugButton(Icon.HIGHLIGHT, @@ -125,79 +106,40 @@ public class HierarchySection implements Section { } }); + hierarchyPanel.addListener(new SelectConnectorListener() { + @Override + public void select(ServerConnector connector, Element element) { + printState(connector, true); + } + }); + + analyzeLayoutsPanel.addListener(new SelectConnectorListener() { + @Override + public void select(ServerConnector connector, Element element) { + printState(connector, true); + } + }); + content.setStylePrimaryName(VDebugWindow.STYLENAME + "-hierarchy"); + initializeHelpPanel(); + content.setWidget(helpPanel); + } + + private void initializeHelpPanel() { HTML info = new HTML(showHierarchy.getHTML() + " " + showHierarchy.getTitle() + "<br/>" + find.getHTML() + " " + find.getTitle() + "<br/>" + analyze.getHTML() + " " + analyze.getTitle() + "<br/>" + generateWS.getHTML() + " " + generateWS.getTitle() + "<br/>"); info.setStyleName(VDebugWindow.STYLENAME + "-info"); - content.add(info); + helpPanel.add(info); } private void showHierarchy() { Highlight.hideAll(); - content.clear(); - - // TODO Clearing and rebuilding the contents is not optimal for UX as - // any previous expansions are lost. - SimplePanel trees = new SimplePanel(); - - for (ApplicationConnection application : ApplicationConfiguration - .getRunningApplications()) { - ServerConnector uiConnector = application.getUIConnector(); - Widget connectorTree = buildConnectorTree(uiConnector); - - trees.add(connectorTree); - } - - content.add(trees); - } - - private Widget buildConnectorTree(final ServerConnector connector) { - String connectorString = Util.getConnectorString(connector); - - List<ServerConnector> children = connector.getChildren(); - - Widget widget; - if (children == null || children.isEmpty()) { - // Leaf node, just add a label - Label label = new Label(connectorString); - label.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - Highlight.showOnly(connector); - Highlight.showServerDebugInfo(connector); - } - }); - widget = label; - } else { - SimpleTree tree = new SimpleTree(connectorString) { - @Override - protected void select(ClickEvent event) { - super.select(event); - Highlight.showOnly(connector); - Highlight.showServerDebugInfo(connector); - } - }; - for (ServerConnector child : children) { - tree.add(buildConnectorTree(child)); - } - widget = tree; - } - - if (widget instanceof HasDoubleClickHandlers) { - HasDoubleClickHandlers has = (HasDoubleClickHandlers) widget; - has.addDoubleClickHandler(new DoubleClickHandler() { - @Override - public void onDoubleClick(DoubleClickEvent event) { - printState(connector, true); - } - }); - } - - return widget; + hierarchyPanel.update(); + content.setWidget(hierarchyPanel); } @Override @@ -226,302 +168,19 @@ public class HierarchySection implements Section { } private void generateWidgetset() { - - content.clear(); - HTML h = new HTML("Getting used connectors"); - content.add(h); - - String s = ""; - for (ApplicationConnection ac : ApplicationConfiguration - .getRunningApplications()) { - ApplicationConfiguration conf = ac.getConfiguration(); - s += "<h1>Used connectors for " + conf.getServiceUrl() + "</h1>"; - - for (String connectorName : getUsedConnectorNames(conf)) { - s += connectorName + "<br/>"; - } - - s += "<h2>To make an optimized widgetset based on these connectors, do:</h2>"; - s += "<h3>1. Add to your widgetset.gwt.xml file:</h2>"; - s += "<textarea rows=\"3\" style=\"width:90%\">"; - s += "<generate-with class=\"OptimizedConnectorBundleLoaderFactory\">\n"; - s += " <when-type-assignable class=\"com.vaadin.client.metadata.ConnectorBundleLoader\" />\n"; - s += "</generate-with>"; - s += "</textarea>"; - - s += "<h3>2. Add the following java file to your project:</h2>"; - s += "<textarea rows=\"5\" style=\"width:90%\">"; - s += generateOptimizedWidgetSet(getUsedConnectorNames(conf)); - s += "</textarea>"; - s += "<h3>3. Recompile widgetset</h2>"; - - } - - h.setHTML(s); - } - - private Set<String> getUsedConnectorNames( - ApplicationConfiguration configuration) { - int tag = 0; - Set<String> usedConnectors = new HashSet<String>(); - while (true) { - String serverSideClass = configuration - .getServerSideClassNameForTag(tag); - if (serverSideClass == null) { - break; - } - Class<? extends ServerConnector> connectorClass = configuration - .getConnectorClassByEncodedTag(tag); - if (connectorClass == null) { - break; - } - - if (connectorClass != UnknownComponentConnector.class) { - usedConnectors.add(connectorClass.getName()); - } - tag++; - if (tag > 10000) { - // Sanity check - VConsole.error("Search for used connector classes was forcefully terminated"); - break; - } - } - return usedConnectors; - } - - public String generateOptimizedWidgetSet(Set<String> usedConnectors) { - String s = "import java.util.HashSet;\n"; - s += "import java.util.Set;\n"; - - s += "import com.google.gwt.core.ext.typeinfo.JClassType;\n"; - s += "import com.vaadin.client.ui.ui.UIConnector;\n"; - s += "import com.vaadin.server.widgetsetutils.ConnectorBundleLoaderFactory;\n"; - s += "import com.vaadin.shared.ui.Connect.LoadStyle;\n\n"; - - s += "public class OptimizedConnectorBundleLoaderFactory extends\n"; - s += " ConnectorBundleLoaderFactory {\n"; - s += " private Set<String> eagerConnectors = new HashSet<String>();\n"; - s += " {\n"; - for (String c : usedConnectors) { - s += " eagerConnectors.add(" + c - + ".class.getName());\n"; - } - s += " }\n"; - s += "\n"; - s += " @Override\n"; - s += " protected LoadStyle getLoadStyle(JClassType connectorType) {\n"; - s += " if (eagerConnectors.contains(connectorType.getQualifiedBinaryName())) {\n"; - s += " return LoadStyle.EAGER;\n"; - s += " } else {\n"; - s += " // Loads all other connectors immediately after the initial view has\n"; - s += " // been rendered\n"; - s += " return LoadStyle.DEFERRED;\n"; - s += " }\n"; - s += " }\n"; - s += "}\n"; - - return s; + widgetsetPanel.update(); + content.setWidget(widgetsetPanel); } private void analyzeLayouts() { - content.clear(); - content.add(new Label("Analyzing layouts...")); - List<ApplicationConnection> runningApplications = ApplicationConfiguration - .getRunningApplications(); - for (ApplicationConnection applicationConnection : runningApplications) { - applicationConnection.analyzeLayouts(); - } + analyzeLayoutsPanel.update(); + content.setWidget(analyzeLayoutsPanel); } @Override public void meta(ApplicationConnection ac, ValueMap meta) { - content.clear(); - JsArray<ValueMap> valueMapArray = meta - .getJSValueMapArray("invalidLayouts"); - int size = valueMapArray.length(); - - if (size > 0) { - SimpleTree root = new SimpleTree("Layouts analyzed, " + size - + " top level problems"); - for (int i = 0; i < size; i++) { - printLayoutError(ac, valueMapArray.get(i), root); - } - root.open(false); - content.add(root); - } else { - content.add(new Label("Layouts analyzed, no top level problems")); - } - - Set<ComponentConnector> zeroHeightComponents = new HashSet<ComponentConnector>(); - Set<ComponentConnector> zeroWidthComponents = new HashSet<ComponentConnector>(); - findZeroSizeComponents(zeroHeightComponents, zeroWidthComponents, - ac.getUIConnector()); - if (zeroHeightComponents.size() > 0 || zeroWidthComponents.size() > 0) { - content.add(new HTML("<h4> Client side notifications</h4>" - + " <em>The following relative sized components were " - + "rendered to a zero size container on the client side." - + " Note that these are not necessarily invalid " - + "states, but reported here as they might be.</em>")); - if (zeroHeightComponents.size() > 0) { - content.add(new HTML( - "<p><strong>Vertically zero size:</strong></p>")); - printClientSideDetectedIssues(zeroHeightComponents, ac); - } - if (zeroWidthComponents.size() > 0) { - content.add(new HTML( - "<p><strong>Horizontally zero size:</strong></p>")); - printClientSideDetectedIssues(zeroWidthComponents, ac); - } - } - - } - - private void printClientSideDetectedIssues( - Set<ComponentConnector> zeroSized, ApplicationConnection ac) { - - // keep track of already highlighted parents - HashSet<String> parents = new HashSet<String>(); - - for (final ComponentConnector connector : zeroSized) { - final ServerConnector parent = connector.getParent(); - final String parentId = parent.getConnectorId(); - - final Label errorDetails = new Label(Util.getSimpleName(connector) - + "[" + connector.getConnectorId() + "]" + " inside " - + Util.getSimpleName(parent)); - - if (parent instanceof ComponentConnector) { - final ComponentConnector parentConnector = (ComponentConnector) parent; - if (!parents.contains(parentId)) { - parents.add(parentId); - Highlight.show(parentConnector, "yellow"); - } - - errorDetails.addMouseOverHandler(new MouseOverHandler() { - @Override - public void onMouseOver(MouseOverEvent event) { - Highlight.hideAll(); - Highlight.show(parentConnector, "yellow"); - Highlight.show(connector); - errorDetails.getElement().getStyle() - .setTextDecoration(TextDecoration.UNDERLINE); - } - }); - errorDetails.addMouseOutHandler(new MouseOutHandler() { - @Override - public void onMouseOut(MouseOutEvent event) { - Highlight.hideAll(); - errorDetails.getElement().getStyle() - .setTextDecoration(TextDecoration.NONE); - } - }); - errorDetails.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - printState(connector, true); - } - }); - - } - - Highlight.show(connector); - content.add(errorDetails); - - } - } - - private void printLayoutError(ApplicationConnection ac, ValueMap valueMap, - SimpleTree root) { - final String pid = valueMap.getString("id"); - - // find connector - final ComponentConnector connector = (ComponentConnector) ConnectorMap - .get(ac).getConnector(pid); - - if (connector == null) { - root.add(new SimpleTree("[" + pid + "] NOT FOUND")); - return; - } - - Highlight.show(connector); - - final SimpleTree errorNode = new SimpleTree( - Util.getSimpleName(connector) + " id: " + pid); - errorNode.addDomHandler(new MouseOverHandler() { - @Override - public void onMouseOver(MouseOverEvent event) { - Highlight.showOnly(connector); - ((Widget) event.getSource()).getElement().getStyle() - .setTextDecoration(TextDecoration.UNDERLINE); - } - }, MouseOverEvent.getType()); - errorNode.addDomHandler(new MouseOutHandler() { - @Override - public void onMouseOut(MouseOutEvent event) { - Highlight.hideAll(); - ((Widget) event.getSource()).getElement().getStyle() - .setTextDecoration(TextDecoration.NONE); - } - }, MouseOutEvent.getType()); - - errorNode.addDomHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - if (event.getNativeEvent().getEventTarget().cast() == errorNode - .getElement().getChild(1).cast()) { - printState(connector, true); - } - } - }, ClickEvent.getType()); - - VerticalPanel errorDetails = new VerticalPanel(); - - if (valueMap.containsKey("heightMsg")) { - errorDetails.add(new Label("Height problem: " - + valueMap.getString("heightMsg"))); - } - if (valueMap.containsKey("widthMsg")) { - errorDetails.add(new Label("Width problem: " - + valueMap.getString("widthMsg"))); - } - if (errorDetails.getWidgetCount() > 0) { - errorNode.add(errorDetails); - } - if (valueMap.containsKey("subErrors")) { - HTML l = new HTML( - "<em>Expand this node to show problems that may be dependent on this problem.</em>"); - errorDetails.add(l); - JsArray<ValueMap> suberrors = valueMap - .getJSValueMapArray("subErrors"); - for (int i = 0; i < suberrors.length(); i++) { - ValueMap value = suberrors.get(i); - printLayoutError(ac, value, errorNode); - } - - } - root.add(errorNode); - } - - private void findZeroSizeComponents( - Set<ComponentConnector> zeroHeightComponents, - Set<ComponentConnector> zeroWidthComponents, - ComponentConnector connector) { - Widget widget = connector.getWidget(); - ComputedStyle computedStyle = new ComputedStyle(widget.getElement()); - if (computedStyle.getIntProperty("height") == 0) { - zeroHeightComponents.add(connector); - } - if (computedStyle.getIntProperty("width") == 0) { - zeroWidthComponents.add(connector); - } - List<ServerConnector> children = connector.getChildren(); - for (ServerConnector serverConnector : children) { - if (serverConnector instanceof ComponentConnector) { - findZeroSizeComponents(zeroHeightComponents, - zeroWidthComponents, - (ComponentConnector) serverConnector); - } - } + // show the results of analyzeLayouts + analyzeLayoutsPanel.meta(ac, meta); } @Override @@ -561,60 +220,11 @@ public class HierarchySection implements Section { private void printState(ServerConnector connector, boolean serverDebug) { Highlight.showOnly(connector); if (serverDebug) { - Highlight.showServerDebugInfo(connector); + HierarchyPanel.showServerDebugInfo(connector); } - SharedState state = connector.getState(); - - Set<String> ignoreProperties = new HashSet<String>(); - ignoreProperties.add("id"); - - String html = getRowHTML("Id", connector.getConnectorId()); - html += getRowHTML("Connector", Util.getSimpleName(connector)); - - if (connector instanceof ComponentConnector) { - ComponentConnector component = (ComponentConnector) connector; - - ignoreProperties.addAll(Arrays.asList("caption", "description", - "width", "height")); - - AbstractComponentState componentState = component.getState(); - - html += getRowHTML("Widget", - Util.getSimpleName(component.getWidget())); - html += getRowHTML("Caption", componentState.caption); - html += getRowHTML("Description", componentState.description); - html += getRowHTML("Width", componentState.width + " (actual: " - + component.getWidget().getOffsetWidth() + "px)"); - html += getRowHTML("Height", componentState.height + " (actual: " - + component.getWidget().getOffsetHeight() + "px)"); - } - - try { - JsArrayObject<Property> properties = AbstractConnector - .getStateType(connector).getPropertiesAsArray(); - for (int i = 0; i < properties.size(); i++) { - Property property = properties.get(i); - String name = property.getName(); - if (!ignoreProperties.contains(name)) { - html += getRowHTML(property.getDisplayName(), - property.getValue(state)); - } - } - } catch (NoDataException e) { - html += "<div>Could not read state, error has been logged to the console</div>"; - VConsole.error(e); - } - - content.clear(); - content.add(new HTML(html)); - } - - private String getRowHTML(String caption, Object value) { - return "<div class=\"" + VDebugWindow.STYLENAME - + "-row\"><span class=\"caption\">" + caption - + "</span><span class=\"value\">" - + Util.escapeHTML(String.valueOf(value)) + "</span></div>"; + infoPanel.update(connector); + content.setWidget(infoPanel); } private final NativePreviewHandler highlightModeHandler = new NativePreviewHandler() { @@ -634,7 +244,7 @@ public class HierarchySection implements Section { .getNativeEvent().getClientX(), event.getNativeEvent() .getClientY()); if (VDebugWindow.get().getElement().isOrHasChild(eventTarget)) { - content.clear(); + infoPanel.clear(); return; } @@ -654,7 +264,7 @@ public class HierarchySection implements Section { return; } } - content.clear(); + infoPanel.clear(); } if (event.getTypeInt() == Event.ONCLICK) { Highlight.hideAll(); diff --git a/client/src/com/vaadin/client/debug/internal/Highlight.java b/client/src/com/vaadin/client/debug/internal/Highlight.java index 3c1af445a9..f2695f58ca 100644 --- a/client/src/com/vaadin/client/debug/internal/Highlight.java +++ b/client/src/com/vaadin/client/debug/internal/Highlight.java @@ -207,19 +207,4 @@ public class Highlight { } } - /** - * Outputs debug information on the server - usually in the console of an - * IDE, with a clickable reference to the relevant code location. - * - * @since 7.1 - * @param connector - * show debug info for this connector - */ - static void showServerDebugInfo(ServerConnector connector) { - if (connector != null) { - connector.getConnection().getUIConnector() - .showServerDebugInfo(connector); - } - } - } diff --git a/client/src/com/vaadin/client/debug/internal/OptimizedWidgetsetPanel.java b/client/src/com/vaadin/client/debug/internal/OptimizedWidgetsetPanel.java new file mode 100644 index 0000000000..a8d8aad888 --- /dev/null +++ b/client/src/com/vaadin/client/debug/internal/OptimizedWidgetsetPanel.java @@ -0,0 +1,137 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * 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 com.vaadin.client.debug.internal; + +import java.util.HashSet; +import java.util.Set; + +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.HTML; +import com.vaadin.client.ApplicationConfiguration; +import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.ServerConnector; +import com.vaadin.client.VConsole; +import com.vaadin.client.ui.UnknownComponentConnector; + +/** + * Optimized widgetset view panel of the debug window. + * + * @since 7.1.4 + */ +public class OptimizedWidgetsetPanel extends FlowPanel { + + /** + * Update the panel contents based on the connectors that have been used so + * far on this execution of the application. + */ + public void update() { + clear(); + HTML h = new HTML("Getting used connectors"); + add(h); + + String s = ""; + for (ApplicationConnection ac : ApplicationConfiguration + .getRunningApplications()) { + ApplicationConfiguration conf = ac.getConfiguration(); + s += "<h1>Used connectors for " + conf.getServiceUrl() + "</h1>"; + + for (String connectorName : getUsedConnectorNames(conf)) { + s += connectorName + "<br/>"; + } + + s += "<h2>To make an optimized widgetset based on these connectors, do:</h2>"; + s += "<h3>1. Add to your widgetset.gwt.xml file:</h2>"; + s += "<textarea rows=\"3\" style=\"width:90%\">"; + s += "<generate-with class=\"OptimizedConnectorBundleLoaderFactory\">\n"; + s += " <when-type-assignable class=\"com.vaadin.client.metadata.ConnectorBundleLoader\" />\n"; + s += "</generate-with>"; + s += "</textarea>"; + + s += "<h3>2. Add the following java file to your project:</h2>"; + s += "<textarea rows=\"5\" style=\"width:90%\">"; + s += generateOptimizedWidgetSet(getUsedConnectorNames(conf)); + s += "</textarea>"; + s += "<h3>3. Recompile widgetset</h2>"; + + } + + h.setHTML(s); + } + + private Set<String> getUsedConnectorNames( + ApplicationConfiguration configuration) { + int tag = 0; + Set<String> usedConnectors = new HashSet<String>(); + while (true) { + String serverSideClass = configuration + .getServerSideClassNameForTag(tag); + if (serverSideClass == null) { + break; + } + Class<? extends ServerConnector> connectorClass = configuration + .getConnectorClassByEncodedTag(tag); + if (connectorClass == null) { + break; + } + + if (connectorClass != UnknownComponentConnector.class) { + usedConnectors.add(connectorClass.getName()); + } + tag++; + if (tag > 10000) { + // Sanity check + VConsole.error("Search for used connector classes was forcefully terminated"); + break; + } + } + return usedConnectors; + } + + public String generateOptimizedWidgetSet(Set<String> usedConnectors) { + String s = "import java.util.HashSet;\n"; + s += "import java.util.Set;\n"; + + s += "import com.google.gwt.core.ext.typeinfo.JClassType;\n"; + s += "import com.vaadin.client.ui.ui.UIConnector;\n"; + s += "import com.vaadin.server.widgetsetutils.ConnectorBundleLoaderFactory;\n"; + s += "import com.vaadin.shared.ui.Connect.LoadStyle;\n\n"; + + s += "public class OptimizedConnectorBundleLoaderFactory extends\n"; + s += " ConnectorBundleLoaderFactory {\n"; + s += " private Set<String> eagerConnectors = new HashSet<String>();\n"; + s += " {\n"; + for (String c : usedConnectors) { + s += " eagerConnectors.add(" + c + + ".class.getName());\n"; + } + s += " }\n"; + s += "\n"; + s += " @Override\n"; + s += " protected LoadStyle getLoadStyle(JClassType connectorType) {\n"; + s += " if (eagerConnectors.contains(connectorType.getQualifiedBinaryName())) {\n"; + s += " return LoadStyle.EAGER;\n"; + s += " } else {\n"; + s += " // Loads all other connectors immediately after the initial view has\n"; + s += " // been rendered\n"; + s += " return LoadStyle.DEFERRED;\n"; + s += " }\n"; + s += " }\n"; + s += "}\n"; + + return s; + } + +} diff --git a/client/src/com/vaadin/client/debug/internal/SelectConnectorListener.java b/client/src/com/vaadin/client/debug/internal/SelectConnectorListener.java new file mode 100644 index 0000000000..409f9d14ce --- /dev/null +++ b/client/src/com/vaadin/client/debug/internal/SelectConnectorListener.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * 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 com.vaadin.client.debug.internal; + +import com.google.gwt.user.client.Element; +import com.vaadin.client.ServerConnector; + +/** + * Listener for the selection of a connector in the debug window. + * + * @since 7.1.4 + */ +public interface SelectConnectorListener { + /** + * Listener method called when a connector has been selected. If a specific + * element of the connector was selected, it is also given. + * + * @param connector + * selected connector + * @param element + * selected element of the connector or null if unknown + */ + public void select(ServerConnector connector, Element element); +}
\ No newline at end of file |