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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.client;
  5. import java.util.List;
  6. import java.util.Set;
  7. import com.google.gwt.core.client.JsArray;
  8. import com.google.gwt.dom.client.Style.FontWeight;
  9. import com.google.gwt.event.dom.client.ClickEvent;
  10. import com.google.gwt.event.dom.client.ClickHandler;
  11. import com.google.gwt.user.client.DOM;
  12. import com.google.gwt.user.client.Element;
  13. import com.google.gwt.user.client.Event;
  14. import com.google.gwt.user.client.EventPreview;
  15. import com.google.gwt.user.client.Window;
  16. import com.google.gwt.user.client.Window.Location;
  17. import com.google.gwt.user.client.ui.Button;
  18. import com.google.gwt.user.client.ui.CheckBox;
  19. import com.google.gwt.user.client.ui.FlowPanel;
  20. import com.google.gwt.user.client.ui.HTML;
  21. import com.google.gwt.user.client.ui.HorizontalPanel;
  22. import com.google.gwt.user.client.ui.Label;
  23. import com.google.gwt.user.client.ui.Panel;
  24. import com.google.gwt.user.client.ui.Tree;
  25. import com.google.gwt.user.client.ui.TreeItem;
  26. import com.google.gwt.user.client.ui.VerticalPanel;
  27. import com.google.gwt.user.client.ui.Widget;
  28. import com.vaadin.terminal.gwt.client.ui.VOverlay;
  29. public final class VDebugConsole extends VOverlay implements Console {
  30. /**
  31. * Builds number. For example 0-custom_tag in 5.0.0-custom_tag.
  32. */
  33. public static final String VERSION;
  34. /* Initialize version numbers from string replaced by build-script. */
  35. static {
  36. if ("@VERSION@".equals("@" + "VERSION" + "@")) {
  37. VERSION = "9.9.9.INTERNAL-DEBUG-BUILD";
  38. } else {
  39. VERSION = "@VERSION@";
  40. }
  41. }
  42. Element caption = DOM.createDiv();
  43. private Panel panel;
  44. private Button clear = new Button("Clear console");
  45. private Button restart = new Button("Restart app");
  46. private Button forceLayout = new Button("Force layout");
  47. private Button analyzeLayout = new Button("Analyze layouts");
  48. private HorizontalPanel actions;
  49. private boolean collapsed = false;
  50. private boolean resizing;
  51. private int startX;
  52. private int startY;
  53. private int initialW;
  54. private int initialH;
  55. private boolean moving = false;
  56. private int origTop;
  57. private int origLeft;
  58. private ApplicationConnection client;
  59. private ApplicationConfiguration conf;
  60. private static final String help = "Drag=move, shift-drag=resize, doubleclick=min/max."
  61. + "Use debug=quiet to log only to browser console.";
  62. public VDebugConsole(ApplicationConnection client,
  63. ApplicationConfiguration cnf, boolean showWindow) {
  64. super(false, false);
  65. this.client = client;
  66. conf = cnf;
  67. panel = new FlowPanel();
  68. if (showWindow) {
  69. DOM.appendChild(getContainerElement(), caption);
  70. setWidget(panel);
  71. caption.setClassName("v-debug-console-caption");
  72. setStyleName("v-debug-console");
  73. DOM.setStyleAttribute(getElement(), "zIndex", 20000 + "");
  74. DOM.setStyleAttribute(getElement(), "overflow", "hidden");
  75. sinkEvents(Event.ONDBLCLICK);
  76. sinkEvents(Event.MOUSEEVENTS);
  77. panel.setStyleName("v-debug-console-content");
  78. caption.setInnerHTML("Debug window");
  79. caption.setTitle(help);
  80. show();
  81. minimize();
  82. actions = new HorizontalPanel();
  83. actions.add(clear);
  84. actions.add(restart);
  85. actions.add(forceLayout);
  86. actions.add(analyzeLayout);
  87. panel.add(actions);
  88. panel.add(new HTML("<i>" + help + "</i>"));
  89. clear.addClickHandler(new ClickHandler() {
  90. public void onClick(ClickEvent event) {
  91. int width = panel.getOffsetWidth();
  92. int height = panel.getOffsetHeight();
  93. panel = new FlowPanel();
  94. panel.setPixelSize(width, height);
  95. panel.setStyleName("v-debug-console-content");
  96. panel.add(actions);
  97. setWidget(panel);
  98. }
  99. });
  100. restart.addClickHandler(new ClickHandler() {
  101. public void onClick(ClickEvent event) {
  102. String queryString = Window.Location.getQueryString();
  103. if (queryString != null
  104. && queryString.contains("restartApplications")) {
  105. Window.Location.reload();
  106. } else {
  107. String url = Location.getHref();
  108. String separator = "?";
  109. if (url.contains("?")) {
  110. separator = "&";
  111. }
  112. if (!url.contains("restartApplication")) {
  113. url += separator;
  114. url += "restartApplication";
  115. }
  116. if (!"".equals(Location.getHash())) {
  117. String hash = Location.getHash();
  118. url = url.replace(hash, "") + hash;
  119. }
  120. Window.Location.replace(url);
  121. }
  122. }
  123. });
  124. forceLayout.addClickHandler(new ClickHandler() {
  125. public void onClick(ClickEvent event) {
  126. VDebugConsole.this.client.forceLayout();
  127. }
  128. });
  129. analyzeLayout.addClickHandler(new ClickHandler() {
  130. public void onClick(ClickEvent event) {
  131. List<ApplicationConnection> runningApplications = ApplicationConfiguration
  132. .getRunningApplications();
  133. for (ApplicationConnection applicationConnection : runningApplications) {
  134. applicationConnection.analyzeLayouts();
  135. }
  136. }
  137. });
  138. analyzeLayout
  139. .setTitle("Analyzes currently rendered view and "
  140. + "reports possible common problems in usage of relative sizes."
  141. + "Will cause server visit/rendering of whole screen + lose of"
  142. + " all non committed variables form client side.");
  143. }
  144. log("Vaadin application servlet version: " + cnf.getServletVersion());
  145. log("Widget set is built on version: " + VERSION);
  146. log("Application version: " + cnf.getApplicationVersion());
  147. if (!cnf.getServletVersion().equals(VERSION)) {
  148. error("Warning: your widget set seems to be built with a different "
  149. + "version than the one used on server. Unexpected "
  150. + "behavior may occur.");
  151. }
  152. logToDebugWindow("<div class=\"v-theme-version v-theme-version-"
  153. + VERSION.replaceAll("\\.", "_")
  154. + "\">Warning: widgetset version " + VERSION
  155. + " does not seem to match theme version </div>", true);
  156. }
  157. private EventPreview dragpreview = new EventPreview() {
  158. public boolean onEventPreview(Event event) {
  159. onBrowserEvent(event);
  160. return false;
  161. }
  162. };
  163. @Override
  164. public void onBrowserEvent(Event event) {
  165. super.onBrowserEvent(event);
  166. switch (DOM.eventGetType(event)) {
  167. case Event.ONMOUSEDOWN:
  168. if (DOM.eventGetShiftKey(event)) {
  169. resizing = true;
  170. DOM.setCapture(getElement());
  171. startX = DOM.eventGetScreenX(event);
  172. startY = DOM.eventGetScreenY(event);
  173. initialW = VDebugConsole.this.getOffsetWidth();
  174. initialH = VDebugConsole.this.getOffsetHeight();
  175. DOM.eventCancelBubble(event, true);
  176. DOM.eventPreventDefault(event);
  177. DOM.addEventPreview(dragpreview);
  178. } else if (DOM.eventGetTarget(event) == caption) {
  179. moving = true;
  180. startX = DOM.eventGetScreenX(event);
  181. startY = DOM.eventGetScreenY(event);
  182. origTop = getAbsoluteTop();
  183. origLeft = getAbsoluteLeft();
  184. DOM.eventCancelBubble(event, true);
  185. DOM.eventPreventDefault(event);
  186. DOM.addEventPreview(dragpreview);
  187. }
  188. break;
  189. case Event.ONMOUSEMOVE:
  190. if (resizing) {
  191. int deltaX = startX - DOM.eventGetScreenX(event);
  192. int detalY = startY - DOM.eventGetScreenY(event);
  193. int w = initialW - deltaX;
  194. if (w < 30) {
  195. w = 30;
  196. }
  197. int h = initialH - detalY;
  198. if (h < 40) {
  199. h = 40;
  200. }
  201. VDebugConsole.this.setPixelSize(w, h);
  202. DOM.eventCancelBubble(event, true);
  203. DOM.eventPreventDefault(event);
  204. } else if (moving) {
  205. int deltaX = startX - DOM.eventGetScreenX(event);
  206. int detalY = startY - DOM.eventGetScreenY(event);
  207. int left = origLeft - deltaX;
  208. if (left < 0) {
  209. left = 0;
  210. }
  211. int top = origTop - detalY;
  212. if (top < 0) {
  213. top = 0;
  214. }
  215. VDebugConsole.this.setPopupPosition(left, top);
  216. DOM.eventCancelBubble(event, true);
  217. DOM.eventPreventDefault(event);
  218. }
  219. break;
  220. case Event.ONLOSECAPTURE:
  221. case Event.ONMOUSEUP:
  222. if (resizing) {
  223. DOM.releaseCapture(getElement());
  224. resizing = false;
  225. } else if (moving) {
  226. DOM.releaseCapture(getElement());
  227. moving = false;
  228. }
  229. DOM.removeEventPreview(dragpreview);
  230. break;
  231. case Event.ONDBLCLICK:
  232. if (DOM.eventGetTarget(event) == caption) {
  233. if (collapsed) {
  234. panel.setVisible(true);
  235. setPixelSize(220, 300);
  236. } else {
  237. panel.setVisible(false);
  238. setPixelSize(120, 20);
  239. }
  240. collapsed = !collapsed;
  241. }
  242. break;
  243. default:
  244. break;
  245. }
  246. }
  247. private void minimize() {
  248. setPixelSize(400, 150);
  249. setPopupPosition(Window.getClientWidth() - 410,
  250. Window.getClientHeight() - 160);
  251. }
  252. @Override
  253. public void setPixelSize(int width, int height) {
  254. panel.setHeight((height - 20) + "px");
  255. panel.setWidth((width - 2) + "px");
  256. }
  257. /*
  258. * (non-Javadoc)
  259. *
  260. * @see com.vaadin.terminal.gwt.client.Console#log(java.lang.String)
  261. */
  262. public void log(String msg) {
  263. if (msg == null) {
  264. msg = "null";
  265. }
  266. logToDebugWindow(msg, false);
  267. System.out.println(msg);
  268. consoleLog(msg);
  269. }
  270. /**
  271. * Logs the given message to the debug window.
  272. *
  273. * @param msg
  274. * The message to log. Must not be null.
  275. */
  276. private void logToDebugWindow(String msg, boolean error) {
  277. if (error) {
  278. panel.add(createErrorHtml(msg));
  279. } else {
  280. panel.add(new HTML(msg));
  281. }
  282. }
  283. private HTML createErrorHtml(String msg) {
  284. HTML html = new HTML(msg);
  285. html.getElement().getStyle().setColor("#f00");
  286. html.getElement().getStyle().setFontWeight(FontWeight.BOLD);
  287. return html;
  288. }
  289. /*
  290. * (non-Javadoc)
  291. *
  292. * @see com.vaadin.terminal.gwt.client.Console#error(java.lang.String)
  293. */
  294. public void error(String msg) {
  295. if (msg == null) {
  296. msg = "null";
  297. }
  298. logToDebugWindow(msg, true);
  299. System.err.println(msg);
  300. consoleErr(msg);
  301. }
  302. /*
  303. * (non-Javadoc)
  304. *
  305. * @see com.vaadin.terminal.gwt.client.Console#printObject(java.lang.
  306. * Object)
  307. */
  308. public void printObject(Object msg) {
  309. String str;
  310. if (msg == null) {
  311. str = "null";
  312. } else {
  313. str = msg.toString();
  314. }
  315. panel.add((new Label(str)));
  316. consoleLog(str);
  317. }
  318. /*
  319. * (non-Javadoc)
  320. *
  321. * @see com.vaadin.terminal.gwt.client.Console#dirUIDL(com.vaadin
  322. * .terminal.gwt.client.UIDL)
  323. */
  324. public void dirUIDL(UIDL u) {
  325. if (panel.isAttached()) {
  326. panel.add(new VUIDLBrowser(u, conf));
  327. }
  328. consoleDir(u);
  329. // consoleLog(u.getChildrenAsXML());
  330. }
  331. private static native void consoleDir(UIDL u)
  332. /*-{
  333. if($wnd.console && $wnd.console.log) {
  334. if($wnd.console.dir) {
  335. $wnd.console.dir(u);
  336. } else {
  337. $wnd.console.log(u);
  338. }
  339. }
  340. }-*/;
  341. private static native void consoleLog(String msg)
  342. /*-{
  343. if($wnd.console && $wnd.console.log) {
  344. $wnd.console.log(msg);
  345. }
  346. }-*/;
  347. private static native void consoleErr(String msg)
  348. /*-{
  349. if($wnd.console) {
  350. if ($wnd.console.error)
  351. $wnd.console.error(msg);
  352. else if ($wnd.console.log)
  353. $wnd.console.log(msg);
  354. }
  355. }-*/;
  356. public void printLayoutProblems(ValueMap meta, ApplicationConnection ac,
  357. Set<Paintable> zeroHeightComponents,
  358. Set<Paintable> zeroWidthComponents) {
  359. JsArray<ValueMap> valueMapArray = meta
  360. .getJSValueMapArray("invalidLayouts");
  361. int size = valueMapArray.length();
  362. panel.add(new HTML("<div>************************</di>"
  363. + "<h4>Layouts analyzed on server, total top level problems: "
  364. + size + " </h4>"));
  365. if (size > 0) {
  366. Tree tree = new Tree();
  367. // Position relative does not work here in IE7
  368. DOM.setStyleAttribute(tree.getElement(), "position", "");
  369. TreeItem root = new TreeItem("Root problems");
  370. for (int i = 0; i < size; i++) {
  371. printLayoutError(valueMapArray.get(i), root, ac);
  372. }
  373. panel.add(tree);
  374. tree.addItem(root);
  375. }
  376. if (zeroHeightComponents.size() > 0 || zeroWidthComponents.size() > 0) {
  377. panel.add(new HTML("<h4> Client side notifications</h4>"
  378. + " <em>Following relative sized components where "
  379. + "rendered to zero size container on client side."
  380. + " Note that these are not necessary invalid "
  381. + "states. Just reported here as they might be.</em>"));
  382. if (zeroHeightComponents.size() > 0) {
  383. panel.add(new HTML(
  384. "<p><strong>Vertically zero size:</strong><p>"));
  385. printClientSideDetectedIssues(zeroHeightComponents, ac);
  386. }
  387. if (zeroWidthComponents.size() > 0) {
  388. panel.add(new HTML(
  389. "<p><strong>Horizontally zero size:</strong><p>"));
  390. printClientSideDetectedIssues(zeroWidthComponents, ac);
  391. }
  392. }
  393. log("************************");
  394. }
  395. private void printClientSideDetectedIssues(
  396. Set<Paintable> zeroHeightComponents, ApplicationConnection ac) {
  397. for (final Paintable paintable : zeroHeightComponents) {
  398. final Container layout = Util.getLayout((Widget) paintable);
  399. VerticalPanel errorDetails = new VerticalPanel();
  400. errorDetails.add(new Label("" + Util.getSimpleName(paintable)
  401. + " inside " + Util.getSimpleName(layout)));
  402. final CheckBox emphasisInUi = new CheckBox(
  403. "Emphasis components parent in UI (actual component is not visible)");
  404. emphasisInUi.addClickHandler(new ClickHandler() {
  405. public void onClick(ClickEvent event) {
  406. if (paintable != null) {
  407. Element element2 = ((Widget) layout).getElement();
  408. Widget.setStyleName(element2, "invalidlayout",
  409. emphasisInUi.getValue());
  410. }
  411. }
  412. });
  413. errorDetails.add(emphasisInUi);
  414. panel.add(errorDetails);
  415. }
  416. }
  417. private void printLayoutError(ValueMap valueMap, TreeItem parent,
  418. final ApplicationConnection ac) {
  419. final String pid = valueMap.getString("id");
  420. final Paintable paintable = ac.getPaintable(pid);
  421. TreeItem errorNode = new TreeItem();
  422. VerticalPanel errorDetails = new VerticalPanel();
  423. errorDetails.add(new Label(Util.getSimpleName(paintable) + " id: "
  424. + pid));
  425. if (valueMap.containsKey("heightMsg")) {
  426. errorDetails.add(new Label("Height problem: "
  427. + valueMap.getString("heightMsg")));
  428. }
  429. if (valueMap.containsKey("widthMsg")) {
  430. errorDetails.add(new Label("Width problem: "
  431. + valueMap.getString("widthMsg")));
  432. }
  433. final CheckBox emphasisInUi = new CheckBox("Emphasis component in UI");
  434. emphasisInUi.addClickHandler(new ClickHandler() {
  435. public void onClick(ClickEvent event) {
  436. if (paintable != null) {
  437. Element element2 = ((Widget) paintable).getElement();
  438. Widget.setStyleName(element2, "invalidlayout",
  439. emphasisInUi.getValue());
  440. }
  441. }
  442. });
  443. errorDetails.add(emphasisInUi);
  444. errorNode.setWidget(errorDetails);
  445. if (valueMap.containsKey("subErrors")) {
  446. HTML l = new HTML(
  447. "<em>Expand this node to show problems that may be dependent on this problem.</em>");
  448. errorDetails.add(l);
  449. JsArray<ValueMap> suberrors = valueMap
  450. .getJSValueMapArray("subErrors");
  451. for (int i = 0; i < suberrors.length(); i++) {
  452. ValueMap value = suberrors.get(i);
  453. printLayoutError(value, errorNode, ac);
  454. }
  455. }
  456. parent.addItem(errorNode);
  457. }
  458. }