/*
* ProfilerPresenter.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.workbench.views.source.editors.profiler;
import org.rstudio.core.client.Debug;
import org.rstudio.core.client.HandlerRegistrations;
import org.rstudio.core.client.command.CommandBinder;
import org.rstudio.core.client.command.Handler;
import org.rstudio.core.client.files.FileSystemItem;
import org.rstudio.core.client.js.JsObject;
import org.rstudio.core.client.widget.Operation;
import org.rstudio.core.client.widget.OperationWithInput;
import org.rstudio.core.client.widget.ProgressIndicator;
import org.rstudio.core.client.widget.ProgressOperationWithInput;
import org.rstudio.studio.client.application.events.EventBus;
import org.rstudio.studio.client.common.FileDialogs;
import org.rstudio.studio.client.common.GlobalDisplay;
import org.rstudio.studio.client.common.SimpleRequestCallback;
import org.rstudio.studio.client.common.dependencies.DependencyManager;
import org.rstudio.studio.client.common.filetypes.FileTypeRegistry;
import org.rstudio.studio.client.server.ServerError;
import org.rstudio.studio.client.server.ServerRequestCallback;
import org.rstudio.studio.client.workbench.WorkbenchContext;
import org.rstudio.studio.client.workbench.commands.Commands;
import org.rstudio.studio.client.workbench.model.RemoteFileSystemContext;
import org.rstudio.studio.client.workbench.views.source.SourceWindowManager;
import org.rstudio.studio.client.workbench.views.source.editors.profiler.model.ProfileOperationRequest;
import org.rstudio.studio.client.workbench.views.source.editors.profiler.model.ProfileOperationResponse;
import org.rstudio.studio.client.workbench.views.source.editors.profiler.model.ProfilerContents;
import org.rstudio.studio.client.workbench.views.source.editors.profiler.model.ProfilerServerOperations;
import org.rstudio.studio.client.workbench.views.source.model.SourceDocument;
import org.rstudio.studio.client.workbench.views.source.model.SourceServerOperations;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.user.client.Command;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@Singleton
public class ProfilerPresenter implements RprofEvent.Handler
{
private final ProfilerServerOperations server_;
private final SourceServerOperations sourceServer_;
private final Commands commands_;
private final DependencyManager dependencyManager_;
private final HandlerRegistrations handlerRegistrations_ = new HandlerRegistrations();
private final GlobalDisplay globalDisplay_;
private final EventBus events_;
private Provider<SourceWindowManager> pSourceWindowManager_;
private final FileDialogs fileDialogs_;
private final RemoteFileSystemContext fileContext_;
private final WorkbenchContext workbenchContext_;
private final FileTypeRegistry fileTypeRegistry_;
private String currentDocId_;
final String profilerDependecyUserAction_ = "Preparing profiler";
private ProfileOperationResponse response_ = null;
public interface Binder extends CommandBinder<Commands, ProfilerPresenter>
{
}
public interface Display
{
}
@Inject
public ProfilerPresenter(ProfilerServerOperations server,
Binder binder,
Commands commands,
DependencyManager dependencyManager,
GlobalDisplay globalDisplay,
EventBus events,
Provider<SourceWindowManager> pSourceWindowManager,
FileDialogs fileDialogs,
RemoteFileSystemContext fileContext,
WorkbenchContext workbenchContext,
FileTypeRegistry fileTypeRegistry,
SourceServerOperations sourceServer)
{
server_ = server;
commands_ = commands;
dependencyManager_ = dependencyManager;
globalDisplay_ = globalDisplay;
events_ = events;
pSourceWindowManager_ = pSourceWindowManager;
fileDialogs_ = fileDialogs;
fileContext_ = fileContext;
workbenchContext_ = workbenchContext;
fileTypeRegistry_ = fileTypeRegistry;
sourceServer_ = sourceServer;
binder.bind(commands, this);
// by default, one can always start profiling
enableStoppedCommands();
events_.addHandler(RprofEvent.TYPE, this);
}
public void onRprofEvent(RprofEvent event)
{
switch (event.getEventType())
{
case START:
enableStartedCommands();
break;
case STOP:
enableStoppedCommands();
break;
case CREATE:
events_.fireEvent(new OpenProfileEvent(
event.getData().getPath(),
event.getData().getHtmlPath(),
event.getData().getHtmlLocalPath(),
true,
currentDocId_));
currentDocId_ = null;
break;
default:
break;
}
}
public void attach(SourceDocument doc, Display view)
{
}
public void detach()
{
// unsubscribe from view
handlerRegistrations_.removeHandler();
}
@Handler
public void onStartProfiler()
{
dependencyManager_.withProfvis(profilerDependecyUserAction_, new Command()
{
@Override
public void execute()
{
ProfileOperationRequest request = ProfileOperationRequest
.create("");
server_.startProfiling(request,
new ServerRequestCallback<ProfileOperationResponse>()
{
@Override
public void onResponseReceived(ProfileOperationResponse response)
{
if (response.getErrorMessage() != null)
{
globalDisplay_.showErrorMessage("Profiler Error",
response.getErrorMessage());
return;
}
pSourceWindowManager_.get().ensureVisibleSourcePaneIfNecessary();
response_ = response;
sourceServer_.newDocument(
FileTypeRegistry.PROFILER.getTypeId(),
null,
(JsObject) ProfilerContents.create(
response.getFileName(),
null,
null,
true).cast(),
new SimpleRequestCallback<SourceDocument>("Show Profiler")
{
@Override
public void onResponseReceived(SourceDocument response)
{
currentDocId_ = response.getId();
}
@Override
public void onError(ServerError error)
{
Debug.logError(error);
}
});
}
@Override
public void onError(ServerError error)
{
Debug.logError(error);
globalDisplay_.showErrorMessage("Failed to Stop Profiler",
error.getMessage());
}
});
}
});
}
@Handler
public void onStopProfiler()
{
ProfileOperationRequest request = ProfileOperationRequest
.create(response_ != null ? response_.getFileName() : null);
response_ = null;
server_.stopProfiling(request,
new ServerRequestCallback<ProfileOperationResponse>()
{
@Override
public void onResponseReceived(ProfileOperationResponse response)
{
if (response.getErrorMessage() != null)
{
globalDisplay_.showErrorMessage("Profiler Error",
response.getErrorMessage());
return;
}
}
@Override
public void onError(ServerError error)
{
Debug.logError(error);
globalDisplay_.showErrorMessage("Failed to Stop Profiler",
error.getMessage());
}
});
}
@Handler
public void onOpenProfile()
{
fileDialogs_.openFile(
"Open File",
fileContext_,
workbenchContext_.getDefaultFileDialogDir(),
"Profvis Profiles (*.Rprofvis)",
new ProgressOperationWithInput<FileSystemItem>()
{
public void execute(final FileSystemItem input,
ProgressIndicator indicator)
{
if (input == null)
return;
workbenchContext_.setDefaultFileDialogDir(
input.getParentPath());
indicator.onCompleted();
Scheduler.get().scheduleDeferred(new ScheduledCommand()
{
public void execute()
{
fileTypeRegistry_.openFile(input);
}
});
}
});
}
@Handler
public void onSaveProfileAs()
{
commands_.saveSourceDocAs().execute();
}
public void buildHtmlPath(final OperationWithInput<ProfileOperationResponse> continuation,
final Operation onError,
final String path)
{
ProfileOperationRequest request = ProfileOperationRequest.create(path);
server_.openProfile(request,
new ServerRequestCallback<ProfileOperationResponse>()
{
@Override
public void onResponseReceived(ProfileOperationResponse response)
{
if (response.getErrorMessage() != null)
{
globalDisplay_.showErrorMessage("Profiler Error",
response.getErrorMessage());
onError.execute();
return;
}
continuation.execute(response);
}
@Override
public void onError(ServerError error)
{
Debug.logError(error);
globalDisplay_.showErrorMessage("Failed to Open Profile",
error.getMessage());
onError.execute();
}
});
}
private void enableStartedCommands()
{
commands_.startProfiler().setEnabled(false);
commands_.stopProfiler().setEnabled(true);
}
private void enableStoppedCommands()
{
commands_.startProfiler().setEnabled(true);
commands_.stopProfiler().setEnabled(false);
}
}