/* * Copyright 2011 Facebook, 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.facebook.tsdb.tsdash.client.presenter; import java.util.ArrayList; import com.facebook.tsdb.tsdash.client.event.ErrorEvent; import com.facebook.tsdb.tsdash.client.event.GraphEvent; import com.facebook.tsdb.tsdash.client.event.MetricHeaderEvent; import com.facebook.tsdb.tsdash.client.event.StateChangeEvent; import com.facebook.tsdb.tsdash.client.event.StateChangeHandler; import com.facebook.tsdb.tsdash.client.model.ApplicationState; import com.facebook.tsdb.tsdash.client.model.MetricHeader; import com.facebook.tsdb.tsdash.client.model.ApplicationState.TimeMode; import com.facebook.tsdb.tsdash.client.plot.ImagePlot; import com.facebook.tsdb.tsdash.client.plot.InteractivePlot; import com.facebook.tsdb.tsdash.client.plot.Plot; import com.facebook.tsdb.tsdash.client.service.HTTPService; import com.facebook.tsdb.tsdash.client.ui.CssHelper; import com.google.gwt.event.logical.shared.AttachEvent; import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; public class GraphPresenter implements Presenter { public interface GraphWidget { HasWidgets container(); public void setDumpJSON(String jsonDump); void setReplacementVisible(boolean visible); } private final HandlerManager eventBus; private final HTTPService service; private final GraphWidget widget; private Plot plot; private final ImagePlot imagePlot; private final InteractivePlot interactivePlot; private boolean initialized = false; public GraphPresenter(HandlerManager eventBus, HTTPService service, GraphWidget widget) { this.eventBus = eventBus; this.service = service; this.widget = widget; imagePlot = new ImagePlot(eventBus, widget.container()); interactivePlot = new InteractivePlot(eventBus, widget.container()); listenApplicatioStateChange(); } private void resetDimensions(ApplicationState appState) { Widget w = (Widget) widget.container(); w.setHeight(estimateHeight(appState) + "px"); w.setWidth(estimateWidth(appState) + "px"); } private void renderPlot(ApplicationState appState) { if (!appState.hasPlot()) { return; } widget.setReplacementVisible(false); if (appState.timeMode == TimeMode.HISTORY) { appState.timeRange = appState.getAndUpdateTimeRange(); } eventBus.fireEvent(new GraphEvent(GraphEvent.Action.LOADING_DATA)); // mass-disable any input CssHelper.toggleClass(RootPanel.get(), "inputdisabled"); // launch the load-and-render plot.loadAndRender(appState.timeRange, appState.metrics, service, new AsyncCallback<ArrayList<MetricHeader>>() { @Override public void onFailure(Throwable caught) { // fire error event eventBus.fireEvent(new ErrorEvent(caught)); // stop the loading eventBus.fireEvent(new GraphEvent( GraphEvent.Action.LOADED)); // mass re-enable the input elements CssHelper.toggleClass(RootPanel.get(), "inputdisabled"); } @Override public void onSuccess(ArrayList<MetricHeader> headers) { eventBus.fireEvent(new GraphEvent( GraphEvent.Action.LOADED)); CssHelper.toggleClass(RootPanel.get(), "inputdisabled"); // do the refresh eventBus.fireEvent(new MetricHeaderEvent(headers)); } }, new Command() { @Override public void execute() { eventBus.fireEvent(new GraphEvent( GraphEvent.Action.START_RENDERING)); } }); } private void listenApplicatioStateChange() { eventBus.addHandler(StateChangeEvent.TYPE, new StateChangeHandler() { @Override public void onViewChange(StateChangeEvent event) { // ignore } @Override public void onMetricChange(StateChangeEvent event) { renderPlot(event.getAppState()); } @Override public void onTimeChange(StateChangeEvent event) { renderPlot(event.getAppState()); } @Override public void onPlotParamsChange(StateChangeEvent event) { ApplicationState appState = event.getAppState(); Plot newPlot = appState.interactive ? interactivePlot : imagePlot; if (newPlot != plot && plot.isRendered()) { widget.container().remove(plot.getWidget()); } plot = newPlot; imagePlot.setOptions(appState.surface, appState.palette); renderPlot(appState); } @Override public void onAutoReloadChange(StateChangeEvent event) { // ignore } @Override public void onScreenChange(StateChangeEvent event) { resetDimensions(event.getAppState()); eventBus.fireEvent(new GraphEvent( GraphEvent.Action.START_RENDERING)); plot.render(new Command() { @Override public void execute() { eventBus.fireEvent(new GraphEvent( GraphEvent.Action.LOADED)); } }); } }); } private int estimateHeight(ApplicationState appState) { // header + auto relaad int topHeight = appState.fullscreen ? 50 : 50 + 50 + 10; return Window.getClientHeight() - topHeight; } private int estimateWidth(ApplicationState appState) { double coef = appState.fullscreen ? 1.0 : 0.72; return (int) ((Window.getClientWidth() - 20) * coef); } @Override public void go(HasWidgets container, final ApplicationState appState) { Widget w = (Widget) widget; resetDimensions(appState); container.add(w); plot = appState.interactive ? interactivePlot : imagePlot; imagePlot.setOptions(appState.surface, appState.palette); if (!initialized) { w.addAttachHandler(new AttachEvent.Handler() { @Override public void onAttachOrDetach(AttachEvent event) { if (event.isAttached()) { renderPlot(appState); initialized = true; } } }); } } }