/*******************************************************************************
* 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.merge;
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.HasDataObject;
import org.eclipse.che.ide.api.data.tree.AbstractTreeNode;
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.resources.Resource;
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.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.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.FLOAT_MODE;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
/**
* Manages merging the branches and folders.
*/
@Singleton
public class MergePresenter extends SubversionActionPresenter implements MergeView.ActionDelegate {
private final MergeView view;
private final SubversionClientService service;
private final NotificationManager notificationManager;
private final SubversionExtensionLocalizationConstants constants;
/** Subversion target to merge. */
private SubversionItem mergeTarget;
/** Source URL to merge with. */
private String sourceURL;
/**
* Creates an instance of this presenter.
*/
@Inject
public MergePresenter(MergeView view,
SubversionClientService service,
AppContext appContext,
SubversionOutputConsoleFactory consoleFactory,
AskCredentialsDialog subversionCredentialsDialog,
ProcessesPanelPresenter processesPanelPresenter,
NotificationManager notificationManager,
SubversionExtensionLocalizationConstants constants,
StatusColors statusColors) {
super(appContext, consoleFactory, processesPanelPresenter, statusColors, constants, notificationManager, subversionCredentialsDialog);
this.view = view;
this.service = service;
this.notificationManager = notificationManager;
this.constants = constants;
view.setDelegate(this);
}
/**
* Prepares to merging and opens Merge dialog.
*/
public void merge() {
view.enableMergeButton(false);
view.sourceCheckBox().setValue(false);
final Project project = appContext.getRootProject();
checkState(project != null);
final Resource[] resources = appContext.getResources();
checkState(resources != null && resources.length == 1);
performOperationWithCredentialsRequestIfNeeded(new RemoteSubversionOperation<InfoResponse>() {
@Override
public Promise<InfoResponse> perform(Credentials credentials) {
return service.info(project.getLocation(), toRelative(project, resources[0]).toString(), "HEAD", false, credentials);
}
}, null).then(new Operation<InfoResponse>() {
@Override
public void apply(InfoResponse response) throws OperationException {
if (response.getErrorOutput() != null && !response.getErrorOutput().isEmpty()) {
printErrors(response.getErrorOutput(), constants.commandInfo());
notificationManager.notify("Unable to execute subversion command", FAIL, FLOAT_MODE);
return;
}
mergeTarget = response.getItems().get(0);
view.targetTextBox().setValue(mergeTarget.getRelativeURL());
String repositoryRoot = mergeTarget.getRepositoryRoot();
service.info(project.getLocation(), repositoryRoot, "HEAD", true)
.then(new Operation<InfoResponse>() {
@Override
public void apply(InfoResponse response) throws OperationException {
if (!response.getErrorOutput().isEmpty()) {
printErrors(response.getErrorOutput(), constants.commandInfo());
notificationManager.notify("Unable to execute subversion command", FAIL, FLOAT_MODE);
return;
}
sourceURL = response.getItems().get(0).getURL();
SubversionItemNode subversionTreeNode = new SubversionItemNode(response.getItems().get(0));
List<Node> children = new ArrayList<>();
if (response.getItems().size() > 1) {
for (int i = 1; i < response.getItems().size(); i++) {
SubversionItem item = response.getItems().get(i);
if (!"file".equals(item.getNodeKind())) {
children.add(new SubversionItemNode(item));
}
}
}
subversionTreeNode.setChildren(children);
view.setRootNode(subversionTreeNode);
view.show();
validateSourceURL();
}
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(error.getMessage(), FAIL, FLOAT_MODE);
}
});
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(error.getMessage(), FAIL, FLOAT_MODE);
}
});
}
/**
* Performs actions when clicking Merge button.
*/
@Override
public void mergeClicked() {
view.hide();
final Project project = appContext.getRootProject();
checkState(project != null);
final Resource[] resources = appContext.getResources();
checkState(resources != null && resources.length == 1);
service.merge(project.getLocation(), resources[0].getLocation(), Path.valueOf(sourceURL))
.then(new Operation<CLIOutputResponse>() {
@Override
public void apply(CLIOutputResponse response) throws OperationException {
printResponse(response.getCommand(), response.getOutput(), null, constants.commandMerge());
}
})
.catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(error.getMessage(), FAIL, FLOAT_MODE);
}
});
}
/**
* Closes the dialog when clicking Cancel button.
*/
@Override
public void cancelClicked() {
view.hide();
}
/** {@inheritDoc} */
@Override
public void onSourceCheckBoxClicked() {
if (view.sourceCheckBox().getValue()) {
view.sourceURLTextBox().setValue(sourceURL);
}
}
/** {@inheritDoc} */
@Override
public void onSourceURLChanged(String sourceURL) {
this.sourceURL = sourceURL;
validateSourceURL();
}
/** {@inheritDoc} */
@Override
public void onNodeSelected(Node node) {
if (!(node instanceof SubversionItemNode)) {
return;
}
SubversionItemNode treeNode = (SubversionItemNode)node;
sourceURL = treeNode.getData().getURL();
validateSourceURL();
}
/** Validates source URL and disables Merge button if it's unable to merge. */
private void validateSourceURL() {
if (sourceURL.startsWith(mergeTarget.getURL())) {
view.setError("Cannot merge directory itself");
view.enableMergeButton(false);
return;
}
if (mergeTarget.getURL().startsWith(sourceURL)) {
view.setError("Cannot merge with parent directory");
view.enableMergeButton(false);
return;
}
view.setError(null);
view.enableMergeButton(true);
}
class SubversionItemNode extends AbstractTreeNode implements HasDataObject<SubversionItem> {
private SubversionItem dataItem;
public SubversionItemNode(SubversionItem dataItem) {
this.dataItem = dataItem;
}
@Override
protected Promise<List<Node>> getChildrenImpl() {
final Project project = appContext.getRootProject();
checkState(project != null);
return service.info(project.getLocation(), getData().getURL(), "HEAD", true)
.then(new Function<InfoResponse, List<Node>>() {
@Override
public List<Node> apply(InfoResponse response) throws FunctionException {
if (response.getErrorOutput() != null && !response.getErrorOutput().isEmpty()) {
printErrors(response.getErrorOutput(), constants.commandInfo());
notificationManager.notify("Unable to execute subversion command", FAIL, FLOAT_MODE);
return Collections.emptyList();
}
List<Node> children = new ArrayList<>();
if (response.getItems().size() > 1) {
for (int i = 1; i < response.getItems().size(); i++) {
SubversionItem item = response.getItems().get(i);
if (!"file".equals(item.getNodeKind())) {
children.add(new SubversionItemNode(item));
}
}
}
return children;
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError error) throws OperationException {
notificationManager.notify(error.getMessage(), FAIL, FLOAT_MODE);
}
});
}
@Override
public SubversionItem getData() {
return dataItem;
}
@Override
public void setData(SubversionItem data) {
dataItem = data;
}
@Override
public String getName() {
if (getData().getRepositoryRoot().equals(getData().getURL())) {
return getData().getRepositoryRoot();
}
return getData().getPath();
}
@Override
public boolean isLeaf() {
return "file".equals(getData().getNodeKind());
}
}
}