/*******************************************************************************
* Copyright (c) 2012-2015 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.ide.core;
import elemental.client.Browser;
import org.eclipse.che.api.project.gwt.client.ProjectServiceClient;
import org.eclipse.che.api.project.shared.dto.ProjectDescriptor;
import org.eclipse.che.ide.core.problemDialog.ProjectProblemDialog;
import org.eclipse.che.ide.CoreLocalizationConstant;
import org.eclipse.che.ide.CoreLocalizationConstant;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.app.CurrentProject;
import org.eclipse.che.ide.api.event.CloseCurrentProjectEvent;
import org.eclipse.che.ide.api.event.CloseCurrentProjectHandler;
import org.eclipse.che.ide.api.event.ConfigureProjectEvent;
import org.eclipse.che.ide.api.event.ConfigureProjectHandler;
import org.eclipse.che.ide.api.event.OpenProjectEvent;
import org.eclipse.che.ide.api.event.OpenProjectHandler;
import org.eclipse.che.ide.api.event.ProjectActionEvent;
import org.eclipse.che.ide.api.event.ProjectDescriptorChangedEvent;
import org.eclipse.che.ide.api.event.ProjectDescriptorChangedHandler;
import org.eclipse.che.ide.api.event.RefreshProjectTreeEvent;
import org.eclipse.che.ide.projecttype.wizard.presenter.ProjectWizardPresenter;
import org.eclipse.che.ide.core.problemDialog.ProjectProblemDialog;
import org.eclipse.che.ide.projecttype.wizard.presenter.ProjectWizardPresenter;
import org.eclipse.che.ide.rest.AsyncRequestCallback;
import org.eclipse.che.ide.rest.DtoUnmarshallerFactory;
import org.eclipse.che.ide.rest.Unmarshallable;
import org.eclipse.che.ide.util.Config;
import org.eclipse.che.ide.util.loging.Log;
import com.google.gwt.core.client.Callback;
import com.google.gwt.dom.client.Document;
import com.google.gwt.user.client.Window;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.web.bindery.event.shared.EventBus;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Component that does some preliminary operations before opening/closing projects.
* <p/>
* E.g.:
* <ul>
* <li>closing already opened project before opening another one;</li>
* <li>setting Browser tab's title;</li>
* <li>rewriting URL in Browser's address bar;</li>
* <li>setting {@link CurrentProject} to {@link AppContext};</li>
* <li>etc.</li>
* </ul>
*
* @author Artem Zatsarynnyy
*/
@Singleton
public class ProjectStateHandler implements Component, OpenProjectHandler, CloseCurrentProjectHandler, ProjectDescriptorChangedHandler,
ConfigureProjectHandler {
private final EventBus eventBus;
private final AppContext appContext;
private final ProjectServiceClient projectServiceClient;
private final ProjectWizardPresenter projectWizardPresenter;
private final DtoUnmarshallerFactory dtoUnmarshallerFactory;
private final CoreLocalizationConstant constant;
@Inject
public ProjectStateHandler(AppContext appContext,
EventBus eventBus,
ProjectServiceClient projectServiceClient,
ProjectWizardPresenter projectWizardPresenter,
CoreLocalizationConstant constant,
DtoUnmarshallerFactory dtoUnmarshallerFactory) {
this.eventBus = eventBus;
this.appContext = appContext;
this.projectServiceClient = projectServiceClient;
this.projectWizardPresenter = projectWizardPresenter;
this.dtoUnmarshallerFactory = dtoUnmarshallerFactory;
this.constant = constant;
}
@Override
public void start(Callback<Component, ComponentException> callback) {
eventBus.addHandler(OpenProjectEvent.TYPE, this);
eventBus.addHandler(CloseCurrentProjectEvent.TYPE, this);
eventBus.addHandler(ProjectDescriptorChangedEvent.TYPE, this);
eventBus.addHandler(ConfigureProjectEvent.TYPE, this);
callback.onSuccess(this);
}
@Override
public void onOpenProject(final OpenProjectEvent event) {
tryOpenProject(event.getProjectName());
}
@Override
public void onCloseCurrentProject(CloseCurrentProjectEvent event) {
closeCurrentProject(null, false);
}
@Override
public void onProjectDescriptorChanged(ProjectDescriptorChangedEvent event) {
final String path = event.getProjectDescriptor().getPath();
final CurrentProject currentProject = appContext.getCurrentProject();
if (currentProject != null && currentProject.getProjectDescription().getPath().equals(path)) {
currentProject.setProjectDescription(event.getProjectDescriptor());
}
}
@Override
public void onConfigureProject(@Nonnull ConfigureProjectEvent event) {
ProjectDescriptor toConfigure = event.getProject();
if (toConfigure != null) {
projectWizardPresenter.show(toConfigure);
}
}
private void closeCurrentProject(CloseCallback closeCallback, boolean closingBeforeOpening) {
final CurrentProject currentProject = appContext.getCurrentProject();
if (currentProject == null) {
return;
}
closeCurrentProject(closingBeforeOpening);
if (closeCallback != null) {
closeCallback.onClosed();
}
}
private void tryOpenProject(String projectName) {
Unmarshallable<ProjectDescriptor> unmarshaller = dtoUnmarshallerFactory.newUnmarshaller(ProjectDescriptor.class);
projectServiceClient.getProject(projectName, new AsyncRequestCallback<ProjectDescriptor>(unmarshaller) {
@Override
protected void onSuccess(final ProjectDescriptor project) {
if (hasProblems(project)) {
if (appContext.getCurrentProject() != null) {
closeCurrentProject(new CloseCallback() {
@Override
public void onClosed() {
openProblemProject(project);
}
}, false);
} else {
openProblemProject(project);
}
} else {
if (appContext.getCurrentProject() != null) {
closeCurrentProject(new CloseCallback() {
@Override
public void onClosed() {
openProject(project);
}
}, true);
} else {
openProject(project);
}
}
}
@Override
protected void onFailure(Throwable throwable) {
Log.error(AppContext.class, throwable);
}
});
}
private boolean hasProblems(ProjectDescriptor project) {
return !project.getProblems().isEmpty();
}
private void closeCurrentProject(boolean closingBeforeOpening) {
final CurrentProject currentProject = appContext.getCurrentProject();
if (currentProject != null) {
ProjectDescriptor closedProject = currentProject.getRootProject();
Document.get().setTitle(constant.codenvyTabTitle());
rewriteBrowserHistory(null);
// notify all listeners about current project has been closed
eventBus.fireEvent(ProjectActionEvent.createProjectClosedEvent(closedProject, closingBeforeOpening));
appContext.setCurrentProject(null);
}
}
private void openProject(ProjectDescriptor project) {
appContext.setCurrentProject(new CurrentProject(project));
Document.get().setTitle(constant.codenvyTabTitle(project.getName()));
rewriteBrowserHistory(project.getName());
// notify all listeners about opening project
eventBus.fireEvent(ProjectActionEvent.createProjectOpenedEvent(project));
}
private void openProblemProject(final ProjectDescriptor project) {
ProjectProblemDialog dialog = new ProjectProblemDialog(
constant.projectProblemTitle(),
constant.projectProblemMessage(),
new ProjectProblemDialog.AskHandler() {
@Override
public void onConfigure() {
openProject(project);
eventBus.fireEvent(new ConfigureProjectEvent(project));
}
@Override
public void onDelete() {
deleteProject(project);
}
@Override
public void onCancel() {
Document.get().setTitle(constant.codenvyTabTitle());
rewriteBrowserHistory(null);
eventBus.fireEvent(new RefreshProjectTreeEvent());
}
});
dialog.show();
}
private void rewriteBrowserHistory(@Nullable String projectName) {
StringBuilder url = new StringBuilder();
url.append(Config.getContext()).append('/').append(Config.getWorkspaceName());
if (projectName != null) {
url.append('/').append(projectName);
}
Browser.getWindow().getHistory().replaceState(null, Window.getTitle(), url.toString());
}
private void deleteProject(ProjectDescriptor project) {
projectServiceClient.delete(project.getPath(), new AsyncRequestCallback<Void>() {
@Override
protected void onSuccess(Void result) {
Document.get().setTitle(constant.codenvyTabTitle());
rewriteBrowserHistory(null);
eventBus.fireEvent(new RefreshProjectTreeEvent());
}
@Override
protected void onFailure(Throwable exception) {
Log.error(ProjectStateHandler.class, exception);
}
});
}
private interface CloseCallback {
void onClosed();
}
}