/*
* PublishingPreferencesPane.java
*
* Copyright (C) 2009-14 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.prefs.views;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.inject.Inject;
import org.rstudio.core.client.CommandWithArg;
import org.rstudio.core.client.prefs.PreferencesDialogBaseResources;
import org.rstudio.core.client.resources.ImageResource2x;
import org.rstudio.core.client.widget.Operation;
import org.rstudio.core.client.widget.OperationWithInput;
import org.rstudio.core.client.widget.ThemedButton;
import org.rstudio.studio.client.common.GlobalDisplay;
import org.rstudio.studio.client.common.dependencies.DependencyManager;
import org.rstudio.studio.client.rsconnect.RSConnect;
import org.rstudio.studio.client.rsconnect.model.RSConnectAccount;
import org.rstudio.studio.client.rsconnect.model.RSConnectServerOperations;
import org.rstudio.studio.client.rsconnect.ui.RSAccountConnector;
import org.rstudio.studio.client.rsconnect.ui.RSConnectAccountList;
import org.rstudio.studio.client.server.Int;
import org.rstudio.studio.client.server.ServerError;
import org.rstudio.studio.client.server.ServerRequestCallback;
import org.rstudio.studio.client.server.Void;
import org.rstudio.studio.client.workbench.prefs.model.RPrefs;
import org.rstudio.studio.client.workbench.prefs.model.UIPrefs;
public class PublishingPreferencesPane extends PreferencesPane
{
@Inject
public PublishingPreferencesPane(GlobalDisplay globalDisplay,
RSConnectServerOperations server,
RSAccountConnector connector,
UIPrefs prefs,
DependencyManager deps)
{
reloadRequired_ = false;
display_ = globalDisplay;
uiPrefs_ = prefs;
server_ = server;
connector_ = connector;
deps_ = deps;
VerticalPanel accountPanel = new VerticalPanel();
Label accountLabel = headerLabel("Publishing Accounts");
HorizontalPanel hpanel = new HorizontalPanel();
accountPanel.add(accountLabel);
accountList_ = new RSConnectAccountList(server, globalDisplay, true,
true);
accountList_.setHeight("200px");
accountList_.setWidth("300px");
accountList_.getElement().getStyle().setMarginBottom(15, Unit.PX);
accountList_.getElement().getStyle().setMarginLeft(3, Unit.PX);
hpanel.add(accountList_);
accountList_.setOnRefreshCompleted(new Operation()
{
@Override
public void execute()
{
setButtonEnabledState();
}
});
accountList_.addChangeHandler(new ChangeHandler()
{
@Override
public void onChange(ChangeEvent arg0)
{
setButtonEnabledState();
}
});
VerticalPanel vpanel = new VerticalPanel();
hpanel.add(vpanel);
connectButton_ = new ThemedButton("Connect...");
connectButton_.getElement().getStyle().setMarginBottom(5, Unit.PX);
connectButton_.setWidth("100%");
connectButton_.setWrapperWidth("100%");
connectButton_.addClickHandler(new ClickHandler()
{
@Override
public void onClick(ClickEvent event)
{
onConnect();
}
});
vpanel.add(connectButton_);
reconnectButton_ = new ThemedButton("Reconnect...");
reconnectButton_.getElement().getStyle().setMarginBottom(5, Unit.PX);
reconnectButton_.setWidth("100%");
reconnectButton_.setWrapperWidth("100%");
reconnectButton_.addClickHandler(new ClickHandler()
{
@Override
public void onClick(ClickEvent event)
{
onReconnect();
}
});
vpanel.add(reconnectButton_);
disconnectButton_ = new ThemedButton("Disconnect");
disconnectButton_.setWidth("100%");
disconnectButton_.setWrapperWidth("100%");
disconnectButton_.addClickHandler(new ClickHandler()
{
@Override
public void onClick(ClickEvent event)
{
onDisconnect();
}
});
vpanel.add(disconnectButton_);
setButtonEnabledState();
accountPanel.add(hpanel);
add(accountPanel);
// special UI to show when we detect that there are account records but
// the RSConnect package isn't installed
final VerticalPanel missingPkgPanel = new VerticalPanel();
missingPkgPanel.setVisible(false);
missingPkgPanel.add(new Label(
"Account records appear to exist, but cannot be viewed because a " +
"required package is not installed."));
ThemedButton installPkgs = new ThemedButton("Install Missing Packages");
installPkgs.addClickHandler(new ClickHandler()
{
@Override
public void onClick(ClickEvent arg0)
{
deps_.withRSConnect("Viewing publish accounts", false, null,
new CommandWithArg<Boolean>()
{
@Override
public void execute(Boolean succeeded)
{
if (succeeded)
{
// refresh the account list to show the accounts
accountList_.refreshAccountList();
// remove the "missing package" UI
missingPkgPanel.setVisible(false);
}
}
});
}
});
installPkgs.getElement().getStyle().setMarginLeft(0, Unit.PX);
installPkgs.getElement().getStyle().setMarginTop(10, Unit.PX);
missingPkgPanel.add(installPkgs);
missingPkgPanel.getElement().getStyle().setMarginBottom(20, Unit.PX);
add(missingPkgPanel);
final CheckBox chkEnableRSConnect = checkboxPref("Enable publishing to RStudio Connect",
uiPrefs_.enableRStudioConnect());
final HorizontalPanel rsconnectPanel = checkBoxWithHelp(chkEnableRSConnect,
"rstudio_connect");
lessSpaced(rsconnectPanel);
add(headerLabel("Settings"));
CheckBox chkEnablePublishing = checkboxPref("Enable publishing documents and apps",
uiPrefs_.showPublishUi());
chkEnablePublishing.addValueChangeHandler(new ValueChangeHandler<Boolean>(){
@Override
public void onValueChange(ValueChangeEvent<Boolean> event)
{
reloadRequired_ = true;
rsconnectPanel.setVisible(
RSConnect.showRSConnectUI() && event.getValue());
}
});
add(chkEnablePublishing);
if (RSConnect.showRSConnectUI())
add(rsconnectPanel);
add(checkboxPref("Show diagnostic information when publishing",
uiPrefs_.showPublishDiagnostics()));
server_.hasOrphanedAccounts(new ServerRequestCallback<Int>()
{
@Override
public void onResponseReceived(Int numOrphans)
{
missingPkgPanel.setVisible(numOrphans.getValue() > 0);
}
@Override
public void onError(ServerError error)
{
// if we can't determine whether orphans exist, presume that they
// don't (this state is recoverable as we'll attempt to install
// rsconnect if necessary and refresh the account list when the user
// tries to interact with it)
}
});
}
@Override
protected void initialize(RPrefs rPrefs)
{
}
@Override
public boolean onApply(RPrefs rPrefs)
{
boolean reload = super.onApply(rPrefs);
return reload || reloadRequired_;
}
@Override
public ImageResource getIcon()
{
return new ImageResource2x(PreferencesDialogBaseResources.INSTANCE.iconPublishing2x());
}
@Override
public boolean validate()
{
return true;
}
@Override
public String getName()
{
return "Publishing";
}
private void onDisconnect()
{
final RSConnectAccount account = accountList_.getSelectedAccount();
if (account == null)
{
display_.showErrorMessage("Error Disconnecting Account",
"Please select an account to disconnect.");
return;
}
display_.showYesNoMessage(
GlobalDisplay.MSG_QUESTION,
"Confirm Remove Account",
"Are you sure you want to disconnect the '" +
account.getName() +
"' account on '" +
account.getServer() + "'" +
"? This won't delete the account on the server.",
false,
new Operation()
{
@Override
public void execute()
{
onConfirmDisconnect(account);
}
}, null, null, "Disconnect Account", "Cancel", false);
}
private void onConfirmDisconnect(final RSConnectAccount account)
{
server_.removeRSConnectAccount(account.getName(),
account.getServer(), new ServerRequestCallback<Void>()
{
@Override
public void onResponseReceived(Void v)
{
accountList_.refreshAccountList();
}
@Override
public void onError(ServerError error)
{
display_.showErrorMessage("Error Disconnecting Account",
error.getMessage());
}
});
}
private void onConnect()
{
// if there's already at least one account connected, the requisite
// packages must be installed
if (accountList_.getAccountCount() > 0)
{
showAccountWizard();
}
else
{
deps_.withRSConnect("Connecting a publishing account", false, null,
new CommandWithArg<Boolean>()
{
@Override
public void execute(Boolean succeeded)
{
// refresh the account list in case there are accounts already on
// the system (e.g. package was installed at one point and some
// metadata remains)
accountList_.refreshAccountList();
showAccountWizard();
}
});
}
}
private void onReconnect()
{
connector_.showReconnectWizard(accountList_.getSelectedAccount(),
new OperationWithInput<Boolean>()
{
@Override
public void execute(Boolean successful)
{
if (successful)
{
accountList_.refreshAccountList();
}
}
});
}
private void showAccountWizard()
{
connector_.showAccountWizard(false, true,
new OperationWithInput<Boolean>()
{
@Override
public void execute(Boolean successful)
{
if (successful)
{
accountList_.refreshAccountList();
}
}
});
}
private void setButtonEnabledState()
{
disconnectButton_.setEnabled(
accountList_.getSelectedAccount() != null);
reconnectButton_.setEnabled(
accountList_.getSelectedAccount() != null &&
!accountList_.getSelectedAccount().isCloudAccount());
}
private final GlobalDisplay display_;
private final UIPrefs uiPrefs_;
private final RSConnectServerOperations server_;
private final RSAccountConnector connector_;
private final DependencyManager deps_;
private RSConnectAccountList accountList_;
private ThemedButton connectButton_;
private ThemedButton disconnectButton_;
private ThemedButton reconnectButton_;
private boolean reloadRequired_;
}