/* @VaadinApache2LicenseForJavaFiles@ */ package com.vaadin.terminal.gwt.client; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.FontWeight; import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.shared.UmbrellaException; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.Response; import com.google.gwt.http.client.UrlBuilder; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.user.client.Cookies; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event.NativePreviewEvent; import com.google.gwt.user.client.Event.NativePreviewHandler; import com.google.gwt.user.client.EventPreview; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window.Location; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Panel; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.ui.VLazyExecutor; import com.vaadin.terminal.gwt.client.ui.VOverlay; import com.vaadin.terminal.gwt.client.ui.notification.VNotification; import com.vaadin.terminal.gwt.client.ui.root.RootConnector; import com.vaadin.terminal.gwt.client.ui.window.WindowConnector; /** * A helper console for client side development. The debug console can also be * used to resolve layout issues, inspect the communication between browser and * the server, start GWT dev mode and restart application. * *
* This implementation is used vaadin is in debug mode (see manual) and * developer appends "?debug" query parameter to url. Debug information can also * be shown on browsers internal console only, by appending "?debug=quiet" query * parameter. *
* This implementation can be overridden with GWT deferred binding.
*
*/
public class VDebugConsole extends VOverlay implements Console {
private final class HighlightModeHandler implements NativePreviewHandler {
private final Label label;
private HighlightModeHandler(Label label) {
this.label = label;
}
public void onPreviewNativeEvent(NativePreviewEvent event) {
if (event.getTypeInt() == Event.ONKEYDOWN
&& event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ESCAPE) {
highlightModeRegistration.removeHandler();
VUIDLBrowser.deHiglight();
return;
}
if (event.getTypeInt() == Event.ONMOUSEMOVE) {
VUIDLBrowser.deHiglight();
Element eventTarget = Util.getElementFromPoint(event
.getNativeEvent().getClientX(), event.getNativeEvent()
.getClientY());
if (getElement().isOrHasChild(eventTarget)) {
return;
}
for (ApplicationConnection a : ApplicationConfiguration
.getRunningApplications()) {
ComponentConnector connector = Util.getConnectorForElement(
a, a.getRootConnector().getWidget(), eventTarget);
if (connector == null) {
connector = Util.getConnectorForElement(a,
RootPanel.get(), eventTarget);
}
if (connector != null) {
String pid = connector.getConnectorId();
VUIDLBrowser.highlight(connector);
label.setText("Currently focused :"
+ connector.getClass() + " ID:" + pid);
event.cancel();
event.consume();
event.getNativeEvent().stopPropagation();
return;
}
}
}
if (event.getTypeInt() == Event.ONCLICK) {
VUIDLBrowser.deHiglight();
event.cancel();
event.consume();
event.getNativeEvent().stopPropagation();
highlightModeRegistration.removeHandler();
Element eventTarget = Util.getElementFromPoint(event
.getNativeEvent().getClientX(), event.getNativeEvent()
.getClientY());
for (ApplicationConnection a : ApplicationConfiguration
.getRunningApplications()) {
ComponentConnector paintable = Util.getConnectorForElement(
a, a.getRootConnector().getWidget(), eventTarget);
if (paintable == null) {
paintable = Util.getConnectorForElement(a,
RootPanel.get(), eventTarget);
}
if (paintable != null) {
a.highlightComponent(paintable);
return;
}
}
}
event.cancel();
}
}
private static final String POS_COOKIE_NAME = "VDebugConsolePos";
private HandlerRegistration highlightModeRegistration;
Element caption = DOM.createDiv();
private Panel panel;
private Button clear = new Button("C");
private Button restart = new Button("R");
private Button forceLayout = new Button("FL");
private Button analyzeLayout = new Button("AL");
private Button savePosition = new Button("S");
private Button highlight = new Button("H");
private Button connectorStats = new Button("CS");
private CheckBox hostedMode = new CheckBox("GWT");
private CheckBox autoScroll = new CheckBox("Autoscroll ");
private HorizontalPanel actions;
private boolean collapsed = false;
private boolean resizing;
private int startX;
private int startY;
private int initialW;
private int initialH;
private boolean moving = false;
private int origTop;
private int origLeft;
private static final String help = "Drag title=move, shift-drag=resize, doubleclick title=min/max."
+ "Use debug=quiet to log only to browser console.";
public VDebugConsole() {
super(false, false);
getElement().getStyle().setOverflow(Overflow.HIDDEN);
clear.setTitle("Clear console");
restart.setTitle("Restart app");
forceLayout.setTitle("Force layout");
analyzeLayout.setTitle("Analyze layouts");
savePosition.setTitle("Save pos");
}
private EventPreview dragpreview = new EventPreview() {
public boolean onEventPreview(Event event) {
onBrowserEvent(event);
return false;
}
};
private boolean quietMode;
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
switch (DOM.eventGetType(event)) {
case Event.ONMOUSEDOWN:
if (DOM.eventGetShiftKey(event)) {
resizing = true;
DOM.setCapture(getElement());
startX = DOM.eventGetScreenX(event);
startY = DOM.eventGetScreenY(event);
initialW = VDebugConsole.this.getOffsetWidth();
initialH = VDebugConsole.this.getOffsetHeight();
DOM.eventCancelBubble(event, true);
DOM.eventPreventDefault(event);
DOM.addEventPreview(dragpreview);
} else if (DOM.eventGetTarget(event) == caption) {
moving = true;
startX = DOM.eventGetScreenX(event);
startY = DOM.eventGetScreenY(event);
origTop = getAbsoluteTop();
origLeft = getAbsoluteLeft();
DOM.eventCancelBubble(event, true);
DOM.eventPreventDefault(event);
DOM.addEventPreview(dragpreview);
}
break;
case Event.ONMOUSEMOVE:
if (resizing) {
int deltaX = startX - DOM.eventGetScreenX(event);
int detalY = startY - DOM.eventGetScreenY(event);
int w = initialW - deltaX;
if (w < 30) {
w = 30;
}
int h = initialH - detalY;
if (h < 40) {
h = 40;
}
VDebugConsole.this.setPixelSize(w, h);
DOM.eventCancelBubble(event, true);
DOM.eventPreventDefault(event);
} else if (moving) {
int deltaX = startX - DOM.eventGetScreenX(event);
int detalY = startY - DOM.eventGetScreenY(event);
int left = origLeft - deltaX;
if (left < 0) {
left = 0;
}
int top = origTop - detalY;
if (top < 0) {
top = 0;
}
VDebugConsole.this.setPopupPosition(left, top);
DOM.eventCancelBubble(event, true);
DOM.eventPreventDefault(event);
}
break;
case Event.ONLOSECAPTURE:
case Event.ONMOUSEUP:
if (resizing) {
DOM.releaseCapture(getElement());
resizing = false;
} else if (moving) {
DOM.releaseCapture(getElement());
moving = false;
}
DOM.removeEventPreview(dragpreview);
break;
case Event.ONDBLCLICK:
if (DOM.eventGetTarget(event) == caption) {
if (collapsed) {
panel.setVisible(true);
setToDefaultSizeAndPos();
} else {
panel.setVisible(false);
setPixelSize(120, 20);
setPopupPosition(Window.getClientWidth() - 125,
Window.getClientHeight() - 25);
}
collapsed = !collapsed;
}
break;
default:
break;
}
}
private void setToDefaultSizeAndPos() {
String cookie = Cookies.getCookie(POS_COOKIE_NAME);
int width, height, top, left;
boolean autoScrollValue = false;
if (cookie != null) {
String[] split = cookie.split(",");
left = Integer.parseInt(split[0]);
top = Integer.parseInt(split[1]);
width = Integer.parseInt(split[2]);
height = Integer.parseInt(split[3]);
autoScrollValue = Boolean.valueOf(split[4]);
} else {
width = 400;
height = 150;
top = Window.getClientHeight() - 160;
left = Window.getClientWidth() - 410;
}
setPixelSize(width, height);
setPopupPosition(left, top);
autoScroll.setValue(autoScrollValue);
}
@Override
public void setPixelSize(int width, int height) {
if (height < 20) {
height = 20;
}
if (width < 2) {
width = 2;
}
panel.setHeight((height - 20) + "px");
panel.setWidth((width - 2) + "px");
getElement().getStyle().setWidth(width, Unit.PX);
}
/*
* (non-Javadoc)
*
* @see com.vaadin.terminal.gwt.client.Console#log(java.lang.String)
*/
public void log(String msg) {
if (msg == null) {
msg = "null";
}
msg = addTimestamp(msg);
// remoteLog(msg);
logToDebugWindow(msg, false);
GWT.log(msg);
consoleLog(msg);
System.out.println(msg);
}
private List Vertically zero size: "));
printClientSideDetectedIssues(zeroHeightComponents, ac);
}
if (zeroWidthComponents.size() > 0) {
panel.add(new HTML(
" Horizontally zero size: "));
printClientSideDetectedIssues(zeroWidthComponents, ac);
}
}
log("************************");
}
private void printClientSideDetectedIssues(
SetLayouts analyzed on server, total top level problems: "
+ size + "
"));
if (size > 0) {
SimpleTree root = new SimpleTree("Root problems");
for (int i = 0; i < size; i++) {
printLayoutError(valueMapArray.get(i), root, ac);
}
panel.add(root);
}
if (zeroHeightComponents.size() > 0 || zeroWidthComponents.size() > 0) {
panel.add(new HTML(" Client side notifications
"
+ " The following relative sized components were "
+ "rendered to a zero size container on the client side."
+ " Note that these are not necessarily invalid "
+ "states, but reported here as they might be."));
if (zeroHeightComponents.size() > 0) {
panel.add(new HTML(
"Uncaught client side exception
"
+ exceptionText, VNotification.CENTERED, "error");
} catch (Exception e2) {
// Just swallow this exception
}
}
public void init() {
panel = new FlowPanel();
if (!quietMode) {
DOM.appendChild(getContainerElement(), caption);
setWidget(panel);
caption.setClassName("v-debug-console-caption");
setStyleName("v-debug-console");
getElement().getStyle().setZIndex(20000);
getElement().getStyle().setOverflow(Overflow.HIDDEN);
sinkEvents(Event.ONDBLCLICK);
sinkEvents(Event.MOUSEEVENTS);
panel.setStyleName("v-debug-console-content");
caption.setInnerHTML("Debug window");
caption.getStyle().setHeight(25, Unit.PX);
caption.setTitle(help);
show();
setToDefaultSizeAndPos();
actions = new HorizontalPanel();
Style style = actions.getElement().getStyle();
style.setPosition(Position.ABSOLUTE);
style.setBackgroundColor("#666");
style.setLeft(135, Unit.PX);
style.setHeight(25, Unit.PX);
style.setTop(0, Unit.PX);
actions.add(clear);
actions.add(restart);
actions.add(forceLayout);
actions.add(analyzeLayout);
actions.add(highlight);
actions.add(connectorStats);
connectorStats.setTitle("Show connector statistics for client");
highlight
.setTitle("Select a component and print details about it to the server log and client side console.");
actions.add(savePosition);
savePosition
.setTitle("Saves the position and size of debug console to a cookie");
actions.add(autoScroll);
actions.add(hostedMode);
if (Location.getParameter("gwt.codesvr") != null) {
hostedMode.setValue(true);
}
hostedMode.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
if (hostedMode.getValue()) {
addHMParameter();
} else {
removeHMParameter();
}
}
private void addHMParameter() {
UrlBuilder createUrlBuilder = Location.createUrlBuilder();
createUrlBuilder.setParameter("gwt.codesvr",
"localhost:9997");
Location.assign(createUrlBuilder.buildString());
}
private void removeHMParameter() {
UrlBuilder createUrlBuilder = Location.createUrlBuilder();
createUrlBuilder.removeParameter("gwt.codesvr");
Location.assign(createUrlBuilder.buildString());
}
});
autoScroll
.setTitle("Automatically scroll so that new messages are visible");
panel.add(actions);
panel.add(new HTML("" + help + ""));
clear.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
int width = panel.getOffsetWidth();
int height = panel.getOffsetHeight();
panel = new FlowPanel();
panel.setPixelSize(width, height);
panel.setStyleName("v-debug-console-content");
panel.add(actions);
setWidget(panel);
}
});
restart.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
String queryString = Window.Location.getQueryString();
if (queryString != null
&& queryString.contains("restartApplications")) {
Window.Location.reload();
} else {
String url = Location.getHref();
String separator = "?";
if (url.contains("?")) {
separator = "&";
}
if (!url.contains("restartApplication")) {
url += separator;
url += "restartApplication";
}
if (!"".equals(Location.getHash())) {
String hash = Location.getHash();
url = url.replace(hash, "") + hash;
}
Window.Location.replace(url);
}
}
});
forceLayout.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
for (ApplicationConnection applicationConnection : ApplicationConfiguration
.getRunningApplications()) {
applicationConnection.forceLayout();
}
}
});
analyzeLayout.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
List