/*
* Satellite.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.satellite;
import org.rstudio.core.client.CommandWithArg;
import org.rstudio.studio.client.application.Desktop;
import org.rstudio.studio.client.application.events.EventBus;
import org.rstudio.studio.client.server.remote.ClientEventDispatcher;
import org.rstudio.studio.client.workbench.commands.Commands;
import org.rstudio.studio.client.workbench.model.Session;
import org.rstudio.studio.client.workbench.model.SessionInfo;
import org.rstudio.studio.client.workbench.prefs.model.UIPrefs;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.HasCloseHandlers;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.ClosingEvent;
import com.google.gwt.user.client.Window.ClosingHandler;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@Singleton
public class Satellite implements HasCloseHandlers<Satellite>
{
@Inject
public Satellite(Session session,
EventBus eventBus,
Commands commands,
Provider<UIPrefs> pUIPrefs)
{
session_ = session;
pUIPrefs_ = pUIPrefs;
commands_ = commands;
eventDispatcher_ = new ClientEventDispatcher(eventBus);
}
public void initialize(String name,
CommandWithArg<JavaScriptObject> onReactivated)
{
onReactivated_ = onReactivated;
initializeNative(name);
// NOTE: Desktop doesn't seem to get onWindowClosing events in Qt 4.8
// so we instead rely on an explicit callback from the desktop frame
// to notifyRStudioSatelliteClosing
if (!Desktop.isDesktop())
{
Window.addWindowClosingHandler(new ClosingHandler() {
@Override
public void onWindowClosing(ClosingEvent event)
{
fireCloseEvent();
}
});
}
}
@Override
public HandlerRegistration addCloseHandler(CloseHandler<Satellite> handler)
{
return handlerManager_.addHandler(CloseEvent.getType(), handler);
}
@Override
public void fireEvent(GwtEvent<?> event)
{
handlerManager_.fireEvent(event);
}
public boolean isReactivatePending()
{
return pendingReactivate_;
}
public native final void flushPendingEvents(String name) /*-{
$wnd.opener.flushPendingEvents(name);
}-*/;
// satellite windows should call this during startup to setup a
// communication channel with the main window
private native void initializeNative(String name) /*-{
// global flag used to conditionalize behavior
$wnd.isRStudioSatellite = true;
$wnd.RStudioSatelliteName = name;
// export setSessionInfo callback
var satellite = this;
$wnd.setRStudioSatelliteSessionInfo = $entry(
function(sessionInfo) {
satellite.@org.rstudio.studio.client.common.satellite.Satellite::setSessionInfo(Lcom/google/gwt/core/client/JavaScriptObject;)(sessionInfo);
}
);
// export setParams callback
$wnd.setRStudioSatelliteParams = $entry(
function(params) {
satellite.@org.rstudio.studio.client.common.satellite.Satellite::setParams(Lcom/google/gwt/core/client/JavaScriptObject;)(params);
}
);
// export notifyReactivated callback
$wnd.notifyRStudioSatelliteReactivated = $entry(
function(params) {
if (params == null)
return;
satellite.@org.rstudio.studio.client.common.satellite.Satellite::notifyReactivated(Lcom/google/gwt/core/client/JavaScriptObject;)(params);
}
);
// export notifyClosing
$wnd.notifyRStudioSatelliteClosing = $entry(function() {
// see remarks in WindowEx::isClosed
$wnd.rstudioSatelliteClosed = true;
satellite.@org.rstudio.studio.client.common.satellite.Satellite::fireCloseEvent()();
});
// export event notification callback
$wnd.dispatchEventToRStudioSatellite = $entry(
function(clientEvent) {
satellite.@org.rstudio.studio.client.common.satellite.Satellite::dispatchEvent(Lcom/google/gwt/core/client/JavaScriptObject;)(clientEvent);
}
);
// export command notification callback
$wnd.dispatchCommandToRStudioSatellite = $entry(
function(commandId) {
satellite.@org.rstudio.studio.client.common.satellite.Satellite::dispatchCommand(Ljava/lang/String;)(commandId);
}
);
// export request activation callback
$wnd.notifyPendingReactivate = $entry(function() {
satellite.@org.rstudio.studio.client.common.satellite.Satellite::notifyPendingReactivate()();
});
// register (this will call the setSessionInfo back)
$wnd.opener.registerAsRStudioSatellite(name, $wnd);
}-*/;
// check whether the current window is a satellite
public native boolean isCurrentWindowSatellite() /*-{
return !!$wnd.isRStudioSatellite;
}-*/;
// get the name of the current satellite window (null if not a satellite)
public native String getSatelliteName() /*-{
return $wnd.RStudioSatelliteName;
}-*/;
public JavaScriptObject getParams()
{
return params_;
}
public void focusMainWindow()
{
if (Desktop.isDesktop())
focusMainWindowDesktop();
else
focusMainWindowWeb();
}
private void focusMainWindowDesktop()
{
Desktop.getFrame().bringMainFrameToFront();
}
private native void focusMainWindowWeb() /*-{
$wnd.opener.focus();
}-*/;
// called by main window to initialize sessionInfo
private void setSessionInfo(JavaScriptObject si)
{
// get the session info and set it
SessionInfo sessionInfo = si.<SessionInfo>cast();
session_.setSessionInfo(sessionInfo);
// ensure ui prefs initialize
pUIPrefs_.get();
}
// called by main window to setParams
private void setParams(JavaScriptObject params)
{
params_ = params;
}
// called by main window to notify us of reactivation with a new
// set of params
private void notifyReactivated(JavaScriptObject params)
{
if (onReactivated_ != null)
onReactivated_.execute(params);
pendingReactivate_ = false;
}
private void fireCloseEvent()
{
CloseEvent.fire(this, this);
}
// called by main window to deliver events
private void dispatchEvent(JavaScriptObject clientEvent)
{
eventDispatcher_.enqueEventAsJso(clientEvent);
}
// called by main window to deliver commands
private void dispatchCommand(String commandId)
{
commands_.getCommandById(commandId).execute();
}
// called by the main window to notify us that we're about to be reactivated
private void notifyPendingReactivate()
{
pendingReactivate_ = true;
}
private final Session session_;
private final Provider<UIPrefs> pUIPrefs_;
private final ClientEventDispatcher eventDispatcher_;
private final HandlerManager handlerManager_ = new HandlerManager(this);
private final Commands commands_;
private boolean pendingReactivate_ = false;
private JavaScriptObject params_ = null;
private CommandWithArg<JavaScriptObject> onReactivated_ = null;
}