You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

HierarchySection.java 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /*
  2. * Copyright 2000-2014 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client.debug.internal;
  17. import java.util.Arrays;
  18. import java.util.HashSet;
  19. import java.util.List;
  20. import java.util.Set;
  21. import com.google.gwt.core.client.JsArray;
  22. import com.google.gwt.dom.client.Style.TextDecoration;
  23. import com.google.gwt.event.dom.client.ClickEvent;
  24. import com.google.gwt.event.dom.client.ClickHandler;
  25. import com.google.gwt.event.dom.client.DoubleClickEvent;
  26. import com.google.gwt.event.dom.client.DoubleClickHandler;
  27. import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
  28. import com.google.gwt.event.dom.client.KeyCodes;
  29. import com.google.gwt.event.dom.client.MouseOutEvent;
  30. import com.google.gwt.event.dom.client.MouseOutHandler;
  31. import com.google.gwt.event.dom.client.MouseOverEvent;
  32. import com.google.gwt.event.dom.client.MouseOverHandler;
  33. import com.google.gwt.event.shared.HandlerRegistration;
  34. import com.google.gwt.user.client.Element;
  35. import com.google.gwt.user.client.Event;
  36. import com.google.gwt.user.client.Event.NativePreviewEvent;
  37. import com.google.gwt.user.client.Event.NativePreviewHandler;
  38. import com.google.gwt.user.client.ui.Button;
  39. import com.google.gwt.user.client.ui.FlowPanel;
  40. import com.google.gwt.user.client.ui.HTML;
  41. import com.google.gwt.user.client.ui.Label;
  42. import com.google.gwt.user.client.ui.RootPanel;
  43. import com.google.gwt.user.client.ui.SimplePanel;
  44. import com.google.gwt.user.client.ui.VerticalPanel;
  45. import com.google.gwt.user.client.ui.Widget;
  46. import com.vaadin.client.ApplicationConfiguration;
  47. import com.vaadin.client.ApplicationConnection;
  48. import com.vaadin.client.ComponentConnector;
  49. import com.vaadin.client.ComputedStyle;
  50. import com.vaadin.client.ConnectorMap;
  51. import com.vaadin.client.JsArrayObject;
  52. import com.vaadin.client.ServerConnector;
  53. import com.vaadin.client.SimpleTree;
  54. import com.vaadin.client.Util;
  55. import com.vaadin.client.VConsole;
  56. import com.vaadin.client.ValueMap;
  57. import com.vaadin.client.metadata.NoDataException;
  58. import com.vaadin.client.metadata.Property;
  59. import com.vaadin.client.ui.AbstractConnector;
  60. import com.vaadin.client.ui.UnknownComponentConnector;
  61. import com.vaadin.shared.AbstractComponentState;
  62. import com.vaadin.shared.communication.SharedState;
  63. /**
  64. * Provides functionality for examining the UI component hierarchy.
  65. *
  66. * @since 7.1
  67. * @author Vaadin Ltd
  68. */
  69. public class HierarchySection implements Section {
  70. private final DebugButton tabButton = new DebugButton(Icon.HIERARCHY,
  71. "Examine component hierarchy");
  72. private final FlowPanel content = new FlowPanel();
  73. private final FlowPanel controls = new FlowPanel();
  74. private final Button find = new DebugButton(Icon.HIGHLIGHT,
  75. "Select a component on the page to inspect it");
  76. private final Button analyze = new DebugButton(Icon.ANALYZE,
  77. "Check layouts for potential problems");
  78. private final Button generateWS = new DebugButton(Icon.OPTIMIZE,
  79. "Show used connectors and how to optimize widgetset");
  80. private final Button showHierarchy = new DebugButton(Icon.HIERARCHY,
  81. "Show the connector hierarchy tree");
  82. private HandlerRegistration highlightModeRegistration = null;
  83. public HierarchySection() {
  84. controls.add(showHierarchy);
  85. showHierarchy.setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
  86. showHierarchy.addClickHandler(new ClickHandler() {
  87. @Override
  88. public void onClick(ClickEvent event) {
  89. showHierarchy();
  90. }
  91. });
  92. controls.add(find);
  93. find.setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
  94. find.addClickHandler(new ClickHandler() {
  95. @Override
  96. public void onClick(ClickEvent event) {
  97. toggleFind();
  98. }
  99. });
  100. controls.add(analyze);
  101. analyze.setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
  102. analyze.addClickHandler(new ClickHandler() {
  103. @Override
  104. public void onClick(ClickEvent event) {
  105. stopFind();
  106. analyzeLayouts();
  107. }
  108. });
  109. controls.add(generateWS);
  110. generateWS.setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
  111. generateWS.addClickHandler(new ClickHandler() {
  112. @Override
  113. public void onClick(ClickEvent event) {
  114. generateWidgetset();
  115. }
  116. });
  117. content.setStylePrimaryName(VDebugWindow.STYLENAME + "-hierarchy");
  118. HTML info = new HTML(showHierarchy.getHTML() + " "
  119. + showHierarchy.getTitle() + "<br/>" + find.getHTML() + " "
  120. + find.getTitle() + "<br/>" + analyze.getHTML() + " "
  121. + analyze.getTitle() + "<br/>" + generateWS.getHTML() + " "
  122. + generateWS.getTitle() + "<br/>");
  123. info.setStyleName(VDebugWindow.STYLENAME + "-info");
  124. content.add(info);
  125. }
  126. private void showHierarchy() {
  127. Highlight.hideAll();
  128. content.clear();
  129. // TODO Clearing and rebuilding the contents is not optimal for UX as
  130. // any previous expansions are lost.
  131. SimplePanel trees = new SimplePanel();
  132. for (ApplicationConnection application : ApplicationConfiguration
  133. .getRunningApplications()) {
  134. ServerConnector uiConnector = application.getUIConnector();
  135. Widget connectorTree = buildConnectorTree(uiConnector);
  136. trees.add(connectorTree);
  137. }
  138. content.add(trees);
  139. }
  140. private Widget buildConnectorTree(final ServerConnector connector) {
  141. String connectorString = Util.getConnectorString(connector);
  142. List<ServerConnector> children = connector.getChildren();
  143. Widget widget;
  144. if (children == null || children.isEmpty()) {
  145. // Leaf node, just add a label
  146. Label label = new Label(connectorString);
  147. label.addClickHandler(new ClickHandler() {
  148. @Override
  149. public void onClick(ClickEvent event) {
  150. Highlight.showOnly(connector);
  151. Highlight.showServerDebugInfo(connector);
  152. }
  153. });
  154. widget = label;
  155. } else {
  156. SimpleTree tree = new SimpleTree(connectorString) {
  157. @Override
  158. protected void select(ClickEvent event) {
  159. super.select(event);
  160. Highlight.showOnly(connector);
  161. Highlight.showServerDebugInfo(connector);
  162. }
  163. };
  164. for (ServerConnector child : children) {
  165. tree.add(buildConnectorTree(child));
  166. }
  167. widget = tree;
  168. }
  169. if (widget instanceof HasDoubleClickHandlers) {
  170. HasDoubleClickHandlers has = (HasDoubleClickHandlers) widget;
  171. has.addDoubleClickHandler(new DoubleClickHandler() {
  172. @Override
  173. public void onDoubleClick(DoubleClickEvent event) {
  174. printState(connector, true);
  175. }
  176. });
  177. }
  178. return widget;
  179. }
  180. @Override
  181. public DebugButton getTabButton() {
  182. return tabButton;
  183. }
  184. @Override
  185. public Widget getControls() {
  186. return controls;
  187. }
  188. @Override
  189. public Widget getContent() {
  190. return content;
  191. }
  192. @Override
  193. public void show() {
  194. }
  195. @Override
  196. public void hide() {
  197. stopFind();
  198. }
  199. private void generateWidgetset() {
  200. content.clear();
  201. HTML h = new HTML("Getting used connectors");
  202. content.add(h);
  203. String s = "";
  204. for (ApplicationConnection ac : ApplicationConfiguration
  205. .getRunningApplications()) {
  206. ApplicationConfiguration conf = ac.getConfiguration();
  207. s += "<h1>Used connectors for " + conf.getServiceUrl() + "</h1>";
  208. for (String connectorName : getUsedConnectorNames(conf)) {
  209. s += connectorName + "<br/>";
  210. }
  211. s += "<h2>To make an optimized widgetset based on these connectors, do:</h2>";
  212. s += "<h3>1. Add to your widgetset.gwt.xml file:</h2>";
  213. s += "<textarea rows=\"3\" style=\"width:90%\">";
  214. s += "<generate-with class=\"OptimizedConnectorBundleLoaderFactory\">\n";
  215. s += " <when-type-assignable class=\"com.vaadin.client.metadata.ConnectorBundleLoader\" />\n";
  216. s += "</generate-with>";
  217. s += "</textarea>";
  218. s += "<h3>2. Add the following java file to your project:</h2>";
  219. s += "<textarea rows=\"5\" style=\"width:90%\">";
  220. s += generateOptimizedWidgetSet(getUsedConnectorNames(conf));
  221. s += "</textarea>";
  222. s += "<h3>3. Recompile widgetset</h2>";
  223. }
  224. h.setHTML(s);
  225. }
  226. private Set<String> getUsedConnectorNames(
  227. ApplicationConfiguration configuration) {
  228. int tag = 0;
  229. Set<String> usedConnectors = new HashSet<String>();
  230. while (true) {
  231. String serverSideClass = configuration
  232. .getServerSideClassNameForTag(tag);
  233. if (serverSideClass == null) {
  234. break;
  235. }
  236. Class<? extends ServerConnector> connectorClass = configuration
  237. .getConnectorClassByEncodedTag(tag);
  238. if (connectorClass == null) {
  239. break;
  240. }
  241. if (connectorClass != UnknownComponentConnector.class) {
  242. usedConnectors.add(connectorClass.getName());
  243. }
  244. tag++;
  245. if (tag > 10000) {
  246. // Sanity check
  247. VConsole.error("Search for used connector classes was forcefully terminated");
  248. break;
  249. }
  250. }
  251. return usedConnectors;
  252. }
  253. public String generateOptimizedWidgetSet(Set<String> usedConnectors) {
  254. String s = "import java.util.HashSet;\n";
  255. s += "import java.util.Set;\n";
  256. s += "import com.google.gwt.core.ext.typeinfo.JClassType;\n";
  257. s += "import com.vaadin.client.ui.ui.UIConnector;\n";
  258. s += "import com.vaadin.server.widgetsetutils.ConnectorBundleLoaderFactory;\n";
  259. s += "import com.vaadin.shared.ui.Connect.LoadStyle;\n\n";
  260. s += "public class OptimizedConnectorBundleLoaderFactory extends\n";
  261. s += " ConnectorBundleLoaderFactory {\n";
  262. s += " private Set<String> eagerConnectors = new HashSet<String>();\n";
  263. s += " {\n";
  264. for (String c : usedConnectors) {
  265. s += " eagerConnectors.add(" + c
  266. + ".class.getName());\n";
  267. }
  268. s += " }\n";
  269. s += "\n";
  270. s += " @Override\n";
  271. s += " protected LoadStyle getLoadStyle(JClassType connectorType) {\n";
  272. s += " if (eagerConnectors.contains(connectorType.getQualifiedBinaryName())) {\n";
  273. s += " return LoadStyle.EAGER;\n";
  274. s += " } else {\n";
  275. s += " // Loads all other connectors immediately after the initial view has\n";
  276. s += " // been rendered\n";
  277. s += " return LoadStyle.DEFERRED;\n";
  278. s += " }\n";
  279. s += " }\n";
  280. s += "}\n";
  281. return s;
  282. }
  283. private void analyzeLayouts() {
  284. content.clear();
  285. content.add(new Label("Analyzing layouts..."));
  286. List<ApplicationConnection> runningApplications = ApplicationConfiguration
  287. .getRunningApplications();
  288. for (ApplicationConnection applicationConnection : runningApplications) {
  289. applicationConnection.analyzeLayouts();
  290. }
  291. }
  292. @Override
  293. public void meta(ApplicationConnection ac, ValueMap meta) {
  294. content.clear();
  295. JsArray<ValueMap> valueMapArray = meta
  296. .getJSValueMapArray("invalidLayouts");
  297. int size = valueMapArray.length();
  298. if (size > 0) {
  299. SimpleTree root = new SimpleTree("Layouts analyzed, " + size
  300. + " top level problems");
  301. for (int i = 0; i < size; i++) {
  302. printLayoutError(ac, valueMapArray.get(i), root);
  303. }
  304. root.open(false);
  305. content.add(root);
  306. } else {
  307. content.add(new Label("Layouts analyzed, no top level problems"));
  308. }
  309. Set<ComponentConnector> zeroHeightComponents = new HashSet<ComponentConnector>();
  310. Set<ComponentConnector> zeroWidthComponents = new HashSet<ComponentConnector>();
  311. findZeroSizeComponents(zeroHeightComponents, zeroWidthComponents,
  312. ac.getUIConnector());
  313. if (zeroHeightComponents.size() > 0 || zeroWidthComponents.size() > 0) {
  314. content.add(new HTML("<h4> Client side notifications</h4>"
  315. + " <em>The following relative sized components were "
  316. + "rendered to a zero size container on the client side."
  317. + " Note that these are not necessarily invalid "
  318. + "states, but reported here as they might be.</em>"));
  319. if (zeroHeightComponents.size() > 0) {
  320. content.add(new HTML(
  321. "<p><strong>Vertically zero size:</strong></p>"));
  322. printClientSideDetectedIssues(zeroHeightComponents, ac);
  323. }
  324. if (zeroWidthComponents.size() > 0) {
  325. content.add(new HTML(
  326. "<p><strong>Horizontally zero size:</strong></p>"));
  327. printClientSideDetectedIssues(zeroWidthComponents, ac);
  328. }
  329. }
  330. }
  331. private void printClientSideDetectedIssues(
  332. Set<ComponentConnector> zeroSized, ApplicationConnection ac) {
  333. // keep track of already highlighted parents
  334. HashSet<String> parents = new HashSet<String>();
  335. for (final ComponentConnector connector : zeroSized) {
  336. final ServerConnector parent = connector.getParent();
  337. final String parentId = parent.getConnectorId();
  338. final Label errorDetails = new Label(Util.getSimpleName(connector)
  339. + "[" + connector.getConnectorId() + "]" + " inside "
  340. + Util.getSimpleName(parent));
  341. if (parent instanceof ComponentConnector) {
  342. final ComponentConnector parentConnector = (ComponentConnector) parent;
  343. if (!parents.contains(parentId)) {
  344. parents.add(parentId);
  345. Highlight.show(parentConnector, "yellow");
  346. }
  347. errorDetails.addMouseOverHandler(new MouseOverHandler() {
  348. @Override
  349. public void onMouseOver(MouseOverEvent event) {
  350. Highlight.hideAll();
  351. Highlight.show(parentConnector, "yellow");
  352. Highlight.show(connector);
  353. errorDetails.getElement().getStyle()
  354. .setTextDecoration(TextDecoration.UNDERLINE);
  355. }
  356. });
  357. errorDetails.addMouseOutHandler(new MouseOutHandler() {
  358. @Override
  359. public void onMouseOut(MouseOutEvent event) {
  360. Highlight.hideAll();
  361. errorDetails.getElement().getStyle()
  362. .setTextDecoration(TextDecoration.NONE);
  363. }
  364. });
  365. errorDetails.addClickHandler(new ClickHandler() {
  366. @Override
  367. public void onClick(ClickEvent event) {
  368. printState(connector, true);
  369. }
  370. });
  371. }
  372. Highlight.show(connector);
  373. content.add(errorDetails);
  374. }
  375. }
  376. private void printLayoutError(ApplicationConnection ac, ValueMap valueMap,
  377. SimpleTree root) {
  378. final String pid = valueMap.getString("id");
  379. // find connector
  380. final ComponentConnector connector = (ComponentConnector) ConnectorMap
  381. .get(ac).getConnector(pid);
  382. if (connector == null) {
  383. root.add(new SimpleTree("[" + pid + "] NOT FOUND"));
  384. return;
  385. }
  386. Highlight.show(connector);
  387. final SimpleTree errorNode = new SimpleTree(
  388. Util.getSimpleName(connector) + " id: " + pid);
  389. errorNode.addDomHandler(new MouseOverHandler() {
  390. @Override
  391. public void onMouseOver(MouseOverEvent event) {
  392. Highlight.showOnly(connector);
  393. ((Widget) event.getSource()).getElement().getStyle()
  394. .setTextDecoration(TextDecoration.UNDERLINE);
  395. }
  396. }, MouseOverEvent.getType());
  397. errorNode.addDomHandler(new MouseOutHandler() {
  398. @Override
  399. public void onMouseOut(MouseOutEvent event) {
  400. Highlight.hideAll();
  401. ((Widget) event.getSource()).getElement().getStyle()
  402. .setTextDecoration(TextDecoration.NONE);
  403. }
  404. }, MouseOutEvent.getType());
  405. errorNode.addDomHandler(new ClickHandler() {
  406. @Override
  407. public void onClick(ClickEvent event) {
  408. if (event.getNativeEvent().getEventTarget().cast() == errorNode
  409. .getElement().getChild(1).cast()) {
  410. printState(connector, true);
  411. }
  412. }
  413. }, ClickEvent.getType());
  414. VerticalPanel errorDetails = new VerticalPanel();
  415. if (valueMap.containsKey("heightMsg")) {
  416. errorDetails.add(new Label("Height problem: "
  417. + valueMap.getString("heightMsg")));
  418. }
  419. if (valueMap.containsKey("widthMsg")) {
  420. errorDetails.add(new Label("Width problem: "
  421. + valueMap.getString("widthMsg")));
  422. }
  423. if (errorDetails.getWidgetCount() > 0) {
  424. errorNode.add(errorDetails);
  425. }
  426. if (valueMap.containsKey("subErrors")) {
  427. HTML l = new HTML(
  428. "<em>Expand this node to show problems that may be dependent on this problem.</em>");
  429. errorDetails.add(l);
  430. JsArray<ValueMap> suberrors = valueMap
  431. .getJSValueMapArray("subErrors");
  432. for (int i = 0; i < suberrors.length(); i++) {
  433. ValueMap value = suberrors.get(i);
  434. printLayoutError(ac, value, errorNode);
  435. }
  436. }
  437. root.add(errorNode);
  438. }
  439. private void findZeroSizeComponents(
  440. Set<ComponentConnector> zeroHeightComponents,
  441. Set<ComponentConnector> zeroWidthComponents,
  442. ComponentConnector connector) {
  443. Widget widget = connector.getWidget();
  444. ComputedStyle computedStyle = new ComputedStyle(widget.getElement());
  445. if (computedStyle.getIntProperty("height") == 0) {
  446. zeroHeightComponents.add(connector);
  447. }
  448. if (computedStyle.getIntProperty("width") == 0) {
  449. zeroWidthComponents.add(connector);
  450. }
  451. List<ServerConnector> children = connector.getChildren();
  452. for (ServerConnector serverConnector : children) {
  453. if (serverConnector instanceof ComponentConnector) {
  454. findZeroSizeComponents(zeroHeightComponents,
  455. zeroWidthComponents,
  456. (ComponentConnector) serverConnector);
  457. }
  458. }
  459. }
  460. @Override
  461. public void uidl(ApplicationConnection ac, ValueMap uidl) {
  462. // NOP
  463. }
  464. private boolean isFindMode() {
  465. return (highlightModeRegistration != null);
  466. }
  467. private void toggleFind() {
  468. if (isFindMode()) {
  469. stopFind();
  470. } else {
  471. startFind();
  472. }
  473. }
  474. private void startFind() {
  475. Highlight.hideAll();
  476. if (!isFindMode()) {
  477. highlightModeRegistration = Event
  478. .addNativePreviewHandler(highlightModeHandler);
  479. find.addStyleDependentName(VDebugWindow.STYLENAME_ACTIVE);
  480. }
  481. }
  482. private void stopFind() {
  483. if (isFindMode()) {
  484. highlightModeRegistration.removeHandler();
  485. highlightModeRegistration = null;
  486. find.removeStyleDependentName(VDebugWindow.STYLENAME_ACTIVE);
  487. }
  488. }
  489. private void printState(ServerConnector connector, boolean serverDebug) {
  490. Highlight.showOnly(connector);
  491. if (serverDebug) {
  492. Highlight.showServerDebugInfo(connector);
  493. }
  494. SharedState state = connector.getState();
  495. Set<String> ignoreProperties = new HashSet<String>();
  496. ignoreProperties.add("id");
  497. String html = getRowHTML("Id", connector.getConnectorId());
  498. html += getRowHTML("Connector", Util.getSimpleName(connector));
  499. if (connector instanceof ComponentConnector) {
  500. ComponentConnector component = (ComponentConnector) connector;
  501. ignoreProperties.addAll(Arrays.asList("caption", "description",
  502. "width", "height"));
  503. AbstractComponentState componentState = component.getState();
  504. html += getRowHTML("Widget",
  505. Util.getSimpleName(component.getWidget()));
  506. html += getRowHTML("Caption", componentState.caption);
  507. html += getRowHTML("Description", componentState.description);
  508. html += getRowHTML("Width", componentState.width + " (actual: "
  509. + component.getWidget().getOffsetWidth() + "px)");
  510. html += getRowHTML("Height", componentState.height + " (actual: "
  511. + component.getWidget().getOffsetHeight() + "px)");
  512. }
  513. try {
  514. JsArrayObject<Property> properties = AbstractConnector
  515. .getStateType(connector).getPropertiesAsArray();
  516. for (int i = 0; i < properties.size(); i++) {
  517. Property property = properties.get(i);
  518. String name = property.getName();
  519. if (!ignoreProperties.contains(name)) {
  520. html += getRowHTML(property.getDisplayName(),
  521. property.getValue(state));
  522. }
  523. }
  524. } catch (NoDataException e) {
  525. html += "<div>Could not read state, error has been logged to the console</div>";
  526. VConsole.error(e);
  527. }
  528. content.clear();
  529. content.add(new HTML(html));
  530. }
  531. private String getRowHTML(String caption, Object value) {
  532. return "<div class=\"" + VDebugWindow.STYLENAME
  533. + "-row\"><span class=\"caption\">" + caption
  534. + "</span><span class=\"value\">"
  535. + Util.escapeHTML(String.valueOf(value)) + "</span></div>";
  536. }
  537. private final NativePreviewHandler highlightModeHandler = new NativePreviewHandler() {
  538. @Override
  539. public void onPreviewNativeEvent(NativePreviewEvent event) {
  540. if (event.getTypeInt() == Event.ONKEYDOWN
  541. && event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ESCAPE) {
  542. stopFind();
  543. Highlight.hideAll();
  544. return;
  545. }
  546. if (event.getTypeInt() == Event.ONMOUSEMOVE) {
  547. Highlight.hideAll();
  548. Element eventTarget = Util.getElementFromPoint(event
  549. .getNativeEvent().getClientX(), event.getNativeEvent()
  550. .getClientY());
  551. if (VDebugWindow.get().getElement().isOrHasChild(eventTarget)) {
  552. content.clear();
  553. return;
  554. }
  555. for (ApplicationConnection a : ApplicationConfiguration
  556. .getRunningApplications()) {
  557. ComponentConnector connector = Util.getConnectorForElement(
  558. a, a.getUIConnector().getWidget(), eventTarget);
  559. if (connector == null) {
  560. connector = Util.getConnectorForElement(a,
  561. RootPanel.get(), eventTarget);
  562. }
  563. if (connector != null) {
  564. printState(connector, false);
  565. event.cancel();
  566. event.consume();
  567. event.getNativeEvent().stopPropagation();
  568. return;
  569. }
  570. }
  571. content.clear();
  572. }
  573. if (event.getTypeInt() == Event.ONCLICK) {
  574. Highlight.hideAll();
  575. event.cancel();
  576. event.consume();
  577. event.getNativeEvent().stopPropagation();
  578. stopFind();
  579. Element eventTarget = Util.getElementFromPoint(event
  580. .getNativeEvent().getClientX(), event.getNativeEvent()
  581. .getClientY());
  582. for (ApplicationConnection a : ApplicationConfiguration
  583. .getRunningApplications()) {
  584. ComponentConnector connector = Util.getConnectorForElement(
  585. a, a.getUIConnector().getWidget(), eventTarget);
  586. if (connector == null) {
  587. connector = Util.getConnectorForElement(a,
  588. RootPanel.get(), eventTarget);
  589. }
  590. if (connector != null) {
  591. printState(connector, true);
  592. return;
  593. }
  594. }
  595. }
  596. event.cancel();
  597. }
  598. };
  599. }