Java tutorial
/* * RequestLogVisualization.java * * Copyright (C) 2009-12 by RStudio, Inc. * * Unless you have received this program directly from RStudio pursuant * to the terms of a commercial license agreement with RStudio, then * this program is licensed to you under the terms of version 3 of the * GNU Affero General Public License. This program is distributed WITHOUT * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. * */ package org.rstudio.studio.client.application.ui; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Style.Cursor; import com.google.gwt.dom.client.Style.FontWeight; import com.google.gwt.dom.client.Style.Overflow; 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.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.event.logical.shared.HasCloseHandlers; import com.google.gwt.event.shared.HandlerRegistration; 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.Timer; import com.google.gwt.user.client.ui.*; import org.rstudio.core.client.CsvReader; import org.rstudio.core.client.CsvWriter; import org.rstudio.core.client.command.KeyboardShortcut; import org.rstudio.core.client.jsonrpc.RequestLog; import org.rstudio.core.client.jsonrpc.RequestLogEntry; import org.rstudio.core.client.jsonrpc.RequestLogEntry.ResponseType; import org.rstudio.core.client.widget.ModalDialog; import org.rstudio.core.client.widget.OperationWithInput; import org.rstudio.core.client.widget.ScrollPanelWithClick; import java.util.ArrayList; import java.util.Iterator; public class RequestLogVisualization extends Composite implements HasCloseHandlers<RequestLogVisualization>, NativePreviewHandler { private class TextBoxDialog extends ModalDialog<String> { private TextBoxDialog(String caption, String initialValue, OperationWithInput<String> operation) { super(caption, operation); textArea_ = new TextArea(); textArea_.setSize("400px", "300px"); textArea_.setText(initialValue); } @Override protected String collectInput() { return textArea_.getText(); } @Override protected boolean validate(String input) { return true; } @Override protected Widget createMainWidget() { return textArea_; } private final TextArea textArea_; } public RequestLogVisualization() { overviewPanel_ = new LayoutPanel(); overviewPanel_.getElement().getStyle().setProperty("borderRight", "2px dashed #888"); scrollPanel_ = new ScrollPanelWithClick(overviewPanel_); scrollPanel_.setSize("100%", "100%"); scrollPanel_.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { detail_.setWidget(instructions_); } }); SplitLayoutPanel outerPanel = new SplitLayoutPanel(); outerPanel.getElement().getStyle().setBackgroundColor("white"); outerPanel.getElement().getStyle().setZIndex(500); outerPanel.getElement().getStyle().setOpacity(0.9); detail_ = new SimplePanel(); detail_.getElement().getStyle().setBackgroundColor("#FFE"); instructions_ = new HTML(); instructions_.setHTML("<p>Click on a request to see details. Click on the " + "background to show these instructions again.</p>" + "<h4>Available commands:</h4>" + "<ul>" + "<li>Esc: Close</li>" + "<li>P: Play/pause</li>" + "<li>E: Export</li>" + "<li>I: Import</li>" + "<li>+/-: Zoom in/out</li>" + "</ul>"); detail_.setWidget(instructions_); outerPanel.addSouth(detail_, 200); outerPanel.add(scrollPanel_); initWidget(outerPanel); handlerRegistration_ = Event.addNativePreviewHandler(this); timer_ = new Timer() { @Override public void run() { refresh(true, false); } }; refresh(true, true); } @Override protected void onUnload() { timer_.cancel(); super.onUnload(); } private void refresh(boolean reloadEntries, boolean scrollToEnd) { if (reloadEntries) { entries_ = RequestLog.getEntries(); now_ = System.currentTimeMillis(); } overviewPanel_.clear(); startTime_ = entries_[0].getRequestTime(); long duration = now_ - startTime_; int totalWidth = (int) (duration * scaleMillisToPixels_); totalHeight_ = entries_.length * BAR_HEIGHT; overviewPanel_.setSize(totalWidth + "px", totalHeight_ + "px"); for (int i = 0, entriesLength = entries_.length; i < entriesLength; i++) { RequestLogEntry entry = entries_[i]; addEntry(i, entry); } if (scrollToEnd) { scrollPanel_.scrollToTop(); scrollPanel_.scrollToRight(); } } @Override protected void onLoad() { super.onLoad(); Scheduler.get().scheduleDeferred(new ScheduledCommand() { public void execute() { scrollPanel_.scrollToTop(); scrollPanel_.scrollToRight(); } }); } private void addEntry(int i, final RequestLogEntry entry) { int top = totalHeight_ - (i + 1) * BAR_HEIGHT; int left = (int) ((entry.getRequestTime() - startTime_) * scaleMillisToPixels_); long endTime = entry.getResponseTime() != null ? entry.getResponseTime() : now_; int right = Math.max(0, (int) ((now_ - endTime) * scaleMillisToPixels_) - 1); boolean active = entry.getResponseType() == ResponseType.None; HTML html = new HTML(); html.getElement().getStyle().setOverflow(Overflow.VISIBLE); html.getElement().getStyle().setProperty("whiteSpace", "nowrap"); html.setText(entry.getRequestMethodName() + (active ? " (active)" : "")); if (active) html.getElement().getStyle().setFontWeight(FontWeight.BOLD); String color; switch (entry.getResponseType()) { case ResponseType.Error: color = "red"; break; case ResponseType.None: color = "#f99"; break; case ResponseType.Normal: color = "#88f"; break; case ResponseType.Cancelled: color = "#E0E0E0"; break; case ResponseType.Unknown: default: color = "yellow"; break; } html.getElement().getStyle().setBackgroundColor(color); html.getElement().getStyle().setCursor(Cursor.POINTER); html.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { event.stopPropagation(); detail_.clear(); RequestLogDetail entryDetail = new RequestLogDetail(entry); entryDetail.setSize("100%", "100%"); detail_.setWidget(entryDetail); } }); overviewPanel_.add(html); overviewPanel_.setWidgetTopHeight(html, top, Unit.PX, BAR_HEIGHT, Unit.PX); overviewPanel_.setWidgetLeftRight(html, left, Unit.PX, right, Unit.PX); overviewPanel_.getWidgetContainerElement(html).getStyle().setOverflow(Overflow.VISIBLE); } public HandlerRegistration addCloseHandler(CloseHandler<RequestLogVisualization> handler) { return addHandler(handler, CloseEvent.getType()); } public void onPreviewNativeEvent(NativePreviewEvent event) { if (event.getTypeInt() == Event.ONKEYDOWN) { int keyCode = event.getNativeEvent().getKeyCode(); if (keyCode == KeyCodes.KEY_ESCAPE) { CloseEvent.fire(RequestLogVisualization.this, RequestLogVisualization.this); handlerRegistration_.removeHandler(); } else if (keyCode == 'R' && KeyboardShortcut.getModifierValue(event.getNativeEvent()) == 0) { refresh(true, true); } else if (keyCode == 'P') { if (timerIsRunning_) timer_.cancel(); else { timer_.run(); timer_.scheduleRepeating(PERIOD_MILLIS); } timerIsRunning_ = !timerIsRunning_; } else if (keyCode == 'E') { CsvWriter writer = new CsvWriter(); writer.writeValue(now_ + ""); writer.endLine(); for (RequestLogEntry entry : entries_) entry.toCsv(writer); TextBoxDialog dialog = new TextBoxDialog("Export", writer.getValue(), null); dialog.showModal(); } else if (keyCode == 'I') { TextBoxDialog dialog = new TextBoxDialog("Import", "", new OperationWithInput<String>() { public void execute(String input) { CsvReader reader = new CsvReader(input); ArrayList<RequestLogEntry> entries = new ArrayList<RequestLogEntry>(); Iterator<String[]> it = reader.iterator(); String now = it.next()[0]; while (it.hasNext()) { String[] line = it.next(); RequestLogEntry entry = RequestLogEntry.fromValues(line); if (entry != null) entries.add(entry); } now_ = Long.parseLong(now); entries_ = entries.toArray(new RequestLogEntry[0]); refresh(false, true); } }); dialog.showModal(); } } else if (event.getTypeInt() == Event.ONKEYPRESS) { if (event.getNativeEvent().getKeyCode() == '+') { scaleMillisToPixels_ *= 2.0; refresh(false, false); } else if (event.getNativeEvent().getKeyCode() == '-') { scaleMillisToPixels_ /= 2.0; refresh(false, false); } } } private static final int BAR_HEIGHT = 15; private double scaleMillisToPixels_ = 0.02; private long now_; private RequestLogEntry[] entries_; private int totalHeight_; private LayoutPanel overviewPanel_; private long startTime_; private ScrollPanelWithClick scrollPanel_; private HandlerRegistration handlerRegistration_; private Timer timer_; private boolean timerIsRunning_; private static final int PERIOD_MILLIS = 2000; private SimplePanel detail_; private HTML instructions_; }