com.google.speedtracer.client.visualizations.view.ReportDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.google.speedtracer.client.visualizations.view.ReportDialog.java

Source

/*
 * Copyright 2009 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.speedtracer.client.visualizations.view;

import com.google.gwt.coreext.client.JsIntegerDoubleMap;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.graphics.client.charts.ColorCodedValue;
import com.google.gwt.graphics.client.charts.PieChart;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.topspin.ui.client.ClickEvent;
import com.google.gwt.topspin.ui.client.ClickListener;
import com.google.gwt.topspin.ui.client.Container;
import com.google.gwt.topspin.ui.client.DefaultContainerImpl;
import com.google.gwt.topspin.ui.client.Div;
import com.google.gwt.topspin.ui.client.Root;
import com.google.gwt.topspin.ui.client.Table;
import com.google.speedtracer.client.model.DataDispatcher;
import com.google.speedtracer.client.model.EventRecord;
import com.google.speedtracer.client.timeline.TimeLineModel;
import com.google.speedtracer.client.util.TimeStampFormatter;
import com.google.speedtracer.client.view.HoveringPopup;
import com.google.speedtracer.client.view.SortableTableHeader;
import com.google.speedtracer.client.visualizations.model.HintletReportModel;
import com.google.speedtracer.client.visualizations.model.ReportDataCollector;
import com.google.speedtracer.client.visualizations.model.ReportDataCollector.ReportData;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * A dialog to hold the Speed Tracer performance report for the current
 * selection window, as well as any hints fired within this window.
 */
public class ReportDialog {

    /**
     * CSS.
     */
    public interface Css extends CssResource {
        String glassPane();

        String reportClose();

        String reportPane();

        String reportPaneInner();

        String reportTitle();
    }

    /**
     * Externalized interface.
     */
    public interface Resources extends HintletReport.Resources, ScopeBar.Resources, SortableTableHeader.Resources,
            HoveringPopup.Resources, PieChart.Resources {

        @Source("resources/ReportDialog.css")
        ReportDialog.Css hintletReportDialogCss();

        @Source("resources/close-x-15px.png")
        ImageResource reportClose();
    }

    private final Div glassPane;

    private PieChart pieChart;

    private HintletReport report;

    private final Div reportPane;

    private final Div closeButton;

    private DivElement summaryTitle;

    private final TimeLineModel timelineModel;

    private final ReportDataCollector dataCollector;

    public ReportDialog(TimeLineModel timelineModel, DataDispatcher dataDispatcher,
            ReportDialog.Resources resources) {
        // Initialize locals.
        this.glassPane = new Div(Root.getContainer());
        this.reportPane = new Div(Root.getContainer());
        closeButton = new Div(Root.getContainer());
        this.timelineModel = timelineModel;
        this.dataCollector = new ReportDataCollector(dataDispatcher);

        // Set style names for the base elements.
        final Css css = resources.hintletReportDialogCss();
        glassPane.setStyleName(css.glassPane());
        reportPane.setStyleName(css.reportPane());
        closeButton.setStyleName(css.reportClose());

        // Make sure the dialog is created hidden.
        glassPane.setVisible(false);
        reportPane.setVisible(false);
        closeButton.setVisible(false);

        closeButton.addClickListener(new ClickListener() {
            public void onClick(ClickEvent event) {
                setVisible(false);
            }
        });

        // Build the UI for the report dialog.
        constructReportUi(resources);
    }

    /**
     * Display the report dialog, first refreshing with the latest info.
     */
    public void setVisible(boolean visible) {
        glassPane.setVisible(visible);
        reportPane.setVisible(visible);
        closeButton.setVisible(visible);
        if (visible) {
            gatherDataWithinWindow();
        }
    }

    /**
     * TODO (jaimeyap): This should be moved into the HintletReport class.
     */
    private void buildHintReportScopeBar(ScopeBar.Resources resources, Container container) {
        ScopeBar scopeBar = new ScopeBar(container, resources);
        scopeBar.add("All", new ClickListener() {
            public void onClick(ClickEvent event) {
                report.setType(HintletReport.REPORT_TYPE_TIME);
            }
        });
        scopeBar.add("Rule", new ClickListener() {
            public void onClick(ClickEvent event) {
                report.setType(HintletReport.REPORT_TYPE_RULE);
            }
        });
        Element severity = scopeBar.add("Severity", new ClickListener() {
            public void onClick(ClickEvent event) {
                report.setType(HintletReport.REPORT_TYPE_SEVERITY);
            }
        });
        scopeBar.setSelected(severity, false);
        scopeBar.getElement().getStyle().setPropertyPx("marginBottom", 5);
    }

