/*
* ErrorManager.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.common.debugging;
import org.rstudio.studio.client.server.Void;
import org.rstudio.core.client.command.CommandBinder;
import org.rstudio.core.client.command.Handler;
import org.rstudio.studio.client.application.events.EventBus;
import org.rstudio.studio.client.common.debugging.events.ErrorHandlerChangedEvent;
import org.rstudio.studio.client.common.debugging.model.ErrorHandlerType;
import org.rstudio.studio.client.common.debugging.model.ErrorManagerState;
import org.rstudio.studio.client.server.ServerError;
import org.rstudio.studio.client.server.ServerRequestCallback;
import org.rstudio.studio.client.workbench.commands.Commands;
import org.rstudio.studio.client.workbench.events.SessionInitEvent;
import org.rstudio.studio.client.workbench.events.SessionInitHandler;
import org.rstudio.studio.client.workbench.model.Session;
import org.rstudio.studio.client.workbench.views.environment.events.DebugModeChangedEvent;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@Singleton
public class ErrorManager
implements DebugModeChangedEvent.Handler,
ErrorHandlerChangedEvent.Handler,
SessionInitHandler
{
public interface Binder
extends CommandBinder<Commands, ErrorManager> {}
private enum DebugHandlerState
{
None,
Pending
}
@Inject
public ErrorManager(EventBus events,
Binder binder,
Commands commands,
DebuggingServerOperations server,
Session session)
{
events_ = events;
server_ = server;
commands_ = commands;
session_ = session;
binder.bind(commands, this);
events_.addHandler(DebugModeChangedEvent.TYPE, this);
events_.addHandler(ErrorHandlerChangedEvent.TYPE, this);
events_.addHandler(SessionInitEvent.TYPE, this);
}
// Event and command handlers ----------------------------------------------
@Override
public void onDebugModeChanged(DebugModeChangedEvent event)
{
// if we expected to go into debug mode, this is what we were waiting
// for--change the error handler back to whatever it was formerly
if (event.debugging() &&
debugHandlerState_ == DebugHandlerState.Pending)
{
setErrorManagementType(previousHandlerType_);
}
debugHandlerState_ = DebugHandlerState.None;
}
@Override
public void onErrorHandlerChanged(ErrorHandlerChangedEvent event)
{
int newType = event.getHandlerType().getType();
if (newType != errorManagerState_.getErrorHandlerType())
{
errorManagerState_.setErrorHandlerType(newType);
syncHandlerCommandsCheckedState();
}
}
@Override
public void onSessionInit(SessionInitEvent sie)
{
errorManagerState_ = session_.getSessionInfo().getErrorState();
if (session_.getSessionInfo().getHaveSrcrefAttribute())
{
syncHandlerCommandsCheckedState();
}
else
{
// If we don't have source references, disable the commands that
// set error handlers (these generally work on user code only, and
// we can't reliably distinguish user code without source refs)
commands_.errorsMessage().setEnabled(false);
commands_.errorsTraceback().setEnabled(false);
commands_.errorsBreak().setEnabled(false);
}
}
@Handler
public void onErrorsMessage()
{
setErrorManagementTypeCommand(ErrorHandlerType.ERRORS_MESSAGE);
}
@Handler
public void onErrorsTraceback()
{
setErrorManagementTypeCommand(ErrorHandlerType.ERRORS_TRACEBACK);
}
@Handler
public void onErrorsBreak()
{
setErrorManagementTypeCommand(ErrorHandlerType.ERRORS_BREAK);
}
// Public methods ----------------------------------------------------------
public void setDebugSessionHandlerType(
int type,
final ServerRequestCallback<Void> callback)
{
if (type == errorManagerState_.getErrorHandlerType())
return;
setErrorManagementType(type, new ServerRequestCallback<Void>()
{
@Override
public void onResponseReceived(Void v)
{
previousHandlerType_ = errorManagerState_.getErrorHandlerType();
debugHandlerState_ = DebugHandlerState.Pending;
callback.onResponseReceived(v);
}
@Override
public void onError(ServerError error)
{
callback.onError(error);
}
});
}
public int getErrorHandlerType()
{
return errorManagerState_.getErrorHandlerType();
}
// Private methods ---------------------------------------------------------
private void setErrorManagementTypeCommand(int type)
{
// The error handler may be currently overridden for debug mode. If the
// user changes the setting via command during debug mode, we don't want
// to change it back when leaving debug mode.
debugHandlerState_ = DebugHandlerState.None;
setErrorManagementType(type);
}
private void setErrorManagementType(
int type,
ServerRequestCallback<Void> callback)
{
server_.setErrorManagementType(type, callback);
}
private void setErrorManagementType(int type)
{
setErrorManagementType(type,
new ServerRequestCallback<Void>()
{
@Override
public void onError(ServerError error)
{
// No action necessary--the server emits an event when the handler
// type changes
}
});
}
private void syncHandlerCommandsCheckedState()
{
int type = getErrorHandlerType();
commands_.errorsMessage().setChecked(
type == ErrorHandlerType.ERRORS_MESSAGE);
commands_.errorsTraceback().setChecked(
type == ErrorHandlerType.ERRORS_TRACEBACK);
commands_.errorsBreak().setChecked(
type == ErrorHandlerType.ERRORS_BREAK);
}
private final EventBus events_;
private final DebuggingServerOperations server_;
private final Session session_;
private final Commands commands_;
private DebugHandlerState debugHandlerState_ = DebugHandlerState.None;
private ErrorManagerState errorManagerState_;
private int previousHandlerType_;
}