/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.svn.ide.sw;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.promises.client.Function;
import org.eclipse.che.api.promises.client.FunctionException;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.data.tree.Node;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.resources.Project;
import org.eclipse.che.ide.api.user.Credentials;
import org.eclipse.che.ide.api.user.AskCredentialsDialog;
import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
import org.eclipse.che.ide.project.shared.NodesResources;
import org.eclipse.che.ide.resource.Path;
import org.eclipse.che.plugin.svn.ide.SubversionClientService;
import org.eclipse.che.plugin.svn.ide.SubversionExtensionLocalizationConstants;
import org.eclipse.che.plugin.svn.ide.common.StatusColors;
import org.eclipse.che.plugin.svn.ide.common.SubversionActionPresenter;
import org.eclipse.che.plugin.svn.ide.common.SubversionOutputConsoleFactory;
import org.eclipse.che.plugin.svn.shared.CLIOutputResponse;
import org.eclipse.che.plugin.svn.shared.CLIOutputWithRevisionResponse;
import org.eclipse.che.plugin.svn.shared.InfoResponse;
import org.eclipse.che.plugin.svn.shared.SubversionItem;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.google.common.base.Preconditions.checkState;
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.EMERGE_MODE;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
import static org.eclipse.che.ide.util.StringUtils.isNullOrEmpty;
/**
* Handler for the {@link org.eclipse.che.plugin.svn.ide.action.SwitchAction} action.
*
* @author Anatolii Bazko
*/
@Singleton
public class SwitchPresenter extends SubversionActionPresenter implements SwitchView.ActionDelegate,
LocationSelectorView.ActionDelegate,
SvnNode.ActionDelegate {
private final NotificationManager notificationManager;
private final SubversionExtensionLocalizationConstants constants;
private final SubversionClientService service;
private final SwitchView switchView;
private final LocationSelectorView selectorView;
private final NodesResources resources;
// Keep list of branches and tags to avoid unnecessary requests
private List<String> branches;
private List<String> tags;
private String projectUri;
@Inject
public SwitchPresenter(AppContext appContext,
NotificationManager notificationManager,
SubversionExtensionLocalizationConstants constants,
SwitchView switchView,
LocationSelectorView selectorView,
SubversionClientService service,
SubversionOutputConsoleFactory consoleFactory,
ProcessesPanelPresenter processesPanelPresenter,
StatusColors statusColors,
NodesResources resources,
SubversionExtensionLocalizationConstants locale,
AskCredentialsDialog credentialsDialog) {
super(appContext, consoleFactory, processesPanelPresenter, statusColors, locale, notificationManager, credentialsDialog);
this.notificationManager = notificationManager;
this.constants = constants;
this.service = service;
this.switchView = switchView;
this.resources = resources;
this.switchView.setDelegate(this);
this.selectorView = selectorView;
this.selectorView.setDelegate(this);
}
public void showWindow() {
final Project project = appContext.getRootProject();
checkState(project != null);
switchView.showWindow();
switchView.setSwitchButtonEnabled(false);
invalidateLoadedData();
performOperationWithCredentialsRequestIfNeeded(new RemoteSubversionOperation<InfoResponse>() {
@Override
public Promise<InfoResponse> perform(Credentials credentials) {
return service.info(appContext.getRootProject().getLocation(), ".", "HEAD", false, credentials);
}
}, null).then(new Operation<InfoResponse>() {
@Override
public void apply(InfoResponse response) throws OperationException {
if (!response.getItems().isEmpty()) {
SubversionItem subversionItem = response.getItems().get(0);
projectUri = subversionItem.getProjectUri();
}
defaultViewInitialization();
handleSwitchButton();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
projectUri = "^";
Path location = appContext.getRootProject().getLocation();
notificationManager.notify(constants.infoRequestError(location.toString()), error.getMessage(), FAIL, EMERGE_MODE);
defaultViewInitialization();
handleSwitchButton();
}
});
}
private void defaultViewInitialization() {
switchView.setSwitchRevisionEnabled(switchView.isSwitchToRevision());
switchView.setLocationEnabled(switchView.isSwitchToOtherLocation());
switchView.setSwitchToLocationEnabled(switchView.isSwitchToBranch() || switchView.isSwitchToTag());
switchView.setLocation(composeSwitchLocation());
switchView.setSelectOtherLocationButtonEnabled(switchView.isSwitchToOtherLocation());
switchView.setWorkingCopyDepthEnabled(switchView.getDepth().isEmpty());
switchView.setDepthEnabled(switchView.getWorkingCopyDepth().isEmpty());
}
@Override
public void onCancelClicked() {
switchView.close();
invalidateLoadedData();
}
@Override
public void onSwitchClicked() {
performOperationWithCredentialsRequestIfNeeded(new RemoteSubversionOperation<CLIOutputWithRevisionResponse>() {
@Override
public Promise<CLIOutputWithRevisionResponse> perform(Credentials credentials) {
return service.doSwitch(switchView.getLocation(),
appContext.getRootProject().getLocation(),
switchView.isSwitchToHeadRevision() ? "HEAD" : switchView.getRevision(),
switchView.getDepth(),
switchView.getWorkingCopyDepth(),
switchView.getAccept(),
switchView.isIgnoreExternals(),
switchView.isIgnoreAncestry(),
false,
switchView.isForce(),
credentials);
}
}, null).then(new Operation<CLIOutputWithRevisionResponse>() {
@Override
public void apply(CLIOutputWithRevisionResponse response) throws OperationException {
printResponse(response.getCommand(), response.getOutput(), response.getErrOutput(), constants.commandSwitch());
SwitchPresenter.this.switchView.close();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(constants.switchRequestError(switchView.getLocation()), error.getMessage(), FAIL, EMERGE_MODE);
}
});
}
@Override
public void onSwitchToTrunkChanged() {
switchView.setSwitchToLocationEnabled(false);
switchView.setLocationEnabled(false);
switchView.setPredefinedLocations(Collections.<String>emptyList());
switchView.setLocation(composeSwitchLocation());
switchView.setSelectOtherLocationButtonEnabled(false);
handleSwitchButton();
}
@Override
public void onSwitchToBranchChanged() {
switchView.setLocationEnabled(false);
switchView.setSwitchToLocationEnabled(true);
switchView.setSelectOtherLocationButtonEnabled(false);
if (branches != null) {
switchView.setPredefinedLocations(branches);
switchView.setLocation(composeSwitchLocation());
handleSwitchButton();
return;
}
performOperationWithCredentialsRequestIfNeeded(new RemoteSubversionOperation<CLIOutputResponse>() {
@Override
public Promise<CLIOutputResponse> perform(Credentials credentials) {
return service.listBranches(appContext.getRootProject().getLocation(), credentials);
}
}, null).then(new Operation<CLIOutputResponse>() {
@Override
public void apply(CLIOutputResponse response) throws OperationException {
branches = response.getOutput();
switchView.setPredefinedLocations(branches);
switchView.setLocation(composeSwitchLocation());
handleSwitchButton();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
branches = Collections.<String>emptyList();
switchView.setPredefinedLocations(branches);
switchView.setLocation(composeSwitchLocation());
handleSwitchButton();
notificationManager.notify(constants.listBranchesRequestError(projectUri), error.getMessage(), FAIL, EMERGE_MODE);
}
});
}
@Override
public void onSwitchToTagChanged() {
switchView.setLocationEnabled(false);
switchView.setSwitchToLocationEnabled(true);
switchView.setSelectOtherLocationButtonEnabled(false);
if (tags != null) {
switchView.setPredefinedLocations(tags);
switchView.setLocation(composeSwitchLocation());
handleSwitchButton();
return;
}
performOperationWithCredentialsRequestIfNeeded(new RemoteSubversionOperation<CLIOutputResponse>() {
@Override
public Promise<CLIOutputResponse> perform(Credentials credentials) {
return service.listTags(appContext.getRootProject().getLocation(), credentials);
}
}, null).then(new Operation<CLIOutputResponse>() {
@Override
public void apply(CLIOutputResponse response) throws OperationException {
tags = response.getOutput();
switchView.setPredefinedLocations(tags);
switchView.setLocation(composeSwitchLocation());
handleSwitchButton();
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
tags = Collections.<String>emptyList();
switchView.setPredefinedLocations(tags);
switchView.setLocation(composeSwitchLocation());
handleSwitchButton();
notificationManager.notify(constants.listTagsRequestError(projectUri), error.getMessage(), FAIL, EMERGE_MODE);
}
});
}
@Override
public void onSwitchToOtherLocationChanged() {
switchView.setSwitchToLocationEnabled(false);
switchView.setLocationEnabled(true);
switchView.setSelectOtherLocationButtonEnabled(true);
switchView.setPredefinedLocations(Collections.<String>emptyList());
handleSwitchButton();
}
@Override
public void onSwitchToHeadRevisionChanged() {
switchView.setSwitchRevisionEnabled(false);
handleSwitchButton();
}
@Override
public void onSwitchToRevisionChanged() {
switchView.setSwitchRevisionEnabled(true);
handleSwitchButton();
}
@Override
public void onRevisionUpdated() {
handleSwitchButton();
}
@Override
public void onSwitchLocationChanged() {
switchView.setLocation(composeSwitchLocation());
}
@Override
public void onSelectOtherLocationClicked() {
selectorView.showWindow();
SvnNode rootNode = new SvnNode(projectUri, resources, this);
selectorView.setRootNode(rootNode);
}
@Override
public void onDepthChanged() {
switchView.setWorkingCopyDepthEnabled(switchView.getDepth().isEmpty());
}
@Override
public void onWorkingCopyDepthChanged() {
switchView.setDepthEnabled(switchView.getWorkingCopyDepth().isEmpty());
}
private String composeSwitchLocation() {
if (switchView.isSwitchToTrunk()) {
return projectUri + "/trunk";
} else {
String switchToLocation = switchView.getSwitchToLocation();
if (switchView.isSwitchToBranch()) {
return projectUri + "/branches/" + (isNullOrEmpty(switchToLocation) ? "" : switchToLocation);
} else if (switchView.isSwitchToTag()) {
return projectUri + "/tags/" + (isNullOrEmpty(switchToLocation) ? "" : switchToLocation);
} else {
return switchView.getLocation();
}
}
}
private void invalidateLoadedData() {
tags = null;
branches = null;
projectUri = null;
}
private void handleSwitchButton() {
if (switchView.getLocation().isEmpty()) {
switchView.setSwitchButtonEnabled(false);
} else if (switchView.isSwitchToRevision() && switchView.getRevision().isEmpty()) {
switchView.setSwitchButtonEnabled(false);
} else {
switchView.setSwitchButtonEnabled(true);
}
}
@Override
public void setSelectedNode(SvnNode node) {
switchView.setLocation(node.getLocation());
}
@Override
public Promise<List<Node>> list(final String location) {
return performOperationWithCredentialsRequestIfNeeded(new RemoteSubversionOperation<CLIOutputResponse>() {
@Override
public Promise<CLIOutputResponse> perform(Credentials credentials) {
return service.list(appContext.getRootProject().getLocation(), location, credentials);
}
}, null).then(new Function<CLIOutputResponse, List<Node>>() {
@Override
public List<Node> apply(CLIOutputResponse response) throws FunctionException {
List<Node> nodes = new ArrayList<>();
List<String> output = response.getOutput();
for (String item : output) {
if (item.endsWith("/")) {
String nodeLocation = location + "/" + item.substring(0, item.length() - 1);
nodes.add(new SvnNode(nodeLocation, resources, SwitchPresenter.this));
}
}
return nodes;
}
}).catchError(new Function<PromiseError, List<Node>>() {
@Override
public List<Node> apply(PromiseError error) throws FunctionException {
notificationManager.notify(constants.listRequestError(location), error.getMessage(), FAIL, EMERGE_MODE);
return Collections.emptyList();
}
});
}
}