Package com.google.speedtracer.client.visualizations.view

Source Code of com.google.speedtracer.client.visualizations.view.MergeProfilesPanel$ProfileClickListener

/*
* Copyright 2010 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.core.client.GWT;
import com.google.gwt.coreext.client.JSOArray;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
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.Window;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.speedtracer.client.MonitorResources;
import com.google.speedtracer.client.SourceViewer;
import com.google.speedtracer.client.SourceViewerServer;
import com.google.speedtracer.client.SymbolServerController;
import com.google.speedtracer.client.SymbolServerService;
import com.google.speedtracer.client.SourceViewer.SourcePresenter;
import com.google.speedtracer.client.SourceViewer.SourceViewerInitializedCallback;
import com.google.speedtracer.client.SourceViewer.SourceViewerLoadedCallback;
import com.google.speedtracer.client.model.DataDispatcher;
import com.google.speedtracer.client.model.JavaScriptProfile;
import com.google.speedtracer.client.model.JavaScriptProfileModel;
import com.google.speedtracer.client.model.LogEvent;
import com.google.speedtracer.client.model.UiEvent;
import com.google.speedtracer.client.util.Url;
import com.google.speedtracer.client.util.dom.EventListenerOwner;
import com.google.speedtracer.client.view.AutoHideDiv;
import com.google.speedtracer.client.view.HotKeyPanel;

/**
* Offers a UI to allow merging together profiles from different events.
*/
public class MergeProfilesPanel extends HotKeyPanel implements SourcePresenter {
  class MySourceViewerLoadedCallback implements SourceViewerLoadedCallback {
    private int lineNumber;
    private String resourceUrl;

    public MySourceViewerLoadedCallback(String resourceUrl, int lineNumber) {
      this.resourceUrl = resourceUrl;
      this.lineNumber = lineNumber;
    }

    public void onSourceFetchFail(int statusCode, SourceViewer viewer) {
      if (errorDiv == null) {
        errorDiv = new ErrorDiv();
      }
      errorDiv.getElement().getStyle().setPosition(Position.ABSOLUTE);
      errorDiv.getElement().getStyle().setTop(0, Unit.PX);
      errorDiv.getElement().getStyle().setLeft(51, Unit.PX);
      errorDiv.getElement().getStyle().setRight(0, Unit.PX);
      errorDiv.getElement().getStyle().setBackgroundColor("#fbe78c");
      errorDiv.getElement().getStyle().setColor("#000");
      errorDiv.getElement().getStyle().setProperty("border", "1px black solid");
      errorDiv.setText("XHR fetch of " + resourceUrl + "failed with status: "
          + statusCode);
      errorDiv.show();
    }

    public void onSourceViewerLoaded(SourceViewer viewer) {
      // Position the source viewer so that it fills half the
      // details view. Below the table header, and flush with the
      // bottom of the window.
      viewer.getElement().getStyle().setTop(1, Unit.PX);
      // Half the width with a little space for border of the
      // table.
      viewer.getElement().getStyle().setLeft(51, Unit.PCT);
      viewer.getElement().getStyle().setRight(0, Unit.PCT);
      viewer.show();
      viewer.highlightLine(lineNumber);
      viewer.scrollHighlightedLineIntoView();
    }
  }

  interface MyUiBinder extends UiBinder<DivElement, MergeProfilesPanel> {
  }

  private class ErrorDiv extends AutoHideDiv {

    public ErrorDiv() {
      super(new DefaultContainerImpl(elem), 3000);
    }
  }

  private class ProfileClickListener implements ClickListener {
    private final int profileType;
    private final JavaScriptProfileRenderer renderer;

    private ProfileClickListener(JavaScriptProfileRenderer renderer,
        int profileType) {
      this.profileType = profileType;
      this.renderer = renderer;
    }

    public void onClick(ClickEvent clickEvent) {
      renderer.show(profileType);
    }
  }

  private class SearchController implements
      JavaScriptProfileModel.EventProcessor, UiEvent.LeafFirstTraversalVoid {
    private int eventsFound = 0;
    // Transient state that is reset each time we search a UiEvent.
    private boolean found;
    private int logsFound = 0;
    private JSOArray<JavaScriptProfile> matchingProfiles;

    private final String regexp;
    private int sequence;

    private SearchController(String regexp) {
      this.regexp = regexp;
    }

    public void onCompleted() {
      onSearchCompleted(eventsFound, logsFound, matchingProfiles);
    }

    public void process(UiEvent event) {
      eventsFound++;
      if (event.hasUserLogs()) {
        logsFound++;
        seachForMatchingLogs(event);
      }
    }

    public void visit(UiEvent event) {
      if (found) {
        return;
      }

      if (event.getType() == LogEvent.TYPE) {
        final LogEvent log = event.cast();
        if (log.getMessage().matches(regexp)) {
          found = true;
          matchingProfiles.push(dataDispatcher.getJavaScriptProfileModel().getProfileForEvent(
              sequence));
        }
      }
    }

    private void seachForMatchingLogs(UiEvent event) {
      found = false;
      sequence = event.getSequence();
      event.apply(this);
    }
  }

