org.rstudio.studio.client.application.ui.RequestLogVisualization.java Source code

Java tutorial

Introduction

Here is the source code for org.rstudio.studio.client.application.ui.RequestLogVisualization.java

Source

/*
 * 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_;
}