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.

VDebugConsole.java 37KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. /*
  2. * Copyright 2000-2013 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;
  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.client.ui.VLazyExecutor;
  68. import com.vaadin.client.ui.VNotification;
  69. import com.vaadin.client.ui.VOverlay;
  70. import com.vaadin.client.ui.ui.UIConnector;
  71. import com.vaadin.client.ui.window.WindowConnector;
  72. import com.vaadin.shared.Version;
  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.getUIConnector().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.getUIConnector().getWidget(), eventTarget);
  142. if (paintable == null) {
  143. paintable = Util.getConnectorForElement(a,
  144. RootPanel.get(), eventTarget);
  145. }
  146. if (paintable != null) {
  147. a.highlightConnector(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.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.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.client.Console#printObject(java.lang. Object)
  437. */
  438. @Override
  439. public void printObject(Object msg) {
  440. String str;
  441. if (msg == null) {
  442. str = "null";
  443. } else {
  444. str = msg.toString();
  445. }
  446. panel.add((new Label(str)));
  447. consoleLog(str);
  448. }
  449. /*
  450. * (non-Javadoc)
  451. *
  452. * @see com.vaadin.client.Console#dirUIDL(com.vaadin.client.UIDL)
  453. */
  454. @Override
  455. public void dirUIDL(ValueMap u, ApplicationConnection client) {
  456. if (panel.isAttached()) {
  457. VUIDLBrowser vuidlBrowser = new VUIDLBrowser(u, client);
  458. vuidlBrowser.setText("Response:");
  459. panel.add(vuidlBrowser);
  460. }
  461. consoleDir(u);
  462. // consoleLog(u.getChildrenAsXML());
  463. }
  464. /**
  465. * Adds a {@link SimpleTree} to the console and prints a string
  466. * representation of the tree structure to the text console.
  467. *
  468. * @param tree
  469. * the simple tree to display in the console window
  470. * @param stringRepresentation
  471. * the string representation of the tree to output to the text
  472. * console
  473. */
  474. public void showTree(SimpleTree tree, String stringRepresentation) {
  475. if (panel.isAttached()) {
  476. panel.add(tree);
  477. }
  478. consoleLog(stringRepresentation);
  479. }
  480. private static native void consoleDir(ValueMap u)
  481. /*-{
  482. if($wnd.console && $wnd.console.log) {
  483. if($wnd.console.dir) {
  484. $wnd.console.dir(u);
  485. } else {
  486. $wnd.console.log(u);
  487. }
  488. }
  489. }-*/;
  490. private static native void consoleLog(String msg)
  491. /*-{
  492. if($wnd.console && $wnd.console.log) {
  493. $wnd.console.log(msg);
  494. }
  495. }-*/;
  496. private static native void consoleErr(String msg)
  497. /*-{
  498. if($wnd.console) {
  499. if ($wnd.console.error)
  500. $wnd.console.error(msg);
  501. else if ($wnd.console.log)
  502. $wnd.console.log(msg);
  503. }
  504. }-*/;
  505. @Override
  506. public void printLayoutProblems(ValueMap meta, ApplicationConnection ac,
  507. Set<ComponentConnector> zeroHeightComponents,
  508. Set<ComponentConnector> zeroWidthComponents) {
  509. JsArray<ValueMap> valueMapArray = meta
  510. .getJSValueMapArray("invalidLayouts");
  511. int size = valueMapArray.length();
  512. panel.add(new HTML("<div>************************</di>"
  513. + "<h4>Layouts analyzed on server, total top level problems: "
  514. + size + " </h4>"));
  515. if (size > 0) {
  516. SimpleTree root = new SimpleTree("Root problems");
  517. for (int i = 0; i < size; i++) {
  518. printLayoutError(valueMapArray.get(i), root, ac);
  519. }
  520. panel.add(root);
  521. }
  522. if (zeroHeightComponents.size() > 0 || zeroWidthComponents.size() > 0) {
  523. panel.add(new HTML("<h4> Client side notifications</h4>"
  524. + " <em>The following relative sized components were "
  525. + "rendered to a zero size container on the client side."
  526. + " Note that these are not necessarily invalid "
  527. + "states, but reported here as they might be.</em>"));
  528. if (zeroHeightComponents.size() > 0) {
  529. panel.add(new HTML(
  530. "<p><strong>Vertically zero size:</strong><p>"));
  531. printClientSideDetectedIssues(zeroHeightComponents, ac);
  532. }
  533. if (zeroWidthComponents.size() > 0) {
  534. panel.add(new HTML(
  535. "<p><strong>Horizontally zero size:</strong><p>"));
  536. printClientSideDetectedIssues(zeroWidthComponents, ac);
  537. }
  538. }
  539. log("************************");
  540. }
  541. private void printClientSideDetectedIssues(
  542. Set<ComponentConnector> zeroHeightComponents,
  543. ApplicationConnection ac) {
  544. for (final ComponentConnector paintable : zeroHeightComponents) {
  545. final ServerConnector parent = paintable.getParent();
  546. VerticalPanel errorDetails = new VerticalPanel();
  547. errorDetails.add(new Label("" + Util.getSimpleName(paintable)
  548. + " inside " + Util.getSimpleName(parent)));
  549. if (parent instanceof ComponentConnector) {
  550. ComponentConnector parentComponent = (ComponentConnector) parent;
  551. final Widget layout = parentComponent.getWidget();
  552. final CheckBox emphasisInUi = new CheckBox(
  553. "Emphasize components parent in UI (the actual component is not visible)");
  554. emphasisInUi.addClickHandler(new ClickHandler() {
  555. @Override
  556. public void onClick(ClickEvent event) {
  557. Element element2 = layout.getElement();
  558. Widget.setStyleName(element2, "invalidlayout",
  559. emphasisInUi.getValue().booleanValue());
  560. }
  561. });
  562. errorDetails.add(emphasisInUi);
  563. }
  564. panel.add(errorDetails);
  565. }
  566. }
  567. private void printLayoutError(ValueMap valueMap, SimpleTree root,
  568. final ApplicationConnection ac) {
  569. final String pid = valueMap.getString("id");
  570. final ComponentConnector paintable = (ComponentConnector) ConnectorMap
  571. .get(ac).getConnector(pid);
  572. SimpleTree errorNode = new SimpleTree();
  573. VerticalPanel errorDetails = new VerticalPanel();
  574. errorDetails.add(new Label(Util.getSimpleName(paintable) + " id: "
  575. + pid));
  576. if (valueMap.containsKey("heightMsg")) {
  577. errorDetails.add(new Label("Height problem: "
  578. + valueMap.getString("heightMsg")));
  579. }
  580. if (valueMap.containsKey("widthMsg")) {
  581. errorDetails.add(new Label("Width problem: "
  582. + valueMap.getString("widthMsg")));
  583. }
  584. final CheckBox emphasisInUi = new CheckBox("Emphasize component in UI");
  585. emphasisInUi.addClickHandler(new ClickHandler() {
  586. @Override
  587. public void onClick(ClickEvent event) {
  588. if (paintable != null) {
  589. Element element2 = paintable.getWidget().getElement();
  590. Widget.setStyleName(element2, "invalidlayout",
  591. emphasisInUi.getValue());
  592. }
  593. }
  594. });
  595. errorDetails.add(emphasisInUi);
  596. errorNode.add(errorDetails);
  597. if (valueMap.containsKey("subErrors")) {
  598. HTML l = new HTML(
  599. "<em>Expand this node to show problems that may be dependent on this problem.</em>");
  600. errorDetails.add(l);
  601. JsArray<ValueMap> suberrors = valueMap
  602. .getJSValueMapArray("subErrors");
  603. for (int i = 0; i < suberrors.length(); i++) {
  604. ValueMap value = suberrors.get(i);
  605. printLayoutError(value, errorNode, ac);
  606. }
  607. }
  608. root.add(errorNode);
  609. }
  610. @Override
  611. public void log(Throwable e) {
  612. if (e instanceof UmbrellaException) {
  613. UmbrellaException ue = (UmbrellaException) e;
  614. for (Throwable t : ue.getCauses()) {
  615. log(t);
  616. }
  617. return;
  618. }
  619. log(Util.getSimpleName(e) + ": " + e.getMessage());
  620. GWT.log(e.getMessage(), e);
  621. }
  622. @Override
  623. public void error(Throwable e) {
  624. handleError(e, this);
  625. }
  626. static void handleError(Throwable e, Console target) {
  627. if (e instanceof UmbrellaException) {
  628. UmbrellaException ue = (UmbrellaException) e;
  629. for (Throwable t : ue.getCauses()) {
  630. target.error(t);
  631. }
  632. return;
  633. }
  634. String exceptionText = Util.getSimpleName(e);
  635. String message = e.getMessage();
  636. if (message != null && message.length() != 0) {
  637. exceptionText += ": " + e.getMessage();
  638. }
  639. target.error(exceptionText);
  640. GWT.log(e.getMessage(), e);
  641. if (!GWT.isProdMode()) {
  642. e.printStackTrace();
  643. }
  644. try {
  645. Widget owner = null;
  646. if (!ApplicationConfiguration.getRunningApplications().isEmpty()) {
  647. // Make a wild guess and use the first available
  648. // ApplicationConnection. This is better than than leaving the
  649. // exception completely unstyled...
  650. ApplicationConnection connection = ApplicationConfiguration
  651. .getRunningApplications().get(0);
  652. owner = connection.getUIConnector().getWidget();
  653. }
  654. VNotification
  655. .createNotification(VNotification.DELAY_FOREVER, owner)
  656. .show("<h1>Uncaught client side exception</h1><br />"
  657. + exceptionText, VNotification.CENTERED, "error");
  658. } catch (Exception e2) {
  659. // Just swallow this exception
  660. }
  661. }
  662. @Override
  663. public void init() {
  664. panel = new FlowPanel();
  665. if (!quietMode) {
  666. DOM.appendChild(getContainerElement(), caption);
  667. setWidget(panel);
  668. caption.setClassName("v-debug-console-caption");
  669. setStyleName("v-debug-console");
  670. getElement().getStyle().setZIndex(20000);
  671. getElement().getStyle().setOverflow(Overflow.HIDDEN);
  672. sinkEvents(Event.ONDBLCLICK);
  673. sinkEvents(Event.MOUSEEVENTS);
  674. panel.setStyleName("v-debug-console-content");
  675. caption.setInnerHTML("Debug window");
  676. caption.getStyle().setHeight(25, Unit.PX);
  677. caption.setTitle(help);
  678. show();
  679. setToDefaultSizeAndPos();
  680. actions = new HorizontalPanel();
  681. Style style = actions.getElement().getStyle();
  682. style.setPosition(Position.ABSOLUTE);
  683. style.setBackgroundColor("#666");
  684. style.setLeft(135, Unit.PX);
  685. style.setHeight(25, Unit.PX);
  686. style.setTop(0, Unit.PX);
  687. actions.add(clear);
  688. actions.add(restart);
  689. actions.add(forceLayout);
  690. actions.add(analyzeLayout);
  691. actions.add(highlight);
  692. actions.add(connectorStats);
  693. connectorStats.setTitle("Show connector statistics for client");
  694. highlight
  695. .setTitle("Select a component and print details about it to the server log and client side console.");
  696. actions.add(savePosition);
  697. savePosition
  698. .setTitle("Saves the position and size of debug console to a cookie");
  699. actions.add(autoScroll);
  700. addDevMode();
  701. addSuperDevMode();
  702. autoScroll
  703. .setTitle("Automatically scroll so that new messages are visible");
  704. panel.add(actions);
  705. panel.add(new HTML("<i>" + help + "</i>"));
  706. clear.addClickHandler(new ClickHandler() {
  707. @Override
  708. public void onClick(ClickEvent event) {
  709. int width = panel.getOffsetWidth();
  710. int height = panel.getOffsetHeight();
  711. panel = new FlowPanel();
  712. panel.setPixelSize(width, height);
  713. panel.setStyleName("v-debug-console-content");
  714. panel.add(actions);
  715. setWidget(panel);
  716. }
  717. });
  718. restart.addClickHandler(new ClickHandler() {
  719. @Override
  720. public void onClick(ClickEvent event) {
  721. String queryString = Window.Location.getQueryString();
  722. if (queryString != null
  723. && queryString.contains("restartApplications")) {
  724. Window.Location.reload();
  725. } else {
  726. String url = Location.getHref();
  727. String separator = "?";
  728. if (url.contains("?")) {
  729. separator = "&";
  730. }
  731. if (!url.contains("restartApplication")) {
  732. url += separator;
  733. url += "restartApplication";
  734. }
  735. if (!"".equals(Location.getHash())) {
  736. String hash = Location.getHash();
  737. url = url.replace(hash, "") + hash;
  738. }
  739. Window.Location.replace(url);
  740. }
  741. }
  742. });
  743. forceLayout.addClickHandler(new ClickHandler() {
  744. @Override
  745. public void onClick(ClickEvent event) {
  746. for (ApplicationConnection applicationConnection : ApplicationConfiguration
  747. .getRunningApplications()) {
  748. applicationConnection.forceLayout();
  749. }
  750. }
  751. });
  752. analyzeLayout.addClickHandler(new ClickHandler() {
  753. @Override
  754. public void onClick(ClickEvent event) {
  755. List<ApplicationConnection> runningApplications = ApplicationConfiguration
  756. .getRunningApplications();
  757. for (ApplicationConnection applicationConnection : runningApplications) {
  758. applicationConnection.analyzeLayouts();
  759. }
  760. }
  761. });
  762. analyzeLayout
  763. .setTitle("Analyzes currently rendered view and "
  764. + "reports possible common problems in usage of relative sizes."
  765. + "Will cause server visit/rendering of whole screen and loss of"
  766. + " all non committed variables form client side.");
  767. savePosition.addClickHandler(new ClickHandler() {
  768. @Override
  769. public void onClick(ClickEvent event) {
  770. String pos = getAbsoluteLeft() + "," + getAbsoluteTop()
  771. + "," + getOffsetWidth() + "," + getOffsetHeight()
  772. + "," + autoScroll.getValue();
  773. Cookies.setCookie(POS_COOKIE_NAME, pos);
  774. }
  775. });
  776. highlight.addClickHandler(new ClickHandler() {
  777. @Override
  778. public void onClick(ClickEvent event) {
  779. final Label label = new Label("--");
  780. log("<i>Use mouse to select a component or click ESC to exit highlight mode.</i>");
  781. panel.add(label);
  782. highlightModeRegistration = Event
  783. .addNativePreviewHandler(new HighlightModeHandler(
  784. label));
  785. }
  786. });
  787. }
  788. connectorStats.addClickHandler(new ClickHandler() {
  789. @Override
  790. public void onClick(ClickEvent event) {
  791. for (ApplicationConnection a : ApplicationConfiguration
  792. .getRunningApplications()) {
  793. dumpConnectorInfo(a);
  794. }
  795. }
  796. });
  797. log("Starting Vaadin client side engine. Widgetset: "
  798. + GWT.getModuleName());
  799. log("Widget set is built on version: " + Version.getFullVersion());
  800. logToDebugWindow("<div class=\"v-theme-version v-theme-version-"
  801. + Version.getFullVersion().replaceAll("\\.", "_")
  802. + "\">Warning: widgetset version " + Version.getFullVersion()
  803. + " does not seem to match theme version </div>", true);
  804. }
  805. private void addSuperDevMode() {
  806. final Storage sessionStorage = Storage.getSessionStorageIfSupported();
  807. if (sessionStorage == null) {
  808. return;
  809. }
  810. actions.add(superDevMode);
  811. if (Location.getParameter("superdevmode") != null) {
  812. superDevMode.setValue(true);
  813. }
  814. superDevMode.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
  815. @Override
  816. public void onValueChange(ValueChangeEvent<Boolean> event) {
  817. SuperDevMode.redirect(event.getValue());
  818. }
  819. });
  820. }
  821. private void addDevMode() {
  822. actions.add(devMode);
  823. if (Location.getParameter("gwt.codesvr") != null) {
  824. devMode.setValue(true);
  825. }
  826. devMode.addClickHandler(new ClickHandler() {
  827. @Override
  828. public void onClick(ClickEvent event) {
  829. if (devMode.getValue()) {
  830. addHMParameter();
  831. } else {
  832. removeHMParameter();
  833. }
  834. }
  835. private void addHMParameter() {
  836. UrlBuilder createUrlBuilder = Location.createUrlBuilder();
  837. createUrlBuilder.setParameter("gwt.codesvr", "localhost:9997");
  838. Location.assign(createUrlBuilder.buildString());
  839. }
  840. private void removeHMParameter() {
  841. UrlBuilder createUrlBuilder = Location.createUrlBuilder();
  842. createUrlBuilder.removeParameter("gwt.codesvr");
  843. Location.assign(createUrlBuilder.buildString());
  844. }
  845. });
  846. }
  847. protected void dumpConnectorInfo(ApplicationConnection a) {
  848. UIConnector root = a.getUIConnector();
  849. log("================");
  850. log("Connector hierarchy for Root: " + root.getState().caption + " ("
  851. + root.getConnectorId() + ")");
  852. Set<ServerConnector> connectorsInHierarchy = new HashSet<ServerConnector>();
  853. SimpleTree rootHierachy = dumpConnectorHierarchy(root, "",
  854. connectorsInHierarchy);
  855. if (panel.isAttached()) {
  856. rootHierachy.open(true);
  857. panel.add(rootHierachy);
  858. }
  859. ConnectorMap connectorMap = a.getConnectorMap();
  860. Collection<? extends ServerConnector> registeredConnectors = connectorMap
  861. .getConnectors();
  862. log("Sub windows:");
  863. Set<ServerConnector> subWindowHierarchyConnectors = new HashSet<ServerConnector>();
  864. for (WindowConnector wc : root.getSubWindows()) {
  865. SimpleTree windowHierachy = dumpConnectorHierarchy(wc, "",
  866. subWindowHierarchyConnectors);
  867. if (panel.isAttached()) {
  868. windowHierachy.open(true);
  869. panel.add(windowHierachy);
  870. }
  871. }
  872. log("Registered connectors not in hierarchy (should be empty):");
  873. for (ServerConnector registeredConnector : registeredConnectors) {
  874. if (connectorsInHierarchy.contains(registeredConnector)) {
  875. continue;
  876. }
  877. if (subWindowHierarchyConnectors.contains(registeredConnector)) {
  878. continue;
  879. }
  880. error(getConnectorString(registeredConnector));
  881. }
  882. log("Unregistered connectors in hierarchy (should be empty):");
  883. for (ServerConnector hierarchyConnector : connectorsInHierarchy) {
  884. if (!connectorMap.hasConnector(hierarchyConnector.getConnectorId())) {
  885. error(getConnectorString(hierarchyConnector));
  886. }
  887. }
  888. log("================");
  889. }
  890. private SimpleTree dumpConnectorHierarchy(final ServerConnector connector,
  891. String indent, Set<ServerConnector> connectors) {
  892. SimpleTree simpleTree = new SimpleTree(getConnectorString(connector)) {
  893. @Override
  894. protected void select(ClickEvent event) {
  895. super.select(event);
  896. if (connector instanceof ComponentConnector) {
  897. VUIDLBrowser.highlight((ComponentConnector) connector);
  898. }
  899. }
  900. };
  901. simpleTree.addDomHandler(new MouseOutHandler() {
  902. @Override
  903. public void onMouseOut(MouseOutEvent event) {
  904. VUIDLBrowser.deHiglight();
  905. }
  906. }, MouseOutEvent.getType());
  907. connectors.add(connector);
  908. String msg = indent + "* " + getConnectorString(connector);
  909. GWT.log(msg);
  910. consoleLog(msg);
  911. System.out.println(msg);
  912. for (ServerConnector c : connector.getChildren()) {
  913. simpleTree.add(dumpConnectorHierarchy(c, indent + " ", connectors));
  914. }
  915. return simpleTree;
  916. }
  917. private static String getConnectorString(ServerConnector connector) {
  918. return Util.getConnectorString(connector);
  919. }
  920. @Override
  921. public void setQuietMode(boolean quietDebugMode) {
  922. quietMode = quietDebugMode;
  923. }
  924. }