  private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);

  @UiField
  DivElement closeButton;

  @UiField
  InputElement regexpInput;

  @UiField
  DivElement resultsDiv;

  @UiField
  InputElement searchButton;

  private final DataDispatcher dataDispatcher;

  private final Element elem;

  private ErrorDiv errorDiv;

  private boolean inSearch = false;

  private final EventListenerOwner listenerOwner = new EventListenerOwner();

  private final MonitorResources.Resources resources;

  private SourceViewer sourceViewer;

  public MergeProfilesPanel(DataDispatcher dataDispatcher,
      MonitorResources.Resources resources) {
    this.dataDispatcher = dataDispatcher;
    this.resources = resources;
    this.elem = uiBinder.createAndBindUi(this);

    // Wire up the close button.
    ClickEvent.addClickListener(closeButton, closeButton, new ClickListener() {

      public void onClick(ClickEvent event) {
        MergeProfilesPanel.this.hide();
      }
    });

    // Wire up the search button.
    ClickEvent.addClickListener(searchButton, searchButton,
        new ClickListener() {
          public void onClick(ClickEvent event) {
            if (null == regexpInput.getValue()) {
              return;
            }
            search(
                regexpInput.getValue(),
                MergeProfilesPanel.this.dataDispatcher.getJavaScriptProfileModel());
          }
        });
  }

  public void showSource(final String resourceUrl,
      SourceViewerServer sourceViewerServer, final int lineNumber,
      final int column, String absoluteFilePath) {
    if (sourceViewer == null) {
      SourceViewer.create(elem, resources,
          new SourceViewerInitializedCallback() {
            public void onSourceViewerInitialized(SourceViewer viewer) {
              sourceViewer = viewer;
              viewer.loadResource(resourceUrl,
                  new MySourceViewerLoadedCallback(resourceUrl, lineNumber));
            }
          });
    } else {
      sourceViewer.loadResource(resourceUrl, new MySourceViewerLoadedCallback(
          resourceUrl, lineNumber));
    }
  }

  @Override
  protected Element createContentElement(Document document) {
    return elem;
  }

  @Override
  protected void populateContent(Element contentElement) {
    regexpInput.setInnerText("");
    resultsDiv.setInnerText("");
  }

  private SymbolServerController getSymbolServerController() {
    String url = dataDispatcher.getTabDescription().getUrl();
    return SymbolServerService.getSymbolServerController(new Url(url));
  }

  /**
   * Runs after the search completes to create a profile that combine all the
   * found profiles into one, then displays a renderer to display the resulting
   * merge profile.
   */
  private void mergeProfiles(JSOArray<JavaScriptProfile> profiles) {
    JavaScriptProfile profile = new JavaScriptProfile();
    for (int i = 0, length = profiles.size(); i < length; ++i) {
      profile.merge(profiles.get(i));
    }
    Container resultsContainer = new DefaultContainerImpl(resultsDiv);
    ScopeBar bar = new ScopeBar(resultsContainer, resources);

    listenerOwner.removeAllEventListeners();
    JavaScriptProfileRenderer renderer = new JavaScriptProfileRenderer(
        resultsContainer, resources, listenerOwner,
        getSymbolServerController(), this, profile,
        new SourceSymbolClickListener() {

          public void onSymbolClicked(String resourceUrl,
              SourceViewerServer sourceViewerServer, int lineNumber,
              int column, String absoluteFilePath) {
            showSource(resourceUrl, sourceViewerServer, lineNumber, column,
                absoluteFilePath);
          }
        }, null);

    Element flatProfile = bar.add("Flat", new ProfileClickListener(renderer,
        JavaScriptProfile.PROFILE_TYPE_FLAT));
    bar.add("Top Down", new ProfileClickListener(renderer,
        JavaScriptProfile.PROFILE_TYPE_TOP_DOWN));
    bar.add("Bottom Up", new ProfileClickListener(renderer,
        JavaScriptProfile.PROFILE_TYPE_BOTTOM_UP));
    bar.setSelected(flatProfile, true);
  }

  private void onSearchCompleted(int eventCount, int logCount,
      JSOArray<JavaScriptProfile> profiles) {
    inSearch = false;
    resultsDiv.setInnerHTML("<div>Found " + eventCount + " events, " + logCount
        + " log entries, and " + profiles.size() + " matching logs.</div><br/>");
    mergeProfiles(profiles);
  }

  private void search(final String regexp, JavaScriptProfileModel profileModel) {
    if (inSearch) {
      // TODO(knorton): It should not be possible to run a search if one is
      // already running.
      Window.alert("A search is already running.");
      return;
    }
    inSearch = true;

    // TODO(zundel): This is kind of ghetto - put up a spinner or something -
    // this takes a while.
    resultsDiv.setInnerHTML("Searching...");
    profileModel.processEventsWithProfiles(new SearchController(regexp));
  }
}
TOP

Related Classes of com.google.speedtracer.client.visualizations.view.MergeProfilesPanel$ProfileClickListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.