/******************************************************************************* * 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.ide.command.editor; import com.google.common.annotations.VisibleForTesting; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.google.gwt.user.client.ui.IsWidget; import com.google.inject.Inject; import com.google.web.bindery.event.shared.EventBus; import com.google.web.bindery.event.shared.HandlerRegistration; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.api.promises.client.PromiseError; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.command.CommandImpl; import org.eclipse.che.ide.api.command.CommandManager; import org.eclipse.che.ide.api.command.CommandRemovedEvent; import org.eclipse.che.ide.api.command.CommandRemovedEvent.CommandRemovedHandler; import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.editor.AbstractEditorPresenter; import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.EditorInput; import org.eclipse.che.ide.api.icon.Icon; import org.eclipse.che.ide.api.icon.IconRegistry; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.parts.WorkspaceAgent; import org.eclipse.che.ide.api.resources.VirtualFile; import org.eclipse.che.ide.command.editor.page.CommandEditorPage; import org.eclipse.che.ide.command.editor.page.commandline.CommandLinePage; import org.eclipse.che.ide.command.editor.page.goal.GoalPage; import org.eclipse.che.ide.command.editor.page.name.NamePage; import org.eclipse.che.ide.command.editor.page.previewurl.PreviewUrlPage; import org.eclipse.che.ide.command.editor.page.project.ProjectsPage; import org.eclipse.che.ide.command.node.CommandFileNode; import org.eclipse.che.ide.command.node.NodeFactory; import org.vectomatic.dom.svg.ui.SVGImage; import org.vectomatic.dom.svg.ui.SVGResource; import java.util.LinkedList; import java.util.List; import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.EMERGE_MODE; import static org.eclipse.che.ide.api.notification.StatusNotification.Status.WARNING; /** Presenter for command editor. */ public class CommandEditor extends AbstractEditorPresenter implements CommandEditorView.ActionDelegate, CommandRemovedHandler { private final CommandEditorView view; private final WorkspaceAgent workspaceAgent; private final IconRegistry iconRegistry; private final CommandManager commandManager; private final NotificationManager notificationManager; private final DialogFactory dialogFactory; private final EditorAgent editorAgent; private final CoreLocalizationConstant coreMessages; private final EditorMessages messages; private final NodeFactory nodeFactory; private final EventBus eventBus; private final List<CommandEditorPage> pages; /** Edited command. */ @VisibleForTesting protected CommandImpl editedCommand; private HandlerRegistration commandRemovedHandlerRegistration; /** Initial (before any modification) name of the edited command. */ private String initialCommandName; @Inject public CommandEditor(CommandEditorView view, WorkspaceAgent workspaceAgent, IconRegistry iconRegistry, CommandManager commandManager, NamePage namePage, ProjectsPage projectsPage, CommandLinePage commandLinePage, GoalPage goalPage, PreviewUrlPage previewUrlPage, NotificationManager notificationManager, DialogFactory dialogFactory, EditorAgent editorAgent, CoreLocalizationConstant coreMessages, EditorMessages messages, NodeFactory nodeFactory, EventBus eventBus) { this.view = view; this.workspaceAgent = workspaceAgent; this.iconRegistry = iconRegistry; this.commandManager = commandManager; this.notificationManager = notificationManager; this.dialogFactory = dialogFactory; this.editorAgent = editorAgent; this.coreMessages = coreMessages; this.messages = messages; this.nodeFactory = nodeFactory; this.eventBus = eventBus; view.setDelegate(this); pages = new LinkedList<>(); pages.add(previewUrlPage); pages.add(projectsPage); pages.add(goalPage); pages.add(commandLinePage); pages.add(namePage); } @Override public void go(AcceptsOneWidget container) { container.setWidget(getView()); } @Override protected void initializeEditor(EditorAgent.OpenEditorCallback callback) { commandRemovedHandlerRegistration = eventBus.addHandler(CommandRemovedEvent.getType(), this); final VirtualFile file = getEditorInput().getFile(); if (file instanceof CommandFileNode) { // make a copy of the given command to avoid modifying of the provided command editedCommand = new CommandImpl(((CommandFileNode)file).getData()); initializePages(); pages.forEach(page -> view.addPage(page.getView(), page.getTitle())); } else { callback.onInitializationFailed(); } } /** Initialize editor's pages with the edited command. */ private void initializePages() { initialCommandName = editedCommand.getName(); pages.forEach(page -> { page.edit(editedCommand); page.setDirtyStateListener(() -> { updateDirtyState(isDirtyPage()); view.setSaveEnabled(isDirtyPage()); }); }); } /** Checks whether any page is dirty. */ private boolean isDirtyPage() { for (CommandEditorPage page : pages) { if (page.isDirty()) { return true; } } return false; } @Nullable @Override public SVGResource getTitleImage() { final VirtualFile file = getEditorInput().getFile(); if (file instanceof CommandFileNode) { final CommandImpl command = ((CommandFileNode)file).getData(); final Icon icon = iconRegistry.getIconIfExist("command.type." + command.getType()); if (icon != null) { final SVGImage svgImage = icon.getSVGImage(); if (svgImage != null) { return icon.getSVGResource(); } } } return input.getSVGResource(); } @Override public String getTitle() { return (isDirty() ? "* " : "") + input.getName(); } @Override public IsWidget getView() { return view; } @Nullable @Override public String getTitleToolTip() { return input.getName(); } @Override public void doSave() { doSave(new AsyncCallback<EditorInput>() { @Override public void onFailure(Throwable caught) { } @Override public void onSuccess(EditorInput result) { } }); } @Override public void doSave(AsyncCallback<EditorInput> callback) { commandManager.updateCommand(initialCommandName, editedCommand).then(arg -> { updateDirtyState(false); // according to the CommandManager#updateCommand contract // command's name after updating may differ from the proposed name // in order to prevent name duplication editedCommand.setName(arg.getName()); if (!initialCommandName.equals(editedCommand.getName())) { input.setFile(nodeFactory.newCommandFileNode(editedCommand)); } initializePages(); callback.onSuccess(getEditorInput()); }).catchError((Operation<PromiseError>)arg -> { notificationManager.notify(messages.editorMessageUnableToSave(), arg.getMessage(), WARNING, EMERGE_MODE); callback.onFailure(arg.getCause()); throw new OperationException(arg.getMessage()); }); } @Override public void doSaveAs() { } @Override public void activate() { } @Override public void close(boolean save) { workspaceAgent.removePart(this); } @Override public void onClosing(AsyncCallback<Void> callback) { if (!isDirty()) { callback.onSuccess(null); } else { dialogFactory.createChoiceDialog( coreMessages.askWindowCloseTitle(), coreMessages.messagesSaveChanges(getEditorInput().getName()), coreMessages.yesButtonTitle(), coreMessages.noButtonTitle(), coreMessages.cancelButton(), () -> doSave(new AsyncCallback<EditorInput>() { @Override public void onSuccess(EditorInput result) { callback.onSuccess(null); } @Override public void onFailure(Throwable caught) { callback.onFailure(null); } }), () -> callback.onSuccess(null), () -> callback.onFailure(null)).show(); } } @Override public void onCommandCancel() { close(false); } @Override public void onCommandSave() { doSave(); } @Override public void onCommandRemoved(CommandRemovedEvent event) { if (event.getCommand().getName().equals(editedCommand.getName())) { editorAgent.closeEditor(this); commandRemovedHandlerRegistration.removeHandler(); } } }