/******************************************************************************* * Copyright (c) 2012-2016 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.extension.machine.client.perspective.widgets.recipe.editor; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.google.gwt.user.client.ui.IsWidget; import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.AssistedInject; import org.eclipse.che.api.machine.shared.dto.recipe.RecipeDescriptor; import org.eclipse.che.ide.api.editor.EditorInitException; import org.eclipse.che.ide.api.editor.EditorPartPresenter; import org.eclipse.che.ide.api.filetypes.FileType; import org.eclipse.che.ide.api.filetypes.FileTypeRegistry; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.parts.PartPresenter; import org.eclipse.che.ide.api.parts.PropertyListener; import org.eclipse.che.ide.api.project.tree.VirtualFile; import org.eclipse.che.ide.api.texteditor.HandlesUndoRedo; import org.eclipse.che.ide.api.texteditor.HasReadOnlyProperty; import org.eclipse.che.ide.api.texteditor.UndoableEditor; import org.eclipse.che.ide.editor.orion.client.OrionEditorWidget; import org.eclipse.che.ide.editor.orion.client.OrionTextEditorFactory; import org.eclipse.che.ide.extension.machine.client.perspective.widgets.tab.content.TabPresenter; import org.eclipse.che.ide.jseditor.client.editorconfig.DefaultTextEditorConfiguration; import org.eclipse.che.ide.jseditor.client.texteditor.EmbeddedTextEditor; import org.eclipse.che.ide.jseditor.client.texteditor.EmbeddedTextEditorPresenter; import org.eclipse.che.ide.jseditor.client.texteditor.TextEditor; import org.eclipse.che.ide.util.loging.Log; import javax.validation.constraints.NotNull; import java.util.List; import static org.eclipse.che.ide.api.editor.EditorPartPresenter.PROP_DIRTY; import static org.eclipse.che.ide.api.editor.EditorPartPresenter.PROP_INPUT; /** * The class that manages Properties panel widget. * * @author Valeriy Svydenko */ public class RecipeEditorPanel implements TabPresenter, RecipeEditorView.ActionDelegate { private final RecipeEditorView view; private final RecipeFileFactory recipeFileFactory; private final FileTypeRegistry fileTypeRegistry; private final RecipeDescriptor recipeDescriptor; private final OrionTextEditorFactory orionTextEditorFactory; private final NotificationManager notificationManager; private EditorPartPresenter editor; private ActionDelegate delegate; private int undoOperations; private boolean isInitialized; @AssistedInject public RecipeEditorPanel(RecipeFileFactory recipeFileFactory, FileTypeRegistry fileTypeRegistry, OrionTextEditorFactory orionTextEditorFactory, NotificationManager notificationManager, RecipeEditorView view, @Assisted @NotNull RecipeDescriptor recipeDescriptor) { this.view = view; this.notificationManager = notificationManager; this.recipeFileFactory = recipeFileFactory; this.orionTextEditorFactory = orionTextEditorFactory; this.fileTypeRegistry = fileTypeRegistry; this.recipeDescriptor = recipeDescriptor; this.isInitialized = false; this.view.setDelegate(this); setEnableSaveAndCancelButtons(false); } /** Sets the delegate to receive events from this view. */ public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; } /** Changes enable state of 'Cancel', 'Save' and 'Delete' buttons. */ public void setEnableSaveCancelCloneDeleteBtns(boolean enable) { view.setEnableCancelButton(enable); view.setEnableSaveButton(enable); view.setEnableDeleteButton(enable); view.setEnableCloneButton(enable); } public void setVisibleSaveCancelCloneDeleteBtns(boolean visible) { view.setVisibleCancelButton(visible); view.setVisibleDeleteButton(visible); view.setVisibleSaveButton(visible); view.setVisibleCloneButton(visible); } /** Returns a script of recipe */ @NotNull public String getScript() { return ((TextEditor)editor).getDocument().getContents(); } /** Returns list of tags. */ @NotNull public List<String> getTags() { return view.getTags(); } /** Returns name of the recipe. */ @NotNull public String getName() { return view.getName(); } /** Sets name of the recipe. */ public void setName(@NotNull String name) { view.setName(name); } /** Sets list of tags. */ public void setTags(@NotNull List<String> tags) { view.setTags(tags); } /** {@inheritDoc} */ @Override public void showEditor() { if (isInitialized) { return; } VirtualFile recipeFile = recipeFileFactory.newInstance(recipeDescriptor.getScript()); initializeEditor(recipeFile); isInitialized = true; } private void setEnableSaveAndCancelButtons(boolean isEnable) { view.setEnableSaveButton(isEnable); view.setEnableCancelButton(isEnable); } private void initializeEditor(@NotNull final VirtualFile file) { FileType fileType = fileTypeRegistry.getFileTypeByFile(file); editor = getEditor(); editor.activate(); editor.onOpen(); view.showEditor(editor); // wait when editor is initialized editor.addPropertyListener(new PropertyListener() { @Override public void propertyChanged(PartPresenter source, int propId) { switch (propId) { case PROP_INPUT: setReadOnlyProperty(file); view.showEditor(editor); break; case PROP_DIRTY: if (validateUndoOperation()) { setEnableSaveAndCancelButtons(true); } break; default: } } }); try { editor.init(new RecipeEditorInput(fileType, file)); } catch (EditorInitException e) { Log.error(getClass(), e); } } private EmbeddedTextEditor getEditor() { EmbeddedTextEditorPresenter<OrionEditorWidget> editor = orionTextEditorFactory.createTextEditor(); editor.initialize(new DefaultTextEditorConfiguration(), notificationManager); return editor; } private void setReadOnlyProperty(VirtualFile file) { if (editor instanceof HasReadOnlyProperty) { ((HasReadOnlyProperty)editor).setReadOnly(file.isReadOnly()); } } private boolean validateUndoOperation() { // this code needs for right behaviour when someone is clicking on 'Cancel' button. We need to make disable some buttons. if (undoOperations == 0) { return true; } undoOperations--; return false; } /** {@inheritDoc} */ @Override public void go(AcceptsOneWidget container) { container.setWidget(view); } /** {@inheritDoc} */ @Override public void onCloneButtonClicked() { delegate.onCloneButtonClicked(); } /** {@inheritDoc} */ @Override public void onNewButtonClicked() { delegate.onNewButtonClicked(); } /** {@inheritDoc} */ @Override public void onSaveButtonClicked() { setEnableSaveAndCancelButtons(false); delegate.onSaveButtonClicked(); } /** {@inheritDoc} */ @Override public void onDeleteButtonClicked() { delegate.onDeleteButtonClicked(); } /** {@inheritDoc} */ @Override public void onCancelButtonClicked() { setEnableSaveAndCancelButtons(false); view.setTags(recipeDescriptor.getTags()); view.setName(recipeDescriptor.getName()); if (editor instanceof UndoableEditor) { HandlesUndoRedo undoRedo = ((UndoableEditor)editor).getUndoRedo(); while (editor.isDirty() && undoRedo.undoable()) { undoOperations++; undoRedo.undo(); } } } /** {@inheritDoc} */ @Override public IsWidget getView() { return view; } /** {@inheritDoc} */ @Override public void setVisible(boolean visible) { } public interface ActionDelegate { /** Performs some actions in response to user's clicking on the 'Delete' button. */ void onDeleteButtonClicked(); /** Performs some actions in response to user's clicking on the 'Create' button. */ void onCloneButtonClicked(); /** Performs some actions in response to user's clicking on the 'Create' button. */ void onNewButtonClicked(); /** Performs some actions in response to user's clicking on the 'Save' button. */ void onSaveButtonClicked(); /** Selects firs created recipe. */ void selectRecipe(); } }