Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

VDebugConsole.java 37KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. /*
  2. * Copyright 2011 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.terminal.gwt.client;
  17. import java.util.Collection;
  18. import java.util.Date;
  19. import java.util.HashSet;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import java.util.Set;
  23. import com.google.gwt.core.client.GWT;
  24. import com.google.gwt.core.client.JsArray;
  25. import com.google.gwt.core.client.Scheduler.ScheduledCommand;
  26. import com.google.gwt.dom.client.Style;
  27. import com.google.gwt.dom.client.Style.FontWeight;
  28. import com.google.gwt.dom.client.Style.Overflow;
  29. import com.google.gwt.dom.client.Style.Position;
  30. import com.google.gwt.dom.client.Style.Unit;
  31. import com.google.gwt.event.dom.client.ClickEvent;
  32. import com.google.gwt.event.dom.client.ClickHandler;
  33. import com.google.gwt.event.dom.client.KeyCodes;
  34. import com.google.gwt.event.dom.client.MouseOutEvent;
  35. import com.google.gwt.event.dom.client.MouseOutHandler;
  36. import com.google.gwt.event.logical.shared.ValueChangeEvent;
  37. import com.google.gwt.event.logical.shared.ValueChangeHandler;
  38. import com.google.gwt.event.shared.HandlerRegistration;
  39. import com.google.gwt.event.shared.UmbrellaException;
  40. import com.google.gwt.http.client.Request;
  41. import com.google.gwt.http.client.RequestBuilder;
  42. import com.google.gwt.http.client.RequestCallback;
  43. import com.google.gwt.http.client.RequestException;
  44. import com.google.gwt.http.client.Response;
  45. import com.google.gwt.http.client.UrlBuilder;
  46. import com.google.gwt.i18n.client.DateTimeFormat;
  47. import com.google.gwt.storage.client.Storage;
  48. import com.google.gwt.user.client.Cookies;
  49. import com.google.gwt.user.client.DOM;
  50. import com.google.gwt.user.client.Element;
  51. import com.google.gwt.user.client.Event;
  52. import com.google.gwt.user.client.Event.NativePreviewEvent;
  53. import com.google.gwt.user.client.Event.NativePreviewHandler;
  54. import com.google.gwt.user.client.EventPreview;
  55. import com.google.gwt.user.client.Window;
  56. import com.google.gwt.user.client.Window.Location;
  57. import com.google.gwt.user.client.ui.Button;
  58. import com.google.gwt.user.client.ui.CheckBox;
  59. import com.google.gwt.user.client.ui.FlowPanel;
  60. import com.google.gwt.user.client.ui.HTML;
  61. import com.google.gwt.user.client.ui.HorizontalPanel;
  62. import com.google.gwt.user.client.ui.Label;
  63. import com.google.gwt.user.client.ui.Panel;
  64. import com.google.gwt.user.client.ui.RootPanel;
  65. import com.google.gwt.user.client.ui.VerticalPanel;
  66. import com.google.gwt.user.client.ui.Widget;
  67. import com.vaadin.shared.Version;
  68. import com.vaadin.terminal.gwt.client.ui.VLazyExecutor;
  69. import com.vaadin.terminal.gwt.client.ui.VOverlay;
  70. import com.vaadin.terminal.gwt.client.ui.notification.VNotification;
  71. import com.vaadin.terminal.gwt.client.ui.root.RootConnector;
  72. import com.vaadin.terminal.gwt.client.ui.window.WindowConnector;
  73. /**
  74. * A helper console for client side development. The debug console can also be
  75. * used to resolve layout issues, inspect the communication between browser and
  76. * the server, start GWT dev mode and restart application.
  77. *
  78. * <p>
  79. * This implementation is used vaadin is in debug mode (see manual) and
  80. * developer appends "?debug" query parameter to url. Debug information can also
  81. * be shown on browsers internal console only, by appending "?debug=quiet" query
  82. * parameter.
  83. * <p>
  84. * This implementation can be overridden with GWT deferred binding.
  85. *
  86. */
  87. public class VDebugConsole extends VOverlay implements Console {
  88. private final class HighlightModeHandler implements NativePreviewHandler {
  89. private final Label label;
  90. private HighlightModeHandler(Label label) {
  91. this.label = label;
  92. }
  93. @Override
  94. public void onPreviewNativeEvent(NativePreviewEvent event) {
  95. if (event.getTypeInt() == Event.ONKEYDOWN
  96. && event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ESCAPE) {
  97. highlightModeRegistration.removeHandler();
  98. VUIDLBrowser.deHiglight();
  99. return;
  100. }
  101. if (event.getTypeInt() == Event.ONMOUSEMOVE) {
  102. VUIDLBrowser.deHiglight();
  103. Element eventTarget = Util.getElementFromPoint(event
  104. .getNativeEvent().getClientX(), event.getNativeEvent()
  105. .getClientY());
  106. if (getElement().isOrHasChild(eventTarget)) {
  107. return;
  108. }
  109. for (ApplicationConnection a : ApplicationConfiguration
  110. .getRunningApplications()) {
  111. ComponentConnector connector = Util.getConnectorForElement(
  112. a, a.getRootConnector().getWidget(), eventTarget);
  113. if (connector == null) {
  114. connector = Util.getConnectorForElement(a,
  115. RootPanel.get(), eventTarget);
  116. }
  117. if (connector != null) {
  118. String pid = connector.getConnectorId();
  119. VUIDLBrowser.highlight(connector);
  120. label.setText("Currently focused :"
  121. + connector.getClass() + " ID:" + pid);
  122. event.cancel();
  123. event.consume();
  124. event.getNativeEvent().stopPropagation();
  125. return;
  126. }
  127. }
  128. }
  129. if (event.getTypeInt() == Event.ONCLICK) {
  130. VUIDLBrowser.deHiglight();
  131. event.cancel();
  132. event.consume();
  133. event.getNativeEvent().stopPropagation();
  134. highlightModeRegistration.removeHandler();
  135. Element eventTarget = Util.getElementFromPoint(event
  136. .getNativeEvent().getClientX(), event.getNativeEvent()
  137. .getClientY());
  138. for (ApplicationConnection a : ApplicationConfiguration
  139. .getRunningApplications()) {
  140. ComponentConnector paintable = Util.getConnectorForElement(
  141. a, a.getRootConnector().getWidget(), eventTarget);
  142. if (paintable == null) {
  143. paintable = Util.getConnectorForElement(a,
  144. RootPanel.get(), eventTarget);
  145. }
  146. if (paintable != null) {
  147. a.highlightComponent(paintable);
  148. return;
  149. }
  150. }
  151. }
  152. event.cancel();
  153. }
  154. }
  155. private static final String POS_COOKIE_NAME = "VDebugConsolePos";
  156. private HandlerRegistration highlightModeRegistration;
  157. Element caption = DOM.createDiv();
  158. private Panel panel;
  159. private Button clear = new Button("C");
  160. private Button restart = new Button("R");
  161. private Button forceLayout = new Button("FL");
  162. private Button analyzeLayout = new Button("AL");
  163. private Button savePosition = new Button("S");
  164. private Button highlight = new Button("H");
  165. private Button connectorStats = new Button("CS");
  166. private CheckBox devMode = new CheckBox("Dev");
  167. private CheckBox superDevMode = new CheckBox("SDev");
  168. private CheckBox autoScroll = new CheckBox("Autoscroll ");
  169. private HorizontalPanel actions;
  170. private boolean collapsed = false;
  171. private boolean resizing;
  172. private int startX;
  173. private int startY;
  174. private int initialW;
  175. private int initialH;
  176. private boolean moving = false;
  177. private int origTop;
  178. private int origLeft;
  179. private static final String help = "Drag title=move, shift-drag=resize, doubleclick title=min/max."
  180. + "Use debug=quiet to log only to browser console.";
  181. private static final int DEFAULT_WIDTH = 650;
  182. private static final int DEFAULT_HEIGHT = 400;
  183. public VDebugConsole() {
  184. super(false, false);
  185. getElement().getStyle().setOverflow(Overflow.HIDDEN);
  186. clear.setTitle("Clear console");
  187. restart.setTitle("Restart app");
  188. forceLayout.setTitle("Force layout");
  189. analyzeLayout.setTitle("Analyze layouts");
  190. savePosition.setTitle("Save pos");
  191. }
  192. private EventPreview dragpreview = new EventPreview() {
  193. @Override
  194. public boolean onEventPreview(Event event) {
  195. onBrowserEvent(event);
  196. return false;
  197. }
  198. };
  199. private boolean quietMode;
  200. @Override
  201. public void onBrowserEvent(Event event) {
  202. super.onBrowserEvent(event);
  203. switch (DOM.eventGetType(event)) {
  204. case Event.ONMOUSEDOWN:
  205. if (DOM.eventGetShiftKey(event)) {
  206. resizing = true;
  207. DOM.setCapture(getElement());
  208. startX = DOM.eventGetScreenX(event);
  209. startY = DOM.eventGetScreenY(event);
  210. initialW = VDebugConsole.this.getOffsetWidth();
  211. initialH = VDebugConsole.this.getOffsetHeight();
  212. DOM.eventCancelBubble(event, true);
  213. DOM.eventPreventDefault(event);
  214. DOM.addEventPreview(dragpreview);
  215. } else if (DOM.eventGetTarget(event) == caption) {
  216. moving = true;
  217. startX = DOM.eventGetScreenX(event);
  218. startY = DOM.eventGetScreenY(event);
  219. origTop = getAbsoluteTop();
  220. origLeft = getAbsoluteLeft();
  221. DOM.eventCancelBubble(event, true);
  222. DOM.eventPreventDefault(event);
  223. DOM.addEventPreview(dragpreview);
  224. }
  225. break;
  226. case Event.ONMOUSEMOVE:
  227. if (resizing) {
  228. int deltaX = startX - DOM.eventGetScreenX(event);
  229. int detalY = startY - DOM.eventGetScreenY(event);
  230. int w = initialW - deltaX;
  231. if (w < 30) {
  232. w = 30;
  233. }
  234. int h = initialH - detalY;
  235. if (h < 40) {
  236. h = 40;
  237. }
  238. VDebugConsole.this.setPixelSize(w, h);
  239. DOM.eventCancelBubble(event, true);
  240. DOM.eventPreventDefault(event);
  241. } else if (moving) {
  242. int deltaX = startX - DOM.eventGetScreenX(event);
  243. int detalY = startY - DOM.eventGetScreenY(event);
  244. int left = origLeft - deltaX;
  245. if (left < 0) {
  246. left = 0;
  247. }
  248. int top = origTop - detalY;
  249. if (top < 0) {
  250. top = 0;
  251. }
  252. VDebugConsole.this.setPopupPosition(left, top);
  253. DOM.eventCancelBubble(event, true);
  254. DOM.eventPreventDefault(event);
  255. }
  256. break;
  257. case Event.ONLOSECAPTURE:
  258. case Event.ONMOUSEUP:
  259. if (resizing) {
  260. DOM.releaseCapture(getElement());
  261. resizing = false;
  262. } else if (moving) {
  263. DOM.releaseCapture(getElement());
  264. moving = false;
  265. }
  266. DOM.removeEventPreview(dragpreview);
  267. break;
  268. case Event.ONDBLCLICK:
  269. if (DOM.eventGetTarget(event) == caption) {
  270. if (collapsed) {
  271. panel.setVisible(true);
  272. setToDefaultSizeAndPos();
  273. } else {
  274. panel.setVisible(false);
  275. setPixelSize(120, 20);
  276. setPopupPosition(Window.getClientWidth() - 125,
  277. Window.getClientHeight() - 25);
  278. }
  279. collapsed = !collapsed;
  280. }
  281. break;
  282. default:
  283. break;
  284. }
  285. }
  286. private void setToDefaultSizeAndPos() {
  287. String cookie = Cookies.getCookie(POS_COOKIE_NAME);
  288. int width, height, top, left;
  289. boolean autoScrollValue = false;
  290. if (cookie != null) {
  291. String[] split = cookie.split(",");
  292. left = Integer.parseInt(split[0]);
  293. top = Integer.parseInt(split[1]);
  294. width = Integer.parseInt(split[2]);
  295. height = Integer.parseInt(split[3]);
  296. autoScrollValue = Boolean.valueOf(split[4]);
  297. } else {
  298. int windowHeight = Window.getClientHeight();
  299. int windowWidth = Window.getClientWidth();
  300. width = DEFAULT_WIDTH;
  301. height = DEFAULT_HEIGHT;
  302. if (height > windowHeight / 2) {
  303. height = windowHeight / 2;
  304. }
  305. if (width > windowWidth / 2) {
  306. width = windowWidth / 2;
  307. }
  308. top = windowHeight - (height + 10);
  309. left = windowWidth - (width + 10);
  310. }
  311. setPixelSize(width, height);
  312. setPopupPosition(left, top);
  313. autoScroll.setValue(autoScrollValue);
  314. }
  315. @Override
  316. public void setPixelSize(int width, int height) {
  317. if (height < 20) {
  318. height = 20;
  319. }
  320. if (width < 2) {
  321. width = 2;
  322. }
  323. panel.setHeight((height - 20) + "px");
  324. panel.setWidth((width - 2) + "px");
  325. getElement().getStyle().setWidth(width, Unit.PX);
  326. }
  327. /*
  328. * (non-Javadoc)
  329. *
  330. * @see com.vaadin.terminal.gwt.client.Console#log(java.lang.String)
  331. */
  332. @Override
  333. public void log(String msg) {
  334. if (msg == null) {
  335. msg = "null";
  336. }
  337. msg = addTimestamp(msg);
  338. // remoteLog(msg);
  339. logToDebugWindow(msg, false);
  340. GWT.log(msg);
  341. consoleLog(msg);
  342. System.out.println(msg);
  343. }
  344. private List<String> msgQueue = new LinkedList<String>();
  345. private ScheduledCommand doSend = new ScheduledCommand() {
  346. @Override
  347. public void execute() {
  348. if (!msgQueue.isEmpty()) {
  349. RequestBuilder requestBuilder = new RequestBuilder(
  350. RequestBuilder.POST, getRemoteLogUrl());
  351. try {
  352. String requestData = "";
  353. for (String str : msgQueue) {
  354. requestData += str;
  355. requestData += "\n";
  356. }
  357. requestBuilder.sendRequest(requestData,
  358. new RequestCallback() {
  359. @Override
  360. public void onResponseReceived(Request request,
  361. Response response) {
  362. // TODO Auto-generated method stub
  363. }
  364. @Override
  365. public void onError(Request request,
  366. Throwable exception) {
  367. // TODO Auto-generated method stub
  368. }
  369. });
  370. } catch (RequestException e) {
  371. // TODO Auto-generated catch block
  372. e.printStackTrace();
  373. }
  374. msgQueue.clear();
  375. }
  376. }
  377. };
  378. private VLazyExecutor sendToRemoteLog = new VLazyExecutor(350, doSend);
  379. protected String getRemoteLogUrl() {
  380. return "http://sun-vehje.local:8080/remotelog/";
  381. }
  382. protected void remoteLog(String msg) {
  383. msgQueue.add(msg);
  384. sendToRemoteLog.trigger();
  385. }
  386. /**
  387. * Logs the given message to the debug window.
  388. *
  389. * @param msg
  390. * The message to log. Must not be null.
  391. */
  392. private void logToDebugWindow(String msg, boolean error) {
  393. Widget row;
  394. if (error) {
  395. row = createErrorHtml(msg);
  396. } else {
  397. row = new HTML(msg);
  398. }
  399. panel.add(row);
  400. if (autoScroll.getValue()) {
  401. row.getElement().scrollIntoView();
  402. }
  403. }
  404. private HTML createErrorHtml(String msg) {
  405. HTML html = new HTML(msg);
  406. html.getElement().getStyle().setColor("#f00");
  407. html.getElement().getStyle().setFontWeight(FontWeight.BOLD);
  408. return html;
  409. }
  410. /*
  411. * (non-Javadoc)
  412. *
  413. * @see com.vaadin.terminal.gwt.client.Console#error(java.lang.String)
  414. */
  415. @Override
  416. public void error(String msg) {
  417. if (msg == null) {
  418. msg = "null";
  419. }
  420. msg = addTimestamp(msg);
  421. logToDebugWindow(msg, true);
  422. GWT.log(msg);
  423. consoleErr(msg);
  424. System.out.println(msg);
  425. }
  426. DateTimeFormat timestampFormat = DateTimeFormat.getFormat("HH:mm:ss:SSS");
  427. @SuppressWarnings("deprecation")
  428. private String addTimestamp(String msg) {
  429. Date date = new Date();
  430. String timestamp = timestampFormat.format(date);
  431. return timestamp + " " + msg;
  432. }
  433. /*
  434. * (non-Javadoc)
  435. *
  436. * @see com.vaadin.terminal.gwt.client.Console#printObject(java.lang.
  437. * Object)
  438. */
  439. @Override
  440. public void printObject(Object msg) {
  441. String str;
  442. if (msg == null) {
  443. str = "null";
  444. } else {
  445. str = msg.toString();
  446. }
  447. panel.add((new Label(str)));
  448. consoleLog(str);
  449. }
  450. /*
  451. * (non-Javadoc)
  452. *
  453. * @see com.vaadin.terminal.gwt.client.Console#dirUIDL(com.vaadin
  454. * .terminal.gwt.client.UIDL)
  455. */
  456. @Override
  457. public void dirUIDL(ValueMap u, ApplicationConnection client) {
  458. if (panel.isAttached()) {
  459. VUIDLBrowser vuidlBrowser = new VUIDLBrowser(u, client);
  460. vuidlBrowser.setText("Response:");
  461. panel.add(vuidlBrowser);
  462. }
  463. consoleDir(u);
  464. // consoleLog(u.getChildrenAsXML());
  465. }
  466. private static native void consoleDir(ValueMap u)
  467. /*-{
  468. if($wnd.console && $wnd.console.log) {
  469. if($wnd.console.dir) {
  470. $wnd.console.dir(u);
  471. } else {
  472. $wnd.console.log(u);
  473. }
  474. }
  475. }-*/;
  476. private static native void consoleLog(String msg)
  477. /*-{
  478. if($wnd.console && $wnd.console.log) {
  479. $wnd.console.log(msg);
  480. }
  481. }-*/;
  482. private static native void consoleErr(String msg)
  483. /*-{
  484. if($wnd.console) {
  485. if ($wnd.console.error)
  486. $wnd.console.error(msg);
  487. else if ($wnd.console.log)
  488. $wnd.console.log(msg);
  489. }
  490. }-*/;
  491. @Override
  492. public void printLayoutProblems(ValueMap meta, ApplicationConnection ac,
  493. Set<ComponentConnector> zeroHeightComponents,
  494. Set<ComponentConnector> zeroWidthComponents) {
  495. JsArray<ValueMap> valueMapArray = meta
  496. .getJSValueMapArray("invalidLayouts");
  497. int size = valueMapArray.length();
  498. panel.add(new HTML("<div>************************</di>"
  499. + "<h4>Layouts analyzed on server, total top level problems: "
  500. + size + " </h4>"));
  501. if (size > 0) {
  502. SimpleTree root = new SimpleTree("Root problems");
  503. for (int i = 0; i < size; i++) {
  504. printLayoutError(valueMapArray.get(i), root, ac);
  505. }
  506. panel.add(root);
  507. }
  508. if (zeroHeightComponents.size() > 0 || zeroWidthComponents.size() > 0) {
  509. panel.add(new HTML("<h4> Client side notifications</h4>"
  510. + " <em>The following relative sized components were "
  511. + "rendered to a zero size container on the client side."
  512. + " Note that these are not necessarily invalid "
  513. + "states, but reported here as they might be.</em>"));
  514. if (zeroHeightComponents.size() > 0) {
  515. panel.add(new HTML(
  516. "<p><strong>Vertically zero size:</strong><p>"));
  517. printClientSideDetectedIssues(zeroHeightComponents, ac);
  518. }
  519. if (zeroWidthComponents.size() > 0) {
  520. panel.add(new HTML(
  521. "<p><strong>Horizontally zero size:</strong><p>"));
  522. printClientSideDetectedIssues(zeroWidthComponents, ac);
  523. }
  524. }
  525. log("************************");
  526. }
  527. private void printClientSideDetectedIssues(
  528. Set<ComponentConnector> zeroHeightComponents,
  529. ApplicationConnection ac) {
  530. for (final ComponentConnector paintable : zeroHeightComponents) {
  531. final ServerConnector parent = paintable.getParent();
  532. VerticalPanel errorDetails = new VerticalPanel();
  533. errorDetails.add(new Label("" + Util.getSimpleName(paintable)
  534. + " inside " + Util.getSimpleName(parent)));
  535. if (parent instanceof ComponentConnector) {
  536. ComponentConnector parentComponent = (ComponentConnector) parent;
  537. final Widget layout = parentComponent.getWidget();
  538. final CheckBox emphasisInUi = new CheckBox(
  539. "Emphasize components parent in UI (the actual component is not visible)");
  540. emphasisInUi.addClickHandler(new ClickHandler() {
  541. @Override
  542. public void onClick(ClickEvent event) {
  543. Element element2 = layout.getElement();
  544. Widget.setStyleName(element2, "invalidlayout",
  545. emphasisInUi.getValue().booleanValue());
  546. }
  547. });
  548. errorDetails.add(emphasisInUi);
  549. }
  550. panel.add(errorDetails);
  551. }
  552. }
  553. private void printLayoutError(ValueMap valueMap, SimpleTree root,
  554. final ApplicationConnection ac) {
  555. final String pid = valueMap.getString("id");
  556. final ComponentConnector paintable = (ComponentConnector) ConnectorMap
  557. .get(ac).getConnector(pid);
  558. SimpleTree errorNode = new SimpleTree();
  559. VerticalPanel errorDetails = new VerticalPanel();
  560. errorDetails.add(new Label(Util.getSimpleName(paintable) + " id: "
  561. + pid));
  562. if (valueMap.containsKey("heightMsg")) {
  563. errorDetails.add(new Label("Height problem: "
  564. + valueMap.getString("heightMsg")));
  565. }
  566. if (valueMap.containsKey("widthMsg")) {
  567. errorDetails.add(new Label("Width problem: "
  568. + valueMap.getString("widthMsg")));
  569. }
  570. final CheckBox emphasisInUi = new CheckBox("Emphasize component in UI");
  571. emphasisInUi.addClickHandler(new ClickHandler() {
  572. @Override
  573. public void onClick(ClickEvent event) {
  574. if (paintable != null) {
  575. Element element2 = paintable.getWidget().getElement();
  576. Widget.setStyleName(element2, "invalidlayout",
  577. emphasisInUi.getValue());
  578. }
  579. }
  580. });
  581. errorDetails.add(emphasisInUi);
  582. errorNode.add(errorDetails);
  583. if (valueMap.containsKey("subErrors")) {
  584. HTML l = new HTML(
  585. "<em>Expand this node to show problems that may be dependent on this problem.</em>");
  586. errorDetails.add(l);
  587. JsArray<ValueMap> suberrors = valueMap
  588. .getJSValueMapArray("subErrors");
  589. for (int i = 0; i < suberrors.length(); i++) {
  590. ValueMap value = suberrors.get(i);
  591. printLayoutError(value, errorNode, ac);
  592. }
  593. }
  594. root.add(errorNode);
  595. }
  596. @Override
  597. public void log(Throwable e) {
  598. if (e instanceof UmbrellaException) {
  599. UmbrellaException ue = (UmbrellaException) e;
  600. for (Throwable t : ue.getCauses()) {
  601. log(t);
  602. }
  603. return;
  604. }
  605. log(Util.getSimpleName(e) + ": " + e.getMessage());
  606. GWT.log(e.getMessage(), e);
  607. }
  608. @Override
  609. public void error(Throwable e) {
  610. handleError(e, this);
  611. }
  612. static void handleError(Throwable e, Console target) {
  613. if (e instanceof UmbrellaException) {
  614. UmbrellaException ue = (UmbrellaException) e;
  615. for (Throwable t : ue.getCauses()) {
  616. target.error(t);
  617. }
  618. return;
  619. }
  620. String exceptionText = Util.getSimpleName(e);
  621. String message = e.getMessage();
  622. if (message != null && message.length() != 0) {
  623. exceptionText += ": " + e.getMessage();
  624. }
  625. target.error(exceptionText);
  626. GWT.log(e.getMessage(), e);
  627. if (!GWT.isProdMode()) {
  628. e.printStackTrace();
  629. }
  630. try {
  631. VNotification.createNotification(VNotification.DELAY_FOREVER).show(
  632. "<h1>Uncaught client side exception</h1><br />"
  633. + exceptionText, VNotification.CENTERED, "error");
  634. } catch (Exception e2) {
  635. // Just swallow this exception
  636. }
  637. }
  638. @Override
  639. public void init() {
  640. panel = new FlowPanel();
  641. if (!quietMode) {
  642. DOM.appendChild(getContainerElement(), caption);
  643. setWidget(panel);
  644. caption.setClassName("v-debug-console-caption");
  645. setStyleName("v-debug-console");
  646. getElement().getStyle().setZIndex(20000);
  647. getElement().getStyle().setOverflow(Overflow.HIDDEN);
  648. sinkEvents(Event.ONDBLCLICK);
  649. sinkEvents(Event.MOUSEEVENTS);
  650. panel.setStyleName("v-debug-console-content");
  651. caption.setInnerHTML("Debug window");
  652. caption.getStyle().setHeight(25, Unit.PX);
  653. caption.setTitle(help);
  654. show();
  655. setToDefaultSizeAndPos();
  656. actions = new HorizontalPanel();
  657. Style style = actions.getElement().getStyle();
  658. style.setPosition(Position.ABSOLUTE);
  659. style.setBackgroundColor("#666");
  660. style.setLeft(135, Unit.PX);
  661. style.setHeight(25, Unit.PX);
  662. style.setTop(0, Unit.PX);
  663. actions.add(clear);
  664. actions.add(restart);
  665. actions.add(forceLayout);
  666. actions.add(analyzeLayout);
  667. actions.add(highlight);
  668. actions.add(connectorStats);
  669. connectorStats.setTitle("Show connector statistics for client");
  670. highlight
  671. .setTitle("Select a component and print details about it to the server log and client side console.");
  672. actions.add(savePosition);
  673. savePosition
  674. .setTitle("Saves the position and size of debug console to a cookie");
  675. actions.add(autoScroll);
  676. addDevMode();
  677. addSuperDevMode();
  678. autoScroll
  679. .setTitle("Automatically scroll so that new messages are visible");
  680. panel.add(actions);
  681. panel.add(new HTML("<i>" + help + "</i>"));
  682. clear.addClickHandler(new ClickHandler() {
  683. @Override
  684. public void onClick(ClickEvent event) {
  685. int width = panel.getOffsetWidth();
  686. int height = panel.getOffsetHeight();
  687. panel = new FlowPanel();
  688. panel.setPixelSize(width, height);
  689. panel.setStyleName("v-debug-console-content");
  690. panel.add(actions);
  691. setWidget(panel);
  692. }
  693. });
  694. restart.addClickHandler(new ClickHandler() {
  695. @Override
  696. public void onClick(ClickEvent event) {
  697. String queryString = Window.Location.getQueryString();
  698. if (queryString != null
  699. && queryString.contains("restartApplications")) {
  700. Window.Location.reload();
  701. } else {
  702. String url = Location.getHref();
  703. String separator = "?";
  704. if (url.contains("?")) {
  705. separator = "&";
  706. }
  707. if (!url.contains("restartApplication")) {
  708. url += separator;
  709. url += "restartApplication";
  710. }
  711. if (!"".equals(Location.getHash())) {
  712. String hash = Location.getHash();
  713. url = url.replace(hash, "") + hash;
  714. }
  715. Window.Location.replace(url);
  716. }
  717. }
  718. });
  719. forceLayout.addClickHandler(new ClickHandler() {
  720. @Override
  721. public void onClick(ClickEvent event) {
  722. for (ApplicationConnection applicationConnection : ApplicationConfiguration
  723. .getRunningApplications()) {
  724. applicationConnection.forceLayout();
  725. }
  726. }
  727. });
  728. analyzeLayout.addClickHandler(new ClickHandler() {
  729. @Override
  730. public void onClick(ClickEvent event) {
  731. List<ApplicationConnection> runningApplications = ApplicationConfiguration
  732. .getRunningApplications();
  733. for (ApplicationConnection applicationConnection : runningApplications) {
  734. applicationConnection.analyzeLayouts();
  735. }
  736. }
  737. });
  738. analyzeLayout
  739. .setTitle("Analyzes currently rendered view and "
  740. + "reports possible common problems in usage of relative sizes."
  741. + "Will cause server visit/rendering of whole screen and loss of"
  742. + " all non committed variables form client side.");
  743. savePosition.addClickHandler(new ClickHandler() {
  744. @Override
  745. public void onClick(ClickEvent event) {
  746. String pos = getAbsoluteLeft() + "," + getAbsoluteTop()
  747. + "," + getOffsetWidth() + "," + getOffsetHeight()
  748. + "," + autoScroll.getValue();
  749. Cookies.setCookie(POS_COOKIE_NAME, pos);
  750. }
  751. });
  752. highlight.addClickHandler(new ClickHandler() {
  753. @Override
  754. public void onClick(ClickEvent event) {
  755. final Label label = new Label("--");
  756. log("<i>Use mouse to select a component or click ESC to exit highlight mode.</i>");
  757. panel.add(label);
  758. highlightModeRegistration = Event
  759. .addNativePreviewHandler(new HighlightModeHandler(
  760. label));
  761. }
  762. });
  763. }
  764. connectorStats.addClickHandler(new ClickHandler() {
  765. @Override
  766. public void onClick(ClickEvent event) {
  767. for (ApplicationConnection a : ApplicationConfiguration
  768. .getRunningApplications()) {
  769. dumpConnectorInfo(a);
  770. }
  771. }
  772. });
  773. log("Starting Vaadin client side engine. Widgetset: "
  774. + GWT.getModuleName());
  775. log("Widget set is built on version: " + Version.getFullVersion());
  776. logToDebugWindow("<div class=\"v-theme-version v-theme-version-"
  777. + Version.getFullVersion().replaceAll("\\.", "_")
  778. + "\">Warning: widgetset version " + Version.getFullVersion()
  779. + " does not seem to match theme version </div>", true);
  780. }
  781. private void addSuperDevMode() {
  782. final Storage sessionStorage = Storage.getSessionStorageIfSupported();
  783. if (sessionStorage == null) {
  784. return;
  785. }
  786. actions.add(superDevMode);
  787. if (Location.getParameter("superdevmode") != null) {
  788. superDevMode.setValue(true);
  789. }
  790. superDevMode.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
  791. @Override
  792. public void onValueChange(ValueChangeEvent<Boolean> event) {
  793. SuperDevMode.redirect(event.getValue());
  794. }
  795. });
  796. }
  797. private void addDevMode() {
  798. actions.add(devMode);
  799. if (Location.getParameter("gwt.codesvr") != null) {
  800. devMode.setValue(true);
  801. }
  802. devMode.addClickHandler(new ClickHandler() {
  803. @Override
  804. public void onClick(ClickEvent event) {
  805. if (devMode.getValue()) {
  806. addHMParameter();
  807. } else {
  808. removeHMParameter();
  809. }
  810. }
  811. private void addHMParameter() {
  812. UrlBuilder createUrlBuilder = Location.createUrlBuilder();
  813. createUrlBuilder.setParameter("gwt.codesvr", "localhost:9997");
  814. Location.assign(createUrlBuilder.buildString());
  815. }
  816. private void removeHMParameter() {
  817. UrlBuilder createUrlBuilder = Location.createUrlBuilder();
  818. createUrlBuilder.removeParameter("gwt.codesvr");
  819. Location.assign(createUrlBuilder.buildString());
  820. }
  821. });
  822. }
  823. protected void dumpConnectorInfo(ApplicationConnection a) {
  824. RootConnector root = a.getRootConnector();
  825. log("================");
  826. log("Connector hierarchy for Root: " + root.getState().getCaption()
  827. + " (" + root.getConnectorId() + ")");
  828. Set<ServerConnector> connectorsInHierarchy = new HashSet<ServerConnector>();
  829. SimpleTree rootHierachy = dumpConnectorHierarchy(root, "",
  830. connectorsInHierarchy);
  831. if (panel.isAttached()) {
  832. rootHierachy.open(true);
  833. panel.add(rootHierachy);
  834. }
  835. ConnectorMap connectorMap = a.getConnectorMap();
  836. Collection<? extends ServerConnector> registeredConnectors = connectorMap
  837. .getConnectors();
  838. log("Sub windows:");
  839. Set<ServerConnector> subWindowHierarchyConnectors = new HashSet<ServerConnector>();
  840. for (WindowConnector wc : root.getSubWindows()) {
  841. SimpleTree windowHierachy = dumpConnectorHierarchy(wc, "",
  842. subWindowHierarchyConnectors);
  843. if (panel.isAttached()) {
  844. windowHierachy.open(true);
  845. panel.add(windowHierachy);
  846. }
  847. }
  848. log("Registered connectors not in hierarchy (should be empty):");
  849. for (ServerConnector registeredConnector : registeredConnectors) {
  850. if (connectorsInHierarchy.contains(registeredConnector)) {
  851. continue;
  852. }
  853. if (subWindowHierarchyConnectors.contains(registeredConnector)) {
  854. continue;
  855. }
  856. error(getConnectorString(registeredConnector));
  857. }
  858. log("Unregistered connectors in hierarchy (should be empty):");
  859. for (ServerConnector hierarchyConnector : connectorsInHierarchy) {
  860. if (!connectorMap.hasConnector(hierarchyConnector.getConnectorId())) {
  861. error(getConnectorString(hierarchyConnector));
  862. }
  863. }
  864. log("================");
  865. }
  866. private SimpleTree dumpConnectorHierarchy(final ServerConnector connector,
  867. String indent, Set<ServerConnector> connectors) {
  868. SimpleTree simpleTree = new SimpleTree(getConnectorString(connector)) {
  869. @Override
  870. protected void select(ClickEvent event) {
  871. super.select(event);
  872. if (connector instanceof ComponentConnector) {
  873. VUIDLBrowser.highlight((ComponentConnector) connector);
  874. }
  875. }
  876. };
  877. simpleTree.addDomHandler(new MouseOutHandler() {
  878. @Override
  879. public void onMouseOut(MouseOutEvent event) {
  880. VUIDLBrowser.deHiglight();
  881. }
  882. }, MouseOutEvent.getType());
  883. connectors.add(connector);
  884. String msg = indent + "* " + getConnectorString(connector);
  885. GWT.log(msg);
  886. consoleLog(msg);
  887. System.out.println(msg);
  888. for (ServerConnector c : connector.getChildren()) {
  889. simpleTree.add(dumpConnectorHierarchy(c, indent + " ", connectors));
  890. }
  891. return simpleTree;
  892. }
  893. private static String getConnectorString(ServerConnector connector) {
  894. return Util.getConnectorString(connector);
  895. }
  896. @Override
  897. public void setQuietMode(boolean quietDebugMode) {
  898. quietMode = quietDebugMode;
  899. }
  900. }