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 36KB

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