    private void constructReportUi(Resources resources) {
        Css css = resources.hintletReportDialogCss();
        Container reportPaneContainer = new DefaultContainerImpl(reportPane.getElement());

        // Create a container for the summary information.
        Div summaryInfoDiv = new Div(reportPaneContainer);
        summaryInfoDiv.setStyleName(css.reportPaneInner());
        Container summaryInfoContainer = new DefaultContainerImpl(summaryInfoDiv.getElement());

        // Create the title for the summary information.
        summaryTitle = summaryInfoDiv.getElement().getOwnerDocument().createDivElement();
        summaryTitle.setClassName(css.reportTitle());
        updateSummaryTitle();
        summaryInfoDiv.getElement().appendChild(summaryTitle);

        // Summary info is a 2 column section. PieChart on the left, and the startup
        // statistics on the right.
        Table summaryLayout = new Table(summaryInfoContainer);
        summaryLayout.setFixedLayout(true);
        TableRowElement row = summaryLayout.insertRow(-1);
        row.setVAlign("top");
        TableCellElement leftCell = row.insertCell(-1);
        Container pieChartContainer = new DefaultContainerImpl(leftCell);

        // Create a piechart with no data initially.
        this.pieChart = new PieChart(pieChartContainer, new ArrayList<ColorCodedValue>(), resources);

        // TODO (jaimeyap): Add startup statistics to the right of the pie chart.
        // Things like "time to first paint" or "page load time".

        // Create the inner container to hold to hint report.
        Div hintReportDiv = new Div(reportPaneContainer);
        hintReportDiv.setStyleName(css.reportPaneInner());
        Container hintReportContainer = new DefaultContainerImpl(hintReportDiv.getElement());

        // Create the title for the hint report.
        DivElement hintTitle = hintReportDiv.getElement().getOwnerDocument().createDivElement();
        hintTitle.setInnerText("Hints");
        hintTitle.setClassName(css.reportTitle());
        hintReportDiv.getElement().appendChild(hintTitle);

        // Construct the scope bar for selecting different type of hint reports.
        buildHintReportScopeBar(resources, hintReportContainer);

        // Create the hint report.
        this.report = new HintletReport(hintReportContainer, new HintletReportModel(), resources,
                HintletReport.REPORT_TYPE_SEVERITY);
    }

    private void gatherDataWithinWindow() {
        ReportData data = dataCollector.gatherDataWithinWindow(timelineModel.getLeftBound(),
                timelineModel.getRightBound());

        // Update the report views.
        updateSummaryTitle();
        populatePieChart(data.getAggregatedTypeDurations());
        report.refresh(data.getHints());
    }

    private void populatePieChart(JsIntegerDoubleMap aggregateTypeDurations) {
        final List<ColorCodedValue> data = new ArrayList<ColorCodedValue>();

        assert (aggregateTypeDurations != null);

        // Flatten the aggregate map into a sorted list.
        aggregateTypeDurations.iterate(new JsIntegerDoubleMap.IterationCallBack() {
            public void onIteration(int key, double val) {
                if (val > 0) {
                    String typeName = (key == -1) ? "UI Thread Available" : EventRecord.typeToString(key);
                    typeName += " (" + TimeStampFormatter.format(val) + ")";
                    data.add(new ColorCodedValue(typeName, val, EventRecordColors.getColorForType(key)));
                }
            }
        });

        Collections.sort(data);
        // Update the piechart with this data.
        this.pieChart.setData(data);
        this.pieChart.render();
        this.pieChart.showLegend();
    }

    private void updateSummaryTitle() {
        double left = timelineModel.getLeftBound();
        double right = timelineModel.getRightBound();
        summaryTitle.setInnerText("Summary Report for Selection: " + TimeStampFormatter.format(left) + " - "
                + TimeStampFormatter.format(right) + " (" + TimeStampFormatter.format(right - left) + ")");
    }
}