diff --git a/dashboard/src/app/ide/ide-iframe-button-link/ide-iframe-button-link.styl b/dashboard/src/app/ide/ide-iframe-button-link/ide-iframe-button-link.styl index 65e8feecb6..9edd0a0ed5 100644 --- a/dashboard/src/app/ide/ide-iframe-button-link/ide-iframe-button-link.styl +++ b/dashboard/src/app/ide/ide-iframe-button-link/ide-iframe-button-link.styl @@ -4,7 +4,7 @@ outline none width 24px height 16px - top 4px + top 9px background-color $navbar-ide-iframe-button-background-color color $light-gray-color font-size 8px diff --git a/dashboard/src/app/navbar/navbar.styl b/dashboard/src/app/navbar/navbar.styl index 9481c4c7d8..ce253d99b6 100644 --- a/dashboard/src/app/navbar/navbar.styl +++ b/dashboard/src/app/navbar/navbar.styl @@ -298,7 +298,7 @@ che-nav-bar .navbar-iframe-button-left-border position absolute - top 4px + top 9px right 0 width 0 height 16px diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/IdeActions.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/IdeActions.java index 4d046912b8..38aa616d21 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/IdeActions.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/action/IdeActions.java @@ -44,6 +44,7 @@ public interface IdeActions { String GROUP_OTHER_MENU = "otherMenu"; String GROUP_LEFT_MAIN_MENU = "leftMainMenu"; + @Deprecated String GROUP_RIGHT_MAIN_MENU = "rightMainMenu"; String GROUP_CENTER_STATUS_PANEL = "centerStatusPanelGroup"; diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/BaseCommandGoal.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/BaseCommandGoal.java new file mode 100644 index 0000000000..819914f304 --- /dev/null +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/BaseCommandGoal.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.api.command; + +import java.util.Objects; + +/** + * Base implementation of the {@link CommandGoal}. + * + * @author Artem Zatsarynnyi + */ +public class BaseCommandGoal implements CommandGoal { + + private final String id; + + public BaseCommandGoal(String id) { + this.id = id; + } + + @Override + public String getId() { + return id; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof CommandGoal)) { + return false; + } + + CommandGoal other = (CommandGoal)o; + + return Objects.equals(getId(), other.getId()); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandExecutor.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandExecutor.java new file mode 100644 index 0000000000..6355bba3af --- /dev/null +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandExecutor.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * 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.api.command; + +import org.eclipse.che.api.core.model.machine.Command; +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.ide.api.macro.Macro; + +/** + * Allows to execute a command. + * + * @author Artem Zatsarynnyi + */ +public interface CommandExecutor { + + /** + * Sends the the given {@code command} to the specified {@code machine} for execution. + *

Note that all {@link Macro}s will be expanded into + * real values before sending the {@code command} for execution. + * + * @param command + * command to execute + * @param machine + * machine to execute the command + * @see Macro + */ + void executeCommand(Command command, Machine machine); + + /** + * Sends the the given {@code command} for execution. + *

If any machine is currently selected it will be used as execution target. + * Otherwise user will be asked for choosing execution target. + *

Note that all {@link Macro}s will be expanded into + * real values before sending the {@code command} for execution. + * + * @param command + * command to execute + * @see Macro + */ + void executeCommand(CommandImpl command); +} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandGoal.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandGoal.java new file mode 100644 index 0000000000..1092083d47 --- /dev/null +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandGoal.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * 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.api.command; + +/** + * Contract for command goal. + * + * @author Artem Zatsarynnyi + */ +public interface CommandGoal { + + /** Returns goal ID. */ + String getId(); +} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandGoalRegistry.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandGoalRegistry.java new file mode 100644 index 0000000000..6f493f3584 --- /dev/null +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandGoalRegistry.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * 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.api.command; + +import org.eclipse.che.commons.annotation.Nullable; + +import java.util.List; +import java.util.Optional; + +/** + * Registry of command goals. + * + * @author Artem Zatsarynnyi + */ +public interface CommandGoalRegistry { + + /** Returns all registered predefined {@link CommandGoal}s. */ + List getAllPredefinedGoals(); + + /** Returns the default command goal which is used for grouping commands which doesn't belong to any goal. */ + CommandGoal getDefaultGoal(); + + /** + * Returns an optional {@link CommandGoal} by the given ID + * or {@code Optional.absent()} if none was registered. + * + * @param id + * the ID of the predefined command goal to get + * @return an optional {@link CommandGoal} or {@code Optional.absent()} if none was registered + */ + Optional getPredefinedGoalById(String id); + + /** + * Returns a predefined {@link CommandGoal} by the given ID + * or the custom (non-predefined) goal if none was registered + * or the default goal if the given {@code id} is {@code null} or empty string. + * + * @param id + * the ID of the command goal + * @return a predefined {@link CommandGoal} with the given ID + * or the custom (non-predefined) goal if none was registered + * or the default goal if the given {@code id} is {@code null} or empty string. Never null. + */ + CommandGoal getGoalForId(@Nullable String id); +} diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandImpl.java index 414f16bea8..3813d0c16d 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandImpl.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandImpl.java @@ -11,42 +11,38 @@ package org.eclipse.che.ide.api.command; import org.eclipse.che.api.core.model.machine.Command; +import org.eclipse.che.commons.annotation.Nullable; -import java.util.Collections; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; -/** - * Model of the command. - * - * @author Artem Zatsarynnyi - */ +import static java.util.Collections.unmodifiableList; +import static org.eclipse.che.api.workspace.shared.Constants.COMMAND_GOAL_ATTRIBUTE_NAME; + +/** Data object for {@link Command}. */ public class CommandImpl implements Command { - private final String type; + private final String typeId; + private final ApplicableContext context; private String name; private String commandLine; private Map attributes; - /** - * Creates new command of the specified type with the given name and command line. - * - * @param name - * command name - * @param commandLine - * command line - * @param type - * type of the command - */ - public CommandImpl(String name, String commandLine, String type) { - this(name, commandLine, type, Collections.emptyMap()); + /** Creates new {@link CommandImpl} based on the given data. */ + public CommandImpl(Command command, ApplicableContext context) { + this(command.getName(), + command.getCommandLine(), + command.getType(), + new HashMap<>(command.getAttributes()), + context); } - public CommandImpl(String name, String commandLine, String type, Map attributes) { - this.name = name; - this.commandLine = commandLine; - this.type = type; - this.attributes = attributes; + /** Creates new {@link CommandImpl} based on the provided data. */ + public CommandImpl(String name, String commandLine, String typeId) { + this(name, commandLine, typeId, new HashMap<>()); } /** Creates copy of the given {@link Command}. */ @@ -54,7 +50,34 @@ public class CommandImpl implements Command { this(command.getName(), command.getCommandLine(), command.getType(), - command.getAttributes()); + new HashMap<>(command.getAttributes())); + } + + /** Creates copy of the given {@code command}. */ + public CommandImpl(CommandImpl command) { + this(command.getName(), + command.getCommandLine(), + command.getType(), + new HashMap<>(command.getAttributes()), + new ApplicableContext(command.getApplicableContext())); + } + + /** Creates new {@link CommandImpl} based on the provided data. */ + public CommandImpl(String name, String commandLine, String typeId, Map attributes) { + this.name = name; + this.commandLine = commandLine; + this.typeId = typeId; + this.attributes = attributes; + this.context = new ApplicableContext(); + } + + /** Creates new {@link CommandImpl} based on the provided data. */ + public CommandImpl(String name, String commandLine, String typeId, Map attributes, ApplicableContext context) { + this.name = name; + this.commandLine = commandLine; + this.typeId = typeId; + this.attributes = attributes; + this.context = context; } @Override @@ -77,7 +100,7 @@ public class CommandImpl implements Command { @Override public String getType() { - return type; + return typeId; } @Override @@ -89,6 +112,27 @@ public class CommandImpl implements Command { this.attributes = attributes; } + /** Returns ID of the command's goal or {@code null} if none. */ + @Nullable + public String getGoal() { + return getAttributes().get(COMMAND_GOAL_ATTRIBUTE_NAME); + } + + /** Sets command's goal ID. */ + public void setGoal(String goalId) { + getAttributes().put(COMMAND_GOAL_ATTRIBUTE_NAME, goalId); + } + + /** Returns command's applicable context. */ + public ApplicableContext getApplicableContext() { + return context; + } + + /** + * {@inheritDoc} + * + * @see #equalsIgnoreContext(CommandImpl) + */ @Override public boolean equals(Object o) { if (this == o) { @@ -102,13 +146,109 @@ public class CommandImpl implements Command { CommandImpl other = (CommandImpl)o; return Objects.equals(getName(), other.getName()) - && Objects.equals(type, other.type) + && Objects.equals(typeId, other.typeId) && Objects.equals(commandLine, other.commandLine) - && Objects.equals(getAttributes(), other.getAttributes()); + && Objects.equals(getAttributes(), other.getAttributes()) + && Objects.equals(getApplicableContext(), other.getApplicableContext()); + } + + /** + * Compares this {@link CommandImpl} to another {@link CommandImpl}, ignoring applicable context considerations. + * + * @param anotherCommand + * the {@link CommandImpl} to compare this {@link CommandImpl} against + * @return {@code true} if the argument represents an equivalent {@link CommandImpl} + * ignoring applicable context; {@code false} otherwise + */ + public boolean equalsIgnoreContext(CommandImpl anotherCommand) { + if (this == anotherCommand) { + return true; + } + + return Objects.equals(getName(), anotherCommand.getName()) + && Objects.equals(typeId, anotherCommand.typeId) + && Objects.equals(commandLine, anotherCommand.commandLine) + && Objects.equals(getAttributes(), anotherCommand.getAttributes()); } @Override public int hashCode() { - return Objects.hash(name, type, commandLine, getAttributes()); + return Objects.hash(name, typeId, commandLine, getAttributes(), getApplicableContext()); + } + + /** Defines the context in which command is applicable. */ + public static class ApplicableContext { + + private boolean workspaceApplicable; + private List projects; + + /** Creates new {@link ApplicableContext} which is workspace applicable. */ + public ApplicableContext() { + workspaceApplicable = true; + projects = new ArrayList<>(); + } + + /** Creates new {@link ApplicableContext} which is applicable to the single project only. */ + public ApplicableContext(String projectPath) { + projects = new ArrayList<>(); + projects.add(projectPath); + } + + /** Creates new {@link ApplicableContext} based on the provided data. */ + public ApplicableContext(boolean workspaceApplicable, List projects) { + this.workspaceApplicable = workspaceApplicable; + this.projects = projects; + } + + /** Creates copy of the given {@code context}. */ + public ApplicableContext(ApplicableContext context) { + this(context.isWorkspaceApplicable(), new ArrayList<>(context.getApplicableProjects())); + } + + /** Returns {@code true} if command is applicable to the workspace and {@code false} otherwise. */ + public boolean isWorkspaceApplicable() { + return workspaceApplicable; + } + + /** Sets whether the command should be applicable to the workspace or not. */ + public void setWorkspaceApplicable(boolean applicable) { + this.workspaceApplicable = applicable; + } + + /** Returns immutable list of the paths of the applicable projects. */ + public List getApplicableProjects() { + return unmodifiableList(projects); + } + + /** Adds applicable project's path. */ + public void addProject(String path) { + projects.add(path); + } + + /** Removes applicable project's path. */ + public void removeProject(String path) { + projects.remove(path); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof ApplicableContext)) { + return false; + } + + ApplicableContext other = (ApplicableContext)o; + + return workspaceApplicable == other.workspaceApplicable && + Objects.equals(projects, other.projects); + } + + @Override + public int hashCode() { + return Objects.hash(workspaceApplicable, projects); + } } } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandManager.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandManager.java index 5c9b70c289..3b1e80d121 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandManager.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/command/CommandManager.java @@ -10,73 +10,158 @@ *******************************************************************************/ package org.eclipse.che.ide.api.command; -import org.eclipse.che.api.core.model.machine.Machine; import org.eclipse.che.api.promises.client.Promise; -import org.eclipse.che.ide.api.macro.Macro; +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.command.CommandImpl.ApplicableContext; import java.util.List; import java.util.Map; +import java.util.Optional; /** - * Facade for command related operations. + * Facade for command management. * - * @author Artem Zatsarynnyi + * @see CommandImpl */ public interface CommandManager { /** Returns all commands. */ List getCommands(); - /** - * Creates new command of the specified type. - *

Note that command's name will be generated by {@link CommandManager} - * and command line will be provided by an appropriate {@link CommandType}. - */ - Promise create(String type); + /** Returns optional command by the specified name or {@link Optional#empty()} if none. */ + Optional getCommand(String name); + + /** Returns commands which are applicable to the current IDE context. */ + List getApplicableCommands(); + + /** Checks whether the given {@code command} is applicable to the current IDE context or not. */ + boolean isCommandApplicable(CommandImpl command); /** - * Creates new command with the specified arguments. - *

Note that name of the created command may differ from - * the specified {@code desirableName} in order to prevent name duplication. + * Creates new command based on the given data. + * Command's name and command line will be generated automatically. + * Command will be bound to the workspace. + * + * @param goalId + * ID of the goal to which created command should belong + * @param typeId + * ID of the type to which created command should belong + * @return created command */ - Promise create(String desirableName, String commandLine, String type, Map attributes); + Promise createCommand(String goalId, String typeId); + + /** + * Creates new command based on the given data. + * Command's name and command line will be generated automatically. + * + * @param goalId + * ID of the goal to which created command should belong + * @param typeId + * ID of the type to which created command should belong + * @param context + * command's {@link ApplicableContext} + * @return created command + */ + Promise createCommand(String goalId, String typeId, ApplicableContext context); + + /** + * Creates new command based on the given data. Command will be bound to the workspace. + * + * @param goalId + * ID of the goal to which created command should belong + * @param typeId + * ID of the type to which created command should belong + * @param name + * command's name. + * Note that actual name may differ from the given one in order to prevent duplication. + * If {@code null}, name will be generated automatically. + * @param commandLine + * actual command line. If {@code null}, command line will be generated by the corresponding command type. + * @param attributes + * command's attributes + * @return created command + */ + Promise createCommand(String goalId, + String typeId, + @Nullable String name, + @Nullable String commandLine, + Map attributes); + + /** + * Creates new command based on the given data. + * + * @param goalId + * ID of the goal to which created command should belong + * @param typeId + * ID of the type to which created command should belong + * @param name + * command's name. + * Note that actual name may differ from the given one in order to prevent duplication. + * If {@code null}, name will be generated automatically. + * @param commandLine + * actual command line. If {@code null}, command line will be generated by the corresponding command type. + * @param attributes + * command's attributes + * @param context + * command's {@link ApplicableContext} + * @return created command + */ + Promise createCommand(String goalId, + String typeId, + @Nullable String name, + @Nullable String commandLine, + Map attributes, + ApplicableContext context); + + /** + * Creates copy of the given {@code command}. + *

Note that name of the created command may differ from + * the given {@code command}'s name in order to prevent name duplication. + */ + Promise createCommand(CommandImpl command); /** * Updates the command with the specified {@code name} by replacing it with the given {@code command}. *

Note that name of the updated command may differ from the name provided by the given {@code command} * in order to prevent name duplication. */ - Promise update(String name, CommandImpl command); + Promise updateCommand(String name, CommandImpl command); - /** Removes the command with the specified {@code name}. */ - Promise remove(String name); + /** Removes command with the specified {@code commandName}. */ + Promise removeCommand(String commandName); - /** Returns the pages for editing command of the specified {@code type}. */ - List getPages(String type); + void addCommandLoadedListener(CommandLoadedListener listener); - /** - * Sends the the given {@code command} to the specified {@code machine} for execution. - *

Note that all {@link Macro}s will be expanded into - * real values before sending the {@code command} for execution. - * - * @param command - * command to execute - * @param machine - * machine to execute the command - * @see Macro - */ - void executeCommand(CommandImpl command, Machine machine); + void removeCommandLoadedListener(CommandLoadedListener listener); void addCommandChangedListener(CommandChangedListener listener); void removeCommandChangedListener(CommandChangedListener listener); - /** Listener that will be called when command has been changed. */ + /** Listener to notify when all commands have been loaded. */ + interface CommandLoadedListener { + + /** Called when all commands have been loaded. */ + void onCommandsLoaded(); + } + + /** Listener to notify when command has been changed. */ interface CommandChangedListener { + + /** Called when command has been added. */ void onCommandAdded(CommandImpl command); - void onCommandUpdated(CommandImpl command); + /** + * Called when command has been updated. + * + * @param previousCommand + * command before updating + * @param command + * updated command + */ + void onCommandUpdated(CommandImpl previousCommand, CommandImpl command); + /** Called when command has been removed. */ void onCommandRemoved(CommandImpl command); } } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/AbstractEditorPresenter.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/AbstractEditorPresenter.java index ffc696677b..3dd2a9a2fe 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/AbstractEditorPresenter.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/AbstractEditorPresenter.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.che.ide.api.editor; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.IsWidget; import org.eclipse.che.ide.api.parts.AbstractPartPresenter; @@ -89,4 +90,9 @@ public abstract class AbstractEditorPresenter extends AbstractPartPresenter impl public void onFileChanged() { firePropertyChange(TITLE_PROPERTY); } + + @Override + public void onClosing(AsyncCallback callback) { + callback.onSuccess(null); + } } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/EditorPartPresenter.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/EditorPartPresenter.java index ce71240e48..cc999eb7f5 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/EditorPartPresenter.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/EditorPartPresenter.java @@ -112,4 +112,13 @@ public interface EditorPartPresenter extends PartPresenter { * true if unsaved changed should be saved, and false if unsaved changed should be discarded */ void close(boolean save); + + /** + * Called when part is going to closing. + * Part can deny closing, by calling {@code callback#onFailure}. + * + * @param callback + * callback to allow or deny closing the part + */ + void onClosing(AsyncCallback callback); } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/document/DocumentStorageImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/document/DocumentStorageImpl.java index 5dbcea7d6c..15fecab6cb 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/document/DocumentStorageImpl.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/document/DocumentStorageImpl.java @@ -76,7 +76,7 @@ public class DocumentStorageImpl implements DocumentStorage { @Override public void apply(Void arg) throws OperationException { Log.debug(DocumentStorageImpl.class, "Document saved (" + file.getLocation() + ")."); - DocumentStorageImpl.this.eventBus.fireEvent(FileEvent.createSaveFileEvent(file)); + DocumentStorageImpl.this.eventBus.fireEvent(FileEvent.createFileSavedEvent(file)); try { callback.onSuccess(editorInput); } catch (final Exception e) { diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/EditorWidget.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/EditorWidget.java index 574b61332c..f3f4fda9c0 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/EditorWidget.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/editor/texteditor/EditorWidget.java @@ -79,6 +79,18 @@ public interface EditorWidget extends IsWidget, */ void setReadOnly(boolean isReadOnly); + /** Sets whether the annotation ruler is visible. */ + void setAnnotationRulerVisible(boolean show); + + /** Sets whether the folding ruler is visible. */ + void setFoldingRulerVisible(boolean show); + + /** Sets whether the zoom ruler is visible. */ + void setZoomRulerVisible(boolean show); + + /** Sets whether the overview ruler is visible. */ + void setOverviewRulerVisible(boolean show); + /** * Returns the readonly state of the editor. * diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/FileEvent.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/FileEvent.java index a9069ffb0b..ca628f31f1 100755 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/FileEvent.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/event/FileEvent.java @@ -10,19 +10,21 @@ *******************************************************************************/ package org.eclipse.che.ide.api.event; -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.ide.api.parts.EditorTab; -import org.eclipse.che.ide.api.resources.VirtualFile; - import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.GwtEvent; +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.editor.EditorPartPresenter; +import org.eclipse.che.ide.api.parts.EditorTab; +import org.eclipse.che.ide.api.resources.VirtualFile; + import static org.eclipse.che.ide.api.event.FileEvent.FileOperation.CLOSE; import static org.eclipse.che.ide.api.event.FileEvent.FileOperation.OPEN; import static org.eclipse.che.ide.api.event.FileEvent.FileOperation.SAVE; /** - * Event that describes the fact that file is going to be opened. + * Event that describes the fact that file is opened/closed/saved. * * @author Nikolay Zamosenchuk * @author Artem Zatsarynnyi @@ -30,11 +32,6 @@ import static org.eclipse.che.ide.api.event.FileEvent.FileOperation.SAVE; */ public class FileEvent extends GwtEvent { - /** Handles OpenFileEvent */ - public interface FileEventHandler extends EventHandler { - void onFileOperation(FileEvent event); - } - public static Type TYPE = new Type<>(); private VirtualFile file; private FileOperation fileOperation; @@ -69,6 +66,12 @@ public class FileEvent extends GwtEvent { /** * Creates a event for {@code FileOperation.OPEN}. */ + public static FileEvent createFileOpenedEvent(VirtualFile file) { + return new FileEvent(file, OPEN); + } + + /** @deprecated use {@link EditorAgent#openEditor(org.eclipse.che.ide.api.resources.VirtualFile)} */ + @Deprecated public static FileEvent createOpenFileEvent(VirtualFile file) { return new FileEvent(file, OPEN); } @@ -80,6 +83,12 @@ public class FileEvent extends GwtEvent { * @param tab * tab of the file to close */ + public static FileEvent createFileClosedEvent(EditorTab tab) { + return new FileEvent(tab, CLOSE); + } + + /** @deprecated use {@link EditorAgent#closeEditor(EditorPartPresenter)} */ + @Deprecated public static FileEvent createCloseFileEvent(EditorTab tab) { return new FileEvent(tab, CLOSE); } @@ -87,6 +96,11 @@ public class FileEvent extends GwtEvent { /** * Creates a event for {@code FileOperation.SAVE}. */ + public static FileEvent createFileSavedEvent(VirtualFile file) { + return new FileEvent(file, SAVE); + } + + @Deprecated public static FileEvent createSaveFileEvent(VirtualFile file) { return new FileEvent(file, SAVE); } @@ -120,4 +134,9 @@ public class FileEvent extends GwtEvent { public enum FileOperation { OPEN, SAVE, CLOSE } + + /** Handles OpenFileEvent */ + public interface FileEventHandler extends EventHandler { + void onFileOperation(FileEvent event); + } } diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/icon/Icon.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/icon/Icon.java index b09bf14407..7f71bddd8d 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/icon/Icon.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/icon/Icon.java @@ -14,11 +14,10 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.ui.Image; +import org.eclipse.che.commons.annotation.Nullable; import org.vectomatic.dom.svg.ui.SVGImage; import org.vectomatic.dom.svg.ui.SVGResource; -import org.eclipse.che.commons.annotation.Nullable; - /** * Icon. * @@ -129,4 +128,14 @@ public class Icon { } return new SVGImage(svgResource); } + + /** + * Returns {@link SVGResource} widget. + * + * @return {@link SVGResource} widget + */ + @Nullable + public SVGResource getSVGResource() { + return svgResource; + } } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/ProcessFinishedEvent.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/events/ProcessFinishedEvent.java similarity index 79% rename from plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/ProcessFinishedEvent.java rename to ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/events/ProcessFinishedEvent.java index 05720c9ee6..f42e1f3621 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/ProcessFinishedEvent.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/events/ProcessFinishedEvent.java @@ -8,11 +8,13 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.extension.machine.client.processes; +package org.eclipse.che.ide.api.machine.events; import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.GwtEvent; +import org.eclipse.che.api.core.model.machine.Machine; + /** * @author Dmitry Shnurenko */ @@ -27,16 +29,22 @@ public class ProcessFinishedEvent extends GwtEvent public static final Type TYPE = new Type<>(); - private final int processID; + private final int processID; + private final Machine machine; - public ProcessFinishedEvent(int processID) { + public ProcessFinishedEvent(int processID, Machine machine) { this.processID = processID; + this.machine = machine; } public int getProcessID() { return processID; } + public Machine getMachine() { + return machine; + } + @Override public Type getAssociatedType() { return TYPE; diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/events/ProcessStartedEvent.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/events/ProcessStartedEvent.java new file mode 100644 index 0000000000..80f0cb2d01 --- /dev/null +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/machine/events/ProcessStartedEvent.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.api.machine.events; + +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.GwtEvent; + +import org.eclipse.che.api.core.model.machine.Machine; + +public class ProcessStartedEvent extends GwtEvent { + + public static final Type TYPE = new Type<>(); + + private final int processID; + private final Machine machine; + + public ProcessStartedEvent(int processID, Machine machine) { + this.processID = processID; + this.machine = machine; + } + + public int getProcessID() { + return processID; + } + + public Machine getMachine() { + return machine; + } + + @Override + public Type getAssociatedType() { + return TYPE; + } + + @Override + protected void dispatch(Handler handler) { + handler.onProcessStarted(this); + } + + public interface Handler extends EventHandler { + + void onProcessStarted(ProcessStartedEvent event); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/CustomMacro.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/macro/BaseMacro.java similarity index 84% rename from ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/CustomMacro.java rename to ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/macro/BaseMacro.java index 349eadf059..a338100403 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/CustomMacro.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/macro/BaseMacro.java @@ -8,32 +8,29 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.macro; +package org.eclipse.che.ide.api.macro; -import com.google.common.annotations.Beta; import com.google.common.base.Objects; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.promises.client.js.Promises; -import org.eclipse.che.ide.api.macro.Macro; import static com.google.common.base.Preconditions.checkNotNull; /** - * Custom macro provider which allows to register user's macro with the provided value. + * Base implementation of {@link Macro}. * * @author Vlad Zhukovskyi * @see Macro * @since 4.7.0 */ -@Beta -public class CustomMacro implements Macro { +public class BaseMacro implements Macro { private final String key; private final String value; private final String description; - public CustomMacro(String key, String value, String description) { + public BaseMacro(String key, String value, String description) { this.key = checkNotNull(key, "Key should not be null"); this.value = checkNotNull(value, "Value should not be null"); this.description = checkNotNull(description, "Description should not be null"); @@ -61,7 +58,7 @@ public class CustomMacro implements Macro { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - CustomMacro that = (CustomMacro)o; + BaseMacro that = (BaseMacro)o; return Objects.equal(key, that.key) && Objects.equal(value, that.value) && Objects.equal(description, that.description); @@ -76,7 +73,7 @@ public class CustomMacro implements Macro { /** {@inheritDoc} */ @Override public String toString() { - return "CustomMacro{" + + return "BaseMacro{" + "key='" + key + '\'' + ", value='" + value + '\'' + ", description='" + description + '\'' + diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/macro/Macro.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/macro/Macro.java index 173c2e1d3b..cad42da8a5 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/macro/Macro.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/macro/Macro.java @@ -22,6 +22,7 @@ import java.util.Set; * Also macro can be registered in 'runtime' with {@link MacroRegistry#register(Set)}. * * @author Artem Zatsarynnyi + * @see BaseMacro * @see MacroProcessor#expandMacros(String) * @see MacroRegistry */ diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/macro/MacroProcessor.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/macro/MacroProcessor.java index da74cd7e4d..7ff6f733d9 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/macro/MacroProcessor.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/macro/MacroProcessor.java @@ -10,17 +10,13 @@ *******************************************************************************/ package org.eclipse.che.ide.api.macro; -import org.eclipse.che.api.core.model.machine.Machine; import org.eclipse.che.api.promises.client.Promise; -import org.eclipse.che.ide.api.command.CommandImpl; -import org.eclipse.che.ide.api.command.CommandManager; /** * Expands all {@link Macro}s in the given string. * * @author Artem Zatsarynnyi * @see Macro - * @see CommandManager#executeCommand(CommandImpl, Machine) */ public interface MacroProcessor { diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/SyntheticFile.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/SyntheticFile.java index a734d02d35..e21205185c 100644 --- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/SyntheticFile.java +++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/resources/SyntheticFile.java @@ -22,8 +22,7 @@ import org.eclipse.che.ide.resource.Path; * Implementation for {@link VirtualFile} which describe resource which doesn't exist on file system and is auto generated. * For example it may be effective version of such resource. *

- * This file is read only and doesn't have link to the content url. - * Calling {@link #updateContent(String)} will cause {@link UnsupportedOperationException}. + * This file doesn't have link to the content url. * * @author Vlad Zhukovskiy * @see VirtualFile @@ -77,7 +76,9 @@ public class SyntheticFile implements VirtualFile { @Override public Promise updateContent(String content) { - throw new UnsupportedOperationException("Synthetic file is read only"); + this.content = content; + + return Promises.resolve(null); } @Override diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/CustomMacroTest.java b/ide/che-core-ide-api/src/test/java/org/eclipse/che/ide/api/macro/BaseMacroTest.java similarity index 58% rename from ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/CustomMacroTest.java rename to ide/che-core-ide-api/src/test/java/org/eclipse/che/ide/api/macro/BaseMacroTest.java index 94b4603000..bbc8436cfb 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/CustomMacroTest.java +++ b/ide/che-core-ide-api/src/test/java/org/eclipse/che/ide/api/macro/BaseMacroTest.java @@ -8,13 +8,10 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.machine; +package org.eclipse.che.ide.api.macro; import com.google.gwtmockito.GwtMockitoTestRunner; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.OperationException; -import org.eclipse.che.ide.macro.CustomMacro; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -22,42 +19,39 @@ import org.junit.runner.RunWith; import static org.junit.Assert.assertSame; /** - * Unit tests for the {@link CustomMacro} + * Unit tests for the {@link BaseMacro} * * @author Vlad Zhukovskyi */ @RunWith(GwtMockitoTestRunner.class) -public class CustomMacroTest { +public class BaseMacroTest { - public static final String KEY = "key"; - public static final String VALUE = "value"; + public static final String NAME = "name"; + public static final String VALUE = "value"; public static final String DESCRIPTION = "description"; - private CustomMacro provider; + private BaseMacro macro; @Before public void init() throws Exception { - provider = new CustomMacro(KEY, VALUE, DESCRIPTION); + macro = new BaseMacro(NAME, VALUE, DESCRIPTION); } @Test public void getKey() throws Exception { - assertSame(provider.getName(), KEY); + assertSame(macro.getName(), NAME); } @Test public void getValue() throws Exception { - provider.expand().then(new Operation() { - @Override - public void apply(String value) throws OperationException { - assertSame(value, VALUE); - } + macro.expand().then(value -> { + assertSame(value, VALUE); }); } @Test public void getDescription() throws Exception { - assertSame(provider.getDescription(), DESCRIPTION); + assertSame(macro.getDescription(), DESCRIPTION); } } \ No newline at end of file diff --git a/ide/che-core-ide-app/pom.xml b/ide/che-core-ide-app/pom.xml index 8c16467ed1..0d064db40e 100644 --- a/ide/che-core-ide-app/pom.xml +++ b/ide/che-core-ide-app/pom.xml @@ -279,27 +279,6 @@ - - - - - - - - - - - - - - - - - - - - - org.eclipse.che.core che-core-dyna-provider-generator-maven-plugin diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/Resources.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/Resources.java index de8476e432..ebba260310 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/Resources.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/Resources.java @@ -15,6 +15,7 @@ import com.google.gwt.resources.client.CssResource.NotStrict; import com.google.gwt.resources.client.TextResource; import org.eclipse.che.ide.api.parts.PartStackUIResources; +import org.eclipse.che.ide.command.CommandResources; import org.eclipse.che.ide.menu.MenuResources; import org.eclipse.che.ide.notification.NotificationResources; import org.eclipse.che.ide.projecttype.wizard.ProjectWizardResources; @@ -46,7 +47,8 @@ public interface Resources extends Tree.Resources, CellTreeResources, CategoriesList.Resources, ButtonLoaderResources, - ProjectWizardResources { + ProjectWizardResources, + CommandResources { @Source({"Core.css", "org/eclipse/che/ide/ui/constants.css", "org/eclipse/che/ide/api/ui/style.css"}) @NotStrict @@ -208,5 +210,8 @@ public interface Resources extends Tree.Resources, String createWsTagsPopup(); String tagsPanel(); + + @ClassName("codeassistant-highlight") + String codeassistantHighlight(); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/EditFileAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/EditFileAction.java index f64cde7c1f..410b71bfbb 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/EditFileAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/EditFileAction.java @@ -12,13 +12,12 @@ package org.eclipse.che.ide.actions; import com.google.inject.Inject; import com.google.inject.Singleton; -import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.Resources; import org.eclipse.che.ide.api.action.AbstractPerspectiveAction; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.event.FileEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.resources.File; import org.eclipse.che.ide.api.resources.Resource; @@ -38,17 +37,16 @@ import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspect @Singleton public class EditFileAction extends AbstractPerspectiveAction { - - private final AppContext appContext; - private final EventBus eventBus; + private final AppContext appContext; + private final EditorAgent editorAgent; @Inject public EditFileAction(AppContext appContext, - EventBus eventBus, - Resources resources) { + Resources resources, + EditorAgent editorAgent) { super(singletonList(PROJECT_PERSPECTIVE_ID), "Edit file", null, null, resources.defaultFile()); this.appContext = appContext; - this.eventBus = eventBus; + this.editorAgent = editorAgent; } /** {@inheritDoc} */ @@ -59,7 +57,7 @@ public class EditFileAction extends AbstractPerspectiveAction { checkState(resources != null && resources.length == 1 && resources[0] instanceof File, "Files only are allowed to be opened in editor"); - eventBus.fireEvent(FileEvent.createOpenFileEvent((File)resources[0])); + editorAgent.openEditor((File)resources[0]); } /** {@inheritDoc} */ diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/OpenFileAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/OpenFileAction.java index c9e63ec822..9462560297 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/OpenFileAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/actions/OpenFileAction.java @@ -28,10 +28,10 @@ import org.eclipse.che.ide.api.action.Action; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.action.PromisableAction; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.EditorPartPresenter; import org.eclipse.che.ide.api.event.ActivePartChangedEvent; import org.eclipse.che.ide.api.event.ActivePartChangedHandler; -import org.eclipse.che.ide.api.event.FileEvent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.File; import org.eclipse.che.ide.resource.Path; @@ -43,6 +43,7 @@ import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAI /** * TODO maybe rename it to factory open file? + * * @author Sergii Leschenko * @author Vlad Zhukovskyi */ @@ -56,6 +57,7 @@ public class OpenFileAction extends Action implements PromisableAction { private final CoreLocalizationConstant localization; private final NotificationManager notificationManager; private final AppContext appContext; + private final EditorAgent editorAgent; private Callback actionCompletedCallback; @@ -63,11 +65,13 @@ public class OpenFileAction extends Action implements PromisableAction { public OpenFileAction(EventBus eventBus, CoreLocalizationConstant localization, NotificationManager notificationManager, - AppContext appContext) { + AppContext appContext, + EditorAgent editorAgent) { this.eventBus = eventBus; this.localization = localization; this.notificationManager = notificationManager; this.appContext = appContext; + this.editorAgent = editorAgent; } @Override @@ -91,7 +95,7 @@ public class OpenFileAction extends Action implements PromisableAction { actionCompletedCallback.onSuccess(null); } - eventBus.fireEvent(FileEvent.createOpenFileEvent(optionalFile.get())); + editorAgent.openEditor(optionalFile.get()); } else { if (actionCompletedCallback != null) { actionCompletedCallback.onFailure(null); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/client/BootstrapController.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/client/BootstrapController.java index 4ab157663a..f133bea44d 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/client/BootstrapController.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/client/BootstrapController.java @@ -10,11 +10,10 @@ *******************************************************************************/ package org.eclipse.che.ide.client; -import com.google.gwt.dom.client.Document; - import com.google.gwt.core.client.Callback; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.dom.client.Document; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.user.client.Window; @@ -97,7 +96,7 @@ public class BootstrapController { @Inject private void startComponents(Map> components) { - startComponents(components.entrySet().iterator()); + startComponents(components.values().iterator()); } @Inject @@ -132,37 +131,23 @@ public class BootstrapController { }); } - private void startComponents(final Iterator>> componentIterator) { - if (componentIterator.hasNext()) { - Map.Entry> entry = componentIterator.next(); - final String componentName = entry.getKey(); + private void startComponents(final Iterator> componentProviderIterator) { + if (componentProviderIterator.hasNext()) { + Provider componentProvider = componentProviderIterator.next(); - try { - Provider componentProvider = entry.getValue(); - - final Component component = componentProvider.get(); - component.start(new Callback() { - @Override - public void onSuccess(Component result) { - Scheduler.get().scheduleDeferred(new ScheduledCommand() { - @Override - public void execute() { - startComponents(componentIterator); - } - }); - } - - @Override - public void onFailure(Exception reason) { - Log.error(getClass(), "Unable to start " + componentName, reason); - initializationFailed(reason.getMessage()); - } - }); - } catch (Exception e) { - Log.error(getClass(), "Unable to start " + componentName, e); - initializationFailed(e.getMessage()); - } + final Component component = componentProvider.get(); + component.start(new Callback() { + @Override + public void onSuccess(Component result) { + startComponents(componentProviderIterator); + } + @Override + public void onFailure(Exception reason) { + Log.error(component.getClass(), reason); + initializationFailed(reason.getMessage()); + } + }); } else { startExtensionsAndDisplayUI(); } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandApiModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandApiModule.java index 8f730cf473..ea0d2fb234 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandApiModule.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandApiModule.java @@ -13,10 +13,63 @@ package org.eclipse.che.ide.command; import com.google.gwt.inject.client.AbstractGinModule; import com.google.gwt.inject.client.assistedinject.GinFactoryModuleBuilder; import com.google.gwt.inject.client.multibindings.GinMapBinder; +import com.google.gwt.inject.client.multibindings.GinMultibinder; +import com.google.inject.Provides; import com.google.inject.Singleton; +import com.google.inject.name.Named; +import org.eclipse.che.ide.Resources; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandGoalRegistry; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.command.CommandType; import org.eclipse.che.ide.api.command.CommandTypeRegistry; import org.eclipse.che.ide.api.component.Component; +import org.eclipse.che.ide.api.filetypes.FileType; +import org.eclipse.che.ide.command.editor.CommandEditorView; +import org.eclipse.che.ide.command.editor.CommandEditorViewImpl; +import org.eclipse.che.ide.command.editor.page.goal.GoalPageView; +import org.eclipse.che.ide.command.editor.page.goal.GoalPageViewImpl; +import org.eclipse.che.ide.command.editor.page.name.NamePageView; +import org.eclipse.che.ide.command.editor.page.name.NamePageViewImpl; +import org.eclipse.che.ide.command.editor.page.project.ProjectsPageView; +import org.eclipse.che.ide.command.editor.page.project.ProjectsPageViewImpl; +import org.eclipse.che.ide.command.editor.page.text.PageWithTextEditorView; +import org.eclipse.che.ide.command.editor.page.text.PageWithTextEditorViewImpl; +import org.eclipse.che.ide.command.execute.ExecuteCommandActionFactory; +import org.eclipse.che.ide.command.execute.ExecuteCommandActionManager; +import org.eclipse.che.ide.command.execute.GoalPopUpGroupFactory; +import org.eclipse.che.ide.command.explorer.CommandsExplorerPresenter; +import org.eclipse.che.ide.command.explorer.CommandsExplorerView; +import org.eclipse.che.ide.command.explorer.CommandsExplorerViewImpl; +import org.eclipse.che.ide.command.goal.BuildGoal; +import org.eclipse.che.ide.command.goal.CommandGoalRegistryImpl; +import org.eclipse.che.ide.command.goal.CommonGoal; +import org.eclipse.che.ide.command.goal.DebugGoal; +import org.eclipse.che.ide.command.goal.DeployGoal; +import org.eclipse.che.ide.command.goal.RunGoal; +import org.eclipse.che.ide.command.goal.TestGoal; +import org.eclipse.che.ide.command.manager.CommandManagerImpl; +import org.eclipse.che.ide.command.node.NodeFactory; +import org.eclipse.che.ide.command.palette.CommandsPaletteView; +import org.eclipse.che.ide.command.palette.CommandsPaletteViewImpl; +import org.eclipse.che.ide.command.producer.CommandProducerActionFactory; +import org.eclipse.che.ide.command.producer.CommandProducerActionManager; +import org.eclipse.che.ide.command.toolbar.CommandToolbarView; +import org.eclipse.che.ide.command.toolbar.CommandToolbarViewImpl; +import org.eclipse.che.ide.command.toolbar.ToolbarButtonsFactory; +import org.eclipse.che.ide.command.toolbar.commands.ExecuteCommandView; +import org.eclipse.che.ide.command.toolbar.commands.ExecuteCommandViewImpl; +import org.eclipse.che.ide.command.toolbar.commands.button.PopupItemFactory; +import org.eclipse.che.ide.command.toolbar.previews.PreviewsView; +import org.eclipse.che.ide.command.toolbar.previews.PreviewsViewImpl; +import org.eclipse.che.ide.command.toolbar.processes.ProcessesListView; +import org.eclipse.che.ide.command.toolbar.processes.ProcessesListViewImpl; +import org.eclipse.che.ide.command.type.CommandTypeRegistryImpl; +import org.eclipse.che.ide.command.type.chooser.CommandTypeChooserView; +import org.eclipse.che.ide.command.type.chooser.CommandTypeChooserViewImpl; + +import static org.eclipse.che.ide.command.node.CommandFileNode.FILE_TYPE_EXT; /** * GIN module for configuring Command API components. @@ -27,11 +80,67 @@ public class CommandApiModule extends AbstractGinModule { @Override protected void configure() { - bind(CommandTypeRegistry.class).to(CommandTypeRegistryImpl.class).in(Singleton.class); + GinMultibinder.newSetBinder(binder(), CommandType.class); + // predefined goals + GinMultibinder goalBinder = GinMultibinder.newSetBinder(binder(), CommandGoal.class); + goalBinder.addBinding().to(BuildGoal.class); + goalBinder.addBinding().to(TestGoal.class); + goalBinder.addBinding().to(RunGoal.class); + goalBinder.addBinding().to(DebugGoal.class); + goalBinder.addBinding().to(DeployGoal.class); + goalBinder.addBinding().to(CommonGoal.class); + + bind(CommandTypeRegistry.class).to(CommandTypeRegistryImpl.class).in(Singleton.class); + bind(CommandGoalRegistry.class).to(CommandGoalRegistryImpl.class).in(Singleton.class); + + bind(CommandManager.class).to(CommandManagerImpl.class).in(Singleton.class); + + // start-up components + GinMapBinder componentBinder = GinMapBinder.newMapBinder(binder(), String.class, Component.class); + componentBinder.addBinding("CommandManagerImpl").to(CommandManagerImpl.class); + componentBinder.addBinding("CommandsExplorerPresenter").to(CommandsExplorerPresenter.class); + componentBinder.addBinding("CommandProducerActionManager").to(CommandProducerActionManager.class); + componentBinder.addBinding("ExecuteCommandActionManager").to(ExecuteCommandActionManager.class); + + install(new GinFactoryModuleBuilder().build(ExecuteCommandActionFactory.class)); + install(new GinFactoryModuleBuilder().build(GoalPopUpGroupFactory.class)); + install(new GinFactoryModuleBuilder().build(NodeFactory.class)); install(new GinFactoryModuleBuilder().build(CommandProducerActionFactory.class)); - GinMapBinder componentsBinder = GinMapBinder.newMapBinder(binder(), String.class, Component.class); - componentsBinder.addBinding("CommandProducerActionManager").to(CommandProducerActionManager.class); + bind(CommandsExplorerView.class).to(CommandsExplorerViewImpl.class).in(Singleton.class); + bind(CommandTypeChooserView.class).to(CommandTypeChooserViewImpl.class); + bind(CommandsPaletteView.class).to(CommandsPaletteViewImpl.class).in(Singleton.class); + + // command editor + bind(CommandEditorView.class).to(CommandEditorViewImpl.class); + bind(NamePageView.class).to(NamePageViewImpl.class); + bind(GoalPageView.class).to(GoalPageViewImpl.class); + bind(ProjectsPageView.class).to(ProjectsPageViewImpl.class); + bind(PageWithTextEditorView.class).to(PageWithTextEditorViewImpl.class); + + // toolbar + bind(CommandToolbarView.class).to(CommandToolbarViewImpl.class).in(Singleton.class); + bind(ExecuteCommandView.class).to(ExecuteCommandViewImpl.class).in(Singleton.class); + bind(ProcessesListView.class).to(ProcessesListViewImpl.class).in(Singleton.class); + bind(PreviewsView.class).to(PreviewsViewImpl.class).in(Singleton.class); + + install(new GinFactoryModuleBuilder().build(ToolbarButtonsFactory.class)); + install(new GinFactoryModuleBuilder().build(PopupItemFactory.class)); + } + + @Provides + @Singleton + @Named("CommandFileType") + protected FileType provideCommandFileType(Resources resources) { + return new FileType(resources.defaultImage(), FILE_TYPE_EXT); + } + + /** Provides the goal which is used for grouping commands which doesn't belong to any goal. */ + @Provides + @Named("default") + @Singleton + protected CommandGoal provideDefaultGoal(CommonGoal commonGoal) { + return commonGoal; } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandResources.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandResources.java new file mode 100644 index 0000000000..82a6874811 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandResources.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * 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; + +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; +import com.google.gwt.resources.client.DataResource; + +import org.vectomatic.dom.svg.ui.SVGResource; + +/** + * Client bundle for Command related resources. + * + * @author Artem Zatsarynnyi + */ +public interface CommandResources extends ClientBundle { + + /** Resource is used as CSS constant's value for setting 'background-image' property. */ + @DataResource.MimeType("image/svg+xml") + @Source("magnifier.svg") + DataResource magnifier(); + + @Source("explorer/explorer-part.svg") + SVGResource explorerPart(); + + @Source("explorer/add-command-button.svg") + SVGResource addCommand(); + + @Source("explorer/duplicate-command-button.svg") + SVGResource duplicateCommand(); + + @Source("explorer/remove-command-button.svg") + SVGResource removeCommand(); + + @Source({"explorer/styles.css", "org/eclipse/che/ide/api/ui/style.css"}) + ExplorerCSS commandsExplorerCss(); + + @Source({"palette/styles.css", "org/eclipse/che/ide/api/ui/style.css"}) + PaletteCSS commandsPaletteCss(); + + @Source({"toolbar/processes/styles.css", "org/eclipse/che/ide/api/ui/style.css"}) + ToolbarCSS commandToolbarCss(); + + @Source({"editor/styles.css", "org/eclipse/che/ide/api/ui/style.css"}) + EditorCSS editorCss(); + + @Source({"type/styles.css", "org/eclipse/che/ide/api/ui/style.css"}) + CommandTypeChooserCSS commandTypeChooserCss(); + + interface ExplorerCSS extends CssResource { + String commandGoalNode(); + + String commandNode(); + + String commandNodeText(); + + String commandNodeButtonsPanel(); + } + + interface PaletteCSS extends CssResource { + String filterField(); + } + + interface ToolbarCSS extends CssResource { + String toolbarButton(); + + String processesListLabel(); + + String processWidgetText(); + + String processWidgetMachineNameLabel(); + + String processWidgetCommandNameLabel(); + + String processWidgetPidLabel(); + + String processWidgetActionButton(); + + String previewUrlWidget(); + } + + interface EditorCSS extends CssResource { + String sectionLabel(); + + String section(); + } + + interface CommandTypeChooserCSS extends CssResource { + String chooserPopup(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandUtils.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandUtils.java new file mode 100644 index 0000000000..a9da4a7d62 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandUtils.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * 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; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandType; +import org.eclipse.che.ide.api.command.CommandTypeRegistry; +import org.eclipse.che.ide.api.command.CommandGoalRegistry; +import org.eclipse.che.ide.api.icon.Icon; +import org.eclipse.che.ide.api.icon.IconRegistry; +import org.vectomatic.dom.svg.ui.SVGImage; +import org.vectomatic.dom.svg.ui.SVGResource; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * A smattering of useful methods to work with commands. + * + * @author Artem Zatsarynnyi + */ +@Singleton +public class CommandUtils { + + private final CommandGoalRegistry goalRegistry; + private final CommandTypeRegistry commandTypeRegistry; + private final IconRegistry iconRegistry; + + @Inject + public CommandUtils(CommandGoalRegistry commandGoalRegistry, + CommandTypeRegistry commandTypeRegistry, + IconRegistry iconRegistry) { + this.goalRegistry = commandGoalRegistry; + this.commandTypeRegistry = commandTypeRegistry; + this.iconRegistry = iconRegistry; + } + + /** + * Groups the given {@code commands} by its goal. + * + * @return map that contains the given {@code commands} grouped by its goal + */ + public Map> groupCommandsByGoal(List commands) { + final Map> commandsByGoal = new HashMap<>(); + + for (CommandImpl command : commands) { + final String goalId = command.getGoal(); + final CommandGoal commandGoal = goalRegistry.getGoalForId(goalId); + + commandsByGoal.computeIfAbsent(commandGoal, key -> new ArrayList<>()) + .add(command); + } + + return commandsByGoal; + } + + /** Returns the icon for the given command type ID or {@code null} if none. */ + @Nullable + public SVGResource getCommandTypeIcon(String typeId) { + final CommandType commandType = commandTypeRegistry.getCommandTypeById(typeId); + + if (commandType != null) { + final Icon icon = iconRegistry.getIconIfExist("command.type." + commandType.getId()); + + if (icon != null) { + final SVGImage svgImage = icon.getSVGImage(); + + if (svgImage != null) { + return icon.getSVGResource(); + } + } + } + + return null; + } + + /** Returns the icon for the given command goal ID or {@code null} if none. */ + @Nullable + public SVGResource getCommandGoalIcon(String goalId) { + final Optional goalOptional = goalRegistry.getPredefinedGoalById(goalId); + + if (goalOptional.isPresent()) { + final Icon icon = iconRegistry.getIconIfExist("command.goal." + goalOptional.get().getId()); + + if (icon != null) { + final SVGImage svgImage = icon.getSVGImage(); + + if (svgImage != null) { + return icon.getSVGResource(); + } + } + } + + return null; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditor.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditor.java new file mode 100644 index 0000000000..b02941c4fb --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditor.java @@ -0,0 +1,305 @@ +/******************************************************************************* + * 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.core.client.Scheduler; +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 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.CommandManager.CommandChangedListener; +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, + CommandChangedListener { + + 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 List pages; + + /** Edited command. */ + @VisibleForTesting + protected CommandImpl editedCommand; + /** Initial (before any modification) name of the edited command. */ + private String commandNameInitial; + + @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) { + 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; + + view.setDelegate(this); + + commandManager.addCommandChangedListener(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) { + 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() { + commandNameInitial = 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() { + @Override + public void onFailure(Throwable caught) { + } + + @Override + public void onSuccess(EditorInput result) { + } + }); + } + + @Override + public void doSave(AsyncCallback callback) { + commandManager.updateCommand(commandNameInitial, 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 (!commandNameInitial.equals(editedCommand.getName())) { + input.setFile(nodeFactory.newCommandFileNode(editedCommand)); + } + + initializePages(); + + callback.onSuccess(getEditorInput()); + }).catchError((Operation)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 callback) { + if (!isDirty()) { + callback.onSuccess(null); + } else { + dialogFactory.createChoiceDialog( + coreMessages.askWindowCloseTitle(), + coreMessages.messagesSaveChanges(getEditorInput().getName()), + coreMessages.yesButtonTitle(), + coreMessages.noButtonTitle(), + coreMessages.cancelButton(), + () -> doSave(new AsyncCallback() { + @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 onCommandAdded(CommandImpl command) { + } + + @Override + public void onCommandUpdated(CommandImpl previousCommand, CommandImpl command) { + } + + @Override + public void onCommandRemoved(CommandImpl command) { + if (command.getName().equals(editedCommand.getName())) { + editorAgent.closeEditor(this); + Scheduler.get().scheduleDeferred(() -> commandManager.removeCommandChangedListener(this)); + } + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorProvider.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorProvider.java new file mode 100644 index 0000000000..d4c4f0a248 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorProvider.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * 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.inject.Inject; +import com.google.inject.Provider; + +import org.eclipse.che.ide.api.editor.EditorPartPresenter; +import org.eclipse.che.ide.api.editor.EditorProvider; + +/** + * Provides {@link CommandEditor} instances. + * + * @author Artem Zatsarynnyi + */ +public class CommandEditorProvider implements EditorProvider { + + private final Provider editorProvider; + private final EditorMessages editorMessages; + + @Inject + public CommandEditorProvider(Provider editorProvider, EditorMessages editorMessages) { + this.editorProvider = editorProvider; + this.editorMessages = editorMessages; + } + + @Override + public String getId() { + return "che_command_editor"; + } + + @Override + public String getDescription() { + return editorMessages.editorDescription(); + } + + @Override + public EditorPartPresenter getEditor() { + return editorProvider.get(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorView.java new file mode 100644 index 0000000000..a3f76f8af3 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorView.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * 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.gwt.user.client.ui.IsWidget; + +import org.eclipse.che.ide.api.mvp.View; + +/** + * The view for {@link CommandEditor}. + * + * @author Artem Zatsarynnyi + */ +public interface CommandEditorView extends View { + + /** + * Add page to the view. New page will be added to the top. + * + * @param page + * page to add + * @param title + * text that should be used as page's title + */ + void addPage(IsWidget page, String title); + + /** + * Set whether saving command is enabled or not. + * + * @param enable + * {@code true} if command saving is enabled and {@code false} otherwise + */ + void setSaveEnabled(boolean enable); + + /** The action delegate for this view. */ + interface ActionDelegate { + + /** Called when reverting command changes is requested. */ + void onCommandCancel(); + + /** Called when saving command is requested. */ + void onCommandSave(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorViewImpl.java new file mode 100644 index 0000000000..14c51eb5db --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorViewImpl.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * 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.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.IsWidget; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.ScrollPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; + +import org.eclipse.che.ide.command.CommandResources; +import org.eclipse.che.ide.ui.window.Window; + +/** + * Implementation of {@link CommandEditorView}. + * + * @author Artem Zatsarynnyi + */ +public class CommandEditorViewImpl extends Composite implements CommandEditorView { + + private static final CommandEditorViewImplUiBinder UI_BINDER = GWT.create(CommandEditorViewImplUiBinder.class); + private static final Window.Resources WINDOW_RESOURCES = GWT.create(Window.Resources.class); + + private final CommandResources resources; + + @UiField + Button cancelButton; + + @UiField + Button saveButton; + + @UiField + ScrollPanel scrollPanel; + + @UiField + FlowPanel pagesPanel; + + /** The delegate to receive events from this view. */ + private ActionDelegate delegate; + + @Inject + public CommandEditorViewImpl(CommandResources resources) { + this.resources = resources; + + initWidget(UI_BINDER.createAndBindUi(this)); + setSaveEnabled(false); + saveButton.addStyleName(WINDOW_RESOURCES.windowCss().primaryButton()); + } + + @Override + public void addPage(IsWidget page, String title) { + page.asWidget().addStyleName(resources.editorCss().section()); + pagesPanel.insert(page, 0); + + if (!title.isEmpty()) { + Label label = new Label(title); + label.addStyleName(resources.editorCss().sectionLabel()); + pagesPanel.insert(label, 0); + } + + // editor must be scrolled to the top immediately after opening + new Timer() { + @Override + public void run() { + scrollPanel.scrollToTop(); + } + }.schedule(1000); + } + + @Override + public void setSaveEnabled(boolean enable) { + saveButton.setEnabled(enable); + } + + @UiHandler("cancelButton") + public void handleCancelButton(ClickEvent clickEvent) { + delegate.onCommandCancel(); + } + + @UiHandler("saveButton") + public void handleSaveButton(ClickEvent clickEvent) { + delegate.onCommandSave(); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + interface CommandEditorViewImplUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorViewImpl.ui.xml new file mode 100644 index 0000000000..2f866e6269 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/CommandEditorViewImpl.ui.xml @@ -0,0 +1,58 @@ + + + + + + + @eval partBackground org.eclipse.che.ide.api.theme.Style.theme.partBackground(); + @eval tabsPanelBackground org.eclipse.che.ide.api.theme.Style.theme.tabsPanelBackground(); + + .mainPanel { + background-color: partBackground; + } + + .header { + height: 38px; + padding-top: 5px; + background-color: tabsPanelBackground; + } + + .button { + float: right; + margin: 5px 0 0 10px; + font-weight: bold; + } + + + + + + + + + + + + + + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/EditorMessages.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/EditorMessages.java new file mode 100644 index 0000000000..4717d8ff70 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/EditorMessages.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * 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.gwt.i18n.client.Messages; + +/** + * I18n messages for the Command Editor. + * + * @author Artem Zatsarynnyi + */ +public interface EditorMessages extends Messages { + + @Key("editor.description") + String editorDescription(); + + @Key("editor.message.unable_save") + String editorMessageUnableToSave(); + + @Key("button.test.text") + String buttonRunText(); + + @Key("button.save.text") + String buttonSaveText(); + + @Key("button.cancel.text") + String buttonCancelText(); + + @Key("page.name.title") + String pageNameTitle(); + + @Key("page.command_line.title") + String pageCommandLineTitle(); + + @Key("page.goal.title") + String pageGoalTitle(); + + @Key("page.projects.title") + String pageProjectsTitle(); + + @Key("page.projects.table.header.project.label") + String pageProjectsTableHeaderProjectLabel(); + + @Key("page.projects.table.header.applicable.label") + String pageProjectsTableHeaderApplicableLabel(); + + @Key("page.with_text_editor.macros") + String pageWithTextEditorMacros(); + + @Key("page.preview_url.title") + String pagePreviewUrlTitle(); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/AbstractCommandEditorPage.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/AbstractCommandEditorPage.java new file mode 100644 index 0000000000..a6deb5861a --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/AbstractCommandEditorPage.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * 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.page; + +import org.eclipse.che.ide.api.command.CommandImpl; + +/** + * Abstract {@link CommandEditorPage} that provides basic functionality. + * + * @author Artem Zatsarynnyi + */ +public abstract class AbstractCommandEditorPage implements CommandEditorPage { + + private final String title; + + protected CommandImpl editedCommand; + + private DirtyStateListener listener; + + /** Creates new page with the given title and tooltip. */ + protected AbstractCommandEditorPage(String title) { + this.title = title; + } + + @Override + public String getTitle() { + return title; + } + + @Override + public void edit(CommandImpl command) { + editedCommand = command; + + initialize(); + notifyDirtyStateChanged(); + } + + /** + * This method is called every time when command is opening in the editor. + * Typically, implementor should do initial setup of the page with the {@link #editedCommand}. + */ + protected abstract void initialize(); + + @Override + public void setDirtyStateListener(DirtyStateListener listener) { + this.listener = listener; + } + + /** + * Should be called by page every time when any command + * modifications on the page have been performed. + */ + protected void notifyDirtyStateChanged() { + if (listener != null) { + listener.onDirtyStateChanged(); + } + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/CommandEditorPage.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/CommandEditorPage.java new file mode 100644 index 0000000000..dc29656731 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/CommandEditorPage.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * 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.page; + +import com.google.gwt.user.client.ui.IsWidget; + +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.command.editor.CommandEditor; + +/** + * Defines the requirements for the page for {@link CommandEditor}. + * + * @author Artem Zatsarynnyi + * @see CommandEditor + */ +public interface CommandEditorPage { + + /** Returns page's title. */ + String getTitle(); + + /** Returns page's view. */ + IsWidget getView(); + + /** + * This method is called every time when command is opening in the editor. + * Typically, implementor should hold the given {@code command} + * instance for subsequent modifying it directly and do pages's initial setup. + */ + void edit(CommandImpl command); + + /** + * Whether the page has been modified or not? + * + * @return {@code true} if page is modified, and {@code false} - otherwise + */ + boolean isDirty(); + + /** Sets {@link DirtyStateListener}. */ + void setDirtyStateListener(DirtyStateListener listener); + + /** + * Listener that should be called by page every time when + * any command modifications on the page have been performed. + */ + interface DirtyStateListener { + void onDirtyStateChanged(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/commandline/CommandLinePage.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/commandline/CommandLinePage.java new file mode 100644 index 0000000000..198036340a --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/commandline/CommandLinePage.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * 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.page.commandline; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.editor.defaulteditor.EditorBuilder; +import org.eclipse.che.ide.api.filetypes.FileTypeRegistry; +import org.eclipse.che.ide.command.editor.EditorMessages; +import org.eclipse.che.ide.command.editor.page.CommandEditorPage; +import org.eclipse.che.ide.command.editor.page.text.AbstractPageWithTextEditor; +import org.eclipse.che.ide.command.editor.page.text.MacroEditorConfiguration; +import org.eclipse.che.ide.command.editor.page.text.PageWithTextEditorView; +import org.eclipse.che.ide.macro.chooser.MacroChooser; + +/** + * Presenter for {@link CommandEditorPage} which allows to edit command line. + * + * @author Artem Zatsarynnyi + */ +public class CommandLinePage extends AbstractPageWithTextEditor { + + @Inject + public CommandLinePage(PageWithTextEditorView view, + EditorBuilder editorBuilder, + FileTypeRegistry fileTypeRegistry, + MacroChooser macroChooser, + EditorMessages messages, + MacroEditorConfiguration editorConfiguration) { + super(view, + editorBuilder, + fileTypeRegistry, + macroChooser, + messages.pageCommandLineTitle(), + editorConfiguration); + + view.asWidget().getElement().setId("command_editor-command_line"); + } + + @Override + protected String getCommandPropertyValue() { + return editedCommand.getCommandLine(); + } + + @Override + protected void updateCommandPropertyValue(String content) { + editedCommand.setCommandLine(content); + } + + @Override + protected String getType() { + return ".sh"; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPage.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPage.java new file mode 100644 index 0000000000..520871e639 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPage.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * 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.page.goal; + +import com.google.gwt.user.client.ui.IsWidget; +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.command.BaseCommandGoal; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.command.CommandGoalRegistry; +import org.eclipse.che.ide.command.editor.EditorMessages; +import org.eclipse.che.ide.command.editor.page.AbstractCommandEditorPage; +import org.eclipse.che.ide.command.editor.page.CommandEditorPage; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import static com.google.common.base.Strings.isNullOrEmpty; + +/** + * {@link CommandEditorPage} which allows to edit command's goal. + * + * @author Artem Zatsarynnyi + */ +public class GoalPage extends AbstractCommandEditorPage implements GoalPageView.ActionDelegate { + + private final GoalPageView view; + private final CommandGoalRegistry goalRegistry; + private final CommandManager commandManager; + + /** Initial value of the command's goal. */ + private String goalInitial; + + @Inject + public GoalPage(GoalPageView view, + CommandGoalRegistry commandGoalRegistry, + CommandManager commandManager, + EditorMessages messages) { + super(messages.pageGoalTitle()); + + this.view = view; + this.goalRegistry = commandGoalRegistry; + this.commandManager = commandManager; + + view.setDelegate(this); + } + + @Override + public IsWidget getView() { + return view; + } + + @Override + protected void initialize() { + final String goalId = editedCommand.getGoal(); + final CommandGoal commandGoal = goalRegistry.getGoalForId(goalId); + + goalInitial = commandGoal.getId(); + + final Set goals = new HashSet<>(); + goals.addAll(goalRegistry.getAllPredefinedGoals()); + goals.addAll(getCustomGoals()); + + view.setAvailableGoals(goals); + view.setGoal(commandGoal.getId()); + } + + @Override + public boolean isDirty() { + if (editedCommand == null) { + return false; + } + + final CommandGoal commandGoal = goalRegistry.getGoalForId(editedCommand.getGoal()); + + return !(goalInitial.equals(commandGoal.getId())); + } + + @Override + public void onGoalChanged(String goalId) { + editedCommand.setGoal(goalId); + + notifyDirtyStateChanged(); + } + + /** Returns all custom (non-predefined) command goals. */ + private Set getCustomGoals() { + final Set list = new HashSet<>(); + + for (CommandImpl command : commandManager.getCommands()) { + final String goalId = command.getGoal(); + + final Optional goalOptional = goalRegistry.getPredefinedGoalById(goalId); + if (!goalOptional.isPresent() && !isNullOrEmpty(goalId)) { + list.add(new BaseCommandGoal(goalId)); + } + } + + return list; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageView.java new file mode 100644 index 0000000000..e7d22d48be --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageView.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * 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.page.goal; + +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.mvp.View; + +import java.util.Set; + +/** + * The view of {@link GoalPage}. + * + * @author Artem Zatsarynnyi + */ +public interface GoalPageView extends View { + + /** Set the list of goals which are available to set for command. */ + void setAvailableGoals(Set goals); + + /** Sets the command's goal value. */ + void setGoal(String goalId); + + /** The action delegate for this view. */ + interface ActionDelegate { + + /** + * Called when command goal has been changed. + * + * @param goalId + * new value of the command goal + */ + void onGoalChanged(String goalId); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageViewImpl.java new file mode 100644 index 0000000000..0235423816 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageViewImpl.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * 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.page.goal; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.KeyUpEvent; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.ui.listbox.CustomComboBox; + +import java.util.Set; + +/** + * Implementation of {@link GoalPageView}. + * + * @author Artem Zatsarynnyi + */ +public class GoalPageViewImpl extends Composite implements GoalPageView { + + private static final GoalPageViewImplUiBinder UI_BINDER = GWT.create(GoalPageViewImplUiBinder.class); + + @UiField + CustomComboBox goalComboBox; + + private ActionDelegate delegate; + + @Inject + public GoalPageViewImpl() { + initWidget(UI_BINDER.createAndBindUi(this)); + } + + @Override + public void setAvailableGoals(Set goals) { + goalComboBox.clear(); + goals.forEach(g -> goalComboBox.addItem(g.getId())); + } + + @Override + public void setGoal(String goalId) { + goalComboBox.setValue(goalId); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @UiHandler({"goalComboBox"}) + void onGoalKeyUp(KeyUpEvent event) { + delegate.onGoalChanged(goalComboBox.getValue()); + } + + @UiHandler({"goalComboBox"}) + void onGoalChanged(ChangeEvent event) { + delegate.onGoalChanged(goalComboBox.getValue()); + } + + interface GoalPageViewImplUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageViewImpl.ui.xml new file mode 100644 index 0000000000..b7f11ec391 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageViewImpl.ui.xml @@ -0,0 +1,23 @@ + + + + + + .combo-box { + display: block; + } + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePage.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePage.java new file mode 100644 index 0000000000..218d795df1 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePage.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * 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.page.name; + +import com.google.gwt.user.client.ui.IsWidget; +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.command.CommandExecutor; +import org.eclipse.che.ide.command.editor.EditorMessages; +import org.eclipse.che.ide.command.editor.page.AbstractCommandEditorPage; +import org.eclipse.che.ide.command.editor.page.CommandEditorPage; + +/** + * Presenter for {@link CommandEditorPage} which allows to edit command's name. + * + * @author Artem Zatsarynnyi + */ +public class NamePage extends AbstractCommandEditorPage implements NamePageView.ActionDelegate { + + private final NamePageView view; + private final CommandExecutor commandExecutor; + + /** Initial value of the command's name. */ + private String commandNameInitial; + + @Inject + public NamePage(NamePageView view, EditorMessages messages, CommandExecutor commandExecutor) { + super(messages.pageNameTitle()); + + this.view = view; + this.commandExecutor = commandExecutor; + + view.setDelegate(this); + } + + @Override + public IsWidget getView() { + return view; + } + + @Override + protected void initialize() { + commandNameInitial = editedCommand.getName(); + + view.setCommandName(editedCommand.getName()); + } + + @Override + public boolean isDirty() { + if (editedCommand == null) { + return false; + } + + return !(commandNameInitial.equals(editedCommand.getName())); + } + + @Override + public void onNameChanged(String name) { + editedCommand.setName(name); + + notifyDirtyStateChanged(); + } + + @Override + public void onCommandRun() { + commandExecutor.executeCommand(editedCommand); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePageView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePageView.java new file mode 100644 index 0000000000..3c2c3c544c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePageView.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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.page.name; + +import org.eclipse.che.ide.api.mvp.View; + +/** + * The view for {@link NamePage}. + * + * @author Artem Zatsarynnyi + */ +public interface NamePageView extends View { + + /** Sets the command's name value. */ + void setCommandName(String name); + + /** The action delegate for this view. */ + interface ActionDelegate { + + /** + * Called when command's name has been changed. + * + * @param name + * changed value of the command's name + */ + void onNameChanged(String name); + + /** Called when executing command is requested. */ + void onCommandRun(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePageViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePageViewImpl.java new file mode 100644 index 0000000000..2c089714a8 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePageViewImpl.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * 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.page.name; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.KeyUpEvent; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; + +/** + * Implementation of {@link NamePageView}. + * + * @author Artem Zatsarynnyi + */ +public class NamePageViewImpl extends Composite implements NamePageView { + + private static final NamePageViewImplUiBinder UI_BINDER = GWT.create(NamePageViewImplUiBinder.class); + + @UiField + TextBox commandName; + + @UiField + Button runButton; + + private ActionDelegate delegate; + + @Inject + public NamePageViewImpl() { + initWidget(UI_BINDER.createAndBindUi(this)); + } + + @Override + public void setCommandName(String name) { + commandName.setValue(name); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @UiHandler({"commandName"}) + void onNameChanged(KeyUpEvent event) { + delegate.onNameChanged(commandName.getValue()); + } + + @UiHandler("runButton") + public void handleRunButton(ClickEvent clickEvent) { + delegate.onCommandRun(); + } + + interface NamePageViewImplUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePageViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePageViewImpl.ui.xml new file mode 100644 index 0000000000..afcc5d4ea4 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/name/NamePageViewImpl.ui.xml @@ -0,0 +1,38 @@ + + + + + + + .button { + float: right; + margin-top: 1px; + font-weight: bold; + background: #51b200; + } + + .button:hover { + background: #51b200; + } + + + + + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/previewurl/PreviewUrlPage.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/previewurl/PreviewUrlPage.java new file mode 100644 index 0000000000..93bc7d1ba9 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/previewurl/PreviewUrlPage.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * 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.page.previewurl; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.editor.defaulteditor.EditorBuilder; +import org.eclipse.che.ide.api.filetypes.FileTypeRegistry; +import org.eclipse.che.ide.command.editor.EditorMessages; +import org.eclipse.che.ide.command.editor.page.CommandEditorPage; +import org.eclipse.che.ide.command.editor.page.text.AbstractPageWithTextEditor; +import org.eclipse.che.ide.command.editor.page.text.MacroEditorConfiguration; +import org.eclipse.che.ide.command.editor.page.text.PageWithTextEditorView; +import org.eclipse.che.ide.macro.chooser.MacroChooser; + +import static org.eclipse.che.api.workspace.shared.Constants.COMMAND_PREVIEW_URL_ATTRIBUTE_NAME; + +/** + * Presenter for {@link CommandEditorPage} which allows to edit command's preview URL. + * + * @author Artem Zatsarynnyi + */ +public class PreviewUrlPage extends AbstractPageWithTextEditor { + + @Inject + public PreviewUrlPage(PageWithTextEditorView view, + EditorBuilder editorBuilder, + FileTypeRegistry fileTypeRegistry, + MacroChooser macroChooser, + EditorMessages messages, + MacroEditorConfiguration editorConfiguration) { + super(view, + editorBuilder, + fileTypeRegistry, + macroChooser, + messages.pagePreviewUrlTitle(), + editorConfiguration); + + view.asWidget().getElement().setId("command_editor-preview_url"); + } + + @Override + protected String getCommandPropertyValue() { + final String previewUrl = editedCommand.getAttributes().get(COMMAND_PREVIEW_URL_ATTRIBUTE_NAME); + + return previewUrl != null ? previewUrl : ""; + } + + @Override + protected void updateCommandPropertyValue(String content) { + editedCommand.getAttributes().put(COMMAND_PREVIEW_URL_ATTRIBUTE_NAME, content); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectSwitcher.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectSwitcher.java new file mode 100644 index 0000000000..2be85aa40d --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectSwitcher.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * 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.page.project; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HasValue; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.Widget; + +import org.eclipse.che.ide.ui.switcher.Switcher; + +/** + * Switcher widget which is associated with some project name. + * + * @author Artem Zatsarynnyi + */ +public class ProjectSwitcher extends Composite implements HasValue { + + private static final ProjectSwitcherUiBinder UI_BINDER = GWT.create(ProjectSwitcherUiBinder.class); + + @UiField + Label label; + + @UiField + Switcher switcher; + + ProjectSwitcher(String projectName) { + initWidget(UI_BINDER.createAndBindUi(this)); + + label.setText(projectName); + } + + @Override + public Boolean getValue() { + return switcher.getValue(); + } + + @Override + public void setValue(Boolean value) { + switcher.setValue(value); + } + + @Override + public void setValue(Boolean value, boolean fireEvents) { + switcher.setValue(value, fireEvents); + } + + @Override + public HandlerRegistration addValueChangeHandler(ValueChangeHandler handler) { + return switcher.addValueChangeHandler(handler); + } + + interface ProjectSwitcherUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectSwitcher.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectSwitcher.ui.xml new file mode 100644 index 0000000000..9e57c1acfd --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectSwitcher.ui.xml @@ -0,0 +1,42 @@ + + + + + + + .panel { + background-color: #3D4650; + padding: 5px 0 5px 0; + } + + .label { + display: inline-block; + width: 150px; + margin: 0 0 0 10px; + } + + .switcher { + display: inline-block; + margin-left: 10px; + vertical-align: middle; + } + + + + + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPage.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPage.java new file mode 100644 index 0000000000..86d0082431 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPage.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * 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.page.project; + +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.user.client.ui.IsWidget; +import com.google.inject.Inject; +import com.google.web.bindery.event.shared.EventBus; + +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandImpl.ApplicableContext; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.api.resources.Resource; +import org.eclipse.che.ide.api.resources.ResourceChangedEvent; +import org.eclipse.che.ide.api.resources.ResourceChangedEvent.ResourceChangedHandler; +import org.eclipse.che.ide.api.resources.ResourceDelta; +import org.eclipse.che.ide.command.editor.EditorMessages; +import org.eclipse.che.ide.command.editor.page.AbstractCommandEditorPage; +import org.eclipse.che.ide.command.editor.page.CommandEditorPage; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Presenter for {@link CommandEditorPage} which allows to edit command's applicable projects. */ +public class ProjectsPage extends AbstractCommandEditorPage implements ProjectsPageView.ActionDelegate, + ResourceChangedHandler { + + private final ProjectsPageView view; + private final AppContext appContext; + + /** Initial value of the applicable projects list. */ + private List applicableProjectsInitial; + + @Inject + public ProjectsPage(ProjectsPageView view, + AppContext appContext, + EditorMessages messages, + EventBus eventBus) { + super(messages.pageProjectsTitle()); + + this.view = view; + this.appContext = appContext; + + eventBus.addHandler(ResourceChangedEvent.getType(), this); + + view.setDelegate(this); + } + + @Override + public IsWidget getView() { + return view; + } + + @Override + protected void initialize() { + final ApplicableContext context = editedCommand.getApplicableContext(); + + applicableProjectsInitial = new ArrayList<>(context.getApplicableProjects()); + + refreshProjects(); + } + + /** Refresh 'Projects' section in the view. */ + private void refreshProjects() { + final Map projectsState = new HashMap<>(); + + for (Project project : appContext.getProjects()) { + ApplicableContext context = editedCommand.getApplicableContext(); + boolean applicable = context.getApplicableProjects().contains(project.getPath()); + + projectsState.put(project, applicable); + } + + view.setProjects(projectsState); + } + + @Override + public boolean isDirty() { + if (editedCommand == null) { + return false; + } + + ApplicableContext context = editedCommand.getApplicableContext(); + + return !(applicableProjectsInitial.equals(context.getApplicableProjects())); + } + + @Override + public void onApplicableProjectChanged(Project project, boolean applicable) { + final ApplicableContext context = editedCommand.getApplicableContext(); + + if (applicable) { + // if command is bound with one project at least + // then remove command from the workspace + if (context.getApplicableProjects().isEmpty()) { + context.setWorkspaceApplicable(false); + } + + context.addProject(project.getPath()); + } else { + context.removeProject(project.getPath()); + + // if command isn't bound to any project + // then save it to the workspace + if (context.getApplicableProjects().isEmpty()) { + context.setWorkspaceApplicable(true); + } + } + + notifyDirtyStateChanged(); + } + + @Override + public void onResourceChanged(ResourceChangedEvent event) { + final ResourceDelta delta = event.getDelta(); + final Resource resource = delta.getResource(); + + if (resource.isProject()) { + // defer refreshing the projects section since appContext#getProjects may return old data + Scheduler.get().scheduleDeferred(this::refreshProjects); + } + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageView.java new file mode 100644 index 0000000000..7cb8309c4c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageView.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * 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.page.project; + +import org.eclipse.che.ide.api.mvp.View; +import org.eclipse.che.ide.api.resources.Project; + +import java.util.Map; + +/** + * The view for {@link ProjectsPage}. + * + * @author Artem Zatsarynnyi + */ +public interface ProjectsPageView extends View { + + /** Sets the applicable projects. */ + void setProjects(Map projects); + + /** The action delegate for this view. */ + interface ActionDelegate { + + /** Called when applicable project has been changed. */ + void onApplicableProjectChanged(Project project, boolean applicable); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageViewImpl.java new file mode 100644 index 0000000000..aaabf216df --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageViewImpl.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * 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.page.project; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.resources.Project; + +import java.util.Map; + +/** + * Implementation of {@link ProjectsPageView}. + * + * @author Artem Zatsarynnyi + */ +public class ProjectsPageViewImpl extends Composite implements ProjectsPageView { + + private static final ProjectsPageViewImplUiBinder UI_BINDER = GWT.create(ProjectsPageViewImplUiBinder.class); + + @UiField + FlowPanel mainPanel; + + @UiField + FlowPanel projectsPanel; + + private ActionDelegate delegate; + + @Inject + public ProjectsPageViewImpl() { + initWidget(UI_BINDER.createAndBindUi(this)); + + mainPanel.setVisible(false); + } + + @Override + public void setProjects(Map projects) { + projectsPanel.clear(); + mainPanel.setVisible(!projects.isEmpty()); + + projects.entrySet().forEach(entry -> addProjectSwitcherToPanel(entry.getKey(), entry.getValue())); + } + + private void addProjectSwitcherToPanel(Project project, boolean applicable) { + final ProjectSwitcher switcher = new ProjectSwitcher(project.getName()); + switcher.setValue(applicable); + switcher.addValueChangeHandler(event -> delegate.onApplicableProjectChanged(project, event.getValue())); + + projectsPanel.add(switcher); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + interface ProjectsPageViewImplUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageViewImpl.ui.xml new file mode 100644 index 0000000000..2a9dc452dc --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageViewImpl.ui.xml @@ -0,0 +1,44 @@ + + + + + + + @eval textFieldBorderColor org.eclipse.che.ide.api.theme.Style.theme.toolButtonActiveBorder(); + + .table { + border: textFieldBorderColor; + } + + .table-header { + background-color: #2E353B; + } + + .column-header { + display: inline-block; + width: 150px; + margin-left: 10px; + margin-top: 3px; + } + + + + + + + + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/AbstractPageWithTextEditor.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/AbstractPageWithTextEditor.java new file mode 100644 index 0000000000..bf7d6b1d29 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/AbstractPageWithTextEditor.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * 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.page.text; + +import com.google.gwt.user.client.ui.IsWidget; + +import org.eclipse.che.ide.api.editor.OpenEditorCallbackImpl; +import org.eclipse.che.ide.api.editor.defaulteditor.EditorBuilder; +import org.eclipse.che.ide.api.editor.document.Document; +import org.eclipse.che.ide.api.editor.editorconfig.TextEditorConfiguration; +import org.eclipse.che.ide.api.editor.texteditor.TextEditor; +import org.eclipse.che.ide.api.filetypes.FileTypeRegistry; +import org.eclipse.che.ide.api.resources.SyntheticFile; +import org.eclipse.che.ide.api.resources.VirtualFile; +import org.eclipse.che.ide.command.editor.page.AbstractCommandEditorPage; +import org.eclipse.che.ide.command.editor.page.CommandEditorPage; +import org.eclipse.che.ide.macro.chooser.MacroChooser; + +import static org.eclipse.che.ide.api.editor.EditorPartPresenter.PROP_DIRTY; +import static org.eclipse.che.ide.api.editor.EditorPartPresenter.PROP_INPUT; + +/** + * Abstract {@link CommandEditorPage} which allows to edit a command's property + * with a text editor that provides autocompletion for macros names. + * + * @author Artem Zatsarynnyi + */ +public abstract class AbstractPageWithTextEditor extends AbstractCommandEditorPage implements PageWithTextEditorView.ActionDelegate { + + private final PageWithTextEditorView view; + private final FileTypeRegistry fileTypeRegistry; + private final MacroChooser macroChooser; + private final TextEditorConfiguration editorConfiguration; + + private TextEditor editor; + + /** Initial value of the edited command's property. */ + private String initialValue; + + protected AbstractPageWithTextEditor(PageWithTextEditorView view, + EditorBuilder editorBuilder, + FileTypeRegistry fileTypeRegistry, + MacroChooser macroChooser, + String title, + TextEditorConfiguration editorConfiguration) { + super(""); + + this.view = view; + this.fileTypeRegistry = fileTypeRegistry; + this.macroChooser = macroChooser; + this.editorConfiguration = editorConfiguration; + + view.setDelegate(this); + view.setHeight(getHeight()); + view.setEditorTitle(title); + + initializeEditor(editorBuilder); + } + + private void initializeEditor(EditorBuilder editorBuilder) { + editor = editorBuilder.buildEditor(); + editor.initialize(editorConfiguration); + editor.activate(); + + editor.addPropertyListener((source, propId) -> { + switch (propId) { + case PROP_INPUT: + editor.go(view.getEditorContainer()); + + editor.getEditorWidget().setAnnotationRulerVisible(false); + editor.getEditorWidget().setFoldingRulerVisible(false); + editor.getEditorWidget().setZoomRulerVisible(false); + editor.getEditorWidget().setOverviewRulerVisible(false); + + break; + case PROP_DIRTY: + updateCommandPropertyValue(editor.getDocument().getContents()); + notifyDirtyStateChanged(); + + break; + default: + } + }); + } + + @Override + public IsWidget getView() { + return view; + } + + @Override + protected void initialize() { + initialValue = getCommandPropertyValue(); + + setContent(initialValue); + } + + /** Sets editor's content. */ + private void setContent(String content) { + VirtualFile file = new SyntheticFile(editedCommand.getName() + getType(), content); + + editor.init(new EditorInputImpl(fileTypeRegistry.getFileTypeByFile(file), file), new OpenEditorCallbackImpl()); + } + + @Override + public boolean isDirty() { + if (editedCommand == null) { + return false; + } + + return !initialValue.equals(getCommandPropertyValue()); + } + + /** Returns the current value of the edited command's property. */ + protected abstract String getCommandPropertyValue(); + + /** + * Updates the value of the edited command's property. + * + * @param newValue + * new value of the edited command's property + */ + protected abstract void updateCommandPropertyValue(String newValue); + + /** Returns height of the page in pixels. Default height is 150 px. */ + protected int getHeight() { + return 150; + } + + /** + * Returns type of the edited content. + * Type must be specified as file's extension e.g.: .sh, .css. + * Default type is text/plain. + */ + protected String getType() { + return ""; + } + + @Override + public void onExploreMacros() { + macroChooser.show(macro -> { + Document document = editor.getDocument(); + document.replace(document.getCursorOffset(), 0, macro.getName()); + }); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/EditorInputImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/EditorInputImpl.java new file mode 100644 index 0000000000..1afa2195bc --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/EditorInputImpl.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.page.text; + +import org.eclipse.che.ide.api.editor.EditorInput; +import org.eclipse.che.ide.api.filetypes.FileType; +import org.eclipse.che.ide.api.resources.VirtualFile; +import org.vectomatic.dom.svg.ui.SVGResource; + +class EditorInputImpl implements EditorInput { + + private VirtualFile file; + private FileType fileType; + + EditorInputImpl(FileType fileType, VirtualFile file) { + this.fileType = fileType; + this.file = file; + } + + @Override + public String getToolTipText() { + return null; + } + + @Override + public String getName() { + return file.getDisplayName(); + } + + @Override + public SVGResource getSVGResource() { + return fileType.getImage(); + } + + @Override + public VirtualFile getFile() { + return file; + } + + @Override + public void setFile(VirtualFile file) { + this.file = file; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/MacroCodeAssistProcessor.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/MacroCodeAssistProcessor.java new file mode 100644 index 0000000000..8b7652d3a0 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/MacroCodeAssistProcessor.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * 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.page.text; + +import org.eclipse.che.ide.Resources; +import org.eclipse.che.ide.api.editor.codeassist.CodeAssistCallback; +import org.eclipse.che.ide.api.editor.codeassist.CodeAssistProcessor; +import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal; +import org.eclipse.che.ide.api.editor.document.Document; +import org.eclipse.che.ide.api.editor.text.TextPosition; +import org.eclipse.che.ide.api.editor.texteditor.TextEditor; +import org.eclipse.che.ide.api.macro.Macro; +import org.eclipse.che.ide.api.macro.MacroRegistry; +import org.eclipse.che.ide.filters.FuzzyMatches; +import org.eclipse.che.ide.filters.Match; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.List; + +/** Code assist processor for macro names. */ +public class MacroCodeAssistProcessor implements CodeAssistProcessor { + + private MacroRegistry registry; + private FuzzyMatches fuzzyMatches; + private Resources resources; + private LastCompletion lastCompletion; + + @Inject + public MacroCodeAssistProcessor(MacroRegistry registry, FuzzyMatches fuzzyMatches, Resources resources) { + this.registry = registry; + this.fuzzyMatches = fuzzyMatches; + this.resources = resources; + lastCompletion = new LastCompletion(); + } + + @Override + public void computeCompletionProposals(TextEditor editor, int offset, boolean triggered, CodeAssistCallback callback) { + Document document = editor.getDocument(); + TextPosition position = document.getPositionFromIndex(offset); + + String currentLine = editor.getDocument().getLineContent(position.getLine()); + final String currentWord = getCurrentWord(currentLine, position.getCharacter()); + + List result = new ArrayList<>(); + if (triggered && !lastCompletion.isGoodFor(currentWord, offset)) { + lastCompletion.offset = offset; + lastCompletion.wordStartOffset = offset - currentWord.length(); // start completion word + lastCompletion.word = currentWord; + } + + List macros = registry.getMacros(); + for (Macro macro : macros) { + List matches = fuzzyMatches.fuzzyMatch(currentWord, macro.getName()); + if (matches != null) { + MacroCompletionProposal proposal = new MacroCompletionProposal(macro, + matches, + resources, + lastCompletion.wordStartOffset, + currentWord.length()); + result.add(proposal); + } + } + + result.sort((o1, o2) -> { + MacroCompletionProposal p1 = ((MacroCompletionProposal)o1); + MacroCompletionProposal p2 = ((MacroCompletionProposal)o2); + + return p1.getMacro().getName().compareTo(p2.getMacro().getName()); + }); + + callback.proposalComputed(result); + } + + private String getCurrentWord(String text, int offset) { + int i = offset - 1; + while (i >= 0 && isWordChar(text.charAt(i))) { + i--; + } + return text.substring(i + 1, offset); + } + + private boolean isWordChar(char c) { + return c >= 'a' && c <= 'z' || + c >= 'A' && c <= 'Z' || + c >= '0' && c <= '9' || + c >= '\u007f' && c <= '\u00ff' || + c == '$' || + c == '{' || + c == '.' || + c == '_' || + c == '-'; + } + + + @Override + public String getErrorMessage() { + return null; + } + + private class LastCompletion { + String word = ""; + int wordStartOffset; + int offset; + + boolean isGoodFor(String currentWord, int offset) { + return currentWord.startsWith(word) && + offset - this.offset == currentWord.length() - word.length(); + } + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/MacroCompletionProposal.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/MacroCompletionProposal.java new file mode 100644 index 0000000000..95fa5901ab --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/MacroCompletionProposal.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * 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.page.text; + +import com.google.gwt.dom.client.Style; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.Widget; +import org.eclipse.che.ide.Resources; +import org.eclipse.che.ide.api.editor.codeassist.Completion; +import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal; +import org.eclipse.che.ide.api.editor.document.Document; +import org.eclipse.che.ide.api.editor.text.LinearRange; +import org.eclipse.che.ide.api.icon.Icon; +import org.eclipse.che.ide.api.macro.Macro; +import org.eclipse.che.ide.filters.Match; + +import java.util.List; + +/** Completion proposal for {@link Macro} that will insert {@link Macro#getName()} value. */ +class MacroCompletionProposal implements CompletionProposal { + + private final Macro macro; + private final List matches; + private Resources resources; + private int offset; + private int length; + + MacroCompletionProposal(Macro macro, List matches, Resources resources, int offset, int length) { + this.macro = macro; + this.matches = matches; + this.resources = resources; + this.offset = offset; + this.length = length; + } + + @Override + public void getAdditionalProposalInfo(AsyncCallback callback) { + String documentation = macro.getDescription(); + if (documentation == null || documentation.trim().isEmpty()) { + documentation = "No documentation found."; + } + + Label label = new Label(documentation); + label.setWordWrap(true); + label.getElement().getStyle().setFontSize(13, Style.Unit.PX); + label.getElement().getStyle().setMarginLeft(4, Style.Unit.PX); + label.setSize("100%", "100%"); + callback.onSuccess(label); + } + + @Override + public String getDisplayString() { + SafeHtmlBuilder builder = new SafeHtmlBuilder(); + + String label = macro.getName(); + int pos = 0; + for (Match highlight : matches) { + if (highlight.getStart() == highlight.getEnd()) { + continue; + } + + if (pos < highlight.getStart()) { + appendPlain(builder, label.substring(pos, highlight.getStart())); + } + + appendHighlighted(builder, label.substring(highlight.getStart(), highlight.getEnd())); + pos = highlight.getEnd(); + } + + if (pos < label.length()) { + appendPlain(builder, label.substring(pos)); + } + + return builder.toSafeHtml().asString(); + } + + private void appendPlain(SafeHtmlBuilder builder, String text) { + builder.appendEscaped(text); + } + + private void appendHighlighted(SafeHtmlBuilder builder, String text) { + builder.appendHtmlConstant(""); + builder.appendEscaped(text); + builder.appendHtmlConstant(""); + } + + @Override + public Icon getIcon() { + return null; + } + + @Override + public void getCompletion(final CompletionCallback callback) { + callback.onCompletion(new Completion() { + @Override + public void apply(Document document) { + document.replace(offset, length, macro.getName()); + } + + @Override + public LinearRange getSelection(Document document) { + LinearRange.PartialLinearRange start = LinearRange.createWithStart(offset + macro.getName().length()); + return start.andLength(0); + } + }); + } + + public Macro getMacro() { + return macro; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/MacroEditorConfiguration.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/MacroEditorConfiguration.java new file mode 100644 index 0000000000..6041930598 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/MacroEditorConfiguration.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * 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.page.text; + +import org.eclipse.che.ide.api.editor.codeassist.CodeAssistProcessor; +import org.eclipse.che.ide.api.editor.editorconfig.DefaultTextEditorConfiguration; +import org.eclipse.che.ide.api.editor.editorconfig.TextEditorConfiguration; +import org.eclipse.che.ide.api.editor.partition.DocumentPartitioner; + +import javax.inject.Inject; +import java.util.HashMap; +import java.util.Map; + +/** + * {@link TextEditorConfiguration} which provides {@link CodeAssistProcessor} for macros names. + */ +public class MacroEditorConfiguration extends DefaultTextEditorConfiguration { + + private MacroCodeAssistProcessor codeAssistProcessor; + + @Inject + public MacroEditorConfiguration(MacroCodeAssistProcessor codeAssistProcessor) { + this.codeAssistProcessor = codeAssistProcessor; + } + + @Override + public Map getContentAssistantProcessors() { + Map map = new HashMap<>(); + map.put(DocumentPartitioner.DEFAULT_CONTENT_TYPE, codeAssistProcessor); + + return map; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/PageWithTextEditorView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/PageWithTextEditorView.java new file mode 100644 index 0000000000..0816b37d69 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/PageWithTextEditorView.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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.page.text; + +import com.google.gwt.user.client.ui.SimpleLayoutPanel; + +import org.eclipse.che.ide.api.mvp.View; + +/** + * View for {@link AbstractPageWithTextEditor}. + * + * @author Artem Zatsarynnyi + */ +public interface PageWithTextEditorView extends View { + + /** Returns the container where the editor should be placed. */ + SimpleLayoutPanel getEditorContainer(); + + /** Sets height of the view. */ + void setHeight(int height); + + /** Sets title for the editor. */ + void setEditorTitle(String title); + + /** The action delegate for this view. */ + interface ActionDelegate { + + /** Called when exploring macros is requested. */ + void onExploreMacros(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/PageWithTextEditorViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/PageWithTextEditorViewImpl.java new file mode 100644 index 0000000000..2fa326d3d2 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/PageWithTextEditorViewImpl.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * 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.page.text; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.DockLayoutPanel; +import com.google.gwt.user.client.ui.Hyperlink; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.SimpleLayoutPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; + +/** + * Implementation of {@link PageWithTextEditorView}. + * + * @author Artem Zatsarynnyi + */ +public class PageWithTextEditorViewImpl extends Composite implements PageWithTextEditorView { + + private static final PageWithTextEditorViewImplUiBinder UI_BINDER = GWT.create(PageWithTextEditorViewImplUiBinder.class); + + @UiField + DockLayoutPanel mainPanel; + + @UiField + Label title; + + @UiField + Hyperlink exploreMacrosLink; + + @UiField + SimpleLayoutPanel editorPanel; + + /** The delegate to receive events from this view. */ + private ActionDelegate delegate; + + @Inject + public PageWithTextEditorViewImpl() { + initWidget(UI_BINDER.createAndBindUi(this)); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @Override + public SimpleLayoutPanel getEditorContainer() { + return editorPanel; + } + + @Override + public void setHeight(int height) { + mainPanel.setHeight(height + "px"); + } + + @Override + public void setEditorTitle(String title) { + this.title.setText(title); + } + + @UiHandler("exploreMacrosLink") + public void handleExploreMacrosLinkClick(ClickEvent event) { + delegate.onExploreMacros(); + } + + interface PageWithTextEditorViewImplUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/PageWithTextEditorViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/PageWithTextEditorViewImpl.ui.xml new file mode 100644 index 0000000000..406b87287d --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/editor/page/text/PageWithTextEditorViewImpl.ui.xml @@ -0,0 +1,52 @@ + + + + + + + + @eval textFieldBorderColor org.eclipse.che.ide.api.theme.Style.theme.toolButtonActiveBorder(); + + .editor { + border: textFieldBorderColor; + } + + .title { + float: left; + margin-left: 0; + } + + .link a, a:visited { + float: right; + margin: 8px 10px 8px 0; + color: #4990E2; + font-size: 11px; + } + + + + + + + + + + + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/CommandsActionGroup.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/CommandsActionGroup.java new file mode 100644 index 0000000000..26999f799c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/CommandsActionGroup.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * 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.execute; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.action.ActionManager; +import org.eclipse.che.ide.api.action.DefaultActionGroup; +import org.eclipse.che.ide.api.resources.Resource; +import org.eclipse.che.ide.api.selection.Selection; +import org.eclipse.che.ide.api.selection.SelectionAgent; +import org.eclipse.che.ide.resources.tree.ResourceNode; + +/** + * Action group that contains all actions for executing commands. + * + * @author Artem Zatsarynnyi + */ +@Singleton +public class CommandsActionGroup extends DefaultActionGroup { + + private final SelectionAgent selectionAgent; + + @Inject + public CommandsActionGroup(ActionManager actionManager, + SelectionAgent selectionAgent, + ExecMessages messages) { + super(messages.actionCommandsTitle(), true, actionManager); + + this.selectionAgent = selectionAgent; + } + + @Override + public void update(ActionEvent e) { + e.getPresentation().setEnabledAndVisible(false); + + // action group should be visible when current selection is machine or project + + final Selection selection = selectionAgent.getSelection(); + + if (selection != null && !selection.isEmpty() && selection.isSingleSelection()) { + final Object possibleNode = selection.getHeadElement(); + + if (possibleNode instanceof Machine) { + e.getPresentation().setEnabledAndVisible(true); + } else if (possibleNode instanceof ResourceNode) { + final Resource selectedResource = ((ResourceNode)possibleNode).getData(); + + e.getPresentation().setEnabledAndVisible(selectedResource.isProject()); + } + } + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecMessages.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecMessages.java new file mode 100644 index 0000000000..71066376f2 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecMessages.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * 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.execute; + +import com.google.gwt.i18n.client.Messages; + +/** + * I18n messages relate to the command execution. + * + * @author Artem Zatsarynnyi + */ +public interface ExecMessages extends Messages { + + @Key("action.commands.title") + String actionCommandsTitle(); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecuteCommandAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecuteCommandAction.java new file mode 100644 index 0000000000..9eb3f81e2f --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecuteCommandAction.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * 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.execute; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; + +import org.eclipse.che.ide.api.action.Action; +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.command.CommandExecutor; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.command.CommandUtils; +import org.vectomatic.dom.svg.ui.SVGResource; + +/** Action for executing a {@link CommandImpl}. */ +class ExecuteCommandAction extends Action { + + private final CommandImpl command; + private final CommandExecutor commandExecutor; + private final CommandManager commandManager; + + @Inject + ExecuteCommandAction(@Assisted CommandImpl command, + CommandUtils commandUtils, + CommandExecutor commandExecutor, + CommandManager commandManager) { + super(command.getName()); + + this.command = command; + this.commandExecutor = commandExecutor; + this.commandManager = commandManager; + + final SVGResource commandIcon = commandUtils.getCommandTypeIcon(command.getType()); + if (commandIcon != null) { + getTemplatePresentation().setSVGResource(commandIcon); + } + } + + @Override + public void update(ActionEvent e) { + e.getPresentation().setEnabledAndVisible(commandManager.isCommandApplicable(command)); + } + + @Override + public void actionPerformed(ActionEvent e) { + commandExecutor.executeCommand(command); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecuteCommandActionFactory.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecuteCommandActionFactory.java new file mode 100644 index 0000000000..b61340a2cf --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecuteCommandActionFactory.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * 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.execute; + +import org.eclipse.che.ide.api.command.CommandImpl; + +/** + * Factory for creating {@link ExecuteCommandAction} instances. + * + * @author Artem Zatsarynnyi + */ +public interface ExecuteCommandActionFactory { + + /** Creates new instance of {@link ExecuteCommandAction} for executing the specified {@code command}. */ + ExecuteCommandAction create(CommandImpl command); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecuteCommandActionManager.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecuteCommandActionManager.java new file mode 100644 index 0000000000..9e6a64e481 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/ExecuteCommandActionManager.java @@ -0,0 +1,185 @@ +/******************************************************************************* + * 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.execute; + +import com.google.gwt.core.client.Callback; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.api.action.Action; +import org.eclipse.che.ide.api.action.ActionManager; +import org.eclipse.che.ide.api.action.DefaultActionGroup; +import org.eclipse.che.ide.api.command.CommandGoalRegistry; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.command.CommandManager.CommandChangedListener; +import org.eclipse.che.ide.api.command.CommandManager.CommandLoadedListener; +import org.eclipse.che.ide.api.component.Component; + +import java.util.HashMap; +import java.util.Map; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static org.eclipse.che.ide.api.action.IdeActions.GROUP_CONSOLES_TREE_CONTEXT_MENU; +import static org.eclipse.che.ide.api.action.IdeActions.GROUP_EDITOR_TAB_CONTEXT_MENU; +import static org.eclipse.che.ide.api.action.IdeActions.GROUP_MAIN_CONTEXT_MENU; + +/** + * Manager listens for creating/removing commands and adds/removes + * related {@link ExecuteCommandAction}s in the context menus. + */ +@Singleton +public class ExecuteCommandActionManager implements Component, CommandLoadedListener, CommandChangedListener { + + private static final String COMMANDS_ACTION_GROUP_ID_PREFIX = "commandsActionGroup"; + private static final String COMMAND_ACTION_ID_PREFIX = "command_"; + private static final String GOAL_ACTION_GROUP_ID_PREFIX = "goal_"; + + private final CommandManager commandManager; + private final ActionManager actionManager; + private final CommandsActionGroup commandsActionGroup; + private final GoalPopUpGroupFactory goalPopUpGroupFactory; + private final ExecuteCommandActionFactory commandActionFactory; + private final CommandGoalRegistry goalRegistry; + + /** Map of command's name to an appropriate {@link ExecuteCommandAction}. */ + private final Map commandActions; + /** Map of command goal's ID to an appropriate action group. */ + private final Map goalPopUpGroups; + + @Inject + public ExecuteCommandActionManager(CommandManager commandManager, + ActionManager actionManager, + CommandsActionGroup commandsActionGroup, + GoalPopUpGroupFactory goalPopUpGroupFactory, + ExecuteCommandActionFactory commandActionFactory, + CommandGoalRegistry goalRegistry) { + this.commandManager = commandManager; + this.actionManager = actionManager; + this.commandsActionGroup = commandsActionGroup; + this.goalPopUpGroupFactory = goalPopUpGroupFactory; + this.commandActionFactory = commandActionFactory; + this.goalRegistry = goalRegistry; + + commandActions = new HashMap<>(); + goalPopUpGroups = new HashMap<>(); + } + + @Override + public void start(Callback callback) { + callback.onSuccess(this); + + commandManager.addCommandLoadedListener(this); + commandManager.addCommandChangedListener(this); + + actionManager.registerAction(COMMANDS_ACTION_GROUP_ID_PREFIX, commandsActionGroup); + + // inject 'Commands' menu into context menus + ((DefaultActionGroup)actionManager.getAction(GROUP_MAIN_CONTEXT_MENU)).add(commandsActionGroup); + ((DefaultActionGroup)actionManager.getAction(GROUP_EDITOR_TAB_CONTEXT_MENU)).add(commandsActionGroup); + ((DefaultActionGroup)actionManager.getAction(GROUP_CONSOLES_TREE_CONTEXT_MENU)).add(commandsActionGroup); + } + + @Override + public void onCommandsLoaded() { + commandManager.getCommands().forEach(this::addAction); + } + + @Override + public void onCommandAdded(CommandImpl command) { + addAction(command); + } + + /** + * Creates action for executing the given command and + * adds created action to the appropriate action group. + */ + private void addAction(CommandImpl command) { + final ExecuteCommandAction action = commandActionFactory.create(command); + + actionManager.registerAction(COMMAND_ACTION_ID_PREFIX + command.getName(), action); + commandActions.put(command.getName(), action); + + getActionGroupForCommand(command).add(action); + } + + /** + * Returns the action group which is appropriate for placing the action for executing the given command. + * If appropriate action group doesn't exist it will be created and added to the right place. + */ + private DefaultActionGroup getActionGroupForCommand(CommandImpl command) { + String goalId = command.getGoal(); + + if (isNullOrEmpty(goalId)) { + goalId = goalRegistry.getDefaultGoal().getId(); + } + + DefaultActionGroup commandGoalPopUpGroup = goalPopUpGroups.get(goalId); + + if (commandGoalPopUpGroup == null) { + commandGoalPopUpGroup = goalPopUpGroupFactory.create(goalId); + + actionManager.registerAction(GOAL_ACTION_GROUP_ID_PREFIX + goalId, commandGoalPopUpGroup); + goalPopUpGroups.put(goalId, commandGoalPopUpGroup); + + commandsActionGroup.add(commandGoalPopUpGroup); + } + + return commandGoalPopUpGroup; + } + + @Override + public void onCommandUpdated(CommandImpl previousCommand, CommandImpl command) { + removeAction(previousCommand); + addAction(command); + } + + @Override + public void onCommandRemoved(CommandImpl command) { + removeAction(command); + } + + /** + * Removes action for executing the given command and + * removes the appropriate action group in case it's empty. + */ + private void removeAction(CommandImpl command) { + final Action commandAction = commandActions.remove(command.getName()); + + if (commandAction != null) { + final String commandActionId = actionManager.getId(commandAction); + if (commandActionId != null) { + actionManager.unregisterAction(commandActionId); + } + + // remove action from it's action group + String goalId = command.getGoal(); + if (isNullOrEmpty(goalId)) { + goalId = goalRegistry.getDefaultGoal().getId(); + } + + // remove action group if it's empty + final DefaultActionGroup goalPopUpGroup = goalPopUpGroups.remove(goalId); + + if (goalPopUpGroup != null) { + goalPopUpGroup.remove(commandAction); + + if (goalPopUpGroup.getChildrenCount() == 0) { + final String goalActionId = actionManager.getId(goalPopUpGroup); + if (goalActionId != null) { + actionManager.unregisterAction(goalActionId); + } + commandsActionGroup.remove(goalPopUpGroup); + } + } + } + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/GoalPopUpGroup.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/GoalPopUpGroup.java new file mode 100644 index 0000000000..28cd7664e1 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/GoalPopUpGroup.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * 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.execute; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; + +import org.eclipse.che.ide.api.action.ActionEvent; +import org.eclipse.che.ide.api.action.ActionManager; +import org.eclipse.che.ide.api.action.DefaultActionGroup; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandGoalRegistry; +import org.eclipse.che.ide.api.icon.Icon; +import org.eclipse.che.ide.api.icon.IconRegistry; +import org.vectomatic.dom.svg.ui.SVGImage; +import org.vectomatic.dom.svg.ui.SVGResource; + +/** + * Action group that represents command goal. + * + * @author Artem Zatsarynnyi + */ +class GoalPopUpGroup extends DefaultActionGroup { + + private final CommandGoal commandGoal; + private final IconRegistry iconRegistry; + + @Inject + GoalPopUpGroup(@Assisted String goalId, + ActionManager actionManager, + CommandGoalRegistry goalRegistry, + IconRegistry iconRegistry) { + super(actionManager); + + this.iconRegistry = iconRegistry; + commandGoal = goalRegistry.getGoalForId(goalId); + + setPopup(true); + + // set icon + final SVGResource commandTypeIcon = getCommandGoalIcon(); + if (commandTypeIcon != null) { + getTemplatePresentation().setSVGResource(commandTypeIcon); + } + } + + @Override + public void update(ActionEvent e) { + e.getPresentation().setText(commandGoal.getId() + " (" + getChildrenCount() + ")"); + } + + private SVGResource getCommandGoalIcon() { + final String goalId = commandGoal.getId(); + + final Icon icon = iconRegistry.getIconIfExist("command.goal." + goalId); + + if (icon != null) { + final SVGImage svgImage = icon.getSVGImage(); + + if (svgImage != null) { + return icon.getSVGResource(); + } + } + + return null; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/GoalPopUpGroupFactory.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/GoalPopUpGroupFactory.java new file mode 100644 index 0000000000..aa51db6baf --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/execute/GoalPopUpGroupFactory.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * 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.execute; + +/** + * Factory for creating {@link GoalPopUpGroup} instances. + * + * @author Artem Zatsarynnyi + */ +public interface GoalPopUpGroupFactory { + + /** Creates new {@link GoalPopUpGroup} for the command goal with the given {@code id}. */ + GoalPopUpGroup create(String id); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerPresenter.java new file mode 100644 index 0000000000..fbf6df576a --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerPresenter.java @@ -0,0 +1,305 @@ +/******************************************************************************* + * 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.explorer; + +import com.google.common.annotations.VisibleForTesting; +import com.google.gwt.core.client.Callback; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.google.gwt.user.client.ui.IsWidget; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +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.DelayedTask; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandGoalRegistry; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandImpl.ApplicableContext; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.command.CommandManager.CommandChangedListener; +import org.eclipse.che.ide.api.command.CommandManager.CommandLoadedListener; +import org.eclipse.che.ide.api.command.CommandType; +import org.eclipse.che.ide.api.component.Component; +import org.eclipse.che.ide.api.constraints.Constraints; +import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.parts.WorkspaceAgent; +import org.eclipse.che.ide.api.parts.base.BasePresenter; +import org.eclipse.che.ide.command.CommandResources; +import org.eclipse.che.ide.command.CommandUtils; +import org.eclipse.che.ide.command.node.NodeFactory; +import org.eclipse.che.ide.command.type.chooser.CommandTypeChooser; +import org.vectomatic.dom.svg.ui.SVGResource; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +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.api.parts.PartStackType.NAVIGATION; + +/** Presenter for Commands Explorer. */ +@Singleton +public class CommandsExplorerPresenter extends BasePresenter implements CommandsExplorerView.ActionDelegate, + Component, + CommandChangedListener, + CommandLoadedListener { + + private final CommandsExplorerView view; + private final CommandResources resources; + private final WorkspaceAgent workspaceAgent; + private final CommandManager commandManager; + private final NotificationManager notificationManager; + private final CommandTypeChooser commandTypeChooser; + private final ExplorerMessages messages; + private final RefreshViewTask refreshViewTask; + private final DialogFactory dialogFactory; + private final NodeFactory nodeFactory; + private final EditorAgent editorAgent; + private final AppContext appContext; + + @Inject + public CommandsExplorerPresenter(CommandsExplorerView view, + CommandResources commandResources, + WorkspaceAgent workspaceAgent, + CommandManager commandManager, + NotificationManager notificationManager, + CommandTypeChooser commandTypeChooser, + ExplorerMessages messages, + RefreshViewTask refreshViewTask, + DialogFactory dialogFactory, + NodeFactory nodeFactory, + EditorAgent editorAgent, + AppContext appContext) { + this.view = view; + this.resources = commandResources; + this.workspaceAgent = workspaceAgent; + this.commandManager = commandManager; + this.notificationManager = notificationManager; + this.commandTypeChooser = commandTypeChooser; + this.messages = messages; + this.refreshViewTask = refreshViewTask; + this.dialogFactory = dialogFactory; + this.nodeFactory = nodeFactory; + this.editorAgent = editorAgent; + this.appContext = appContext; + + view.setDelegate(this); + } + + @Override + public void start(Callback callback) { + workspaceAgent.openPart(this, NAVIGATION, Constraints.LAST); + + commandManager.addCommandLoadedListener(this); + commandManager.addCommandChangedListener(this); + + callback.onSuccess(this); + } + + @Override + public void go(AcceptsOneWidget container) { + refreshView(); + + container.setWidget(getView()); + } + + @Override + public String getTitle() { + return messages.partTitle(); + } + + @Override + public IsWidget getView() { + return view; + } + + @Nullable + @Override + public String getTitleToolTip() { + return messages.partTooltip(); + } + + @Nullable + @Override + public SVGResource getTitleImage() { + return resources.explorerPart(); + } + + @Override + public void onCommandAdd(int left, int top) { + commandTypeChooser.show(left, top).then(createCommand(getDefaultContext())); + } + + /** Returns the default {@link ApplicableContext} for the new command. */ + private ApplicableContext getDefaultContext() { + final ApplicableContext context = new ApplicableContext(); + + if (appContext.getProjects().length > 0) { + context.setWorkspaceApplicable(false); + + Arrays.stream(appContext.getProjects()) + .forEach(p -> context.addProject(p.getPath())); + } + + return context; + } + + /** Returns an operation which creates a command with the given context. */ + private Operation createCommand(ApplicableContext context) { + return selectedCommandType -> { + final CommandGoal selectedGoal = view.getSelectedGoal(); + + if (selectedGoal == null) { + return; + } + + commandManager.createCommand(selectedGoal.getId(), selectedCommandType.getId(), context) + .then(command -> { + refreshViewAndSelectCommand(command); + editorAgent.openEditor(nodeFactory.newCommandFileNode(command)); + }) + .catchError(showErrorNotification(messages.unableCreate())); + }; + } + + @Override + public void onCommandDuplicate(CommandImpl command) { + commandManager.createCommand(command) + .then(this::refreshViewAndSelectCommand) + .catchError(showErrorNotification(messages.unableDuplicate())); + } + + @Override + public void onCommandRemove(CommandImpl command) { + dialogFactory.createConfirmDialog(messages.removeCommandConfirmationTitle(), + messages.removeCommandConfirmationMessage(command.getName()), + () -> commandManager.removeCommand(command.getName()) + .catchError(showErrorNotification(messages.unableRemove())), + null).show(); + } + + /** Returns an operation which shows an error notification with the given title. */ + private Operation showErrorNotification(String title) { + return err -> { + notificationManager.notify(title, err.getMessage(), FAIL, EMERGE_MODE); + throw new OperationException(err.getMessage()); + }; + } + + @Override + public void onCommandsLoaded() { + refreshView(); + } + + @Override + public void onCommandAdded(CommandImpl command) { + refreshView(); + } + + @Override + public void onCommandUpdated(CommandImpl previousCommand, CommandImpl command) { + refreshView(); + } + + @Override + public void onCommandRemoved(CommandImpl command) { + refreshView(); + } + + /** Refresh view and preserve current selection. */ + private void refreshView() { + refreshViewAndSelectCommand(null); + } + + private void refreshViewAndSelectCommand(CommandImpl command) { + refreshViewTask.delayAndSelectCommand(command); + } + + /** + * {@link DelayedTask} for refreshing the view and optionally selecting the specified command. + *

Tree widget in the view works asynchronously using events + * and it needs some time to be fully rendered. + * So successive refreshing view must be called with some delay. + */ + // since GIN can't instantiate inner classes + // made it nested in order to allow injection + @VisibleForTesting + static class RefreshViewTask extends DelayedTask { + + // 300 milliseconds should be enough to fully refreshing the tree + private static final int DELAY_MILLIS = 300; + + private final CommandsExplorerView view; + private final CommandGoalRegistry goalRegistry; + private final CommandManager commandManager; + private final CommandUtils commandUtils; + + private CommandImpl commandToSelect; + + @Inject + public RefreshViewTask(CommandsExplorerView view, + CommandGoalRegistry goalRegistry, + CommandManager commandManager, + CommandUtils commandUtils) { + this.view = view; + this.goalRegistry = goalRegistry; + this.commandManager = commandManager; + this.commandUtils = commandUtils; + } + + @Override + public void onExecute() { + refreshView(); + + if (commandToSelect != null) { + // wait some time while tree in the view will be fully refreshed + new Timer() { + @Override + public void run() { + view.selectCommand(commandToSelect); + } + }.schedule(DELAY_MILLIS); + } + } + + void delayAndSelectCommand(@Nullable CommandImpl command) { + if (command != null) { + commandToSelect = command; + } + + delay(DELAY_MILLIS); + } + + private void refreshView() { + final Map> commandsByGoals = new HashMap<>(); + + // all predefined commandToSelect goals must be shown in the view + // so populate map by all registered commandToSelect goals + for (CommandGoal goal : goalRegistry.getAllPredefinedGoals()) { + commandsByGoals.put(goal, new ArrayList<>()); + } + + commandsByGoals.putAll(commandUtils.groupCommandsByGoal(commandManager.getCommands())); + + view.setCommands(commandsByGoals); + } + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerView.java new file mode 100644 index 0000000000..a4bd7bb0f4 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerView.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * 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.explorer; + +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.mvp.View; +import org.eclipse.che.ide.api.parts.base.BaseActionDelegate; + +import java.util.List; +import java.util.Map; + +/** + * The view for {@link CommandsExplorerPresenter}. + * + * @author Artem Zatsarynnyi + */ +public interface CommandsExplorerView extends View { + + /** + * Sets the commands to display in the view. + * + * @param commands + * commands grouped by its type + */ + void setCommands(Map> commands); + + /** Returns the currently selected command goal or {@code null} if none. */ + @Nullable + CommandGoal getSelectedGoal(); + + /** Returns the currently selected command or {@code null} if none. */ + @Nullable + CommandImpl getSelectedCommand(); + + /** Select the given {@code command}. */ + void selectCommand(CommandImpl command); + + /** The action delegate for this view. */ + interface ActionDelegate extends BaseActionDelegate { + + /** Called when adding new command is requested. */ + void onCommandAdd(int left, int top); + + /** + * Called when duplicating command is requested. + * + * @param command + * command duplication of which is requested + */ + void onCommandDuplicate(CommandImpl command); + + /** + * Called when removing command is requested. + * + * @param command + * command removing of which is requested + */ + void onCommandRemove(CommandImpl command); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerViewImpl.java new file mode 100644 index 0000000000..7656f6fcd8 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerViewImpl.java @@ -0,0 +1,170 @@ +/******************************************************************************* + * 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.explorer; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Element; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.Resources; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.data.tree.Node; +import org.eclipse.che.ide.api.parts.base.BaseView; +import org.eclipse.che.ide.command.CommandResources; +import org.eclipse.che.ide.command.node.CommandFileNode; +import org.eclipse.che.ide.command.node.CommandGoalNode; +import org.eclipse.che.ide.command.node.NodeFactory; +import org.eclipse.che.ide.ui.smartTree.NodeLoader; +import org.eclipse.che.ide.ui.smartTree.NodeStorage; +import org.eclipse.che.ide.ui.smartTree.Tree; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import static java.util.Collections.singletonList; +import static org.eclipse.che.ide.ui.smartTree.SelectionModel.Mode.SINGLE; + +/** + * Implementation of {@link CommandsExplorerView}. + * + * @author Artem Zatsarynnyi + */ +@Singleton +public class CommandsExplorerViewImpl extends BaseView implements CommandsExplorerView { + + private static final CommandsExplorerViewImplUiBinder UI_BINDER = GWT.create(CommandsExplorerViewImplUiBinder.class); + + private final CommandsTreeRenderer treeRenderer; + private final NodeFactory nodeFactory; + /** Mapping of the commands to the rendered tree nodes. */ + private final Map commandNodes; + + @UiField(provided = true) + Tree tree; + + @Inject + public CommandsExplorerViewImpl(Resources coreResources, + ExplorerMessages messages, + CommandResources resources, + NodeFactory nodeFactory) { + super(coreResources); + + this.nodeFactory = nodeFactory; + commandNodes = new HashMap<>(); + + setTitle(messages.viewTitle()); + + tree = new Tree(new NodeStorage(), new NodeLoader()); + tree.ensureDebugId("commands-explorer"); + + treeRenderer = new CommandsTreeRenderer(tree.getTreeStyles(), resources, delegate); + + tree.setPresentationRenderer(treeRenderer); + tree.getSelectionModel().setSelectionMode(SINGLE); + + tree.getSelectionModel().addSelectionHandler(event -> { + for (Node node : tree.getNodeStorage().getAll()) { + final Element nodeContainerElement = tree.getNodeDescriptor(node).getNodeContainerElement(); + + if (nodeContainerElement != null) { + nodeContainerElement.removeAttribute("selected"); + } + } + + tree.getNodeDescriptor(event.getSelectedItem()) + .getNodeContainerElement() + .setAttribute("selected", "selected"); + }); + + setContentWidget(UI_BINDER.createAndBindUi(this)); + } + + @Override + protected void focusView() { + tree.setFocus(true); + } + + @Override + public void setCommands(Map> commands) { + treeRenderer.setDelegate(delegate); + + renderCommands(commands); + } + + private void renderCommands(Map> commands) { + commandNodes.clear(); + tree.getNodeStorage().clear(); + + for (Entry> entry : commands.entrySet()) { + List commandNodes = new ArrayList<>(entry.getValue().size()); + for (CommandImpl command : entry.getValue()) { + final CommandFileNode commandFileNode = nodeFactory.newCommandFileNode(command); + commandNodes.add(commandFileNode); + + this.commandNodes.put(command, commandFileNode); + } + + final CommandGoalNode commandGoalNode = nodeFactory.newCommandGoalNode(entry.getKey(), commandNodes); + tree.getNodeStorage().add(commandGoalNode); + } + + tree.expandAll(); + } + + @Nullable + @Override + public CommandGoal getSelectedGoal() { + final List selectedNodes = tree.getSelectionModel().getSelectedNodes(); + + if (!selectedNodes.isEmpty()) { + final Node selectedNode = selectedNodes.get(0); + + if (selectedNode instanceof CommandGoalNode) { + return ((CommandGoalNode)selectedNode).getData(); + } + } + + return null; + } + + @Nullable + @Override + public CommandImpl getSelectedCommand() { + final List selectedNodes = tree.getSelectionModel().getSelectedNodes(); + + if (!selectedNodes.isEmpty()) { + final Node selectedNode = selectedNodes.get(0); + + if (selectedNode instanceof CommandFileNode) { + return ((CommandFileNode)selectedNode).getData(); + } + } + + return null; + } + + @Override + public void selectCommand(CommandImpl command) { + tree.getSelectionModel().setSelection(singletonList(commandNodes.get(command))); + } + + interface CommandsExplorerViewImplUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerViewImpl.ui.xml new file mode 100644 index 0000000000..c565a1d31b --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsExplorerViewImpl.ui.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsTreeRenderer.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsTreeRenderer.java new file mode 100644 index 0000000000..59963b42e2 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/CommandsTreeRenderer.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * 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.explorer; + +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Element; +import com.google.gwt.user.client.Event; + +import org.eclipse.che.ide.api.data.tree.Node; +import org.eclipse.che.ide.command.CommandResources; +import org.eclipse.che.ide.command.explorer.CommandsExplorerView.ActionDelegate; +import org.eclipse.che.ide.command.node.CommandFileNode; +import org.eclipse.che.ide.command.node.CommandGoalNode; +import org.eclipse.che.ide.ui.smartTree.Tree; +import org.eclipse.che.ide.ui.smartTree.TreeStyles; +import org.eclipse.che.ide.ui.smartTree.presentation.DefaultPresentationRenderer; +import org.vectomatic.dom.svg.ui.SVGResource; + +import static com.google.gwt.user.client.Event.ONCLICK; + +/** + * Renderer for the commands tree. + * + * @author Artem Zatsarynnyi + */ +class CommandsTreeRenderer extends DefaultPresentationRenderer { + + private final CommandResources resources; + + private ActionDelegate delegate; + + CommandsTreeRenderer(TreeStyles treeStyles, CommandResources resources, ActionDelegate delegate) { + super(treeStyles); + + this.resources = resources; + this.delegate = delegate; + } + + /** Sets the delegate that will handle events from the rendered DOM elements. */ + void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @Override + public Element getPresentableTextContainer(Element content) { + final Element presentableTextContainer = super.getPresentableTextContainer(content); + presentableTextContainer.addClassName(resources.commandsExplorerCss().commandNodeText()); + + return presentableTextContainer; + } + + @Override + public Element render(Node node, String domID, Tree.Joint joint, int depth) { + final Element element = super.render(node, domID, joint, depth); + final Element nodeContainerElement = element.getFirstChildElement(); + + if (node instanceof CommandFileNode) { + CommandFileNode commandNode = (CommandFileNode)node; + + nodeContainerElement.setId("command_" + commandNode.getDisplayName()); + + renderCommandNode(commandNode, nodeContainerElement); + } else if (node instanceof CommandGoalNode) { + CommandGoalNode goalNode = (CommandGoalNode)node; + + nodeContainerElement.setId("goal_" + goalNode.getName()); + + renderCommandGoalNode(nodeContainerElement); + } + + return element; + } + + private void renderCommandNode(CommandFileNode node, Element nodeContainerElement) { + nodeContainerElement.addClassName(resources.commandsExplorerCss().commandNode()); + + final Element removeCommandButton = createButton(resources.removeCommand()); + Event.setEventListener(removeCommandButton, event -> { + if (ONCLICK == event.getTypeInt()) { + event.stopPropagation(); + delegate.onCommandRemove(node.getData()); + } + }); + + final Element duplicateCommandButton = createButton(resources.duplicateCommand()); + Event.setEventListener(duplicateCommandButton, event -> { + if (ONCLICK == event.getTypeInt()) { + event.stopPropagation(); + delegate.onCommandDuplicate(node.getData()); + } + }); + + final Element buttonsPanel = Document.get().createSpanElement(); + buttonsPanel.setClassName(resources.commandsExplorerCss().commandNodeButtonsPanel()); + buttonsPanel.appendChild(removeCommandButton); + buttonsPanel.appendChild(duplicateCommandButton); + + nodeContainerElement.appendChild(buttonsPanel); + + removeCommandButton.setId("commands_tree-button-remove"); + duplicateCommandButton.setId("commands_tree-button-duplicate"); + } + + private void renderCommandGoalNode(Element nodeContainerElement) { + nodeContainerElement.addClassName(resources.commandsExplorerCss().commandGoalNode()); + + final Element addCommandButton = createButton(resources.addCommand()); + + Event.setEventListener(addCommandButton, event -> { + if (ONCLICK == event.getTypeInt()) { + event.stopPropagation(); + delegate.onCommandAdd(addCommandButton.getAbsoluteLeft(), addCommandButton.getAbsoluteTop()); + } + }); + + nodeContainerElement.appendChild(addCommandButton); + + addCommandButton.setId("commands_tree-button-add"); + } + + private Element createButton(SVGResource icon) { + final Element button = Document.get().createSpanElement(); + button.appendChild(icon.getSvg().getElement()); + + Event.sinkEvents(button, ONCLICK); + + return button; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/ExplorerMessages.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/ExplorerMessages.java new file mode 100644 index 0000000000..8126e15d9f --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/explorer/ExplorerMessages.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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.explorer; + +import com.google.gwt.i18n.client.Messages; + +/** + * I18n messages for the Command Explorer. + * + * @author Artem Zatsarynnyi + */ +public interface ExplorerMessages extends Messages { + + @Key("explorer.part.title") + String partTitle(); + + @Key("explorer.part.tooltip") + String partTooltip(); + + @Key("explorer.view.title") + String viewTitle(); + + @Key("explorer.message.unable_create") + String unableCreate(); + + @Key("explorer.message.unable_duplicate") + String unableDuplicate(); + + @Key("explorer.message.unable_remove") + String unableRemove(); + + @Key("explorer.remove_confirmation.title") + String removeCommandConfirmationTitle(); + + @Key("explorer.remove_confirmation.message") + String removeCommandConfirmationMessage(String commandName); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/BuildGoal.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/BuildGoal.java new file mode 100644 index 0000000000..85d88abd5c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/BuildGoal.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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.goal; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.command.BaseCommandGoal; + +/** + * Represents predefined 'Build' goal. + * + * @author Artem Zatsarynnyi + */ +public class BuildGoal extends BaseCommandGoal { + + @Inject + public BuildGoal() { + super("Build"); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/CommandGoalRegistryImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/CommandGoalRegistryImpl.java new file mode 100644 index 0000000000..500f8926f6 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/CommandGoalRegistryImpl.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * 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.goal; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; + +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.command.BaseCommandGoal; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandGoalRegistry; +import org.eclipse.che.ide.util.loging.Log; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.util.Collections.unmodifiableList; +import static java.util.Optional.ofNullable; + +/** + * Implementation of {@link CommandGoalRegistry}. + * + * @author Artem Zatsarynnyi + */ +@Singleton +public class CommandGoalRegistryImpl implements CommandGoalRegistry { + + private final CommandGoal defaultGoal; + private final GoalMessages messages; + private final Map commandGoals; + + @Inject + public CommandGoalRegistryImpl(@Named("default") CommandGoal defaultCommandGoal, GoalMessages messages) { + defaultGoal = defaultCommandGoal; + this.messages = messages; + + commandGoals = new HashMap<>(); + } + + @Inject(optional = true) + private void register(Set goals) { + for (CommandGoal type : goals) { + final String id = type.getId(); + + if (commandGoals.containsKey(id)) { + Log.warn(getClass(), messages.messageGoalAlreadyRegistered(id)); + } else { + commandGoals.put(id, type); + } + } + } + + @Override + public List getAllPredefinedGoals() { + return unmodifiableList(new ArrayList<>(commandGoals.values())); + } + + @Override + public CommandGoal getDefaultGoal() { + return defaultGoal; + } + + @Override + public Optional getPredefinedGoalById(String id) { + return ofNullable(commandGoals.get(id)); + } + + @Override + public CommandGoal getGoalForId(@Nullable String id) { + if (isNullOrEmpty(id)) { + return getDefaultGoal(); + } + + return getPredefinedGoalById(id).orElse(new BaseCommandGoal(id)); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/CommonGoal.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/CommonGoal.java new file mode 100644 index 0000000000..1dcc880193 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/CommonGoal.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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.goal; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.command.BaseCommandGoal; + +/** + * Represents predefined 'Common' goal. + * By default it's used for grouping commands which doesn't belong to any goal. + * + * @author Artem Zatsarynnyi + */ +public class CommonGoal extends BaseCommandGoal { + + @Inject + public CommonGoal() { + super("Common"); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/DebugGoal.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/DebugGoal.java new file mode 100644 index 0000000000..c988451013 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/DebugGoal.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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.goal; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.command.BaseCommandGoal; + +/** + * Represents predefined 'Debug' goal. + * + * @author Artem Zatsarynnyi + */ +public class DebugGoal extends BaseCommandGoal { + + @Inject + public DebugGoal() { + super("Debug"); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/DeployGoal.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/DeployGoal.java new file mode 100644 index 0000000000..a4694cc536 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/DeployGoal.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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.goal; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.command.BaseCommandGoal; + +/** + * Represents predefined 'Deploy' goal. + * + * @author Artem Zatsarynnyi + */ +public class DeployGoal extends BaseCommandGoal { + + @Inject + public DeployGoal() { + super("Deploy"); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/GoalMessages.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/GoalMessages.java new file mode 100644 index 0000000000..93b12fd978 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/GoalMessages.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * 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.goal; + +import com.google.gwt.i18n.client.Messages; + +/** + * I18n messages relate to the command goals. + * + * @author Artem Zatsarynnyi + */ +public interface GoalMessages extends Messages { + + @Key("message.goal_already_registered") + String messageGoalAlreadyRegistered(String goalId); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/RunGoal.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/RunGoal.java new file mode 100644 index 0000000000..7b5dd34da6 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/RunGoal.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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.goal; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.command.BaseCommandGoal; + +/** + * Represents predefined 'Run' goal. + * + * @author Artem Zatsarynnyi + */ +public class RunGoal extends BaseCommandGoal { + + @Inject + public RunGoal() { + super("Run"); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/TestGoal.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/TestGoal.java new file mode 100644 index 0000000000..87c6354c45 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/goal/TestGoal.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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.goal; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.command.BaseCommandGoal; + +/** + * Represents predefined 'Test' goal. + * + * @author Artem Zatsarynnyi + */ +public class TestGoal extends BaseCommandGoal { + + @Inject + public TestGoal() { + super("Test"); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/CommandManagerImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/CommandManagerImpl.java new file mode 100644 index 0000000000..012605dbec --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/CommandManagerImpl.java @@ -0,0 +1,456 @@ +/******************************************************************************* + * 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.manager; + +import elemental.util.ArrayOf; +import elemental.util.Collections; + +import com.google.gwt.core.client.Callback; +import com.google.gwt.core.client.Scheduler; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.web.bindery.event.shared.EventBus; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.api.promises.client.Function; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.promises.client.PromiseProvider; +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandImpl.ApplicableContext; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.command.CommandType; +import org.eclipse.che.ide.api.command.CommandTypeRegistry; +import org.eclipse.che.ide.api.component.Component; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.api.resources.Resource; +import org.eclipse.che.ide.api.selection.Selection; +import org.eclipse.che.ide.api.selection.SelectionAgent; +import org.eclipse.che.ide.api.workspace.WorkspaceReadyEvent; +import org.eclipse.che.ide.api.workspace.WorkspaceReadyEvent.WorkspaceReadyHandler; +import org.eclipse.che.ide.util.loging.Log; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.util.stream.Collectors.toList; +import static org.eclipse.che.api.workspace.shared.Constants.COMMAND_GOAL_ATTRIBUTE_NAME; +import static org.eclipse.che.api.workspace.shared.Constants.COMMAND_PREVIEW_URL_ATTRIBUTE_NAME; + +/** Implementation of {@link CommandManager}. */ +@Singleton +public class CommandManagerImpl implements CommandManager, Component, WorkspaceReadyHandler { + + private final AppContext appContext; + private final PromiseProvider promiseProvider; + private final CommandTypeRegistry commandTypeRegistry; + private final ProjectCommandManagerDelegate projectCommandManager; + private final WorkspaceCommandManagerDelegate workspaceCommandManager; + private final EventBus eventBus; + private final SelectionAgent selectionAgent; + + /** Map of the commands' names to the commands. */ + private final Map commands; + private final Set commandLoadedListeners; + private final Set commandChangedListeners; + + @Inject + public CommandManagerImpl(AppContext appContext, + PromiseProvider promiseProvider, + CommandTypeRegistry commandTypeRegistry, + ProjectCommandManagerDelegate projectCommandManagerDelegate, + WorkspaceCommandManagerDelegate workspaceCommandManagerDelegate, + EventBus eventBus, + SelectionAgent selectionAgent) { + this.appContext = appContext; + this.promiseProvider = promiseProvider; + this.commandTypeRegistry = commandTypeRegistry; + this.projectCommandManager = projectCommandManagerDelegate; + this.workspaceCommandManager = workspaceCommandManagerDelegate; + this.eventBus = eventBus; + this.selectionAgent = selectionAgent; + + commands = new HashMap<>(); + commandLoadedListeners = new HashSet<>(); + commandChangedListeners = new HashSet<>(); + } + + @Override + public void start(Callback callback) { + eventBus.addHandler(WorkspaceReadyEvent.getType(), this); + + callback.onSuccess(this); + } + + @Override + public void onWorkspaceReady(WorkspaceReadyEvent event) { + fetchCommands(); + } + + private void fetchCommands() { + // get all commands related to the workspace + workspaceCommandManager.getCommands(appContext.getWorkspaceId()).then(workspaceCommands -> { + workspaceCommands.forEach(workspaceCommand -> commands.put(workspaceCommand.getName(), + new CommandImpl(workspaceCommand, new ApplicableContext()))); + + // get all commands related to the projects + Arrays.stream(appContext.getProjects()) + .forEach(project -> projectCommandManager.getCommands(project).forEach(projectCommand -> { + final CommandImpl existedCommand = commands.get(projectCommand.getName()); + + if (existedCommand == null) { + commands.put(projectCommand.getName(), + new CommandImpl(projectCommand, new ApplicableContext(project.getPath()))); + } else { + if (projectCommand.equalsIgnoreContext(existedCommand)) { + existedCommand.getApplicableContext().addProject(project.getPath()); + } else { + // normally, should never happen + Log.error(CommandManagerImpl.this.getClass(), "Different commands with the same names found"); + } + } + })); + + notifyCommandsLoaded(); + }); + } + + @Override + public List getCommands() { + return commands.values() + .stream() + .map(CommandImpl::new) + .collect(toList()); + } + + @Override + public java.util.Optional getCommand(String name) { + return commands.values() + .stream() + .filter(command -> name.equals(command.getName())) + .findFirst(); + } + + @Override + public List getApplicableCommands() { + return commands.values() + .stream() + .filter(this::isCommandApplicable) + .map(CommandImpl::new) + .collect(toList()); + } + + @Override + public boolean isCommandApplicable(CommandImpl command) { + return isMachineSelected() || isCommandApplicableToCurrentProject(command); + + } + + /** Checks whether the machine is currently selected. */ + private boolean isMachineSelected() { + final Selection selection = selectionAgent.getSelection(); + + if (selection != null && !selection.isEmpty() && selection.isSingleSelection()) { + return selection.getHeadElement() instanceof Machine; + } + + return false; + } + + /** Checks whether the given command is applicable to the current project. */ + private boolean isCommandApplicableToCurrentProject(CommandImpl command) { + final List applicableProjects = command.getApplicableContext().getApplicableProjects(); + + if (applicableProjects.isEmpty()) { + return true; + } + + final Resource currentResource = appContext.getResource(); + if (currentResource != null) { + final Project currentProject = currentResource.getProject(); + if (currentProject != null) { + return applicableProjects.contains(currentProject.getPath()); + } + } + + return false; + } + + @Override + public Promise createCommand(String goalId, String typeId) { + return createCommand(goalId, + typeId, + null, + null, + new HashMap<>(), + new ApplicableContext()); + } + + @Override + public Promise createCommand(String goalId, String typeId, ApplicableContext context) { + return createCommand(goalId, typeId, null, null, new HashMap<>(), context); + } + + @Override + public Promise createCommand(String goalId, + String typeId, + String name, + String commandLine, + Map attributes) { + return createCommand(goalId, typeId, name, commandLine, attributes, new ApplicableContext()); + } + + @Override + public Promise createCommand(String goalId, + String typeId, + @Nullable String name, + @Nullable String commandLine, + Map attributes, + ApplicableContext context) { + final CommandType commandType = commandTypeRegistry.getCommandTypeById(typeId); + + if (commandType == null) { + return promiseProvider.reject(new Exception("Unknown command type: '" + typeId + "'")); + } + + final Map attr = new HashMap<>(attributes); + attr.put(COMMAND_PREVIEW_URL_ATTRIBUTE_NAME, commandType.getPreviewUrlTemplate()); + attr.put(COMMAND_GOAL_ATTRIBUTE_NAME, goalId); + + return createCommand(new CommandImpl(getUniqueCommandName(typeId, name), + commandLine != null ? commandLine : commandType.getCommandLineTemplate(), + typeId, + attr, + context)); + } + + @Override + public Promise createCommand(CommandImpl command) { + return doCreateCommand(command).then((Function)newCommand -> { + // postpone the notification because + // listeners should be notified after returning from #createCommand method + Scheduler.get().scheduleDeferred(() -> notifyCommandAdded(newCommand)); + + return newCommand; + }); + } + + /** Does the actual work for command creation. Doesn't notify listeners. */ + private Promise doCreateCommand(CommandImpl command) { + final ApplicableContext context = command.getApplicableContext(); + if (!context.isWorkspaceApplicable() && context.getApplicableProjects().isEmpty()) { + return promiseProvider.reject(new Exception("Command has to be applicable to the workspace or at least one project")); + } + + final CommandType commandType = commandTypeRegistry.getCommandTypeById(command.getType()); + if (commandType == null) { + return promiseProvider.reject(new Exception("Unknown command type: '" + command.getType() + "'")); + } + + final CommandImpl newCommand = new CommandImpl(command); + newCommand.setName(getUniqueCommandName(command.getType(), command.getName())); + + final ArrayOf> commandPromises = Collections.arrayOf(); + + if (context.isWorkspaceApplicable()) { + Promise p = workspaceCommandManager.createCommand(newCommand) + .then((Function)arg -> { + newCommand.getApplicableContext().setWorkspaceApplicable(true); + return newCommand; + }); + + commandPromises.push(p); + } + + for (final String projectPath : context.getApplicableProjects()) { + final Project project = getProjectByPath(projectPath); + + if (project == null) { + continue; + } + + Promise p = projectCommandManager.createCommand(project, newCommand) + .then((Function)arg -> { + newCommand.getApplicableContext().addProject(projectPath); + return newCommand; + }); + + commandPromises.push(p); + } + + return promiseProvider.all2(commandPromises) + .then((Function, CommandImpl>)ignore -> { + commands.put(newCommand.getName(), newCommand); + return newCommand; + }); + } + + @Override + public Promise updateCommand(String name, CommandImpl commandToUpdate) { + final CommandImpl existedCommand = commands.get(name); + + if (existedCommand == null) { + return promiseProvider.reject(new Exception("Command '" + name + "' does not exist.")); + } + + return doRemoveCommand(name).thenPromise(aVoid -> doCreateCommand(commandToUpdate) + .then((Function)updatedCommand -> { + // listeners should be notified after returning from #updateCommand method + // so let's postpone notification + Scheduler.get().scheduleDeferred(() -> notifyCommandUpdated(existedCommand, updatedCommand)); + + return updatedCommand; + })); + } + + @Override + public Promise removeCommand(String name) { + final CommandImpl command = commands.get(name); + + if (command == null) { + return promiseProvider.reject(new Exception("Command '" + name + "' does not exist.")); + } + + return doRemoveCommand(name).then(aVoid -> { + // listeners should be notified after returning from #removeCommand method + // so let's postpone notification + Scheduler.get().scheduleDeferred(() -> notifyCommandRemoved(command)); + }); + } + + /** Removes the command without notifying listeners. */ + private Promise doRemoveCommand(String name) { + final CommandImpl command = commands.get(name); + + if (command == null) { + return promiseProvider.reject(new Exception("Command '" + name + "' does not exist.")); + } + + final ApplicableContext context = command.getApplicableContext(); + + final ArrayOf> commandPromises = Collections.arrayOf(); + + if (context.isWorkspaceApplicable()) { + final Promise p = workspaceCommandManager.removeCommand(name).then((Function)aVoid -> { + command.getApplicableContext().setWorkspaceApplicable(false); + return null; + }); + + commandPromises.push(p); + } + + for (final String projectPath : context.getApplicableProjects()) { + final Project project = getProjectByPath(projectPath); + + if (project == null) { + continue; + } + + final Promise p = projectCommandManager.removeCommand(project, name).then((Function)aVoid -> { + command.getApplicableContext().removeProject(projectPath); + return null; + }); + + commandPromises.push(p); + } + + return promiseProvider.all2(commandPromises) + .then((Function, Void>)arg -> { + commands.remove(command.getName()); + return null; + }); + } + + @Nullable + private Project getProjectByPath(String path) { + for (Project project : appContext.getProjects()) { + if (path.equals(project.getPath())) { + return project; + } + } + + return null; + } + + @Override + public void addCommandLoadedListener(CommandLoadedListener listener) { + commandLoadedListeners.add(listener); + } + + @Override + public void removeCommandLoadedListener(CommandLoadedListener listener) { + commandLoadedListeners.remove(listener); + } + + @Override + public void addCommandChangedListener(CommandChangedListener listener) { + commandChangedListeners.add(listener); + } + + @Override + public void removeCommandChangedListener(CommandChangedListener listener) { + commandChangedListeners.remove(listener); + } + + private void notifyCommandsLoaded() { + commandLoadedListeners.forEach(CommandLoadedListener::onCommandsLoaded); + } + + private void notifyCommandAdded(CommandImpl command) { + commandChangedListeners.forEach(listener -> listener.onCommandAdded(command)); + } + + private void notifyCommandRemoved(CommandImpl command) { + commandChangedListeners.forEach(listener -> listener.onCommandRemoved(command)); + } + + private void notifyCommandUpdated(CommandImpl prevCommand, CommandImpl command) { + commandChangedListeners.forEach(listener -> listener.onCommandUpdated(prevCommand, command)); + } + + /** + * Returns {@code customName} if it's unique within the given {@code commandTypeId} + * or newly generated name if it isn't unique within the given {@code commandTypeId}. + */ + private String getUniqueCommandName(String commandTypeId, @Nullable String customName) { + final CommandType commandType = commandTypeRegistry.getCommandTypeById(commandTypeId); + final Set commandNames = commands.keySet(); + + final String newCommandName; + + if (isNullOrEmpty(customName)) { + newCommandName = "new" + commandType.getDisplayName(); + } else { + if (!commandNames.contains(customName)) { + return customName; + } + newCommandName = customName + " copy"; + } + + if (!commandNames.contains(newCommandName)) { + return newCommandName; + } + + for (int count = 1; count < 1000; count++) { + if (!commandNames.contains(newCommandName + "-" + count)) { + return newCommandName + "-" + count; + } + } + + return newCommandName; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/ProjectCommandManagerDelegate.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/ProjectCommandManagerDelegate.java new file mode 100644 index 0000000000..fcd4c23d7b --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/ProjectCommandManagerDelegate.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * 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.manager; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.api.machine.shared.dto.CommandDto; +import org.eclipse.che.api.promises.client.Function; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.promises.client.PromiseProvider; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.command.CommandType; +import org.eclipse.che.ide.api.project.MutableProjectConfig; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.dto.DtoFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.eclipse.che.api.project.shared.Constants.COMMANDS_ATTRIBUTE_NAME; + +/** Responsible for managing the commands which are stored with projects. */ +@Singleton +class ProjectCommandManagerDelegate { + + private final DtoFactory dtoFactory; + private final PromiseProvider promiseProvider; + + @Inject + ProjectCommandManagerDelegate(DtoFactory dtoFactory, PromiseProvider promiseProvider) { + this.dtoFactory = dtoFactory; + this.promiseProvider = promiseProvider; + } + + /** Returns commands for the specified {@code project}. */ + List getCommands(Project project) { + List attrValues = project.getAttributes(COMMANDS_ATTRIBUTE_NAME); + if (attrValues == null) { + return new ArrayList<>(); + } + + Map commands = new HashMap<>(attrValues.size()); + for (String commandJson : attrValues) { + CommandDto command = dtoFactory.createDtoFromJson(commandJson, CommandDto.class); + commands.put(command.getName(), new CommandImpl(command)); + } + + return new ArrayList<>(commands.values()); + } + + /** + * Creates new command of the specified type. + *

Note that command's name will be generated by {@link CommandManager} + * and command line will be provided by an appropriate {@link CommandType}. + */ + Promise createCommand(Project project, final CommandImpl newCommand) { + final List commands = getCommands(project); + + for (CommandImpl projectCommand : commands) { + if (projectCommand.getName().equals(newCommand.getName())) { + return promiseProvider.reject(new Exception("Command '" + newCommand.getName() + + "' is already associated to the project '" + project.getName() + "'")); + } + } + + commands.add(newCommand); + + return updateProject(project, commands).then((Function)arg -> newCommand); + } + + /** Updates the specified {@code project} with the given {@code commands}. */ + private Promise updateProject(Project project, List commands) { + MutableProjectConfig config = new MutableProjectConfig(project); + Map> attributes = config.getAttributes(); + + List attrValue = new ArrayList<>(attributes.size()); + for (CommandImpl command : commands) { + CommandDto commandDto = dtoFactory.createDto(CommandDto.class) + .withName(command.getName()) + .withType(command.getType()) + .withCommandLine(command.getCommandLine()) + .withAttributes(command.getAttributes()); + attrValue.add(dtoFactory.toJson(commandDto)); + } + + attributes.put(COMMANDS_ATTRIBUTE_NAME, attrValue); + + return project.update() + .withBody(config) + .send() + .then((Function)arg -> null); + } + + /** + * Updates the command with the specified {@code name} by replacing it with the given {@code command}. + *

Note that name of the updated command may differ from the name provided by the given {@code command} + * in order to prevent name duplication. + */ + Promise updateCommand(Project project, final CommandImpl command) { + final List projectCommands = getCommands(project); + + if (projectCommands.isEmpty()) { + return promiseProvider.reject(new Exception("Command '" + command.getName() + "' is not associated with the project '" + + project.getName() + "'")); + } + + final List commandsToUpdate = new ArrayList<>(); + for (CommandImpl projectCommand : projectCommands) { + // skip existed command with the same name + if (!command.getName().equals(projectCommand.getName())) { + commandsToUpdate.add(projectCommand); + } + } + + commandsToUpdate.add(command); + + return updateProject(project, new ArrayList<>(commandsToUpdate)) + .then((Function)arg -> command); + } + + /** Removes the command with the specified {@code commandName}. */ + Promise removeCommand(Project project, String commandName) { + final List commands = getCommands(project); + + if (commands.isEmpty()) { + return promiseProvider.reject(new Exception("Command '" + commandName + "' is not associated with the project '" + + project.getName() + "'")); + } + + final List commandsToUpdate = new ArrayList<>(); + for (CommandImpl projectCommand : commands) { + if (!commandName.equals(projectCommand.getName())) { + commandsToUpdate.add(projectCommand); + } + } + + return updateProject(project, new ArrayList<>(commandsToUpdate)); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/WorkspaceCommandManagerDelegate.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/WorkspaceCommandManagerDelegate.java new file mode 100644 index 0000000000..7dfe27d1e6 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/manager/WorkspaceCommandManagerDelegate.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * 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.manager; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.api.machine.shared.dto.CommandDto; +import org.eclipse.che.api.promises.client.Function; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.command.CommandType; +import org.eclipse.che.ide.api.workspace.WorkspaceServiceClient; +import org.eclipse.che.ide.dto.DtoFactory; + +import java.util.List; + +import static java.util.stream.Collectors.toList; + +/** Responsible for managing the commands which are stored with workspace. */ +@Singleton +class WorkspaceCommandManagerDelegate { + + private final DtoFactory dtoFactory; + private final WorkspaceServiceClient workspaceServiceClient; + private final AppContext appContext; + + @Inject + WorkspaceCommandManagerDelegate(DtoFactory dtoFactory, + WorkspaceServiceClient workspaceServiceClient, + AppContext appContext) { + this.dtoFactory = dtoFactory; + this.workspaceServiceClient = workspaceServiceClient; + this.appContext = appContext; + } + + /** Returns commands which are stored in the workspace with the specified {@code workspaceId}. */ + Promise> getCommands(String workspaceId) { + return workspaceServiceClient.getCommands(workspaceId) + .then((Function, + List>)commands -> commands.stream() + .map(CommandImpl::new) + .collect(toList())); + } + + /** + * Creates new command of the specified type. + *

Note that command's name will be generated by {@link CommandManager} + * and command line will be provided by an appropriate {@link CommandType}. + */ + Promise createCommand(final CommandImpl command) { + final CommandDto commandDto = dtoFactory.createDto(CommandDto.class) + .withName(command.getName()) + .withCommandLine(command.getCommandLine()) + .withType(command.getType()) + .withAttributes(command.getAttributes()); + + return workspaceServiceClient.addCommand(appContext.getWorkspaceId(), commandDto) + .then((Function)arg -> command); + } + + /** + * Updates the command with the specified {@code name} by replacing it with the given {@code command}. + *

Note that name of the updated command may differ from the name provided by the given {@code command} + * in order to prevent name duplication. + */ + Promise updateCommand(final CommandImpl command) { + final CommandDto commandDto = dtoFactory.createDto(CommandDto.class) + .withName(command.getName()) + .withCommandLine(command.getCommandLine()) + .withType(command.getType()) + .withAttributes(command.getAttributes()); + + return workspaceServiceClient.updateCommand(appContext.getWorkspaceId(), command.getName(), commandDto) + .then((Function)arg -> command); + } + + /** Removes the command with the specified {@code commandName}. */ + Promise removeCommand(String commandName) { + return workspaceServiceClient.deleteCommand(appContext.getWorkspaceId(), commandName) + .then((Function)arg -> null); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/AbstractCommandNode.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/AbstractCommandNode.java new file mode 100644 index 0000000000..432992bf2d --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/AbstractCommandNode.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * 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.node; + +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.data.tree.Node; +import org.eclipse.che.ide.api.data.tree.settings.NodeSettings; +import org.eclipse.che.ide.command.CommandUtils; +import org.eclipse.che.ide.project.node.SyntheticNode; +import org.eclipse.che.ide.ui.smartTree.presentation.NodePresentation; +import org.vectomatic.dom.svg.ui.SVGResource; + +import java.util.List; + +/** Abstract tree node that represents {@link CommandImpl}. */ +class AbstractCommandNode extends SyntheticNode { + + private final CommandUtils commandUtils; + + AbstractCommandNode(CommandImpl data, NodeSettings nodeSettings, CommandUtils commandUtils) { + super(data, nodeSettings); + + this.commandUtils = commandUtils; + } + + @Override + public void updatePresentation(NodePresentation presentation) { + presentation.setPresentableText(getName()); + + final SVGResource commandTypeIcon = commandUtils.getCommandTypeIcon(getData().getType()); + + if (commandTypeIcon != null) { + presentation.setPresentableIcon(commandTypeIcon); + } + } + + @Override + public String getName() { + return getData().getName(); + } + + @Override + public boolean isLeaf() { + return true; + } + + @Override + protected Promise> getChildrenImpl() { + return null; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/CommandFileNode.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/CommandFileNode.java new file mode 100644 index 0000000000..f096ab2faa --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/CommandFileNode.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * 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.node; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; + +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.data.tree.HasAction; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.resources.VirtualFile; +import org.eclipse.che.ide.command.CommandUtils; +import org.eclipse.che.ide.resource.Path; +import org.eclipse.che.ide.ui.smartTree.presentation.NodePresentation; + +/** Extension of {@link AbstractCommandNode} that also acts as a {@link VirtualFile} for using it in editor. */ +public class CommandFileNode extends AbstractCommandNode implements HasAction, VirtualFile { + + /** Extension for the file type that represents a command. */ + public static final String FILE_TYPE_EXT = "che_command_internal"; + + private final EditorAgent editorAgent; + + @Inject + public CommandFileNode(@Assisted CommandImpl data, + CommandUtils commandUtils, + EditorAgent editorAgent) { + super(data, null, commandUtils); + + this.editorAgent = editorAgent; + } + + @Override + public void updatePresentation(NodePresentation presentation) { + super.updatePresentation(presentation); + + presentation.setPresentableText(getDisplayName()); + presentation.setPresentableTextCss("overflow: hidden; text-overflow: ellipsis;"); + } + + @Override + public void actionPerformed() { + editorAgent.openEditor(this); + } + + @Override + public Path getLocation() { + return Path.valueOf("commands/" + getData().getType() + "/" + getData().getName()); + } + + @Override + public String getName() { + return getData().getName() + "." + FILE_TYPE_EXT; + } + + @Override + public String getDisplayName() { + return getData().getName(); + } + + @Override + public boolean isReadOnly() { + return false; + } + + @Override + public String getContentUrl() { + return null; + } + + @Override + public Promise getContent() { + return null; + } + + @Override + public Promise updateContent(String content) { + return null; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/CommandGoalNode.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/CommandGoalNode.java new file mode 100644 index 0000000000..aebde39774 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/CommandGoalNode.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * 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.node; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; + +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.promises.client.PromiseProvider; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.data.tree.Node; +import org.eclipse.che.ide.command.CommandUtils; +import org.eclipse.che.ide.project.node.SyntheticNode; +import org.eclipse.che.ide.ui.smartTree.presentation.NodePresentation; +import org.vectomatic.dom.svg.ui.SVGResource; + +import java.util.ArrayList; +import java.util.List; + +/** Tree node that represents {@link CommandGoal}. */ +public class CommandGoalNode extends SyntheticNode { + + private final List commands; + private final PromiseProvider promiseProvider; + private final CommandUtils commandUtils; + + @Inject + public CommandGoalNode(@Assisted CommandGoal data, + @Assisted List commands, + PromiseProvider promiseProvider, + CommandUtils commandUtils) { + super(data, null); + + this.commands = commands; + this.promiseProvider = promiseProvider; + this.commandUtils = commandUtils; + } + + @Override + public void updatePresentation(NodePresentation presentation) { + presentation.setPresentableText(getName().toUpperCase() + " (" + commands.size() + ")"); + presentation.setPresentableTextCss("font-weight: bold;"); + + final SVGResource goalIcon = commandUtils.getCommandGoalIcon(getData().getId()); + if (goalIcon != null) { + presentation.setPresentableIcon(goalIcon); + } + } + + @Override + public String getName() { + return getData().getId(); + } + + @Override + public boolean isLeaf() { + return false; + } + + @Override + protected Promise> getChildrenImpl() { + List children = new ArrayList<>(); + children.addAll(commands); + + return promiseProvider.resolve(children); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/ExecutableCommandNode.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/ExecutableCommandNode.java new file mode 100644 index 0000000000..cde81f59eb --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/ExecutableCommandNode.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * 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.node; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; + +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.data.tree.HasAction; +import org.eclipse.che.ide.command.CommandUtils; + +/** + * Extension of {@link AbstractCommandNode} that can execute + * a command when performing an action is requested. + */ +public class ExecutableCommandNode extends AbstractCommandNode implements HasAction { + + private final ActionDelegate actionDelegate; + + @Inject + public ExecutableCommandNode(@Assisted CommandImpl data, + @Assisted ActionDelegate actionDelegate, + CommandUtils commandUtils) { + super(data, null, commandUtils); + + this.actionDelegate = actionDelegate; + } + + @Override + public void actionPerformed() { + actionDelegate.actionPerformed(); + } + + /** Interface for delegating performing action on node. */ + public interface ActionDelegate { + void actionPerformed(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/NodeFactory.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/NodeFactory.java new file mode 100644 index 0000000000..8bda3339d1 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/node/NodeFactory.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * 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.node; + +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; + +import java.util.List; + +/** Factory for different command tree nodes. */ +public interface NodeFactory { + + CommandGoalNode newCommandGoalNode(CommandGoal data, List commands); + + ExecutableCommandNode newExecutableCommandNode(CommandImpl command, ExecutableCommandNode.ActionDelegate actionDelegate); + + CommandFileNode newCommandFileNode(CommandImpl data); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPalettePresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPalettePresenter.java new file mode 100644 index 0000000000..241b7a6c4e --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPalettePresenter.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * 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.palette; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.api.core.model.workspace.WorkspaceRuntime; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandExecutor; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.command.CommandUtils; +import org.eclipse.che.ide.machine.chooser.MachineChooser; + +import java.util.List; +import java.util.ListIterator; + +import static java.util.Collections.emptyList; +import static org.eclipse.che.ide.util.StringUtils.containsIgnoreCase; + +/** + * Presenter for Commands Palette. + * + * @author Artem Zatsarynnyi + */ +@Singleton +public class CommandsPalettePresenter implements CommandsPaletteView.ActionDelegate { + + private final CommandsPaletteView view; + private final CommandManager commandManager; + private final CommandExecutor commandExecutor; + private final DialogFactory dialogFactory; + private final AppContext appContext; + private final MachineChooser machineChooser; + private final CommandUtils commandUtils; + private final PaletteMessages messages; + + @Inject + public CommandsPalettePresenter(CommandsPaletteView view, + CommandManager commandManager, + CommandExecutor commandExecutor, + DialogFactory dialogFactory, + AppContext appContext, + MachineChooser machineChooser, + CommandUtils commandUtils, + PaletteMessages messages) { + this.view = view; + this.commandManager = commandManager; + this.commandExecutor = commandExecutor; + this.dialogFactory = dialogFactory; + this.appContext = appContext; + this.machineChooser = machineChooser; + this.commandUtils = commandUtils; + this.messages = messages; + + view.setDelegate(this); + } + + public void showDialog() { + view.show(); + view.setCommands(commandUtils.groupCommandsByGoal(commandManager.getCommands())); + } + + @Override + public void onFilterChanged(String filterValue) { + final List filteredCommands = commandManager.getCommands(); + + if (!filterValue.isEmpty()) { + final ListIterator it = filteredCommands.listIterator(); + + while (it.hasNext()) { + final CommandImpl command = it.next(); + + if (!containsIgnoreCase(command.getName(), filterValue)) { + it.remove(); + } + } + } + + view.setCommands(commandUtils.groupCommandsByGoal(filteredCommands)); + } + + @Override + public void onCommandExecute(CommandImpl command) { + view.close(); + + if (getMachines().isEmpty()) { + // should not happen, but let's play safe + dialogFactory.createMessageDialog("", messages.messageNoMachine(), null).show(); + } else { + machineChooser.show().then(machine -> { + commandExecutor.executeCommand(command, machine); + }); + } + } + + private List getMachines() { + final WorkspaceRuntime runtime = appContext.getWorkspace().getRuntime(); + + if (runtime != null) { + return runtime.getMachines(); + } + + return emptyList(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPaletteView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPaletteView.java new file mode 100644 index 0000000000..532a55a24e --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPaletteView.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * 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.palette; + +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.mvp.View; + +import java.util.List; +import java.util.Map; + +/** + * The view for {@link CommandsPalettePresenter}. + * + * @author Artem Zatsarynnyi + */ +public interface CommandsPaletteView extends View { + + /** Show the view. */ + void show(); + + /** Close the view. */ + void close(); + + /** + * Sets the commands to display in the view. + * + * @param commands + * commands grouped by type + */ + void setCommands(Map> commands); + + /** The action delegate for this view. */ + interface ActionDelegate { + + /** Called when filtering commands is requested. */ + void onFilterChanged(String filterValue); + + /** Called when command execution is requested. */ + void onCommandExecute(CommandImpl command); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPaletteViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPaletteViewImpl.java new file mode 100644 index 0000000000..fb95274b17 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPaletteViewImpl.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * 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.palette; + +import elemental.html.DivElement; +import elemental.html.SpanElement; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Element; +import com.google.gwt.event.dom.client.KeyUpEvent; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.FontAwesome; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.data.tree.Node; +import org.eclipse.che.ide.command.node.CommandGoalNode; +import org.eclipse.che.ide.command.node.ExecutableCommandNode; +import org.eclipse.che.ide.command.node.NodeFactory; +import org.eclipse.che.ide.ui.smartTree.NodeLoader; +import org.eclipse.che.ide.ui.smartTree.NodeStorage; +import org.eclipse.che.ide.ui.smartTree.Tree; +import org.eclipse.che.ide.ui.window.Window; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import static com.google.gwt.event.dom.client.KeyCodes.KEY_DOWN; +import static com.google.gwt.event.dom.client.KeyCodes.KEY_ENTER; +import static com.google.gwt.event.dom.client.KeyCodes.KEY_UP; +import static org.eclipse.che.ide.ui.smartTree.SelectionModel.Mode.SINGLE; +import static org.eclipse.che.ide.util.dom.Elements.createDivElement; +import static org.eclipse.che.ide.util.dom.Elements.createSpanElement; +import static org.eclipse.che.ide.util.dom.Elements.createTextNode; + +/** Implementation of {@link CommandsPaletteView}. */ +@Singleton +public class CommandsPaletteViewImpl extends Window implements CommandsPaletteView { + + private static final CommandsPaletteViewImplUiBinder UI_BINDER = GWT.create(CommandsPaletteViewImplUiBinder.class); + + private final NodeFactory nodeFactory; + + @UiField + TextBox filterField; + + @UiField(provided = true) + Tree tree; + + @UiField + Label hintLabel; + + private ActionDelegate delegate; + + @Inject + public CommandsPaletteViewImpl(NodeFactory nodeFactory, PaletteMessages messages) { + this.nodeFactory = nodeFactory; + + tree = new Tree(new NodeStorage(), new NodeLoader()); + tree.getSelectionModel().setSelectionMode(SINGLE); + + setWidget(UI_BINDER.createAndBindUi(this)); + setTitle(messages.viewTitle()); + + filterField.getElement().setAttribute("placeholder", messages.filterPlaceholder()); + initHintLabel(); + getFooter().removeFromParent(); + } + + private void initHintLabel() { + final SpanElement upKeyLabel = createKeyLabel(); + upKeyLabel.setInnerHTML(FontAwesome.ARROW_UP); + + final SpanElement downKeyLabel = createKeyLabel(); + downKeyLabel.setInnerHTML(FontAwesome.ARROW_DOWN); + + final SpanElement enterKeyLabel = createKeyLabel(); + enterKeyLabel.getStyle().setPadding("0px 1px 1px 4px"); + enterKeyLabel.setInnerText(" Enter "); + + final DivElement hintElement = createDivElement(); + hintElement.appendChild(upKeyLabel); + hintElement.appendChild(downKeyLabel); + hintElement.appendChild(createTextNode(" to select and ")); + hintElement.appendChild(enterKeyLabel); + hintElement.appendChild(createTextNode(" to execute")); + + hintLabel.getElement().appendChild((Element)hintElement); + } + + /** Creates an html element for displaying keyboard key. */ + private SpanElement createKeyLabel() { + SpanElement element = createSpanElement(); + + element.getStyle().setFontWeight("bold"); + element.getStyle().setPadding("0 4px 1px 4px"); + element.getStyle().setMargin("0 3px"); + element.getStyle().setBorderWidth("1px"); + element.getStyle().setBorderStyle("solid"); + element.getStyle().setProperty("border-radius", "3px"); + + return element; + } + + @Override + public void show() { + super.show(); + + filterField.setValue(""); + filterField.setFocus(true); + } + + @Override + public void close() { + hide(); + } + + @Override + public void setCommands(Map> commands) { + renderCommands(commands); + } + + /** Render commands grouped by goals. */ + private void renderCommands(Map> commands) { + tree.getNodeStorage().clear(); + + for (Entry> entry : commands.entrySet()) { + List commandNodes = new ArrayList<>(entry.getValue().size()); + + for (final CommandImpl command : entry.getValue()) { + commandNodes.add(nodeFactory.newExecutableCommandNode(command, () -> delegate.onCommandExecute(command))); + } + + final CommandGoalNode commandGoalNode = nodeFactory.newCommandGoalNode(entry.getKey(), commandNodes); + tree.getNodeStorage().add(commandGoalNode); + } + + tree.expandAll(); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @UiHandler({"filterField"}) + void onFilterChanged(KeyUpEvent event) { + switch (event.getNativeKeyCode()) { + case KEY_UP: + tree.getSelectionModel().selectPrevious(); + break; + case KEY_DOWN: + tree.getSelectionModel().selectNext(); + break; + case KEY_ENTER: + final List selectedNodes = tree.getSelectionModel().getSelectedNodes(); + + if (!selectedNodes.isEmpty()) { + final Node node = selectedNodes.get(0); + + if (node instanceof ExecutableCommandNode) { + delegate.onCommandExecute(((ExecutableCommandNode)node).getData()); + } + } + break; + default: + delegate.onFilterChanged(filterField.getValue()); + } + } + + interface CommandsPaletteViewImplUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPaletteViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPaletteViewImpl.ui.xml new file mode 100644 index 0000000000..6b6470aae3 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/CommandsPaletteViewImpl.ui.xml @@ -0,0 +1,55 @@ + + + + + + + + + @eval partBackground org.eclipse.che.ide.api.theme.Style.theme.partBackground(); + @eval borderColor org.eclipse.che.ide.api.theme.Style.theme.getTextFieldBackgroundColor(); + + .tree { + border: 1px solid; + border-color: borderColor; + background-color: partBackground; + margin-top: 7px; + min-width: 99%; + } + + .hint-label { + margin: 7px auto; + } + + + + + + + + + + + + + + + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/PaletteMessages.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/PaletteMessages.java new file mode 100644 index 0000000000..af6007d3e6 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/PaletteMessages.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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.palette; + +import com.google.gwt.i18n.client.Messages; + +/** + * I18n messages for the Commands Palette. + * + * @author Artem Zatsarynnyi + */ +public interface PaletteMessages extends Messages { + + @Key("action.show_palette.title") + String actionShowPaletteTitle(); + + @Key("action.show_palette.description") + String actionShowPaletteDescription(); + + @Key("view.title") + String viewTitle(); + + @Key("view.filter.placeholder") + String filterPlaceholder(); + + @Key("view.hint.text") + String viewHintText(); + + @Key("message.no_machine") + String messageNoMachine(); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/ShowCommandsPaletteAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/ShowCommandsPaletteAction.java new file mode 100644 index 0000000000..8625bfc7cf --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/palette/ShowCommandsPaletteAction.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * 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.palette; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.api.action.Action; +import org.eclipse.che.ide.api.action.ActionEvent; + +/** + * Action for opening Commands Palette. + * + * @author Artem Zatsarynnyi + */ +@Singleton +public class ShowCommandsPaletteAction extends Action { + + private final CommandsPalettePresenter presenter; + + @Inject + public ShowCommandsPaletteAction(PaletteMessages messages, CommandsPalettePresenter presenter) { + super(messages.actionShowPaletteTitle(), + messages.actionShowPaletteDescription(), + null, + null); + + this.presenter = presenter; + } + + @Override + public void actionPerformed(ActionEvent e) { + presenter.showDialog(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandProducerAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/CommandProducerAction.java similarity index 84% rename from ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandProducerAction.java rename to ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/CommandProducerAction.java index 291d8b70fa..312dbc9a7b 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandProducerAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/CommandProducerAction.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.command; +package org.eclipse.che.ide.command.producer; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; @@ -17,7 +17,7 @@ import org.eclipse.che.api.core.model.machine.Machine; import org.eclipse.che.ide.api.action.Action; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.command.CommandImpl; -import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.command.CommandExecutor; import org.eclipse.che.ide.api.command.CommandProducer; /** @@ -30,18 +30,18 @@ public class CommandProducerAction extends Action { private final CommandProducer commandProducer; private final Machine machine; - private final CommandManager commandManager; + private final CommandExecutor commandExecutor; @Inject public CommandProducerAction(@Assisted String name, @Assisted CommandProducer commandProducer, @Assisted Machine machine, - CommandManager commandManager) { + CommandExecutor commandExecutor) { super(name); this.commandProducer = commandProducer; this.machine = machine; - this.commandManager = commandManager; + this.commandExecutor = commandExecutor; } @Override @@ -52,6 +52,6 @@ public class CommandProducerAction extends Action { @Override public void actionPerformed(ActionEvent e) { CommandImpl command = commandProducer.createCommand(machine); - commandManager.executeCommand(command, machine); + commandExecutor.executeCommand(command, machine); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandProducerActionFactory.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/CommandProducerActionFactory.java similarity index 95% rename from ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandProducerActionFactory.java rename to ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/CommandProducerActionFactory.java index 58f04e3b65..29c13bb38f 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandProducerActionFactory.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/CommandProducerActionFactory.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.command; +package org.eclipse.che.ide.command.producer; import org.eclipse.che.api.core.model.machine.Machine; import org.eclipse.che.ide.api.command.CommandProducer; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandProducerActionManager.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/CommandProducerActionManager.java similarity index 92% rename from ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandProducerActionManager.java rename to ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/CommandProducerActionManager.java index cf962f7c7d..219f9c9e15 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandProducerActionManager.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/CommandProducerActionManager.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.command; +package org.eclipse.che.ide.command.producer; import com.google.gwt.core.client.Callback; import com.google.inject.Inject; @@ -43,7 +43,7 @@ import static org.eclipse.che.ide.api.action.IdeActions.GROUP_MAIN_TOOLBAR; import static org.eclipse.che.ide.api.constraints.Anchor.AFTER; /** - * Manages actions for the contextual commands. + * Manages actions for the commands. *

Manager gets all registered {@link CommandProducer}s and creates related actions in context menus. *

Manager listens all machines's state (running/destroyed) in order to * create/remove actions for the related {@link CommandProducer}s in case @@ -53,12 +53,15 @@ import static org.eclipse.che.ide.api.constraints.Anchor.AFTER; * @see CommandProducer */ @Singleton -public class CommandProducerActionManager implements MachineStateEvent.Handler, WsAgentStateHandler, Component { +public class CommandProducerActionManager implements MachineStateEvent.Handler, + WsAgentStateHandler, + Component { private final ActionManager actionManager; private final CommandProducerActionFactory commandProducerActionFactory; private final AppContext appContext; private final Resources resources; + private final ProducerMessages messages; private final List machines; private final Set commandProducers; @@ -73,11 +76,13 @@ public class CommandProducerActionManager implements MachineStateEvent.Handler, ActionManager actionManager, CommandProducerActionFactory commandProducerActionFactory, AppContext appContext, - Resources resources) { + Resources resources, + ProducerMessages messages) { this.actionManager = actionManager; this.commandProducerActionFactory = commandProducerActionFactory; this.appContext = appContext; this.resources = resources; + this.messages = messages; machines = new ArrayList<>(); commandProducers = new HashSet<>(); @@ -93,10 +98,10 @@ public class CommandProducerActionManager implements MachineStateEvent.Handler, private void start(Set commandProducers) { this.commandProducers.addAll(commandProducers); - commandActionsPopUpGroup = new DefaultActionGroup("Commands", true, actionManager); + commandActionsPopUpGroup = new DefaultActionGroup(messages.actionCommandsTitle(), true, actionManager); actionManager.registerAction("commandActionsPopUpGroup", commandActionsPopUpGroup); commandActionsPopUpGroup.getTemplatePresentation().setSVGResource(resources.compile()); - commandActionsPopUpGroup.getTemplatePresentation().setDescription("Execute command"); + commandActionsPopUpGroup.getTemplatePresentation().setDescription(messages.actionCommandsDescription()); DefaultActionGroup mainContextMenu = (DefaultActionGroup)actionManager.getAction(GROUP_MAIN_CONTEXT_MENU); mainContextMenu.add(commandActionsPopUpGroup); @@ -183,11 +188,7 @@ public class CommandProducerActionManager implements MachineStateEvent.Handler, CommandProducerAction machineAction = commandProducerActionFactory.create(machine.getConfig().getName(), commandProducer, machine); - List actionList = actionsByMachines.get(machine); - if (actionList == null) { - actionList = new ArrayList<>(); - actionsByMachines.put(machine, actionList); - } + final List actionList = actionsByMachines.computeIfAbsent(machine, key -> new ArrayList<>()); actionList.add(machineAction); actionManager.registerAction(machine.getConfig().getName(), machineAction); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/ProducerMessages.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/ProducerMessages.java new file mode 100644 index 0000000000..503ba298ad --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/producer/ProducerMessages.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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.producer; + +import com.google.gwt.i18n.client.Messages; + +/** + * I18n messages for the command producers related UI. + * + * @author Artem Zatsarynnyi + */ +public interface ProducerMessages extends Messages { + + @Key("action.commands.title") + String actionCommandsTitle(); + + @Key("action.commands.description") + String actionCommandsDescription(); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandCreationGuide.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandCreationGuide.java new file mode 100644 index 0000000000..bc25808a3e --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandCreationGuide.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * 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.toolbar; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.parts.WorkspaceAgent; +import org.eclipse.che.ide.command.explorer.CommandsExplorerPresenter; +import org.eclipse.che.ide.command.goal.RunGoal; +import org.eclipse.che.ide.command.node.NodeFactory; + +/** + * Guides the user into the flow of creating a command and helps + * him to understand how he can configure his workspace's commands. + */ +@Singleton +public class CommandCreationGuide { + + private final Provider workspaceAgentProvider; + private final Provider commandsExplorerPresenterProvider; + private final CommandManager commandManager; + private final Provider editorAgentProvider; + private final NodeFactory nodeFactory; + private final RunGoal runGoal; + + @Inject + public CommandCreationGuide(Provider workspaceAgentProvider, + Provider commandsExplorerPresenterProvider, + CommandManager commandManager, + Provider editorAgentProvider, + NodeFactory nodeFactory, + RunGoal runGoal) { + this.workspaceAgentProvider = workspaceAgentProvider; + this.commandsExplorerPresenterProvider = commandsExplorerPresenterProvider; + this.commandManager = commandManager; + this.editorAgentProvider = editorAgentProvider; + this.nodeFactory = nodeFactory; + this.runGoal = runGoal; + } + + + /** Shows the guide of creating a command. */ + public void guide() { + guide(runGoal); + } + + /** Shows the guide of creating a command of the specified {@code goal}. */ + public void guide(CommandGoal goal) { + workspaceAgentProvider.get().setActivePart(commandsExplorerPresenterProvider.get()); + + commandManager.createCommand(goal.getId(), "custom").then(command -> { + editorAgentProvider.get().openEditor(nodeFactory.newCommandFileNode(command)); + }); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarPresenter.java new file mode 100644 index 0000000000..857c974d44 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarPresenter.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * 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.toolbar; + +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.client.ui.AcceptsOneWidget; + +import org.eclipse.che.ide.FontAwesome; +import org.eclipse.che.ide.api.mvp.Presenter; +import org.eclipse.che.ide.command.toolbar.commands.ExecuteCommandPresenter; +import org.eclipse.che.ide.command.toolbar.previews.PreviewsPresenter; +import org.eclipse.che.ide.command.toolbar.processes.ProcessesListPresenter; +import org.eclipse.che.ide.ui.menubutton.MenuPopupButton; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** Presenter for command toolbar. */ +@Singleton +public class CommandToolbarPresenter implements Presenter, CommandToolbarView.ActionDelegate { + + private final ProcessesListPresenter processesListPresenter; + private final PreviewsPresenter previewsPresenter; + private final ExecuteCommandPresenter executeCommandPresenter; + private final ToolbarButtonsFactory toolbarButtonsFactory; + private final CommandToolbarView view; + private MenuPopupButton openCommandsPaletteButton; + + @Inject + public CommandToolbarPresenter(CommandToolbarView view, + ProcessesListPresenter processesListPresenter, + PreviewsPresenter previewsPresenter, + ExecuteCommandPresenter executeCommandPresenter, + ToolbarButtonsFactory toolbarButtonsFactory) { + this.view = view; + this.processesListPresenter = processesListPresenter; + this.previewsPresenter = previewsPresenter; + this.executeCommandPresenter = executeCommandPresenter; + this.toolbarButtonsFactory = toolbarButtonsFactory; + + initButtons(); + + view.setDelegate(this); + } + + private void initButtons() { + final SafeHtmlBuilder safeHtmlBuilder = new SafeHtmlBuilder(); + safeHtmlBuilder.appendHtmlConstant(FontAwesome.LIST); + + openCommandsPaletteButton = toolbarButtonsFactory.createOpenPaletteButton(safeHtmlBuilder.toSafeHtml()); + } + + @Override + public void go(AcceptsOneWidget container) { + container.setWidget(view); + + executeCommandPresenter.go(view.getCommandsPanelContainer()); + processesListPresenter.go(view.getProcessesListContainer()); + previewsPresenter.go(view.getPreviewUrlsListContainer()); + + view.addButton(openCommandsPaletteButton); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarView.java new file mode 100644 index 0000000000..78e31c7608 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarView.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * 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.toolbar; + +import com.google.gwt.user.client.ui.AcceptsOneWidget; + +import org.eclipse.che.ide.api.mvp.View; +import org.eclipse.che.ide.ui.menubutton.MenuPopupButton; + +/** View for command toolbar. */ +public interface CommandToolbarView extends View { + + AcceptsOneWidget getCommandsPanelContainer(); + + AcceptsOneWidget getProcessesListContainer(); + + AcceptsOneWidget getPreviewUrlsListContainer(); + + void addButton(MenuPopupButton button); + + interface ActionDelegate { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarViewImpl.java new file mode 100644 index 0000000000..cd8f7c2ffc --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarViewImpl.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * 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.toolbar; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.Widget; + +import org.eclipse.che.ide.ui.menubutton.MenuPopupButton; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** Implementation of {@link CommandToolbarView}. */ +@Singleton +public class CommandToolbarViewImpl implements CommandToolbarView { + + private static final CommandToolbarViewImplUiBinder UI_BINDER = GWT.create(CommandToolbarViewImplUiBinder.class); + + @UiField + FlowPanel rootPanel; + @UiField + SimplePanel commandsPanel; + @UiField + SimplePanel processesListPanel; + @UiField + SimplePanel buttonsPanel; + @UiField + SimplePanel previewUrlListPanel; + + private ActionDelegate delegate; + + @Inject + public CommandToolbarViewImpl() { + UI_BINDER.createAndBindUi(this); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @Override + public Widget asWidget() { + return rootPanel; + } + + @Override + public AcceptsOneWidget getCommandsPanelContainer() { + return commandsPanel; + } + + @Override + public AcceptsOneWidget getProcessesListContainer() { + return processesListPanel; + } + + @Override + public AcceptsOneWidget getPreviewUrlsListContainer() { + return previewUrlListPanel; + } + + @Override + public void addButton(MenuPopupButton button) { + buttonsPanel.add(button); + } + + interface CommandToolbarViewImplUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarViewImpl.ui.xml new file mode 100644 index 0000000000..10cb06ebac --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/CommandToolbarViewImpl.ui.xml @@ -0,0 +1,48 @@ + + + + + .rootPanel { + margin-top: 5px; + } + + .commandsPanel { + float: left; + } + + .processesListPanel { + width: literal("calc(100% - 285px)"); + float: left; + margin-left: 15px; + } + + .buttonsPanel { + float: right; + } + + .previewUrlListPanel { + float: right; + margin-left: 15px; + margin-right: 15px; + } + + + + + + + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/OpenCommandsPaletteButton.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/OpenCommandsPaletteButton.java new file mode 100644 index 0000000000..915a772c41 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/OpenCommandsPaletteButton.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * 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.toolbar; + +import elemental.dom.Element; +import elemental.html.DivElement; +import elemental.html.SpanElement; + +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.user.client.Timer; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.assistedinject.Assisted; + +import org.eclipse.che.ide.api.action.Action; +import org.eclipse.che.ide.api.action.ActionManager; +import org.eclipse.che.ide.api.keybinding.KeyBindingAgent; +import org.eclipse.che.ide.command.palette.CommandsPalettePresenter; +import org.eclipse.che.ide.command.palette.PaletteMessages; +import org.eclipse.che.ide.command.palette.ShowCommandsPaletteAction; +import org.eclipse.che.ide.ui.Tooltip; +import org.eclipse.che.ide.ui.menubutton.MenuPopupButton; +import org.eclipse.che.ide.ui.menubutton.MenuPopupItemDataProvider; +import org.eclipse.che.ide.ui.menubutton.PopupItem; +import org.eclipse.che.ide.util.Pair; +import org.eclipse.che.ide.util.dom.Elements; +import org.eclipse.che.ide.util.input.CharCodeWithModifiers; +import org.eclipse.che.ide.util.input.KeyMapUtil; + +import java.util.List; + +import static org.eclipse.che.ide.ui.menu.PositionController.HorizontalAlign.MIDDLE; +import static org.eclipse.che.ide.ui.menu.PositionController.VerticalAlign.BOTTOM; + +/** Button for opening Commands Palette. */ +class OpenCommandsPaletteButton extends MenuPopupButton { + + private final Provider actionManagerProvider; + private final Provider keyBindingAgentProvider; + + @Inject + OpenCommandsPaletteButton(Provider commandsPalettePresenterProvider, + PaletteMessages messages, + Provider actionManagerProvider, + Provider keyBindingAgentProvider, + Provider showCommandsPaletteActionProvider, + @Assisted SafeHtml content) { + super(content, new MenuPopupItemDataProvider() { + @Override + public PopupItem getDefaultItem() { + return null; + } + + @Override + public List getItems() { + return null; + } + + @Override + public boolean isGroup(PopupItem item) { + return false; + } + + @Override + public Pair, String> getChildren(PopupItem parent) { + return null; + } + + @Override + public void setItemDataChangedHandler(ItemDataChangeHandler handler) { + } + }); + + this.actionManagerProvider = actionManagerProvider; + this.keyBindingAgentProvider = keyBindingAgentProvider; + + addClickHandler(event -> commandsPalettePresenterProvider.get().showDialog()); + + // We need to get action's shortcut but action may not be registered yet. + // So postpone tooltip creation and wait 1 sec. while action will be registered. + new Timer() { + @Override + public void run() { + final DivElement divElement = Elements.createDivElement(); + divElement.setInnerText(messages.actionShowPaletteTitle()); + divElement.appendChild(getHotKey(showCommandsPaletteActionProvider.get())); + + Tooltip.create((Element)OpenCommandsPaletteButton.this.getElement(), BOTTOM, MIDDLE, divElement); + } + }.schedule(1000); + + ensureDebugId("button-open_command_palette"); + } + + private SpanElement getHotKey(Action action) { + final SpanElement spanElement = Elements.createSpanElement(); + spanElement.getStyle().setMarginLeft("5px"); + spanElement.getStyle().setColor("#aaaaaa"); + + final String actionId = actionManagerProvider.get().getId(action); + final CharCodeWithModifiers keyBinding = keyBindingAgentProvider.get().getKeyBinding(actionId); + final String hotKey = KeyMapUtil.getShortcutText(keyBinding); + + if (hotKey != null) { + spanElement.setInnerText("[" + hotKey + "]"); + } + + return spanElement; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/ToolbarButtonsFactory.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/ToolbarButtonsFactory.java new file mode 100644 index 0000000000..7545f39873 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/ToolbarButtonsFactory.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * 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.toolbar; + +import com.google.gwt.safehtml.shared.SafeHtml; + +/** Factory for the buttons placed on Commands Toolbar. */ +public interface ToolbarButtonsFactory { + + OpenCommandsPaletteButton createOpenPaletteButton(SafeHtml content); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/ToolbarMessages.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/ToolbarMessages.java new file mode 100644 index 0000000000..94ec0903d2 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/ToolbarMessages.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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.toolbar; + +import com.google.gwt.i18n.client.Messages; + +/** + * I18n messages for the Command Toolbar. + * + * @author Artem Zatsarynnyi + */ +public interface ToolbarMessages extends Messages { + + @Key("guide.label") + String guideItemLabel(); + + @Key("goal_button.tooltip.no_command") + String goalButtonTooltipNoCommand(String goalId); + + @Key("goal_button.tooltip.choose_command") + String goalButtonTooltipChooseCommand(String goalId); + + @Key("goal_button.tooltip.execute_prompt") + String goalButtonTooltipExecutePrompt(String commandName); + + @Key("previews.tooltip") + String previewsTooltip(); + + @Key("previews.error.not_available") + String previewsNotAvailableError(); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/ExecuteCommandPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/ExecuteCommandPresenter.java new file mode 100644 index 0000000000..ed90347ec3 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/ExecuteCommandPresenter.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * 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.toolbar.commands; + +import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.command.CommandExecutor; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.mvp.Presenter; +import org.eclipse.che.ide.command.CommandUtils; +import org.eclipse.che.ide.command.toolbar.CommandCreationGuide; + +/** Presenter drives UI of the toolbar for executing commands. */ +@Singleton +public class ExecuteCommandPresenter implements Presenter, ExecuteCommandView.ActionDelegate { + + private final ExecuteCommandView view; + private final CommandManager commandManager; + private final CommandUtils commandUtils; + private final Provider commandExecutorProvider; + private final CommandCreationGuide commandCreationGuide; + + @Inject + public ExecuteCommandPresenter(ExecuteCommandView view, + CommandManager commandManager, + CommandUtils commandUtils, + Provider commandExecutorProvider, + CommandCreationGuide commandCreationGuide) { + this.view = view; + this.commandManager = commandManager; + this.commandUtils = commandUtils; + this.commandExecutorProvider = commandExecutorProvider; + this.commandCreationGuide = commandCreationGuide; + + view.setDelegate(this); + + commandManager.addCommandLoadedListener(this::updateView); + commandManager.addCommandChangedListener(new CommandManager.CommandChangedListener() { + @Override + public void onCommandAdded(CommandImpl command) { + updateView(); + } + + @Override + public void onCommandUpdated(CommandImpl previousCommand, CommandImpl command) { + updateView(); + } + + @Override + public void onCommandRemoved(CommandImpl command) { + updateView(); + } + }); + } + + private void updateView() { + view.setCommands(commandUtils.groupCommandsByGoal(commandManager.getCommands())); + } + + @Override + public void go(AcceptsOneWidget container) { + container.setWidget(view); + } + + @Override + public void onCommandExecute(CommandImpl command, @Nullable Machine machine) { + final CommandExecutor commandExecutor = commandExecutorProvider.get(); + + if (machine == null) { + commandExecutor.executeCommand(command); + } else { + commandExecutor.executeCommand(command, machine); + } + } + + @Override + public void onGuide(CommandGoal goal) { + commandCreationGuide.guide(goal); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/ExecuteCommandView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/ExecuteCommandView.java new file mode 100644 index 0000000000..affda3049b --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/ExecuteCommandView.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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.toolbar.commands; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.mvp.View; + +import java.util.List; +import java.util.Map; + +/** View for {@link ExecuteCommandPresenter}. */ +public interface ExecuteCommandView extends View { + + /** Set commands grouped by goals for displaying in the view. */ + void setCommands(Map> commands); + + interface ActionDelegate { + + /** Called when command execution is requested. */ + void onCommandExecute(CommandImpl command, @Nullable Machine machine); + + /** Called when guide of commands creation is requested. */ + void onGuide(CommandGoal goal); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/ExecuteCommandViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/ExecuteCommandViewImpl.java new file mode 100644 index 0000000000..69de2ea104 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/ExecuteCommandViewImpl.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * 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.toolbar.commands; + +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.command.goal.DebugGoal; +import org.eclipse.che.ide.command.goal.RunGoal; +import org.eclipse.che.ide.command.toolbar.commands.button.GoalButton; +import org.eclipse.che.ide.command.toolbar.commands.button.GoalButtonDataProvider; +import org.eclipse.che.ide.command.toolbar.commands.button.GoalButtonFactory; +import org.eclipse.che.ide.ui.menubutton.MenuPopupButton; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.util.Collections.emptyList; + +/** + * Implementation of {@link ExecuteCommandView} uses {@link MenuPopupButton}s + * for displaying commands grouped by goal. + * Allows to execute command by choosing one from the button's dropdown menu. + */ +@Singleton +public class ExecuteCommandViewImpl implements ExecuteCommandView { + + private final Map> commands; + /** Stores created buttons by goals in order to reuse it. */ + private final Map buttonsCache; + + private final FlowPanel buttonsPanel; + private final RunGoal runGoal; + private final DebugGoal debugGoal; + private final GoalButtonFactory goalButtonFactory; + + private ActionDelegate delegate; + + @Inject + public ExecuteCommandViewImpl(RunGoal runGoal, DebugGoal debugGoal, GoalButtonFactory goalButtonFactory) { + this.runGoal = runGoal; + this.debugGoal = debugGoal; + this.goalButtonFactory = goalButtonFactory; + + commands = new HashMap<>(); + buttonsCache = new HashMap<>(); + buttonsPanel = new FlowPanel(); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @Override + public Widget asWidget() { + return buttonsPanel; + } + + @Override + public void setCommands(Map> commands) { + this.commands.clear(); + this.commands.putAll(commands); + + buttonsCache.clear(); + buttonsPanel.clear(); + + createOrUpdateButtons(); + } + + /** Add buttons with commands to panel. */ + private void createOrUpdateButtons() { + // for now, display commands of Run and Debug goals only + List goals = new ArrayList<>(); + goals.add(runGoal); + goals.add(debugGoal); + + goals.forEach(this::createOrUpdateButton); + } + + /** Add button with commands of the given goal to panel. */ + private void createOrUpdateButton(CommandGoal goal) { + final GoalButton button = buttonsCache.getOrDefault(goal, goalButtonFactory.newButton(goal, delegate)); + buttonsCache.put(goal, button); + + final List commandsOfGoal = commands.getOrDefault(goal, emptyList()); + final GoalButtonDataProvider dataProvider = button.getPopupItemDataProvider(); + + dataProvider.setCommands(commandsOfGoal); + + button.updateTooltip(); + + buttonsPanel.add(button); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/CommandPopupItem.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/CommandPopupItem.java new file mode 100644 index 0000000000..ff80d1cd2c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/CommandPopupItem.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * 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.toolbar.commands.button; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; + +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.ui.menubutton.PopupItem; + +/** A {@link PopupItem} represents {@link CommandImpl}. */ +public class CommandPopupItem implements PopupItem { + + private final CommandImpl command; + + @Inject + public CommandPopupItem(@Assisted CommandImpl command) { + this.command = command; + } + + @Override + public String getName() { + return command.getName(); + } + + @Override + public boolean isDisabled() { + return command.getApplicableContext().isWorkspaceApplicable(); + } + + public CommandImpl getCommand() { + return command; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GoalButton.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GoalButton.java new file mode 100644 index 0000000000..290aaba7ba --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GoalButton.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * 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.toolbar.commands.button; + +import elemental.dom.Element; + +import com.google.gwt.safehtml.shared.SafeHtml; + +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.command.toolbar.ToolbarMessages; +import org.eclipse.che.ide.ui.Tooltip; +import org.eclipse.che.ide.ui.menubutton.MenuPopupButton; +import org.eclipse.che.ide.ui.menubutton.MenuPopupItemDataProvider; +import org.eclipse.che.ide.ui.menubutton.PopupItem; + +import static org.eclipse.che.ide.ui.menu.PositionController.HorizontalAlign.MIDDLE; +import static org.eclipse.che.ide.ui.menu.PositionController.VerticalAlign.BOTTOM; + +/** {@link MenuPopupButton} for displaying commands belong to the same {@link CommandGoal}. */ +public class GoalButton extends MenuPopupButton { + + private final CommandGoal goal; + private final ToolbarMessages messages; + + private Tooltip tooltip; + private String tooltipText; + + GoalButton(CommandGoal goal, + SafeHtml icon, + MenuPopupItemDataProvider dataProvider, + ToolbarMessages messages) { + super(icon, dataProvider); + + this.goal = goal; + this.messages = messages; + } + + public GoalButtonDataProvider getPopupItemDataProvider() { + return (GoalButtonDataProvider)dataProvider; + } + + public CommandGoal getGoal() { + return goal; + } + + /** Updates button's tooltip depending on it's state (what child elements it contains). */ + public void updateTooltip() { + final PopupItem defaultItem = dataProvider.getDefaultItem(); + + if (defaultItem != null) { + setTooltip(messages.goalButtonTooltipExecutePrompt(defaultItem.getName())); + } else if (getPopupItemDataProvider().hasGuideOnly()) { + setTooltip(messages.goalButtonTooltipNoCommand(goal.getId())); + } else { + setTooltip(messages.goalButtonTooltipChooseCommand(goal.getId())); + } + } + + private void setTooltip(String newTooltipText) { + if (newTooltipText.equals(tooltipText)) { + return; + } + + tooltipText = newTooltipText; + + if (tooltip != null) { + tooltip.destroy(); + } + + tooltip = Tooltip.create((Element)getElement(), BOTTOM, MIDDLE, newTooltipText); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GoalButtonDataProvider.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GoalButtonDataProvider.java new file mode 100644 index 0000000000..41ee18ad74 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GoalButtonDataProvider.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * 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.toolbar.commands.button; + +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.machine.MachineEntity; +import org.eclipse.che.ide.ui.menubutton.MenuPopupItemDataProvider; +import org.eclipse.che.ide.ui.menubutton.PopupItem; +import org.eclipse.che.ide.util.Pair; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.stream.Collectors.toList; + +/** Provides items for {@link GoalButton}. */ +public class GoalButtonDataProvider implements MenuPopupItemDataProvider { + + private final List commands; + private final AppContext appContext; + private final PopupItemFactory popupItemFactory; + + private ItemDataChangeHandler handler; + private PopupItem defaultItem; + + public GoalButtonDataProvider(AppContext appContext, PopupItemFactory popupItemFactory) { + this.appContext = appContext; + this.popupItemFactory = popupItemFactory; + this.commands = new ArrayList<>(); + } + + @Nullable + @Override + public PopupItem getDefaultItem() { + if (defaultItem != null) { + return defaultItem; + } + + return null; + } + + public void setDefaultItem(PopupItem item) { + defaultItem = item; + } + + @Override + public List getItems() { + List items = new ArrayList<>(commands.size()); + + if (defaultItem != null && defaultItem instanceof MachinePopupItem) { + items.add(popupItemFactory.newMachinePopupItem((MachinePopupItem)defaultItem)); + } + + for (CommandImpl command : commands) { + items.add(popupItemFactory.newCommandPopupItem(command)); + } + + if (items.isEmpty()) { + items.add(popupItemFactory.newHintPopupItem()); + } + + return items; + } + + @Override + public boolean isGroup(PopupItem item) { + if (item instanceof CommandPopupItem) { + return appContext.getWorkspace().getRuntime().getMachines().size() > 1; + } + + return false; + } + + @Override + public Pair, String> getChildren(PopupItem parent) { + List items = new ArrayList<>(); + + if (parent instanceof CommandPopupItem) { + CommandImpl command = ((CommandPopupItem)parent).getCommand(); + List machines = appContext.getActiveRuntime().getMachines(); + + items.addAll(machines.stream() + .map(machine -> popupItemFactory.newMachinePopupItem(command, machine)) + .collect(toList())); + } + + return Pair.of(items, null); + } + + @Override + public void setItemDataChangedHandler(ItemDataChangeHandler handler) { + this.handler = handler; + } + + public void setCommands(List commands) { + this.commands.clear(); + this.commands.addAll(commands); + + handler.onItemDataChanged(); + } + + /** Checks whether the {@link GuidePopupItem} is the only item. */ + public boolean hasGuideOnly() { + List items = getItems(); + return items.isEmpty() || (items.size() == 1 && items.get(0) instanceof GuidePopupItem); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GoalButtonFactory.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GoalButtonFactory.java new file mode 100644 index 0000000000..54896b9277 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GoalButtonFactory.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * 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.toolbar.commands.button; + +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.FontAwesome; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.command.CommandResources; +import org.eclipse.che.ide.command.goal.DebugGoal; +import org.eclipse.che.ide.command.goal.RunGoal; +import org.eclipse.che.ide.command.toolbar.ToolbarMessages; +import org.eclipse.che.ide.command.toolbar.commands.ExecuteCommandView.ActionDelegate; + +/** + * Factory for {@link GoalButton}s. + * + * @see GoalButton + */ +@Singleton +public class GoalButtonFactory { + + private final CommandResources resources; + private final AppContext appContext; + private final PopupItemFactory popupItemFactory; + private final ToolbarMessages messages; + private final RunGoal runGoal; + private final DebugGoal debugGoal; + + @Inject + public GoalButtonFactory(CommandResources resources, + AppContext appContext, + PopupItemFactory popupItemFactory, + ToolbarMessages messages, + RunGoal runGoal, + DebugGoal debugGoal) { + this.resources = resources; + this.appContext = appContext; + this.popupItemFactory = popupItemFactory; + this.messages = messages; + this.runGoal = runGoal; + this.debugGoal = debugGoal; + } + + /** + * Creates new instance of the {@link GoalButton}. + * + * @param goal + * {@link CommandGoal} for displaying commands + * @param delegate + * delegate for receiving events + * @return {@link GoalButton} + */ + public GoalButton newButton(CommandGoal goal, ActionDelegate delegate) { + final GoalButtonDataProvider dataProvider = new GoalButtonDataProvider(appContext, popupItemFactory); + final GoalButton button = new GoalButton(goal, getIconForGoal(goal), dataProvider, messages); + + button.setActionHandler(item -> { + if (item instanceof CommandPopupItem) { + final CommandImpl command = ((CommandPopupItem)item).getCommand(); + + delegate.onCommandExecute(command, null); + dataProvider.setDefaultItem(item); + button.updateTooltip(); + } else if (item instanceof MachinePopupItem) { + final MachinePopupItem machinePopupItem = (MachinePopupItem)item; + + delegate.onCommandExecute(machinePopupItem.getCommand(), machinePopupItem.getMachine()); + dataProvider.setDefaultItem(item); + button.updateTooltip(); + } else if (item instanceof GuidePopupItem) { + delegate.onGuide(goal); + } + }); + + button.addStyleName(resources.commandToolbarCss().toolbarButton()); + + button.ensureDebugId("command_toolbar-button_" + goal.getId()); + + return button; + } + + /** Returns {@link FontAwesome} icon for the given goal. */ + private SafeHtml getIconForGoal(CommandGoal goal) { + final SafeHtmlBuilder safeHtmlBuilder = new SafeHtmlBuilder(); + + if (goal.equals(runGoal)) { + safeHtmlBuilder.appendHtmlConstant(FontAwesome.PLAY); + } else if (goal.equals(debugGoal)) { + safeHtmlBuilder.appendHtmlConstant(FontAwesome.BUG); + } + + return safeHtmlBuilder.toSafeHtml(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GuidePopupItem.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GuidePopupItem.java new file mode 100644 index 0000000000..7e25adb3d7 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/GuidePopupItem.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * 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.toolbar.commands.button; + +import com.google.inject.Inject; + +import org.eclipse.che.ide.command.toolbar.ToolbarMessages; +import org.eclipse.che.ide.ui.menubutton.PopupItem; + +/** A {@link PopupItem} represents a hint which guides the user into the flow of creating a command. */ +public class GuidePopupItem implements PopupItem { + + private final ToolbarMessages messages; + + @Inject + public GuidePopupItem(ToolbarMessages messages) { + this.messages = messages; + } + + @Override + public String getName() { + return messages.guideItemLabel(); + } + + @Override + public boolean isDisabled() { + return false; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/MachinePopupItem.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/MachinePopupItem.java new file mode 100644 index 0000000000..b42b6b9c10 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/MachinePopupItem.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * 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.toolbar.commands.button; + +import com.google.inject.assistedinject.Assisted; +import com.google.inject.assistedinject.AssistedInject; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.ui.menubutton.PopupItem; + +/** Item contains {@link CommandImpl} and {@link Machine}. */ +public class MachinePopupItem implements PopupItem { + + private final CommandImpl command; + private final Machine machine; + private final String name; + + @AssistedInject + public MachinePopupItem(@Assisted CommandImpl command, @Assisted Machine machine) { + this.command = command; + this.machine = machine; + this.name = machine.getConfig().getName(); + } + + @AssistedInject + public MachinePopupItem(@Assisted MachinePopupItem item) { + this.command = item.command; + this.machine = item.machine; + this.name = command.getName() + " on " + machine.getConfig().getName(); + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean isDisabled() { + return false; + } + + public CommandImpl getCommand() { + return command; + } + + public Machine getMachine() { + return machine; + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/PopupItemFactory.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/PopupItemFactory.java new file mode 100644 index 0000000000..acb8a45044 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/commands/button/PopupItemFactory.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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.toolbar.commands.button; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.ui.menubutton.PopupItem; + +/** Factory for {@link PopupItem}s for {@link GoalButton}. */ +public interface PopupItemFactory { + + GuidePopupItem newHintPopupItem(); + + CommandPopupItem newCommandPopupItem(CommandImpl command); + + MachinePopupItem newMachinePopupItem(CommandImpl command, Machine machine); + + MachinePopupItem newMachinePopupItem(MachinePopupItem item); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewUrl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewUrl.java new file mode 100644 index 0000000000..4826a1be97 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewUrl.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * 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.toolbar.previews; + +import java.util.Objects; + +/** Holds preview URL and it's name displaying in a 'Previews' list. */ +class PreviewUrl { + + private final String url; + private final String displayName; + + PreviewUrl(String url, String displayName) { + this.url = url; + this.displayName = displayName; + } + + public String getUrl() { + return url; + } + + public String getDisplayName() { + return displayName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PreviewUrl that = (PreviewUrl)o; + return Objects.equals(url, that.url) && + Objects.equals(displayName, that.displayName); + } + + @Override + public int hashCode() { + return Objects.hash(url, displayName); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewUrlItemRenderer.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewUrlItemRenderer.java new file mode 100644 index 0000000000..d17eb41b7c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewUrlItemRenderer.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * 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.toolbar.previews; + +import elemental.dom.Element; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.Widget; + +import org.eclipse.che.ide.FontAwesome; +import org.eclipse.che.ide.command.CommandResources; +import org.eclipse.che.ide.command.toolbar.ToolbarMessages; +import org.eclipse.che.ide.ui.Tooltip; +import org.eclipse.che.ide.ui.dropdown.BaseListItem; +import org.eclipse.che.ide.ui.dropdown.DropdownListItemRenderer; + +import static com.google.gwt.dom.client.Style.Unit.PX; +import static org.eclipse.che.ide.ui.menu.PositionController.HorizontalAlign.MIDDLE; +import static org.eclipse.che.ide.ui.menu.PositionController.VerticalAlign.BOTTOM; + +/** Renders widgets for the 'Previews' list. Always returns the same instance of header widget. */ +class PreviewUrlItemRenderer implements DropdownListItemRenderer { + + static final HeaderWidget HEADER_WIDGET = new HeaderWidget(); + + private final BaseListItem item; + + private Widget listWidget; + + PreviewUrlItemRenderer(BaseListItem item) { + this.item = item; + } + + @Override + public Widget renderHeaderWidget() { + return HEADER_WIDGET; + } + + @Override + public Widget renderListWidget() { + if (listWidget == null) { + listWidget = new Label(item.getValue().getDisplayName()); + listWidget.getElement().getStyle().setMarginBottom(0, PX); + } + + return listWidget; + } + + private static class HeaderWidget extends Label { + + private static final CommandResources RESOURCES = GWT.create(CommandResources.class); + private static final ToolbarMessages MESSAGES = GWT.create(ToolbarMessages.class); + + HeaderWidget() { + super(); + + addStyleName(RESOURCES.commandToolbarCss().previewUrlWidget()); + + final SafeHtmlBuilder safeHtmlBuilder = new SafeHtmlBuilder(); + safeHtmlBuilder.appendHtmlConstant(FontAwesome.BULLSEYE); + getElement().setInnerSafeHtml(safeHtmlBuilder.toSafeHtml()); + + Tooltip.create((Element)getElement(), BOTTOM, MIDDLE, MESSAGES.previewsTooltip()); + } + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewsPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewsPresenter.java new file mode 100644 index 0000000000..c589bb84b9 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewsPresenter.java @@ -0,0 +1,166 @@ +/******************************************************************************* + * 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.toolbar.previews; + +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; +import com.google.web.bindery.event.shared.EventBus; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.api.core.model.machine.Server; +import org.eclipse.che.api.core.model.workspace.WorkspaceRuntime; +import org.eclipse.che.api.machine.shared.dto.execagent.GetProcessResponseDto; +import org.eclipse.che.api.promises.client.Function; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.promises.client.PromiseProvider; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.machine.DevMachine; +import org.eclipse.che.ide.api.machine.ExecAgentCommandManager; +import org.eclipse.che.ide.api.machine.events.ProcessFinishedEvent; +import org.eclipse.che.ide.api.machine.events.ProcessStartedEvent; +import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; +import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; +import org.eclipse.che.ide.api.macro.MacroProcessor; +import org.eclipse.che.ide.api.mvp.Presenter; +import org.eclipse.che.ide.command.toolbar.ToolbarMessages; + +import java.util.Map; +import java.util.Optional; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static org.eclipse.che.api.workspace.shared.Constants.COMMAND_PREVIEW_URL_ATTRIBUTE_NAME; + +/** Drives the UI for displaying preview URLs of the running processes. */ +@Singleton +public class PreviewsPresenter implements Presenter, PreviewsView.ActionDelegate { + + private final PreviewsView view; + private final ExecAgentCommandManager execAgentClient; + private final CommandManager commandManager; + private final AppContext appContext; + private final Provider macroProcessorProvider; + private final PromiseProvider promiseProvider; + private final ToolbarMessages messages; + + @Inject + public PreviewsPresenter(PreviewsView view, + ExecAgentCommandManager execAgentClient, + CommandManager commandManager, + AppContext appContext, + EventBus eventBus, + Provider macroProcessorProvider, + PromiseProvider promiseProvider, + ToolbarMessages messages) { + this.view = view; + this.execAgentClient = execAgentClient; + this.commandManager = commandManager; + this.appContext = appContext; + this.macroProcessorProvider = macroProcessorProvider; + this.promiseProvider = promiseProvider; + this.messages = messages; + + view.setDelegate(this); + + eventBus.addHandler(WsAgentStateEvent.TYPE, new WsAgentStateHandler() { + @Override + public void onWsAgentStarted(WsAgentStateEvent event) { + updateView(); + } + + @Override + public void onWsAgentStopped(WsAgentStateEvent event) { + view.removeAll(); + } + }); + + eventBus.addHandler(ProcessStartedEvent.TYPE, event -> updateView()); + eventBus.addHandler(ProcessFinishedEvent.TYPE, event -> updateView()); + } + + /** Updates view with preview URLs of all running processes. */ + private void updateView() { + view.removeAll(); + + final WorkspaceRuntime runtime = appContext.getActiveRuntime(); + + if (runtime != null) { + runtime.getMachines().forEach(machine -> execAgentClient.getProcesses(machine.getId(), false).then(processes -> { + processes.forEach(process -> getPreviewUrl(process.getPid(), machine).then(view::addUrl)); + })); + } + } + + /** + * Returns promise that resolves preview URL of the command which has launched + * the process with the given {@code pid} on the specified {@code machine}. + * Returns promise that rejects with an error if preview URL isn't available. + */ + private Promise getPreviewUrl(int pid, Machine machine) { + return execAgentClient.getProcess(machine.getId(), pid) + // get command's preview URL + .then((Function)process -> { + final Optional commandOptional = commandManager.getCommand(process.getName()); + + return commandOptional.map(command -> command.getAttributes().get(COMMAND_PREVIEW_URL_ATTRIBUTE_NAME)) + .orElse(null); + }) + // expand macros used in preview URL + .thenPromise(previewUrl -> { + if (!isNullOrEmpty(previewUrl)) { + return macroProcessorProvider.get().expandMacros(previewUrl); + } + return promiseProvider.reject(new Exception(messages.previewsNotAvailableError())); + }) + // compose preview URL's display name + .then((Function)previewUrl -> new PreviewUrl(previewUrl, + getPreviewUrlDisplayName(previewUrl) + .orElse(previewUrl))); + } + + private Optional getPreviewUrlDisplayName(String previewUrl) { + final DevMachine devMachine = appContext.getDevMachine(); + final Map servers = devMachine.getRuntime().getServers(); + + for (Map.Entry entry : servers.entrySet()) { + Server server = entry.getValue(); + String serverUrl = server.getUrl(); + + if (previewUrl.startsWith(serverUrl)) { + String displayName = previewUrl.replace(serverUrl, devMachine.getDisplayName() + ':' + entry.getKey()); + + // cut protocol from display name + final int protocolIndex = displayName.lastIndexOf('/'); + if (protocolIndex > -1) { + displayName = displayName.substring(0, protocolIndex); + } + + return Optional.of(displayName); + } + } + + return Optional.empty(); + } + + @Override + public void go(AcceptsOneWidget container) { + container.setWidget(view); + } + + @Override + public void onUrlChosen(PreviewUrl previewUrl) { + Window.open(previewUrl.getUrl(), "_blank", null); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewsView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewsView.java new file mode 100644 index 0000000000..e269d2b90e --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewsView.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * 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.toolbar.previews; + +import org.eclipse.che.ide.api.mvp.View; + +/** View for displaying preview URLs. */ +public interface PreviewsView extends View { + + /** Add preview URL to the view. */ + void addUrl(PreviewUrl previewUrl); + + /** Remove preview URL from the view. */ + void removeUrl(PreviewUrl previewUrl); + + /** Remove all preview URLs from the view. */ + void removeAll(); + + interface ActionDelegate { + + /** Called when preview URL has been chosen. */ + void onUrlChosen(PreviewUrl previewUrl); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewsViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewsViewImpl.java new file mode 100644 index 0000000000..86d32f230e --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/previews/PreviewsViewImpl.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * 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.toolbar.previews; + +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.ui.dropdown.BaseListItem; +import org.eclipse.che.ide.ui.dropdown.DropdownList; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import static org.eclipse.che.ide.command.toolbar.previews.PreviewUrlItemRenderer.HEADER_WIDGET; + +/** Implementation of {@link PreviewsView} that displays preview URLs in a dropdown list. */ +@Singleton +public class PreviewsViewImpl implements PreviewsView { + + /** Mapping of URL to list item. */ + private final Map> listItems; + private final DropdownList dropdownList; + + private ActionDelegate delegate; + + @Inject + public PreviewsViewImpl() { + listItems = new HashMap<>(); + + dropdownList = new DropdownList(HEADER_WIDGET); + dropdownList.setWidth("43px"); + dropdownList.ensureDebugId("dropdown-preview_url"); + dropdownList.setSelectionHandler(item -> { + for (Entry> entry : listItems.entrySet()) { + if (item.equals(entry.getValue())) { + delegate.onUrlChosen(entry.getKey()); + return; + } + } + }); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @Override + public Widget asWidget() { + return dropdownList; + } + + @Override + public void addUrl(PreviewUrl previewUrl) { + if (listItems.containsKey(previewUrl)) { + return; // no sense to add the equals URLs even if they belong to different commands + } + + BaseListItem listItem = new BaseListItem<>(previewUrl); + PreviewUrlItemRenderer renderer = new PreviewUrlItemRenderer(listItem); + + listItems.put(previewUrl, listItem); + dropdownList.addItem(listItem, renderer); + } + + @Override + public void removeUrl(PreviewUrl previewUrl) { + final BaseListItem listItem = listItems.remove(previewUrl); + + if (listItem != null) { + dropdownList.removeItem(listItem); + } + } + + @Override + public void removeAll() { + listItems.clear(); + dropdownList.clear(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ActivateProcessOutputEvent.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ActivateProcessOutputEvent.java new file mode 100644 index 0000000000..9ed84cc178 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ActivateProcessOutputEvent.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * 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.toolbar.processes; + +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.GwtEvent; + +/** Event should be fired for activating particular process's output panel. */ +public class ActivateProcessOutputEvent extends GwtEvent { + + public static final Type TYPE = new Type<>(); + + private final int pid; + + /** Creates new event with the given PID. */ + public ActivateProcessOutputEvent(int pid) { + this.pid = pid; + } + + public int getPid() { + return pid; + } + + @Override + public Type getAssociatedType() { + return TYPE; + } + + @Override + protected void dispatch(Handler handler) { + handler.onActivateProcessOutput(this); + } + + public interface Handler extends EventHandler { + + /** Called when activating process's output is requested. */ + void onActivateProcessOutput(ActivateProcessOutputEvent event); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/EmptyListWidget.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/EmptyListWidget.java new file mode 100644 index 0000000000..38df19882b --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/EmptyListWidget.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * 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.toolbar.processes; + +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.InlineHTML; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.command.CommandResources; +import org.eclipse.che.ide.command.toolbar.CommandCreationGuide; +import org.eclipse.che.ide.command.toolbar.ToolbarMessages; + +/** + * Empty state widget for processes dropdown list. Has two states: + *

+ * + * @see org.eclipse.che.ide.ui.dropdown.DropdownList#DropdownList(Widget) + */ +@Singleton +public class EmptyListWidget extends FlowPanel { + + private final CommandManager commandManager; + private final CommandCreationGuide commandCreationGuide; + + private FlowPanel noProcessWidget; + private FlowPanel noCommandWidget; + + @Inject + public EmptyListWidget(CommandManager commandManager, CommandCreationGuide commandCreationGuide) { + this.commandManager = commandManager; + this.commandCreationGuide = commandCreationGuide; + + commandManager.addCommandLoadedListener(this::updateState); + commandManager.addCommandChangedListener(new CommandManager.CommandChangedListener() { + @Override + public void onCommandAdded(CommandImpl command) { + updateState(); + } + + @Override + public void onCommandUpdated(CommandImpl previousCommand, CommandImpl command) { + } + + @Override + public void onCommandRemoved(CommandImpl command) { + updateState(); + } + }); + } + + @Inject + private void init(CommandResources resources, ToolbarMessages messages) { + // initialize widget for the state when there's no process + final Label commandNameLabel = new InlineHTML("Ready"); + commandNameLabel.addStyleName(resources.commandToolbarCss().processWidgetText()); + commandNameLabel.addStyleName(resources.commandToolbarCss().processWidgetCommandNameLabel()); + + final Label machineNameLabel = new InlineHTML("  - start command"); + machineNameLabel.addStyleName(resources.commandToolbarCss().processWidgetText()); + machineNameLabel.addStyleName(resources.commandToolbarCss().processWidgetMachineNameLabel()); + + noProcessWidget = new FlowPanel(); + noProcessWidget.addStyleName(resources.commandToolbarCss().processWidgetText()); + noProcessWidget.add(commandNameLabel); + noProcessWidget.add(machineNameLabel); + + + // initialize widget for the state when there's no command + final Label hintLabel = new InlineHTML(messages.guideItemLabel()); + hintLabel.addStyleName(resources.commandToolbarCss().processWidgetText()); + hintLabel.addStyleName(resources.commandToolbarCss().processWidgetCommandNameLabel()); + hintLabel.addClickHandler(event -> commandCreationGuide.guide()); + + noCommandWidget = new FlowPanel(); + noCommandWidget.addStyleName(resources.commandToolbarCss().processWidgetText()); + noCommandWidget.add(hintLabel); + } + + private void updateState() { + if (commandManager.getCommands().isEmpty()) { + showNoCommandWidget(); + } else { + showNoProcessWidget(); + } + } + + private void showNoCommandWidget() { + noProcessWidget.removeFromParent(); + add(noCommandWidget); + } + + private void showNoProcessWidget() { + noCommandWidget.removeFromParent(); + add(noProcessWidget); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/Process.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/Process.java new file mode 100644 index 0000000000..5ea7171d41 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/Process.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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.toolbar.processes; + +import org.eclipse.che.api.core.model.machine.Machine; + +/** Model of the process. */ +public interface Process { + + String getName(); + + String getCommandLine(); + + int getPid(); + + boolean isAlive(); + + Machine getMachine(); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessImpl.java new file mode 100644 index 0000000000..d7df5886ec --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessImpl.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * 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.toolbar.processes; + +import org.eclipse.che.api.core.model.machine.Machine; + +import java.util.Objects; + +/** Data object for {@link Process}. */ +public class ProcessImpl implements Process { + + private final String commandName; + private final String commandLine; + private final int pid; + private final boolean alive; + private final Machine machine; + + public ProcessImpl(String commandName, String commandLine, int pid, boolean alive, Machine machine) { + this.commandName = commandName; + this.commandLine = commandLine; + this.pid = pid; + this.alive = alive; + this.machine = machine; + } + + @Override + public String getName() { + return commandName; + } + + @Override + public String getCommandLine() { + return commandLine; + } + + @Override + public int getPid() { + return pid; + } + + @Override + public boolean isAlive() { + return alive; + } + + @Override + public Machine getMachine() { + return machine; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ProcessImpl process = (ProcessImpl)o; + + return pid == process.pid && + alive == process.alive && + Objects.equals(commandName, process.commandName) && + Objects.equals(commandLine, process.commandLine) && + Objects.equals(machine, process.machine); + } + + @Override + public int hashCode() { + return Objects.hash(commandName, commandLine, pid, alive, machine); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessItemRenderer.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessItemRenderer.java new file mode 100644 index 0000000000..08ecb87d7a --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessItemRenderer.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * 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.toolbar.processes; + +import com.google.gwt.user.client.ui.Widget; + +import org.eclipse.che.ide.ui.dropdown.BaseListItem; +import org.eclipse.che.ide.ui.dropdown.DropdownListItemRenderer; + +/** Renders widgets for representing a {@link Process}. */ +class ProcessItemRenderer implements DropdownListItemRenderer { + + private final BaseListItem item; + private final StopProcessHandler stopHandler; + private final RerunProcessHandler reRunHandler; + + private ProcessWidget headerWidget; + private ProcessWidget listWidget; + + ProcessItemRenderer(BaseListItem listItem, + StopProcessHandler stopProcessHandler, + RerunProcessHandler reRunProcessHandler) { + item = listItem; + stopHandler = stopProcessHandler; + reRunHandler = reRunProcessHandler; + } + + @Override + public Widget renderHeaderWidget() { + if (headerWidget == null) { + headerWidget = new ProcessWidget(item, stopHandler, reRunHandler); + } + + return headerWidget; + } + + @Override + public Widget renderListWidget() { + if (listWidget == null) { + listWidget = new ProcessWidget(item, stopHandler, reRunHandler); + } + + return listWidget; + } + + /** Informs rendered widgets that related process has been stopped. */ + void notifyProcessStopped() { + headerWidget.toggleStopped(); + listWidget.toggleStopped(); + } + + interface StopProcessHandler { + /** Called when stopping {@code process} is requested. */ + void onStopProcess(Process process); + } + + interface RerunProcessHandler { + /** Called when rerunning {@code process} is requested. */ + void onRerunProcess(Process process); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessOutputClosedEvent.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessOutputClosedEvent.java new file mode 100644 index 0000000000..aa393ae52c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessOutputClosedEvent.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * 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.toolbar.processes; + +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.GwtEvent; + +/** Event fired when process's output panel has been closed. */ +public class ProcessOutputClosedEvent extends GwtEvent { + + public static final Type TYPE = new Type<>(); + + private final int pid; + + /** Creates new event with the given PID. */ + public ProcessOutputClosedEvent(int pid) { + this.pid = pid; + } + + /** PID of the associated process. */ + public int getPid() { + return pid; + } + + @Override + public Type getAssociatedType() { + return TYPE; + } + + @Override + protected void dispatch(Handler handler) { + handler.onProcessOutputClosed(this); + } + + public interface Handler extends EventHandler { + + /** Called when process's output panel has been closed. */ + void onProcessOutputClosed(ProcessOutputClosedEvent event); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessWidget.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessWidget.java new file mode 100644 index 0000000000..e8e0f16e1d --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessWidget.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * 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.toolbar.processes; + +import elemental.dom.Element; + +import com.google.gwt.core.client.Duration; +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Document; +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.ButtonBase; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.InlineHTML; +import com.google.gwt.user.client.ui.Label; + +import org.eclipse.che.ide.FontAwesome; +import org.eclipse.che.ide.command.CommandResources; +import org.eclipse.che.ide.command.toolbar.processes.ProcessItemRenderer.RerunProcessHandler; +import org.eclipse.che.ide.command.toolbar.processes.ProcessItemRenderer.StopProcessHandler; +import org.eclipse.che.ide.ui.Tooltip; +import org.eclipse.che.ide.ui.dropdown.BaseListItem; + +import static com.google.gwt.dom.client.Style.Float.RIGHT; +import static org.eclipse.che.ide.ui.menu.PositionController.HorizontalAlign.MIDDLE; +import static org.eclipse.che.ide.ui.menu.PositionController.VerticalAlign.BOTTOM; + +/** + * Widget for representing a {@link Process}. + * Has different states for representing stopped and running processes. + */ +class ProcessWidget extends FlowPanel { + + private static final CommandResources RESOURCES = GWT.create(CommandResources.class); + + private final Label pidLabel; + private final Label durationLabel; + private final ActionButton stopButton; + private final ActionButton reRunButton; + private final Timer updateDurationTimer; + + /** Stores true if widget displays stopped process and false for running process. */ + private boolean stopped; + + ProcessWidget(BaseListItem item, + StopProcessHandler stopProcessHandler, + RerunProcessHandler rerunProcessHandler) { + super(); + + final Process process = item.getValue(); + stopped = !process.isAlive(); + + durationLabel = new Label(); + durationLabel.addStyleName(RESOURCES.commandToolbarCss().processWidgetText()); + durationLabel.addStyleName(RESOURCES.commandToolbarCss().processWidgetPidLabel()); + durationLabel.ensureDebugId("dropdown-processes-label-duration"); + + updateDurationTimer = new UpdateDurationTimer(); + if (!stopped) { + updateDurationTimer.scheduleRepeating(1000); + } + + pidLabel = new Label('#' + Integer.toString(process.getPid())); + pidLabel.addStyleName(RESOURCES.commandToolbarCss().processWidgetText()); + pidLabel.addStyleName(RESOURCES.commandToolbarCss().processWidgetPidLabel()); + pidLabel.ensureDebugId("dropdown-processes-label-pid"); + Tooltip.create((Element)pidLabel.getElement(), BOTTOM, MIDDLE, "PID"); + + add(createMachineNameLabel(process)); + add(createCommandNameLabel(process)); + add(stopButton = createStopButton(process, stopProcessHandler)); + add(reRunButton = createRerunButton(process, rerunProcessHandler)); + add(durationLabel); + add(pidLabel); + + checkStopped(); + } + + private Label createMachineNameLabel(Process process) { + final Label label = new InlineHTML(process.getMachine().getConfig().getName() + ": "); + + label.addStyleName(RESOURCES.commandToolbarCss().processWidgetText()); + label.addStyleName(RESOURCES.commandToolbarCss().processWidgetMachineNameLabel()); + label.ensureDebugId("dropdown-processes-machine-name"); + + Tooltip.create((Element)label.getElement(), + BOTTOM, + MIDDLE, + process.getCommandLine().split("\\n")); + + return label; + } + + private Label createCommandNameLabel(Process process) { + final Label label = new InlineHTML(process.getName()); + + label.addStyleName(RESOURCES.commandToolbarCss().processWidgetText()); + label.addStyleName(RESOURCES.commandToolbarCss().processWidgetCommandNameLabel()); + label.ensureDebugId("dropdown-processes-command-name"); + + Tooltip.create((Element)label.getElement(), + BOTTOM, + MIDDLE, + process.getCommandLine().split("\\n")); + + return label; + } + + private ActionButton createStopButton(Process process, StopProcessHandler handler) { + final SafeHtmlBuilder safeHtmlBuilder = new SafeHtmlBuilder(); + safeHtmlBuilder.appendHtmlConstant(FontAwesome.STOP); + + final ActionButton button = new ActionButton(safeHtmlBuilder.toSafeHtml()); + button.addClickHandler(event -> handler.onStopProcess(process)); + button.ensureDebugId("dropdown-processes-stop"); + + Tooltip.create((Element)button.getElement(), BOTTOM, MIDDLE, "Stop"); + + return button; + } + + private ActionButton createRerunButton(Process process, RerunProcessHandler handler) { + final SafeHtmlBuilder safeHtmlBuilder = new SafeHtmlBuilder(); + safeHtmlBuilder.appendHtmlConstant(FontAwesome.REPEAT); + + final ActionButton button = new ActionButton(safeHtmlBuilder.toSafeHtml()); + button.addClickHandler(event -> handler.onRerunProcess(process)); + button.ensureDebugId("dropdown-processes-rerun"); + + Tooltip.create((Element)button.getElement(), BOTTOM, MIDDLE, "Re-run"); + + return button; + } + + /** Toggle widget's state for displaying running or stopped process. */ + void toggleStopped() { + stopped = !stopped; + checkStopped(); + updateDurationTimer.cancel(); + } + + /** Check whether widget displays stopped or running process and changes widget's state if it's required. */ + private void checkStopped() { + pidLabel.setVisible(!stopped); + reRunButton.setVisible(stopped); + stopButton.setVisible(!stopped); + } + + private static class ActionButton extends ButtonBase { + ActionButton(SafeHtml content) { + super(Document.get().createDivElement()); + + getElement().getStyle().setFloat(RIGHT); + getElement().setInnerSafeHtml(content); + asWidget().addStyleName(RESOURCES.commandToolbarCss().processWidgetActionButton()); + } + } + + /** Timer that updates duration label. */ + private class UpdateDurationTimer extends Timer { + final Duration duration = new Duration(); + + @Override + public void run() { + durationLabel.setText(getElapsedTime()); + } + + /** Returns the time (mm:ss) that have elapsed since this timer was created. */ + private String getElapsedTime() { + final int elapsedSec = duration.elapsedMillis() / 1000; + final int minutesPart = elapsedSec / 60; + final int secondsPart = elapsedSec - minutesPart * 60; + + return (minutesPart < 10 ? "0" + minutesPart : minutesPart) + ":" + + (secondsPart < 10 ? "0" + secondsPart : secondsPart); + } + + @Override + public void cancel() { + super.cancel(); + + durationLabel.setVisible(false); + } + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessesListPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessesListPresenter.java new file mode 100644 index 0000000000..ef3e2e9b8c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessesListPresenter.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * 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.toolbar.processes; + +import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.google.inject.Provider; +import com.google.web.bindery.event.shared.EventBus; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.api.core.model.workspace.WorkspaceRuntime; +import org.eclipse.che.api.machine.shared.dto.execagent.GetProcessesResponseDto; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandExecutor; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.machine.ExecAgentCommandManager; +import org.eclipse.che.ide.api.machine.events.ProcessFinishedEvent; +import org.eclipse.che.ide.api.machine.events.ProcessStartedEvent; +import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; +import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; +import org.eclipse.che.ide.api.mvp.Presenter; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.HashMap; +import java.util.Map; + +/** Drives the UI for displaying list of running and stopped processes. */ +@Singleton +public class ProcessesListPresenter implements Presenter, ProcessesListView.ActionDelegate { + + private final ProcessesListView view; + private final EventBus eventBus; + private final ExecAgentCommandManager execAgentClient; + private final AppContext appContext; + private final CommandManager commandManager; + private final Provider commandExecutorProvider; + + private final Map runningProcesses; + + @Inject + public ProcessesListPresenter(final ProcessesListView view, + EventBus eventBus, + final ExecAgentCommandManager execAgentClient, + final AppContext appContext, + CommandManager commandManager, + Provider commandExecutorProvider) { + this.view = view; + this.eventBus = eventBus; + this.execAgentClient = execAgentClient; + this.appContext = appContext; + this.commandManager = commandManager; + this.commandExecutorProvider = commandExecutorProvider; + + view.setDelegate(this); + + runningProcesses = new HashMap<>(); + + eventBus.addHandler(WsAgentStateEvent.TYPE, new WsAgentStateHandler() { + @Override + public void onWsAgentStarted(WsAgentStateEvent event) { + updateView(); + } + + @Override + public void onWsAgentStopped(WsAgentStateEvent event) { + runningProcesses.clear(); + view.clearList(); + } + }); + + eventBus.addHandler(ProcessStartedEvent.TYPE, event -> addProcessToList(event.getProcessID(), + event.getMachine())); + + eventBus.addHandler(ProcessFinishedEvent.TYPE, event -> { + final Process process = runningProcesses.get(event.getProcessID()); + + if (process != null) { + view.processStopped(process); + } + }); + + eventBus.addHandler(ProcessOutputClosedEvent.TYPE, event -> { + final Process process = runningProcesses.get(event.getPid()); + + if (process != null) { + view.removeProcess(process); + } + }); + } + + /** Updates view with all running processes. */ + private void updateView() { + view.clearList(); + runningProcesses.clear(); + + final WorkspaceRuntime runtime = appContext.getActiveRuntime(); + + if (runtime != null) { + for (Machine machine : runtime.getMachines()) { + execAgentClient.getProcesses(machine.getId(), false).then(processes -> { + for (GetProcessesResponseDto p : processes) { + final Process process = new ProcessImpl(p.getName(), + p.getCommandLine(), + p.getPid(), + p.isAlive(), + machine); + runningProcesses.put(process.getPid(), process); + + view.addProcess(process); + } + }); + } + } + } + + /** + * Adds process to the view. + * + * @param pid + * PID of the process to add to the view + * @param machine + * machine where process were run or currently running + */ + private void addProcessToList(int pid, Machine machine) { + execAgentClient.getProcess(machine.getId(), pid).then(processDto -> { + final Process process = new ProcessImpl(processDto.getName(), + processDto.getCommandLine(), + processDto.getPid(), + processDto.isAlive(), + machine); + runningProcesses.put(process.getPid(), process); + + view.addProcess(process); + }); + } + + @Override + public void go(AcceptsOneWidget container) { + container.setWidget(view); + } + + @Override + public void onProcessChosen(Process process) { + eventBus.fireEvent(new ActivateProcessOutputEvent(process.getPid())); + } + + @Override + public void onReRunProcess(Process process) { + commandManager.getCommand(process.getName()).ifPresent(command -> { + view.removeProcess(process); + commandExecutorProvider.get().executeCommand(command, process.getMachine()); + }); + } + + @Override + public void onStopProcess(Process process) { + execAgentClient.killProcess(process.getMachine().getId(), process.getPid()); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessesListView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessesListView.java new file mode 100644 index 0000000000..d6c934b471 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessesListView.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * 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.toolbar.processes; + +import org.eclipse.che.ide.api.mvp.View; + +/** View for {@link ProcessesListPresenter}. */ +public interface ProcessesListView extends View { + + /** Add process to the list. */ + void addProcess(Process process); + + /** Remove process from the list. */ + void removeProcess(Process process); + + /** Clear processes list. */ + void clearList(); + + /** Informs view that the specified {@code process} has been stopped. */ + void processStopped(Process process); + + interface ActionDelegate { + + /** Called when process has been chosen. */ + void onProcessChosen(Process process); + + /** Called when rerunning process is requested. */ + void onReRunProcess(Process process); + + /** Called when stopping process is requested. */ + void onStopProcess(Process process); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessesListViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessesListViewImpl.java new file mode 100644 index 0000000000..37ccd80fd2 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/toolbar/processes/ProcessesListViewImpl.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * 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.toolbar.processes; + +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Singleton; + +import org.eclipse.che.ide.command.CommandResources; +import org.eclipse.che.ide.ui.dropdown.BaseListItem; +import org.eclipse.che.ide.ui.dropdown.DropdownList; + +import javax.inject.Inject; +import java.util.HashMap; +import java.util.Map; + +/** Implementation of {@link ProcessesListView} that displays processes in a dropdown list. */ +@Singleton +public class ProcessesListViewImpl implements ProcessesListView { + + private final FlowPanel rootPanel; + private final DropdownList dropdownList; + + private final Map> listItems; + private final Map renderers; + + private ActionDelegate delegate; + + @Inject + public ProcessesListViewImpl(CommandResources resources, EmptyListWidget emptyListWidget) { + listItems = new HashMap<>(); + renderers = new HashMap<>(); + + final Label label = new Label("EXEC"); + label.addStyleName(resources.commandToolbarCss().processesListLabel()); + + dropdownList = new DropdownList(emptyListWidget); + dropdownList.setWidth("100%"); + dropdownList.ensureDebugId("dropdown-processes"); + dropdownList.syncWidths(); + dropdownList.setSelectionHandler(item -> listItems.entrySet() + .stream() + .filter(entry -> item.equals(entry.getValue())) + .forEach(entry -> delegate.onProcessChosen(entry.getKey()))); + + rootPanel = new FlowPanel(); + rootPanel.add(label); + rootPanel.add(dropdownList); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @Override + public Widget asWidget() { + return rootPanel; + } + + @Override + public void clearList() { + dropdownList.clear(); + } + + @Override + public void processStopped(Process process) { + final ProcessItemRenderer renderer = renderers.get(process); + + if (renderer != null) { + renderer.notifyProcessStopped(); + } + } + + @Override + public void addProcess(Process process) { + final BaseListItem listItem = new BaseListItem<>(process); + final ProcessItemRenderer renderer = new ProcessItemRenderer(listItem, + p -> delegate.onStopProcess(p), + p -> delegate.onReRunProcess(p)); + + listItems.put(process, listItem); + renderers.put(process, renderer); + + dropdownList.addItem(listItem, renderer); + } + + @Override + public void removeProcess(Process process) { + final BaseListItem listItem = listItems.get(process); + + if (listItem != null) { + listItems.remove(process); + renderers.remove(process); + + dropdownList.removeItem(listItem); + } + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/CommandTypeMessages.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/CommandTypeMessages.java new file mode 100644 index 0000000000..c7fc72880c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/CommandTypeMessages.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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.type; + +import com.google.gwt.i18n.client.Messages; + +/** + * I18n messages relate to command type. + * + * @author Artem Zatsarynnyi + */ +public interface CommandTypeMessages extends Messages { + + @Key("type.registry.message.already_registered") + String typeRegistryMessageAlreadyRegistered(String id); + + @Key("type.chooser.message.canceled") + String typeChooserMessageCanceled(); +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandTypeRegistryImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/CommandTypeRegistryImpl.java similarity index 81% rename from ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandTypeRegistryImpl.java rename to ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/CommandTypeRegistryImpl.java index 0850cac601..a181975896 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/CommandTypeRegistryImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/CommandTypeRegistryImpl.java @@ -8,9 +8,11 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.command; + +package org.eclipse.che.ide.command.type; import com.google.inject.Inject; +import com.google.inject.Singleton; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.api.command.CommandType; @@ -23,18 +25,21 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static java.util.Collections.unmodifiableList; - /** * Implementation of {@link CommandTypeRegistry}. * * @author Artem Zatsarynnyi */ +@Singleton public class CommandTypeRegistryImpl implements CommandTypeRegistry { + private final CommandTypeMessages messages; + private final Map commandTypes; - public CommandTypeRegistryImpl() { + @Inject + public CommandTypeRegistryImpl(CommandTypeMessages messages) { + this.messages = messages; this.commandTypes = new HashMap<>(); } @@ -42,8 +47,9 @@ public class CommandTypeRegistryImpl implements CommandTypeRegistry { private void register(Set commandTypes) { for (CommandType type : commandTypes) { final String id = type.getId(); + if (this.commandTypes.containsKey(id)) { - Log.warn(getClass(), "Command type with ID " + id + " is already registered."); + Log.warn(getClass(), messages.typeRegistryMessageAlreadyRegistered(id)); } else { this.commandTypes.put(id, type); } @@ -58,6 +64,6 @@ public class CommandTypeRegistryImpl implements CommandTypeRegistry { @Override public List getCommandTypes() { - return unmodifiableList(new ArrayList<>(commandTypes.values())); + return new ArrayList<>(commandTypes.values()); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooser.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooser.java new file mode 100644 index 0000000000..e5d0d29208 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooser.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * 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.type.chooser; + +import com.google.inject.Inject; + +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.promises.client.PromiseProvider; +import org.eclipse.che.api.promises.client.js.Executor; +import org.eclipse.che.api.promises.client.js.Executor.ExecutorBody; +import org.eclipse.che.api.promises.client.js.JsPromiseError; +import org.eclipse.che.api.promises.client.js.RejectFunction; +import org.eclipse.che.api.promises.client.js.ResolveFunction; +import org.eclipse.che.ide.api.command.CommandType; +import org.eclipse.che.ide.api.command.CommandTypeRegistry; +import org.eclipse.che.ide.command.type.CommandTypeMessages; + +import java.util.List; + +import static java.util.Comparator.comparing; + +/** + * Provides a simple mechanism for the user to choose a {@link CommandType}. + * + * @author Artem Zatsarynnyi + */ +public class CommandTypeChooser implements CommandTypeChooserView.ActionDelegate { + + private final CommandTypeChooserView view; + private final CommandTypeRegistry commandTypeRegistry; + private final PromiseProvider promiseProvider; + private final CommandTypeMessages messages; + + private ResolveFunction resolveFunction; + private RejectFunction rejectFunction; + + @Inject + public CommandTypeChooser(CommandTypeChooserView view, + CommandTypeRegistry commandTypeRegistry, + PromiseProvider promiseProvider, + CommandTypeMessages messages) { + this.view = view; + this.commandTypeRegistry = commandTypeRegistry; + this.promiseProvider = promiseProvider; + this.messages = messages; + + view.setDelegate(this); + } + + /** + * Pops up a command type chooser dialog at the position relative to the browser's client area. + * + * @param left + * the left position, in pixels + * @param top + * the top position, in pixels + * @return promise that will be resolved with a chosen {@link CommandType} + * or rejected in case command type selection has been cancelled + */ + public Promise show(int left, int top) { + final List commandTypes = commandTypeRegistry.getCommandTypes(); + + if (commandTypes.size() == 1) { + return promiseProvider.resolve(commandTypes.get(0)); + } + + commandTypes.sort(comparing(CommandType::getDisplayName)); + + view.setCommandTypes(commandTypes); + + view.show(left, top); + + return promiseProvider.create(Executor.create((ExecutorBody)(resolve, reject) -> { + resolveFunction = resolve; + rejectFunction = reject; + })); + } + + @Override + public void onSelected(CommandType commandType) { + view.close(); + + resolveFunction.apply(commandType); + } + + @Override + public void onCanceled() { + rejectFunction.apply(JsPromiseError.create(messages.typeChooserMessageCanceled())); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooserView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooserView.java new file mode 100644 index 0000000000..e81e234928 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooserView.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * 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.type.chooser; + +import org.eclipse.che.ide.api.command.CommandType; +import org.eclipse.che.ide.api.mvp.View; + +import java.util.List; + +/** + * View for command type chooser. + * + * @author Artem Zatsarynnyi + */ +public interface CommandTypeChooserView extends View { + + /** + * Show the view at the position relative to the browser's client area. + * + * @param left + * the left position, in pixels + * @param top + * the top position, in pixels + */ + void show(int left, int top); + + /** Close the view. */ + void close(); + + /** Sets the command types to display in the view. */ + void setCommandTypes(List commandTypes); + + /** The action delegate for this view. */ + interface ActionDelegate { + + /** Called when command type is selected. */ + void onSelected(CommandType commandType); + + /** Called when command type selection has been canceled. Note that view will be already closed. */ + void onCanceled(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooserViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooserViewImpl.java new file mode 100644 index 0000000000..7cd16bd2f3 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooserViewImpl.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * 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.type.chooser; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.PopupPanel; +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.command.CommandType; +import org.eclipse.che.ide.command.CommandResources; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.google.gwt.user.client.ui.PopupPanel.AnimationType.ROLL_DOWN; + +/** + * Implementation of {@link CommandTypeChooserView} which which pops up list of the command types. + * User can select command type with Enter key or cancel selection with Esc key. + * + * @author Artem Zatsarynnyi + */ +public class CommandTypeChooserViewImpl extends PopupPanel implements CommandTypeChooserView { + + private static final CommandTypeChooserViewImplUiBinder UI_BINDER = GWT.create(CommandTypeChooserViewImplUiBinder.class); + + /** Map that contains all shown command types. */ + private final Map commandTypesById; + + @UiField + ListBox typesList; + + private ActionDelegate delegate; + + @Inject + public CommandTypeChooserViewImpl(CommandResources resources) { + commandTypesById = new HashMap<>(); + + addStyleName(resources.commandTypeChooserCss().chooserPopup()); + + setWidget(UI_BINDER.createAndBindUi(this)); + + initView(); + addHandlers(); + } + + private void initView() { + setAutoHideEnabled(true); + setAnimationEnabled(true); + setAnimationType(ROLL_DOWN); + } + + private void addHandlers() { + addCloseHandler(event -> { + if (event.isAutoClosed()) { + delegate.onCanceled(); + } + }); + + typesList.addDoubleClickHandler(event -> { + final String selectedTypeId = typesList.getSelectedValue(); + + if (selectedTypeId != null) { + final CommandType selectedCommandType = commandTypesById.get(selectedTypeId); + + if (selectedCommandType != null) { + delegate.onSelected(selectedCommandType); + } + } + }); + + typesList.addKeyPressHandler(event -> { + final int keyCode = event.getNativeEvent().getKeyCode(); + + if (KeyCodes.KEY_ENTER == keyCode || KeyCodes.KEY_MAC_ENTER == keyCode) { + final String selectedTypeId = typesList.getSelectedValue(); + + if (selectedTypeId != null) { + final CommandType selectedCommandType = commandTypesById.get(selectedTypeId); + + if (selectedCommandType != null) { + delegate.onSelected(selectedCommandType); + } + } + } + }); + + typesList.addKeyDownHandler(event -> { + if (KeyCodes.KEY_ESCAPE == event.getNativeKeyCode()) { + hide(true); + } + }); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @Override + public void show(int left, int top) { + setPopupPosition(left, top); + + super.show(); + + typesList.setFocus(true); + } + + @Override + public void close() { + hide(); + } + + @Override + public void setCommandTypes(List commandTypes) { + typesList.clear(); + commandTypesById.clear(); + + commandTypes.forEach(commandType -> { + commandTypesById.put(commandType.getId(), commandType); + typesList.addItem(commandType.getDisplayName(), commandType.getId()); + }); + + typesList.setVisibleItemCount(commandTypes.size()); + typesList.setSelectedIndex(0); + } + + interface CommandTypeChooserViewImplUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooserViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooserViewImpl.ui.xml new file mode 100644 index 0000000000..9a8d00a6c1 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/command/type/chooser/CommandTypeChooserViewImpl.ui.xml @@ -0,0 +1,21 @@ + + + + .list-box { + border: none; + } + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/CoreGinModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/CoreGinModule.java index 421c4da81e..0bbc8d4758 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/CoreGinModule.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/CoreGinModule.java @@ -51,6 +51,7 @@ import org.eclipse.che.ide.editor.preferences.EditorPreferencesModule; import org.eclipse.che.ide.factory.FactoryApiModule; import org.eclipse.che.ide.filetypes.FileTypeApiModule; import org.eclipse.che.ide.keybinding.KeyBindingManager; +import org.eclipse.che.ide.machine.MachineApiModule; import org.eclipse.che.ide.macro.MacroApiModule; import org.eclipse.che.ide.notification.NotificationApiModule; import org.eclipse.che.ide.oauth.OAuthApiModule; @@ -104,6 +105,7 @@ public class CoreGinModule extends AbstractGinModule { install(new MacroApiModule()); install(new UserApiModule()); install(new WorkspaceApiModule()); + install(new MachineApiModule()); install(new CommandApiModule()); install(new ProjectApiModule()); install(new ProjectImportModule()); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/StandardComponentInitializer.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/StandardComponentInitializer.java index b85fd052c2..b4bf77027a 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/StandardComponentInitializer.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/StandardComponentInitializer.java @@ -56,6 +56,7 @@ import org.eclipse.che.ide.api.action.Action; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.action.ActionManager; import org.eclipse.che.ide.api.action.DefaultActionGroup; +import org.eclipse.che.ide.api.action.IdeActions; import org.eclipse.che.ide.api.constraints.Constraints; import org.eclipse.che.ide.api.editor.EditorRegistry; import org.eclipse.che.ide.api.editor.texteditor.EditorResources; @@ -67,6 +68,8 @@ import org.eclipse.che.ide.api.keybinding.KeyBindingAgent; import org.eclipse.che.ide.api.keybinding.KeyBuilder; import org.eclipse.che.ide.api.parts.Perspective; import org.eclipse.che.ide.api.parts.PerspectiveManager; +import org.eclipse.che.ide.command.editor.CommandEditorProvider; +import org.eclipse.che.ide.command.palette.ShowCommandsPaletteAction; import org.eclipse.che.ide.connection.WsConnectionListener; import org.eclipse.che.ide.imageviewer.ImageViewerProvider; import org.eclipse.che.ide.macro.ServerHostNameMacro; @@ -143,24 +146,25 @@ import static org.eclipse.che.ide.projecttype.BlankProjectWizardRegistrar.BLANK_ @Singleton public class StandardComponentInitializer { - public static final String NAVIGATE_TO_FILE = "navigateToFile"; - public static final String FULL_TEXT_SEARCH = "fullTextSearch"; - public static final String FIND_ACTION = "findActionAction"; - public static final String FORMAT = "format"; - public static final String COPY = "copy"; - public static final String CUT = "cut"; - public static final String PASTE = "paste"; - public static final String SWITCH_LEFT_TAB = "switchLeftTab"; - public static final String SWITCH_RIGHT_TAB = "switchRightTab"; - public static final String OPEN_RECENT_FILES = "openRecentFiles"; - public static final String DELETE_ITEM = "deleteItem"; - public static final String NEW_FILE = "newFile"; - public static final String CREATE_PROJECT = "createProject"; - public static final String IMPORT_PROJECT = "importProject"; - public static final String CLOSE_ACTIVE_EDITOR = "closeActiveEditor"; - public static final String SIGNATURE_HELP = "signatureHelp"; - public static final String RENAME = "renameResource"; - public static final String SHOW_REFERENCE = "showReference"; + public static final String NAVIGATE_TO_FILE = "navigateToFile"; + public static final String FULL_TEXT_SEARCH = "fullTextSearch"; + public static final String FIND_ACTION = "findActionAction"; + public static final String FORMAT = "format"; + public static final String COPY = "copy"; + public static final String CUT = "cut"; + public static final String PASTE = "paste"; + public static final String SWITCH_LEFT_TAB = "switchLeftTab"; + public static final String SWITCH_RIGHT_TAB = "switchRightTab"; + public static final String OPEN_RECENT_FILES = "openRecentFiles"; + public static final String DELETE_ITEM = "deleteItem"; + public static final String NEW_FILE = "newFile"; + public static final String CREATE_PROJECT = "createProject"; + public static final String IMPORT_PROJECT = "importProject"; + public static final String CLOSE_ACTIVE_EDITOR = "closeActiveEditor"; + public static final String SIGNATURE_HELP = "signatureHelp"; + public static final String RENAME = "renameResource"; + public static final String SHOW_REFERENCE = "showReference"; + public static final String SHOW_COMMANDS_PALETTE = "showCommandsPalette"; public interface ParserResource extends ClientBundle { @Source("org/eclipse/che/ide/blank.svg") @@ -363,6 +367,9 @@ public class StandardComponentInitializer { @Inject private RestorePartAction restorePartAction; + @Inject + private ShowCommandsPaletteAction showCommandsPaletteAction; + @Inject private PerspectiveManager perspectiveManager; @@ -414,6 +421,11 @@ public class StandardComponentInitializer { @Named("JPGFileType") private FileType jpgFile; + @Inject + private CommandEditorProvider commandEditorProvider; + @Inject + @Named("CommandFileType") + private FileType commandFileType; @Inject private WsConnectionListener wsConnectionListener; @@ -481,6 +493,9 @@ public class StandardComponentInitializer { fileTypeRegistry.registerFileType(jpgFile); editorRegistry.registerDefaultEditor(jpgFile, imageViewerProvider); + fileTypeRegistry.registerFileType(commandFileType); + editorRegistry.registerDefaultEditor(commandFileType, commandEditorProvider); + // Workspace (New Menu) DefaultActionGroup workspaceGroup = (DefaultActionGroup)actionManager.getAction(GROUP_WORKSPACE); @@ -715,6 +730,10 @@ public class StandardComponentInitializer { editorTabContextMenu.add(splitVerticallyAction); actionManager.registerAction(SIGNATURE_HELP, signatureHelpAction); + actionManager.registerAction(SHOW_COMMANDS_PALETTE, showCommandsPaletteAction); + DefaultActionGroup runGroup = (DefaultActionGroup)actionManager.getAction(IdeActions.GROUP_RUN); + runGroup.add(showCommandsPaletteAction); + DefaultActionGroup editorContextMenuGroup = new DefaultActionGroup(actionManager); actionManager.registerAction(GROUP_EDITOR_CONTEXT_MENU, editorContextMenuGroup); @@ -746,6 +765,8 @@ public class StandardComponentInitializer { keyBinding.getGlobal().addKey(new KeyBuilder().alt().charCode('x').build(), CREATE_PROJECT); keyBinding.getGlobal().addKey(new KeyBuilder().alt().charCode('A').build(), IMPORT_PROJECT); + keyBinding.getGlobal().addKey(new KeyBuilder().shift().charCode(KeyCodeMap.F10).build(), SHOW_COMMANDS_PALETTE); + if (UserAgent.isMac()) { keyBinding.getGlobal().addKey(new KeyBuilder().control().charCode('w').build(), CLOSE_ACTIVE_EDITOR); keyBinding.getGlobal().addKey(new KeyBuilder().control().charCode('p').build(), SIGNATURE_HELP); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/UiModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/UiModule.java index 4cf3c6d055..d0ee18f441 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/UiModule.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/core/UiModule.java @@ -14,7 +14,6 @@ import com.google.gwt.inject.client.AbstractGinModule; import com.google.gwt.inject.client.assistedinject.GinFactoryModuleBuilder; import com.google.gwt.inject.client.multibindings.GinMapBinder; import com.google.inject.Singleton; - import org.eclipse.che.ide.api.component.Component; import org.eclipse.che.ide.api.dialogs.ChoiceDialog; import org.eclipse.che.ide.api.dialogs.ConfirmDialog; @@ -47,9 +46,6 @@ import org.eclipse.che.ide.ui.dialogs.message.MessageDialogFooter; import org.eclipse.che.ide.ui.dialogs.message.MessageDialogPresenter; import org.eclipse.che.ide.ui.dialogs.message.MessageDialogView; import org.eclipse.che.ide.ui.dialogs.message.MessageDialogViewImpl; -import org.eclipse.che.ide.ui.dropdown.DropDownListFactory; -import org.eclipse.che.ide.ui.dropdown.DropDownWidget; -import org.eclipse.che.ide.ui.dropdown.DropDownWidgetImpl; import org.eclipse.che.ide.ui.multisplitpanel.SubPanel; import org.eclipse.che.ide.ui.multisplitpanel.SubPanelFactory; import org.eclipse.che.ide.ui.multisplitpanel.panel.SubPanelPresenter; @@ -111,11 +107,6 @@ public class UiModule extends AbstractGinModule { .implement(InputDialog.class, InputDialogPresenter.class) .build(DialogFactory.class)); - // drop down list widget - install(new GinFactoryModuleBuilder() - .implement(DropDownWidget.class, DropDownWidgetImpl.class) - .build(DropDownListFactory.class)); - // multi-split panel install(new GinFactoryModuleBuilder() .implement(SubPanel.class, SubPanelPresenter.class) diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/EditorAgentImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/EditorAgentImpl.java index 916b14fe4e..76c10cbaca 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/EditorAgentImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/editor/EditorAgentImpl.java @@ -10,16 +10,18 @@ *******************************************************************************/ package org.eclipse.che.ide.editor; +import elemental.json.Json; +import elemental.json.JsonArray; +import elemental.json.JsonObject; +import elemental.util.ArrayOf; + import com.google.common.base.Optional; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; -import elemental.json.Json; -import elemental.json.JsonArray; -import elemental.json.JsonObject; -import elemental.util.ArrayOf; + import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.api.promises.client.Promise; @@ -47,7 +49,6 @@ import org.eclipse.che.ide.api.editor.texteditor.TextEditor; import org.eclipse.che.ide.api.event.ActivePartChangedEvent; import org.eclipse.che.ide.api.event.ActivePartChangedHandler; import org.eclipse.che.ide.api.event.FileEvent; -import org.eclipse.che.ide.api.event.FileEvent.FileEventHandler; import org.eclipse.che.ide.api.event.SelectionChangedEvent; import org.eclipse.che.ide.api.event.SelectionChangedHandler; import org.eclipse.che.ide.api.event.WindowActionEvent; @@ -91,7 +92,6 @@ import static org.eclipse.che.ide.api.parts.PartStackType.EDITING; @Singleton public class EditorAgentImpl implements EditorAgent, EditorPartCloseHandler, - FileEventHandler, ActivePartChangedHandler, SelectionChangedHandler, WindowActionHandler, @@ -140,7 +140,6 @@ public class EditorAgentImpl implements EditorAgent, eventBus.addHandler(ActivePartChangedEvent.TYPE, this); eventBus.addHandler(SelectionChangedEvent.TYPE, this); - eventBus.addHandler(FileEvent.TYPE, this); eventBus.addHandler(WindowActionEvent.TYPE, this); } @@ -149,17 +148,6 @@ public class EditorAgentImpl implements EditorAgent, closeEditor(editor); } - @Override - public void onFileOperation(FileEvent event) { - switch (event.getOperationType()) { - case OPEN: - openEditor(event.getFile()); - break; - case CLOSE: - closeEditor(event.getEditorTab()); - } - } - @Override public void onActivePartChanged(ActivePartChangedEvent event) { activePart = event.getActivePart(); @@ -200,7 +188,31 @@ public class EditorAgentImpl implements EditorAgent, doOpen(file, new OpenEditorCallbackImpl(), constraints); } - private void closeEditor(EditorTab tab) { + @Override + public void closeEditor(final EditorPartPresenter editor) { + if (editor == null) { + return; + } + + final EditorPartStack editorPartStack = editorMultiPartStack.getPartStackByPart(editor); + if (editorPartStack == null) { + return; + } + + editor.onClosing(new AsyncCallback() { + @Override + public void onSuccess(Void result) { + EditorTab editorTab = editorPartStack.getTabByPart(editor); + doCloseEditor(editorTab); + } + + @Override + public void onFailure(Throwable caught) { + } + }); + } + + private void doCloseEditor(EditorTab tab) { checkArgument(tab != null, "Null editor tab occurred"); EditorPartPresenter editor = tab.getRelativeEditorPart(); @@ -220,23 +232,8 @@ public class EditorAgentImpl implements EditorAgent, if (activeEditor != null && activeEditor == editor) { activeEditor = null; } - } - @Override - public void closeEditor(EditorPartPresenter editor) { - if (editor == null) { - return; - } - - EditorPartStack editorPartStack = editorMultiPartStack.getPartStackByPart(editor); - if (editorPartStack == null) { - return; - } - - EditorTab editorTab = editorPartStack.getTabByPart(editor); - //we have the handlers for the closing file event in different places of the project - //so we need to notify them about it (we can't just pass doClose() method) - eventBus.fireEvent(FileEvent.createCloseFileEvent(editorTab)); + eventBus.fireEvent(FileEvent.createFileClosedEvent(tab)); } @Override @@ -302,6 +299,7 @@ public class EditorAgentImpl implements EditorAgent, editorContentSynchronizerProvider.get().trackEditor(editor); } callback.onEditorOpened(editor); + eventBus.fireEvent(FileEvent.createFileOpenedEvent(file)); eventBus.fireEvent(new EditorOpenedEvent(file, editor)); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/MachineApiModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/MachineApiModule.java new file mode 100644 index 0000000000..c3f0b733b3 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/MachineApiModule.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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.machine; + +import com.google.gwt.inject.client.AbstractGinModule; + +import org.eclipse.che.ide.machine.chooser.MachineChooserView; +import org.eclipse.che.ide.machine.chooser.MachineChooserViewImpl; + +/** + * GIN module for configuring Machine API related components. + * + * @author Artem Zatsarynnyi + */ +public class MachineApiModule extends AbstractGinModule { + + @Override + protected void configure() { + bind(MachineChooserView.class).to(MachineChooserViewImpl.class); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooser.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooser.java new file mode 100644 index 0000000000..e60a2e8745 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooser.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * 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.machine.chooser; + +import com.google.inject.Inject; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.api.core.model.workspace.WorkspaceRuntime; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.promises.client.PromiseProvider; +import org.eclipse.che.api.promises.client.js.Executor; +import org.eclipse.che.api.promises.client.js.Executor.ExecutorBody; +import org.eclipse.che.api.promises.client.js.JsPromiseError; +import org.eclipse.che.api.promises.client.js.RejectFunction; +import org.eclipse.che.api.promises.client.js.ResolveFunction; +import org.eclipse.che.ide.api.app.AppContext; + +import java.util.List; + +/** + * Provides a simple mechanism for the user to choose a {@link Machine}. + * + * @author Artem Zatsarynnyi + */ +public class MachineChooser implements MachineChooserView.ActionDelegate { + + private final MachineChooserView view; + private final AppContext appContext; + private final PromiseProvider promiseProvider; + + private ResolveFunction resolveFunction; + private RejectFunction rejectFunction; + + @Inject + public MachineChooser(MachineChooserView view, + AppContext appContext, + PromiseProvider promiseProvider) { + this.view = view; + this.appContext = appContext; + this.promiseProvider = promiseProvider; + + view.setDelegate(this); + } + + /** + * Pops up a dialog for choosing a machine. + *

Note: if there is only one machine running in the workspace + * then returned promise will be resolved with that machine without asking user. + * + * @return promise that will be resolved with a chosen {@link Machine} + * or rejected in case machine selection has been cancelled. + */ + public Promise show() { + final WorkspaceRuntime runtime = appContext.getWorkspace().getRuntime(); + + if (runtime != null) { + final List machines = runtime.getMachines(); + + if (machines.size() == 1) { + return promiseProvider.resolve(machines.get(0)); + } + + view.setMachines(machines); + } + + view.show(); + + return promiseProvider.create(Executor.create((ExecutorBody)(resolve, reject) -> { + resolveFunction = resolve; + rejectFunction = reject; + })); + } + + @Override + public void onMachineSelected(Machine machine) { + view.close(); + + resolveFunction.apply(machine); + } + + @Override + public void onCanceled() { + rejectFunction.apply(JsPromiseError.create("Machine selection has been canceled")); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooserView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooserView.java new file mode 100644 index 0000000000..ed14fca7b1 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooserView.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * 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.machine.chooser; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.ide.api.mvp.View; + +import java.util.List; + +/** + * Contract for the view of the machine chooser. + * + * @author Artem Zatsarynnyi + */ +public interface MachineChooserView extends View { + + /** Show the view. */ + void show(); + + /** Close the view. */ + void close(); + + /** Sets the machines to display in the view. */ + void setMachines(List machines); + + /** The action delegate for this view. */ + interface ActionDelegate { + + /** Called when machine is selected. */ + void onMachineSelected(Machine machine); + + /** Called when machine selection has been canceled. Note that view will be already closed. */ + void onCanceled(); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooserViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooserViewImpl.java new file mode 100644 index 0000000000..e48ae24d8c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooserViewImpl.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * 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.machine.chooser; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.PopupPanel; +import com.google.inject.Inject; + +import org.eclipse.che.api.core.model.machine.Machine; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Implementation of {@link MachineChooserView} which pops up list of the machines. + * User can select machine with Enter key or cancel selection with Esc key. + * + * @author Artem Zatsarynnyi + */ +public class MachineChooserViewImpl extends PopupPanel implements MachineChooserView { + + private static final MachineChooserViewImplUiBinder UI_BINDER = GWT.create(MachineChooserViewImplUiBinder.class); + + /** Map that contains all shown machines. */ + private final Map machinesById; + + @UiField + ListBox machinesList; + + private ActionDelegate delegate; + + @Inject + public MachineChooserViewImpl() { + machinesById = new HashMap<>(); + + setWidget(UI_BINDER.createAndBindUi(this)); + + initView(); + addHandlers(); + } + + private void initView() { + setAutoHideEnabled(true); + setAnimationEnabled(true); + setAnimationType(AnimationType.ROLL_DOWN); + } + + private void addHandlers() { + addCloseHandler(event -> { + if (event.isAutoClosed()) { + delegate.onCanceled(); + } + }); + + machinesList.addDoubleClickHandler(event -> { + final String selectedMachineId = machinesList.getSelectedValue(); + + if (selectedMachineId != null) { + final Machine selectedMachine = machinesById.get(selectedMachineId); + + if (selectedMachine != null) { + delegate.onMachineSelected(selectedMachine); + } + } + }); + + machinesList.addKeyPressHandler(event -> { + final int keyCode = event.getNativeEvent().getKeyCode(); + + if (KeyCodes.KEY_ENTER == keyCode || KeyCodes.KEY_MAC_ENTER == keyCode) { + final String selectedMachineId = machinesList.getSelectedValue(); + + if (selectedMachineId != null) { + final Machine selectedMachine = machinesById.get(selectedMachineId); + + if (selectedMachine != null) { + delegate.onMachineSelected(selectedMachine); + } + } + } + }); + + machinesList.addKeyDownHandler(event -> { + if (KeyCodes.KEY_ESCAPE == event.getNativeKeyCode()) { + hide(true); + } + }); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @Override + public void show() { + super.show(); + + center(); + machinesList.setFocus(true); + } + + @Override + public void close() { + hide(); + } + + @Override + public void setMachines(List machines) { + machinesList.clear(); + machinesById.clear(); + + machines.forEach(machine -> { + machinesById.put(machine.getId(), machine); + machinesList.addItem(machine.getConfig().getName(), machine.getId()); + }); + + machinesList.setVisibleItemCount(machines.size()); + machinesList.setSelectedIndex(0); + } + + interface MachineChooserViewImplUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooserViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooserViewImpl.ui.xml new file mode 100644 index 0000000000..b06459afd1 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/machine/chooser/MachineChooserViewImpl.ui.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/AbstractServerMacro.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/AbstractServerMacro.java index 93aad0860c..858e9fac45 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/AbstractServerMacro.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/AbstractServerMacro.java @@ -25,7 +25,7 @@ import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; /** - * Base macro provider which belongs to the current server configuration. Provides easy access to the developer machine + * Base macro which belongs to the current server configuration. Provides easy access to the developer machine * to allow fetch necessary information to use in custom commands, preview urls, etc. * * @author Vlad Zhukovskyi @@ -40,13 +40,13 @@ import static com.google.common.base.Preconditions.checkNotNull; @Beta public abstract class AbstractServerMacro implements WsAgentStateHandler { - private final MacroRegistry providerRegistry; + private final MacroRegistry macroRegistry; private final AppContext appContext; - public AbstractServerMacro(MacroRegistry providerRegistry, + public AbstractServerMacro(MacroRegistry macroRegistry, EventBus eventBus, AppContext appContext) { - this.providerRegistry = providerRegistry; + this.macroRegistry = macroRegistry; this.appContext = appContext; eventBus.addHandler(WsAgentStateEvent.TYPE, this); @@ -58,21 +58,21 @@ public abstract class AbstractServerMacro implements WsAgentStateHandler { * @see AbstractServerMacro#getMacros(DevMachine) * @since 4.7.0 */ - private void registerProviders() { + private void registerMacros() { final DevMachine devMachine = appContext.getDevMachine(); if (devMachine == null) { return; } - final Set providers = getMacros(devMachine); - checkNotNull(providers); + final Set macros = getMacros(devMachine); + checkNotNull(macros); - if (providers.isEmpty()) { + if (macros.isEmpty()) { return; } - providerRegistry.register(providers); + macroRegistry.register(macros); } /** @@ -81,7 +81,7 @@ public abstract class AbstractServerMacro implements WsAgentStateHandler { * @see AbstractServerMacro#getMacros(DevMachine) * @since 4.7.0 */ - private void unregisterProviders() { + private void unregisterMacros() { final DevMachine devMachine = appContext.getDevMachine(); if (devMachine == null) { @@ -89,7 +89,7 @@ public abstract class AbstractServerMacro implements WsAgentStateHandler { } for (Macro provider : getMacros(devMachine)) { - providerRegistry.unregister(provider); + macroRegistry.unregister(provider); } } @@ -108,12 +108,12 @@ public abstract class AbstractServerMacro implements WsAgentStateHandler { /** {@inheritDoc} */ @Override public void onWsAgentStarted(WsAgentStateEvent event) { - registerProviders(); + registerMacros(); } /** {@inheritDoc} */ @Override public void onWsAgentStopped(WsAgentStateEvent event) { - unregisterProviders(); + unregisterMacros(); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroApiModule.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroApiModule.java index eed50a53e2..be5db2e9f9 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroApiModule.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroApiModule.java @@ -22,6 +22,8 @@ import org.eclipse.che.ide.editor.macro.EditorCurrentFilePathMacro; import org.eclipse.che.ide.editor.macro.EditorCurrentFileRelativePathMacro; import org.eclipse.che.ide.editor.macro.EditorCurrentProjectNameMacro; import org.eclipse.che.ide.editor.macro.EditorCurrentProjectTypeMacro; +import org.eclipse.che.ide.macro.chooser.MacroChooserView; +import org.eclipse.che.ide.macro.chooser.MacroChooserViewImpl; import org.eclipse.che.ide.part.explorer.project.macro.ExplorerCurrentFileNameMacro; import org.eclipse.che.ide.part.explorer.project.macro.ExplorerCurrentFileParentPathMacro; import org.eclipse.che.ide.part.explorer.project.macro.ExplorerCurrentFilePathMacro; @@ -56,5 +58,7 @@ public class MacroApiModule extends AbstractGinModule { macrosBinder.addBinding().to(ExplorerCurrentProjectNameMacro.class); macrosBinder.addBinding().to(ExplorerCurrentProjectTypeMacro.class); macrosBinder.addBinding().to(WorkspaceNameMacro.class); + + bind(MacroChooserView.class).to(MacroChooserViewImpl.class); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroProcessorImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroProcessorImpl.java index 383478a6ef..a15e2c402b 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroProcessorImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroProcessorImpl.java @@ -12,13 +12,10 @@ package org.eclipse.che.ide.macro; import com.google.inject.Inject; -import org.eclipse.che.api.core.model.machine.Machine; import org.eclipse.che.api.promises.client.Function; import org.eclipse.che.api.promises.client.FunctionException; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.promises.client.js.Promises; -import org.eclipse.che.ide.api.command.CommandImpl; -import org.eclipse.che.ide.api.command.CommandManager; import org.eclipse.che.ide.api.macro.Macro; import org.eclipse.che.ide.api.macro.MacroProcessor; import org.eclipse.che.ide.api.macro.MacroRegistry; @@ -30,7 +27,6 @@ import java.util.Iterator; * * @author Artem Zatsarynnyi * @see Macro - * @see CommandManager#executeCommand(CommandImpl, Machine) */ public class MacroProcessorImpl implements MacroProcessor { diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroRegistryImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroRegistryImpl.java index 292d2a60ee..20dfcacf6d 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroRegistryImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/MacroRegistryImpl.java @@ -11,6 +11,7 @@ package org.eclipse.che.ide.macro; import com.google.inject.Inject; +import com.google.inject.Singleton; import org.eclipse.che.ide.api.macro.Macro; import org.eclipse.che.ide.api.macro.MacroRegistry; @@ -27,6 +28,7 @@ import java.util.Set; * * @author Artem Zatsarynnyi */ +@Singleton public class MacroRegistryImpl implements MacroRegistry { private final Map macros; diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerHostNameMacro.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerHostNameMacro.java index 5099e2c5bd..af463ad278 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerHostNameMacro.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerHostNameMacro.java @@ -19,6 +19,7 @@ import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.core.model.machine.Server; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.macro.BaseMacro; import org.eclipse.che.ide.api.macro.Macro; import org.eclipse.che.ide.api.macro.MacroRegistry; import org.eclipse.che.ide.api.machine.DevMachine; @@ -27,7 +28,7 @@ import java.util.Map; import java.util.Set; /** - * Provider which is responsible for the retrieving the hostname (reference) of the registered server. + * Macro which is responsible for the retrieving the hostname (reference) of the registered server. *

* Macro provided: ${server.[port].hostname} * @@ -44,16 +45,16 @@ public class ServerHostNameMacro extends AbstractServerMacro { public static final String KEY = "${server.%.hostname}"; @Inject - public ServerHostNameMacro(MacroRegistry providerRegistry, + public ServerHostNameMacro(MacroRegistry macroRegistry, EventBus eventBus, AppContext appContext) { - super(providerRegistry, eventBus, appContext); + super(macroRegistry, eventBus, appContext); } /** {@inheritDoc} */ @Override public Set getMacros(DevMachine devMachine) { - final Set providers = Sets.newHashSet(); + final Set macros = Sets.newHashSet(); for (Map.Entry entry : devMachine.getDescriptor().getRuntime().getServers().entrySet()) { @@ -61,24 +62,24 @@ public class ServerHostNameMacro extends AbstractServerMacro { continue; } - Macro macro = new CustomMacro(KEY.replace("%", entry.getKey()), - entry.getValue().getRef(), - "Returns hostname of a server registered by name"); + Macro macro = new BaseMacro(KEY.replace("%", entry.getKey()), + entry.getValue().getRef(), + "Returns hostname of a server registered by name"); - providers.add(macro); + macros.add(macro); // register port without "/tcp" suffix if (entry.getKey().endsWith("/tcp")) { final String port = entry.getKey().substring(0, entry.getKey().length() - 4); - Macro shortMacro = new CustomMacro(KEY.replace("%", port), - entry.getValue().getRef(), - "Returns hostname of a server registered by name"); + Macro shortMacro = new BaseMacro(KEY.replace("%", port), + entry.getValue().getRef(), + "Returns hostname of a server registered by name"); - providers.add(shortMacro); + macros.add(shortMacro); } } - return providers; + return macros; } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerMacro.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerMacro.java index 5aad566a43..af24be4bc1 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerMacro.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerMacro.java @@ -18,6 +18,7 @@ import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.core.model.machine.Server; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.macro.BaseMacro; import org.eclipse.che.ide.api.macro.Macro; import org.eclipse.che.ide.api.macro.MacroRegistry; import org.eclipse.che.ide.api.machine.DevMachine; @@ -28,7 +29,7 @@ import java.util.Set; import static com.google.common.base.Strings.isNullOrEmpty; /** - * Provider which is responsible for the retrieving the address of the registered server. + * Macro which is responsible for the retrieving the address of the registered server. *

* Macro provided: ${server.[port]} * @@ -45,40 +46,40 @@ public class ServerMacro extends AbstractServerMacro { public static final String KEY = "${server.%}"; @Inject - public ServerMacro(MacroRegistry providerRegistry, + public ServerMacro(MacroRegistry macroRegistry, EventBus eventBus, AppContext appContext) { - super(providerRegistry, eventBus, appContext); + super(macroRegistry, eventBus, appContext); } /** {@inheritDoc} */ @Override public Set getMacros(DevMachine devMachine) { - final Set providers = Sets.newHashSet(); + final Set macros = Sets.newHashSet(); for (Map.Entry entry : devMachine.getDescriptor().getRuntime().getServers().entrySet()) { final String prefix = isNullOrEmpty(entry.getValue().getProtocol()) ? "" : entry.getValue().getProtocol() + "://"; final String value = prefix + entry.getValue().getAddress() + (isNullOrEmpty(prefix) ? "" : "/"); - Macro macro = new CustomMacro(KEY.replace("%", entry.getKey()), - value, - "Returns protocol, hostname and port of an internal server"); + Macro macro = new BaseMacro(KEY.replace("%", entry.getKey()), + value, + "Returns protocol, hostname and port of an internal server"); - providers.add(macro); + macros.add(macro); // register port without "/tcp" suffix if (entry.getKey().endsWith("/tcp")) { final String port = entry.getKey().substring(0, entry.getKey().length() - 4); - Macro shortMacro = new CustomMacro(KEY.replace("%", port), - value, - "Returns protocol, hostname and port of an internal server"); + Macro shortMacro = new BaseMacro(KEY.replace("%", port), + value, + "Returns protocol, hostname and port of an internal server"); - providers.add(shortMacro); + macros.add(shortMacro); } } - return providers; + return macros; } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerPortMacro.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerPortMacro.java index 2c73c5ecb5..204c6aef92 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerPortMacro.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerPortMacro.java @@ -18,6 +18,7 @@ import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.core.model.machine.Server; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.macro.BaseMacro; import org.eclipse.che.ide.api.macro.Macro; import org.eclipse.che.ide.api.macro.MacroRegistry; import org.eclipse.che.ide.api.machine.DevMachine; @@ -26,7 +27,7 @@ import java.util.Map; import java.util.Set; /** - * Provider which is responsible for the retrieving the port of the registered server. + * Macro which is responsible for the retrieving the port of the registered server. *

* Macro provided: ${server.[port].port} * @@ -43,16 +44,16 @@ public class ServerPortMacro extends AbstractServerMacro { public static final String KEY = "${server.%.port}"; @Inject - public ServerPortMacro(MacroRegistry providerRegistry, + public ServerPortMacro(MacroRegistry macroRegistry, EventBus eventBus, AppContext appContext) { - super(providerRegistry, eventBus, appContext); + super(macroRegistry, eventBus, appContext); } /** {@inheritDoc} */ @Override public Set getMacros(DevMachine devMachine) { - final Set providers = Sets.newHashSet(); + final Set macros = Sets.newHashSet(); for (Map.Entry entry : devMachine.getDescriptor().getRuntime().getServers().entrySet()) { @@ -62,24 +63,24 @@ public class ServerPortMacro extends AbstractServerMacro { final String externalPort = entry.getValue().getAddress().split(":")[1]; - Macro macro = new CustomMacro(KEY.replace("%", entry.getKey()), - externalPort, - "Returns port of a server registered by name"); + Macro macro = new BaseMacro(KEY.replace("%", entry.getKey()), + externalPort, + "Returns port of a server registered by name"); - providers.add(macro); + macros.add(macro); // register port without "/tcp" suffix if (entry.getKey().endsWith("/tcp")) { final String port = entry.getKey().substring(0, entry.getKey().length() - 4); - Macro shortMacro = new CustomMacro(KEY.replace("%", port), - externalPort, - "Returns port of a server registered by name"); + Macro shortMacro = new BaseMacro(KEY.replace("%", port), + externalPort, + "Returns port of a server registered by name"); - providers.add(shortMacro); + macros.add(shortMacro); } } - return providers; + return macros; } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerProtocolMacro.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerProtocolMacro.java index 886db4ad0b..c90b4174a5 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerProtocolMacro.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/ServerProtocolMacro.java @@ -19,6 +19,7 @@ import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.core.model.machine.Server; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.macro.BaseMacro; import org.eclipse.che.ide.api.macro.Macro; import org.eclipse.che.ide.api.macro.MacroRegistry; import org.eclipse.che.ide.api.machine.DevMachine; @@ -27,7 +28,7 @@ import java.util.Map; import java.util.Set; /** - * Provider which is responsible for the retrieving the protocol of the registered server. + * Macro which is responsible for the retrieving the protocol of the registered server. *

* Macro provided: ${server.[port].protocol} * @@ -44,16 +45,16 @@ public class ServerProtocolMacro extends AbstractServerMacro { public static final String KEY = "${server.%.protocol}"; @Inject - public ServerProtocolMacro(MacroRegistry providerRegistry, + public ServerProtocolMacro(MacroRegistry macroRegistry, EventBus eventBus, AppContext appContext) { - super(providerRegistry, eventBus, appContext); + super(macroRegistry, eventBus, appContext); } /** {@inheritDoc} */ @Override public Set getMacros(DevMachine devMachine) { - final Set providers = Sets.newHashSet(); + final Set macros = Sets.newHashSet(); for (Map.Entry entry : devMachine.getDescriptor().getRuntime().getServers().entrySet()) { @@ -61,24 +62,24 @@ public class ServerProtocolMacro extends AbstractServerMacro { continue; } - Macro macro = new CustomMacro(KEY.replace("%", entry.getKey()), - entry.getValue().getProtocol(), - "Returns protocol of a server registered by name"); + Macro macro = new BaseMacro(KEY.replace("%", entry.getKey()), + entry.getValue().getProtocol(), + "Returns protocol of a server registered by name"); - providers.add(macro); + macros.add(macro); // register port without "/tcp" suffix if (entry.getKey().endsWith("/tcp")) { final String port = entry.getKey().substring(0, entry.getKey().length() - 4); - Macro shortMacro = new CustomMacro(KEY.replace("%", port), - entry.getValue().getProtocol(), - "Returns protocol of a server registered by name"); + Macro shortMacro = new BaseMacro(KEY.replace("%", port), + entry.getValue().getProtocol(), + "Returns protocol of a server registered by name"); - providers.add(shortMacro); + macros.add(shortMacro); } } - return providers; + return macros; } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooser.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooser.java new file mode 100644 index 0000000000..720341782c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooser.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * 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.macro.chooser; + +import com.google.gwt.view.client.ListDataProvider; +import com.google.inject.Inject; + +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.macro.Macro; +import org.eclipse.che.ide.api.macro.MacroRegistry; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Comparator.comparing; +import static org.eclipse.che.ide.util.StringUtils.containsIgnoreCase; + +/** + * Provides a simple mechanism for the user to choose a {@link Macro}. + * + * @author Artem Zatsarynnyi + * @see #show(MacroChosenCallback) + */ +public class MacroChooser implements MacroChooserView.ActionDelegate { + + private final MacroChooserView view; + private final MacroRegistry macroRegistry; + + /** + * Provides macros list for the view. + * All changes made in provider should be reflected in the view automatically. + */ + private final ListDataProvider macrosProvider; + + private MacroChosenCallback callback; + + @Inject + public MacroChooser(MacroChooserView view, MacroRegistry macroRegistry) { + this.view = view; + this.macroRegistry = macroRegistry; + + macrosProvider = new ListDataProvider<>(); + + view.setDelegate(this); + view.bindMacrosList(macrosProvider); + } + + /** + * Pops up a macro chooser dialog. + * {@link MacroChosenCallback} can be specified to be invoked when the user chose a {@link Macro}. + * + * @param callback + * callback that will be called to report about chosen {@link Macro} + */ + public void show(@Nullable MacroChosenCallback callback) { + this.callback = callback; + + updateMacrosProvider(macroRegistry.getMacros()); + + view.show(); + } + + @Override + public void onMacroChosen(Macro macro) { + view.close(); + + if (callback != null) { + callback.onMacroChosen(macro); + } + } + + @Override + public void onFilterChanged(String filterValue) { + final List macrosList = new ArrayList<>(); + + if (filterValue.isEmpty()) { + macrosList.addAll(macroRegistry.getMacros()); + } else { + // filter works by macro's name and description + for (Macro macro : macroRegistry.getMacros()) { + if (containsIgnoreCase(macro.getName(), filterValue) || containsIgnoreCase(macro.getDescription(), filterValue)) { + macrosList.add(macro); + } + } + } + + updateMacrosProvider(macrosList); + } + + /** Updates internal {@link #macrosProvider} with the given {@code macrosList}. */ + private void updateMacrosProvider(List macrosList) { + macrosProvider.getList().clear(); + macrosProvider.getList().addAll(macrosList); + macrosProvider.getList().sort(comparing(Macro::getName)); + } + + /** Callback to notify when some macro has been chosen. */ + public interface MacroChosenCallback { + + /** Called when macro has been chosen. */ + void onMacroChosen(Macro macro); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooserView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooserView.java new file mode 100644 index 0000000000..f8b8092e6c --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooserView.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * 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.macro.chooser; + +import com.google.gwt.view.client.ListDataProvider; + +import org.eclipse.che.ide.api.macro.Macro; +import org.eclipse.che.ide.api.mvp.View; + +/** + * Defines requirements for the view for the macros explorer. + * + * @author Artem Zatsarynnyi + */ +public interface MacroChooserView extends View { + + /** Show the view. */ + void show(); + + /** Close the view. */ + void close(); + + /** Bind the given {@code dataProvider} to the view. */ + void bindMacrosList(ListDataProvider dataProvider); + + /** The delegate to receive events from this view. */ + interface ActionDelegate { + + /** + * Called when macro has been chosen. + * + * @param macro + * {@link Macro} which has been chosen + */ + void onMacroChosen(Macro macro); + + /** + * Called when filtering macros list is requested. + * + * @param filterValue + * value for filtering the macros list + */ + void onFilterChanged(String filterValue); + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooserViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooserViewImpl.java new file mode 100644 index 0000000000..6d8179cc11 --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooserViewImpl.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * 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.macro.chooser; + +import com.google.gwt.cell.client.TextCell; +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.DoubleClickEvent; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.dom.client.KeyUpEvent; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.cellview.client.CellTable; +import com.google.gwt.user.cellview.client.Column; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.view.client.ListDataProvider; +import com.google.gwt.view.client.SingleSelectionModel; +import com.google.inject.Inject; + +import org.eclipse.che.ide.api.macro.Macro; +import org.eclipse.che.ide.ui.window.Window; + +/** + * The implementation of the {@link MacroChooserView} that shows table for exploring and choosing macros. + * Also provides ability to filter data in the table. + * + * @author Artem Zatsarynnyi + */ +public class MacroChooserViewImpl extends Window implements MacroChooserView { + + private static final MacroChooserViewImplUiBinder UI_BINDER = GWT.create(MacroChooserViewImplUiBinder.class); + + @UiField(provided = true) + CellTable macrosTable; + + @UiField + TextBox filterField; + + private ActionDelegate delegate; + + @Inject + public MacroChooserViewImpl(org.eclipse.che.ide.Resources resources) { + setTitle("Command Macros"); + + initMacrosTable(resources); + + setWidget(UI_BINDER.createAndBindUi(this)); + + filterField.getElement().setAttribute("placeholder", "Search macro"); + + // hide footer + getFooter().removeFromParent(); + } + + private void initMacrosTable(org.eclipse.che.ide.Resources resources) { + macrosTable = new CellTable<>(500, resources); + + final Column nameColumn = new Column(new TextCell()) { + @Override + public String getValue(Macro remote) { + return remote.getName(); + } + }; + + final Column descriptionColumn = new Column(new TextCell()) { + @Override + public String getValue(Macro remote) { + return remote.getDescription(); + } + }; + + macrosTable.addColumn(nameColumn, "Macro"); + macrosTable.setColumnWidth(nameColumn, "40%"); + macrosTable.addColumn(descriptionColumn, "Description"); + macrosTable.setColumnWidth(descriptionColumn, "60%"); + + final SingleSelectionModel selectionModel = new SingleSelectionModel<>(); + + macrosTable.setSelectionModel(selectionModel); + + macrosTable.addDomHandler(event -> { + if (selectionModel.getSelectedObject() != null) { + delegate.onMacroChosen(selectionModel.getSelectedObject()); + } + }, DoubleClickEvent.getType()); + + macrosTable.addDomHandler(event -> { + if (selectionModel.getSelectedObject() != null && + (KeyCodes.KEY_ENTER == event.getNativeKeyCode() || KeyCodes.KEY_MAC_ENTER == event.getNativeKeyCode())) { + + delegate.onMacroChosen(selectionModel.getSelectedObject()); + } + }, KeyUpEvent.getType()); + } + + @Override + public void setDelegate(ActionDelegate delegate) { + this.delegate = delegate; + } + + @Override + public void show() { + super.show(); + + filterField.setValue(""); + filterField.setFocus(true); + } + + @Override + public void close() { + hide(); + } + + @Override + public void bindMacrosList(ListDataProvider dataProvider) { + dataProvider.addDataDisplay(macrosTable); + } + + @UiHandler({"filterField"}) + void onFilterChanged(@SuppressWarnings("UnusedParameters") KeyUpEvent event) { + delegate.onFilterChanged(filterField.getValue()); + } + + interface MacroChooserViewImplUiBinder extends UiBinder { + } +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooserViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooserViewImpl.ui.xml new file mode 100644 index 0000000000..8efaaa06ed --- /dev/null +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/macro/chooser/MacroChooserViewImpl.ui.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MainMenuView.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MainMenuView.java index 8509f87918..88d5fcbfee 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MainMenuView.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MainMenuView.java @@ -16,7 +16,6 @@ import org.eclipse.che.ide.api.mvp.View; /** Main Menu View */ public interface MainMenuView extends View { /** Needs for delegate some function into MainMenu view. */ - public interface ActionDelegate { + interface ActionDelegate { } - -} \ No newline at end of file +} diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MainMenuViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MainMenuViewImpl.java index fb1d063342..e0f518cff3 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MainMenuViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MainMenuViewImpl.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.che.ide.menu; +import elemental.html.DivElement; + import com.google.gwt.dom.client.Element; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; @@ -32,9 +34,11 @@ import org.eclipse.che.ide.api.action.Presentation; import org.eclipse.che.ide.api.action.Separator; import org.eclipse.che.ide.api.keybinding.KeyBindingAgent; import org.eclipse.che.ide.api.parts.PerspectiveManager; +import org.eclipse.che.ide.command.toolbar.CommandToolbarPresenter; import org.eclipse.che.ide.ui.toolbar.CloseMenuHandler; import org.eclipse.che.ide.ui.toolbar.MenuLockLayer; import org.eclipse.che.ide.ui.toolbar.PresentationFactory; +import org.eclipse.che.ide.util.dom.Elements; import java.util.ArrayList; import java.util.HashMap; @@ -57,7 +61,7 @@ public class MainMenuViewImpl extends Composite implements MainMenuView, CloseMe private final PresentationFactory presentationFactory = new PresentationFactory(); /** Working table, cells of which are contains element of Menu. */ - private final MenuBarTable table = new MenuBarTable(); + private final MenuBarTable table = new MenuBarTable(); private final FlowPanel rightPanel = new FlowPanel(); @@ -73,9 +77,8 @@ public class MainMenuViewImpl extends Composite implements MainMenuView, CloseMe /** Store selected Menu Bar item. */ private MenuBarItem selectedMenuBarItem; - private List leftVisibleActions = new ArrayList<>(); - private List menuVisibleActions = new ArrayList<>(); - private List rightVisibleActions = new ArrayList<>(); + private List leftVisibleActions = new ArrayList<>(); + private List menuVisibleActions = new ArrayList<>(); private ActionManager actionManager; private KeyBindingAgent keyBindingAgent; @@ -84,7 +87,8 @@ public class MainMenuViewImpl extends Composite implements MainMenuView, CloseMe public MainMenuViewImpl(MenuResources resources, ActionManager actionManager, KeyBindingAgent keyBindingAgent, - Provider managerProvider) { + Provider managerProvider, + CommandToolbarPresenter toolbarPresenter) { this.resources = resources; this.actionManager = actionManager; this.keyBindingAgent = keyBindingAgent; @@ -92,15 +96,25 @@ public class MainMenuViewImpl extends Composite implements MainMenuView, CloseMe initWidget(rootPanel); disableTextSelection(rootPanel.getElement(), true); + rootPanel.setStyleName(resources.menuCss().menuBar()); + leftPanel.addStyleName(resources.menuCss().leftPanel()); - rootPanel.add(leftPanel); + table.setStyleName(resources.menuCss().menuBarTable()); table.setCellPadding(0); table.setCellSpacing(0); - rootPanel.add(table); + + final DivElement triangleSeparator = Elements.createDivElement(resources.menuCss().triangleSeparator()); + rightPanel.addStyleName(resources.menuCss().rightPanel()); + + rootPanel.add(leftPanel); + rootPanel.add(table); + rootPanel.getElement().appendChild((Element)triangleSeparator); rootPanel.add(rightPanel); + + toolbarPresenter.go(rightPanel::add); } @Override @@ -134,15 +148,6 @@ public class MainMenuViewImpl extends Composite implements MainMenuView, CloseMe } menuVisibleActions = newMenuVisibleActions; } - List newRightVisibleActions = new ArrayList<>(); - expandActionGroup(IdeActions.GROUP_RIGHT_MAIN_MENU, newRightVisibleActions, actionManager); - if (!newRightVisibleActions.equals(rightVisibleActions)) { - rightPanel.clear(); - for (Action action : newRightVisibleActions) { - addToPanel(rightPanel, action, presentationFactory); - } - rightVisibleActions = newRightVisibleActions; - } List newLeftVisibleActions = new ArrayList<>(); expandActionGroup(IdeActions.GROUP_LEFT_MAIN_MENU, newLeftVisibleActions, actionManager); if (!newLeftVisibleActions.equals(leftVisibleActions)) { @@ -259,6 +264,19 @@ public class MainMenuViewImpl extends Composite implements MainMenuView, CloseMe } } + private static class SeparatorItem extends Composite { + public SeparatorItem(String styleName) { + final FlowPanel widget = new FlowPanel(); + widget.addStyleName(styleName); + Element separator = widget.getElement(); + for (int i = 0; i < 6; i++) { + separator.appendChild(DOM.createDiv()); + } + + initWidget(widget); + } + } + /** * This is visual component. * Uses for handling mouse events on MenuBar. @@ -312,17 +330,4 @@ public class MainMenuViewImpl extends Composite implements MainMenuView, CloseMe } } - - private static class SeparatorItem extends Composite { - public SeparatorItem(String styleName) { - final FlowPanel widget = new FlowPanel(); - widget.addStyleName(styleName); - Element separator = widget.getElement(); - for (int i = 0; i < 6; i++) { - separator.appendChild(DOM.createDiv()); - } - - initWidget(widget); - } - } } \ No newline at end of file diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MenuResources.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MenuResources.java index fca84459ce..0468120da0 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MenuResources.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/MenuResources.java @@ -33,11 +33,15 @@ public interface MenuResources extends ClientBundle { String leftPanel(); + String triangleSeparator(); + String rightPanel(); String customComponent(); String panelSeparator(); + + String statusPanel(); } @Source({"menu.css", "org/eclipse/che/ide/api/ui/style.css"}) diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/StatusPanelGroupViewImpl.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/StatusPanelGroupViewImpl.java index 5c3302efe3..caa12c808c 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/StatusPanelGroupViewImpl.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/menu/StatusPanelGroupViewImpl.java @@ -82,6 +82,7 @@ public class StatusPanelGroupViewImpl extends Composite implements StatusPanelGr initWidget(rootPanel); rootPanel.setStyleName(resources.menuCss().menuBar()); + rootPanel.addStyleName(resources.menuCss().statusPanel()); leftPanel.addStyleName(resources.menuCss().leftPanel()); leftPanel.getElement().getStyle().setPropertyPx("marginLeft", 1); @@ -206,7 +207,7 @@ public class StatusPanelGroupViewImpl extends Composite implements StatusPanelGr } private static class SeparatorItem extends Composite { - public SeparatorItem(String styleName) { + SeparatorItem(String styleName) { final FlowPanel widget = new FlowPanel(); widget.addStyleName(styleName); Element separator = widget.getElement(); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/navigation/NavigateToFilePresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/navigation/NavigateToFilePresenter.java index e71469f645..7d4840642e 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/navigation/NavigateToFilePresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/navigation/NavigateToFilePresenter.java @@ -20,7 +20,7 @@ import org.eclipse.che.api.project.shared.dto.ItemReference; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.event.FileEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; import org.eclipse.che.ide.api.resources.File; @@ -53,7 +53,7 @@ import static org.eclipse.che.ide.rest.HTTPHeader.ACCEPT; public class NavigateToFilePresenter implements NavigateToFileView.ActionDelegate, WsAgentStateHandler { private final MessageBusProvider messageBusProvider; - private final EventBus eventBus; + private final EditorAgent editorAgent; private final DtoUnmarshallerFactory dtoUnmarshallerFactory; private final NavigateToFileView view; private final AppContext appContext; @@ -66,12 +66,13 @@ public class NavigateToFilePresenter implements NavigateToFileView.ActionDelegat EventBus eventBus, DtoUnmarshallerFactory dtoUnmarshallerFactory, MessageBusProvider messageBusProvider, - AppContext appContext) { + AppContext appContext, + EditorAgent editorAgent) { this.view = view; this.appContext = appContext; this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; this.messageBusProvider = messageBusProvider; - this.eventBus = eventBus; + this.editorAgent = editorAgent; this.view.setDelegate(this); @@ -101,7 +102,7 @@ public class NavigateToFilePresenter implements NavigateToFileView.ActionDelegat @Override public void apply(Optional optFile) throws OperationException { if (optFile.isPresent()) { - eventBus.fireEvent(FileEvent.createOpenFileEvent(optFile.get())); + editorAgent.openEditor(optFile.get()); } } }); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/AbstractNewResourceAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/AbstractNewResourceAction.java index 9a68d54cad..817654bcc1 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/AbstractNewResourceAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/AbstractNewResourceAction.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.che.ide.newresource; +import com.google.common.base.Optional; +import com.google.inject.Provider; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.promises.client.Operation; @@ -25,7 +27,7 @@ import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.dialogs.InputCallback; import org.eclipse.che.ide.api.dialogs.InputDialog; import org.eclipse.che.ide.api.dialogs.InputValidator; -import org.eclipse.che.ide.api.event.FileEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.File; @@ -52,13 +54,16 @@ import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspect * @author Vlad Zhukovskyi */ public abstract class AbstractNewResourceAction extends AbstractPerspectiveAction { - private final InputValidator fileNameValidator; + protected final String title; protected final DialogFactory dialogFactory; protected final CoreLocalizationConstant coreLocalizationConstant; protected final EventBus eventBus; protected final AppContext appContext; - private final NotificationManager notificationManager; + protected final Provider editorAgentProvider; + + private final InputValidator fileNameValidator; + private final NotificationManager notificationManager; public AbstractNewResourceAction(String title, String description, @@ -67,13 +72,15 @@ public abstract class AbstractNewResourceAction extends AbstractPerspectiveActio CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(singletonList(PROJECT_PERSPECTIVE_ID), title, description, null, svgIcon); this.dialogFactory = dialogFactory; this.coreLocalizationConstant = coreLocalizationConstant; this.eventBus = eventBus; this.appContext = appContext; this.notificationManager = notificationManager; + this.editorAgentProvider = editorAgentProvider; this.fileNameValidator = new FileNameValidator(); this.title = title; } @@ -108,7 +115,7 @@ public abstract class AbstractNewResourceAction extends AbstractPerspectiveActio ((Container)resource).newFile(name, getDefaultContent()).then(new Operation() { @Override public void apply(File newFile) throws OperationException { - eventBus.fireEvent(FileEvent.createOpenFileEvent(newFile)); + editorAgentProvider.get().openEditor(newFile); eventBus.fireEvent(new RevealResourceEvent(newFile)); } }).catchError(new Operation() { diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFileAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFileAction.java index af7ece71fd..839baac487 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFileAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFileAction.java @@ -14,9 +14,11 @@ import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.Resources; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; @@ -33,9 +35,10 @@ public class NewFileAction extends AbstractNewResourceAction { DialogFactory dialogFactory, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.actionNewFileTitle(), localizationConstant.actionNewFileDescription(), - resources.defaultFile(), dialogFactory, localizationConstant, eventBus, appContext, notificationManager); + resources.defaultFile(), dialogFactory, localizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFolderAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFolderAction.java index bb78075d3d..9157eea908 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFolderAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/newresource/NewFolderAction.java @@ -11,6 +11,7 @@ package org.eclipse.che.ide.newresource; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; @@ -26,6 +27,7 @@ import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.dialogs.InputCallback; import org.eclipse.che.ide.api.dialogs.InputDialog; import org.eclipse.che.ide.api.dialogs.InputValidator; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.Folder; @@ -52,10 +54,11 @@ public class NewFolderAction extends AbstractNewResourceAction { DialogFactory dialogFactory, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.actionNewFolderTitle(), localizationConstant.actionNewFolderDescription(), - resources.defaultFolder(), dialogFactory, localizationConstant, eventBus, appContext, notificationManager); + resources.defaultFolder(), dialogFactory, localizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); this.folderNameValidator = new FolderNameValidator(); } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenter.java index 40d054b1b2..758e02fe81 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenter.java @@ -24,10 +24,10 @@ import org.eclipse.che.ide.api.action.ActionManager; import org.eclipse.che.ide.api.action.Presentation; import org.eclipse.che.ide.api.constraints.Constraints; import org.eclipse.che.ide.api.editor.AbstractEditorPresenter; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.EditorPartPresenter; import org.eclipse.che.ide.api.editor.EditorWithErrors; import org.eclipse.che.ide.api.editor.EditorWithErrors.EditorState; -import org.eclipse.che.ide.api.event.FileEvent; import org.eclipse.che.ide.api.parts.EditorPartStack; import org.eclipse.che.ide.api.parts.EditorTab; import org.eclipse.che.ide.api.parts.PartPresenter; @@ -92,6 +92,7 @@ public class EditorPartStackPresenter extends PartStackPresenter implements Edit private final ActionManager actionManager; private final ClosePaneAction closePaneAction; private final CloseAllTabsPaneAction closeAllTabsPaneAction; + private final EditorAgent editorAgent; private final Map items; //this list need to save order of added parts @@ -118,7 +119,8 @@ public class EditorPartStackPresenter extends PartStackPresenter implements Edit EditorPaneMenu editorPaneMenu, ActionManager actionManager, ClosePaneAction closePaneAction, - CloseAllTabsPaneAction closeAllTabsPaneAction) { + CloseAllTabsPaneAction closeAllTabsPaneAction, + EditorAgent editorAgent) { super(eventBus, partMenu, partStackEventHandler, tabItemFactory, partsComparator, view, null); this.editorPaneMenuItemFactory = editorPaneMenuItemFactory; this.eventBus = eventBus; @@ -127,6 +129,7 @@ public class EditorPartStackPresenter extends PartStackPresenter implements Edit this.actionManager = actionManager; this.closePaneAction = closePaneAction; this.closeAllTabsPaneAction = closeAllTabsPaneAction; + this.editorAgent = editorAgent; this.view.setDelegate(this); this.items = new HashMap<>(); this.partsOrder = new LinkedList<>(); @@ -341,7 +344,7 @@ public class EditorPartStackPresenter extends PartStackPresenter implements Edit Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { @Override public void execute() { - eventBus.fireEvent(FileEvent.createCloseFileEvent((EditorTab)tabItem)); + editorAgent.closeEditor(((EditorTab)tabItem).getRelativeEditorPart()); } }); } @@ -502,7 +505,7 @@ public class EditorPartStackPresenter extends PartStackPresenter implements Edit final TabItem tabItem = item.getData(); if (tabItem instanceof EditorTab) { EditorTab editorTab = (EditorTab)tabItem; - eventBus.fireEvent(FileEvent.createCloseFileEvent(editorTab)); + editorAgent.closeEditor(editorTab.getRelativeEditorPart()); } } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/actions/CloseAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/actions/CloseAction.java index d125383f44..70407ff51a 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/actions/CloseAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/actions/CloseAction.java @@ -17,8 +17,9 @@ import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.editor.EditorAgent; -import org.eclipse.che.ide.api.event.FileEvent; +import org.eclipse.che.ide.api.editor.EditorPartPresenter; import org.eclipse.che.ide.api.parts.EditorTab; +import org.eclipse.che.ide.api.resources.VirtualFile; /** * Performs closing selected editor. @@ -43,6 +44,10 @@ public class CloseAction extends EditorAbstractAction { if (editorTab == null) { return; } - eventBus.fireEvent(FileEvent.createCloseFileEvent(editorTab)); + + final VirtualFile editorFile = getEditorFile(e); + final EditorPartPresenter openedEditor = editorAgent.getOpenedEditor(editorFile.getLocation()); + + editorAgent.closeEditor(openedEditor); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/actions/ReopenClosedFileAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/actions/ReopenClosedFileAction.java index 4abc23dfb5..3e38fb2aa4 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/actions/ReopenClosedFileAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/actions/ReopenClosedFileAction.java @@ -18,7 +18,6 @@ import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.EditorPartPresenter; -import org.eclipse.che.ide.api.event.FileEvent; import org.eclipse.che.ide.api.parts.EditorPartStack; import org.eclipse.che.ide.api.resources.VirtualFile; @@ -56,6 +55,6 @@ public class ReopenClosedFileAction extends EditorAbstractAction { EditorPartPresenter lastClosed = currentPartStack.getLastClosed(); VirtualFile file = lastClosed.getEditorInput().getFile(); - eventBus.fireEvent(FileEvent.createOpenFileEvent(file)); + editorAgent.openEditor(file); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/recent/RecentFileAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/recent/RecentFileAction.java index c02ae67e46..e65268ca03 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/recent/RecentFileAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/editor/recent/RecentFileAction.java @@ -12,11 +12,10 @@ package org.eclipse.che.ide.part.editor.recent; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; -import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.api.action.AbstractPerspectiveAction; import org.eclipse.che.ide.api.action.ActionEvent; -import org.eclipse.che.ide.api.event.FileEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.resources.File; import javax.validation.constraints.NotNull; @@ -32,15 +31,14 @@ import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspect */ public class RecentFileAction extends AbstractPerspectiveAction { - private final File file; - private final EventBus eventBus; + private final File file; + private final EditorAgent editorAgent; @Inject - public RecentFileAction(@Assisted File file, - EventBus eventBus) { + public RecentFileAction(@Assisted File file, EditorAgent editorAgent) { super(singletonList(PROJECT_PERSPECTIVE_ID), getShortPath(file.getLocation().toString()), null, null, null); this.file = file; - this.eventBus = eventBus; + this.editorAgent = editorAgent; } /** {@inheritDoc} */ @@ -52,7 +50,7 @@ public class RecentFileAction extends AbstractPerspectiveAction { /** {@inheritDoc} */ @Override public void actionPerformed(ActionEvent e) { - eventBus.fireEvent(FileEvent.createOpenFileEvent(file)); + editorAgent.openEditor(file); } /** diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidget.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidget.java index ff48b097fb..6abb09456e 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidget.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidget.java @@ -29,11 +29,10 @@ import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import com.google.web.bindery.event.shared.EventBus; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.EditorPartPresenter; import org.eclipse.che.ide.api.event.FileEvent; import org.eclipse.che.ide.api.event.FileEvent.FileEventHandler; -import org.eclipse.che.ide.api.filetypes.FileType; -import org.eclipse.che.ide.api.filetypes.FileTypeRegistry; import org.eclipse.che.ide.api.parts.EditorPartStack; import org.eclipse.che.ide.api.parts.EditorTab; import org.eclipse.che.ide.api.parts.PartPresenter; @@ -86,12 +85,11 @@ public class EditorTabWidget extends Composite implements EditorTab, ContextMenu @UiField(provided = true) final PartStackUIResources resources; - private final EventBus eventBus; private final EditorTabContextMenuFactory editorTabContextMenu; - private final FileTypeRegistry fileTypeRegistry; private final String id; private final EditorPartPresenter relatedEditorPart; private final EditorPartStack relatedEditorPartStack; + private final EditorAgent editorAgent; private ActionDelegate delegate; private SVGResource icon; @@ -99,17 +97,16 @@ public class EditorTabWidget extends Composite implements EditorTab, ContextMenu private VirtualFile file; @Inject - public EditorTabWidget(@Assisted EditorPartPresenter relatedEditorPart, + public EditorTabWidget(@Assisted final EditorPartPresenter relatedEditorPart, @Assisted EditorPartStack relatedEditorPartStack, PartStackUIResources resources, EditorTabContextMenuFactory editorTabContextMenu, final EventBus eventBus, - FileTypeRegistry fileTypeRegistry) { + final EditorAgent editorAgent) { this.resources = resources; - this.eventBus = eventBus; - this.fileTypeRegistry = fileTypeRegistry; this.relatedEditorPart = relatedEditorPart; this.relatedEditorPartStack = relatedEditorPartStack; + this.editorAgent = editorAgent; initWidget(UI_BINDER.createAndBindUi(this)); @@ -131,7 +128,7 @@ public class EditorTabWidget extends Composite implements EditorTab, ContextMenu closeButton.addDomHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - eventBus.fireEvent(FileEvent.createCloseFileEvent(EditorTabWidget.this)); + editorAgent.closeEditor(relatedEditorPart); } }, ClickEvent.getType()); } @@ -162,9 +159,9 @@ public class EditorTabWidget extends Composite implements EditorTab, ContextMenu title.setText(part.getTitle()); if (part instanceof EditorPartPresenter) { - file = ((EditorPartPresenter)part).getEditorInput().getFile(); - FileType fileType = fileTypeRegistry.getFileTypeByFile(file); - icon = fileType.getImage(); + final EditorPartPresenter editorPartPresenter = (EditorPartPresenter)part; + file = editorPartPresenter.getEditorInput().getFile(); + icon = editorPartPresenter.getTitleImage(); iconPanel.setWidget(getIcon()); } } @@ -220,7 +217,7 @@ public class EditorTabWidget extends Composite implements EditorTab, ContextMenu if (NativeEvent.BUTTON_LEFT == event.getNativeButton()) { delegate.onTabClicked(this); } else if (NativeEvent.BUTTON_MIDDLE == event.getNativeButton()) { - eventBus.fireEvent(FileEvent.createCloseFileEvent(this)); + editorAgent.closeEditor(relatedEditorPart); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/StyleInjector.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/StyleInjector.java index 93d234a61d..8c7a51201c 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/StyleInjector.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/preferences/StyleInjector.java @@ -10,10 +10,11 @@ *******************************************************************************/ package org.eclipse.che.ide.preferences; -import org.eclipse.che.ide.Resources; import com.google.inject.Inject; import com.google.inject.Singleton; +import org.eclipse.che.ide.Resources; + /** @author Evgen Vidolob */ @Singleton public class StyleInjector { @@ -37,5 +38,11 @@ public class StyleInjector { resources.defaultCategoriesListCss().ensureInjected(); resources.Css().ensureInjected(); resources.menuCss().ensureInjected(); + + resources.commandsExplorerCss().ensureInjected(); + resources.commandsPaletteCss().ensureInjected(); + resources.commandToolbarCss().ensureInjected(); + resources.editorCss().ensureInjected(); + resources.commandTypeChooserCss().ensureInjected(); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizard.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizard.java index 8416607b4c..8a4fe051f3 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizard.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizard.java @@ -10,19 +10,16 @@ *******************************************************************************/ package org.eclipse.che.ide.projecttype.wizard; -import com.google.common.base.Optional; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import org.eclipse.che.api.machine.shared.dto.CommandDto; -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.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandImpl.ApplicableContext; import org.eclipse.che.ide.api.command.CommandManager; import org.eclipse.che.ide.api.project.MutableProjectConfig; import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardMode; @@ -52,7 +49,7 @@ import static org.eclipse.che.ide.api.resources.Resource.PROJECT; * @author Valeriy Svydenko */ public class ProjectWizard extends AbstractWizard { - + private final static String PROJECT_PATH_MACRO_REGEX = "\\$\\{current.project.path\\}"; private final ProjectWizardMode mode; @@ -73,7 +70,6 @@ public class ProjectWizard extends AbstractWizard { context.put(PROJECT_NAME_KEY, dataObject.getName()); } - /** {@inheritDoc} */ @Override public void complete(@NotNull final CompleteCallback callback) { if (mode == CREATE) { @@ -84,97 +80,77 @@ public class ProjectWizard extends AbstractWizard { .then(onComplete(callback)) .catchError(onFailure(callback)); } else if (mode == UPDATE) { - appContext.getWorkspaceRoot().getContainer(Path.valueOf(dataObject.getPath())).then(new Operation>() { - @Override - public void apply(Optional optContainer) throws OperationException { - checkState(optContainer.isPresent(), "Failed to update non existed path"); + appContext.getWorkspaceRoot() + .getContainer(Path.valueOf(dataObject.getPath())) + .then(optContainer -> { + checkState(optContainer.isPresent(), "Failed to update non existed path"); - final Container container = optContainer.get(); - if (container.getResourceType() == PROJECT) { - ((Project)container).update() - .withBody(dataObject) - .send() - .then(onComplete(callback)) - .catchError(onFailure(callback)); - } else if (container.getResourceType() == FOLDER) { - ((Folder)container).toProject() - .withBody(dataObject) - .send() - .then(onComplete(callback)) - .catchError(onFailure(callback)); - } - } - }); + final Container container = optContainer.get(); + if (container.getResourceType() == PROJECT) { + ((Project)container).update() + .withBody(dataObject) + .send() + .then(onComplete(callback)) + .catchError(onFailure(callback)); + } else if (container.getResourceType() == FOLDER) { + ((Folder)container).toProject() + .withBody(dataObject) + .send() + .then(onComplete(callback)) + .catchError(onFailure(callback)); + } + }); } else if (mode == IMPORT) { appContext.getWorkspaceRoot() .newProject() .withBody(dataObject) .send() - .thenPromise(new Function>() { - @Override - public Promise apply(Project project) throws FunctionException { - return project.update().withBody(dataObject).send(); - } - }) + .thenPromise(project -> project.update().withBody(dataObject).send()) .then(addCommands(callback)) .catchError(onFailure(callback)); } } - private Operation addCommands(final CompleteCallback callback) { - return new Operation() { - @Override - public void apply(final Project project) throws OperationException { - Promise chain = null; - for (final CommandDto command : dataObject.getCommands()) { - if (chain == null) { - chain = addCommand(project, command); - } else { - chain = chain.thenPromise(new Function>() { - @Override - public Promise apply(CommandImpl ignored) throws FunctionException { - return addCommand(project, command); - } - }); - } - } - + private Operation addCommands(CompleteCallback callback) { + return project -> { + Promise chain = null; + for (final CommandDto command : dataObject.getCommands()) { if (chain == null) { - callback.onCompleted(); + chain = addCommand(project, command); } else { - chain.then(new Operation() { - @Override - public void apply(CommandImpl ignored) throws OperationException { - callback.onCompleted(); - } - }).catchError(onFailure(callback)); + chain = chain.thenPromise(ignored -> addCommand(project, command)); } } + + if (chain == null) { + callback.onCompleted(); + } else { + chain.then(ignored -> { + callback.onCompleted(); + }).catchError(onFailure(callback)); + } }; } - private Promise addCommand(Project project, CommandDto command) { - String name = project.getName() + ": " + command.getName(); - String projectPath = appContext.getProjectsRoot().append(project.getPath()).toString(); - String commandLine = command.getCommandLine().replaceAll(PROJECT_PATH_MACRO_REGEX, projectPath); - return commandManager.create(name, commandLine, command.getType(), command.getAttributes()); + private Promise addCommand(Project project, CommandDto commandDto) { + final String name = project.getName() + ": " + commandDto.getName(); + final String absoluteProjectPath = appContext.getProjectsRoot().append(project.getPath()).toString(); + final String commandLine = commandDto.getCommandLine().replaceAll(PROJECT_PATH_MACRO_REGEX, absoluteProjectPath); + + final CommandImpl command = new CommandImpl(name, + commandLine, + commandDto.getType(), + commandDto.getAttributes(), + new ApplicableContext(project.getPath())); + + return commandManager.createCommand(command); } private Operation onComplete(final CompleteCallback callback) { - return new Operation() { - @Override - public void apply(Project ignored) throws OperationException { - callback.onCompleted(); - } - }; + return ignored -> callback.onCompleted(); } private Operation onFailure(final CompleteCallback callback) { - return new Operation() { - @Override - public void apply(PromiseError error) throws OperationException { - callback.onFailure(error.getCause()); - } - }; + return error -> callback.onFailure(error.getCause()); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/tree/FileNode.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/tree/FileNode.java index eef7bd1087..0164e445fa 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/tree/FileNode.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/resources/tree/FileNode.java @@ -17,7 +17,7 @@ import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.api.data.tree.HasAction; import org.eclipse.che.ide.api.data.tree.settings.NodeSettings; -import org.eclipse.che.ide.api.event.FileEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.resources.File; import org.eclipse.che.ide.project.node.icon.NodeIconProvider; import org.eclipse.che.ide.project.shared.NodesResources; @@ -34,8 +34,8 @@ import java.util.Set; */ @Beta public class FileNode extends ResourceNode implements HasAction { - protected final EventBus eventBus; protected final Set nodeIconProvider; + private final EditorAgent editorAgent; @Inject public FileNode(@Assisted File resource, @@ -43,15 +43,16 @@ public class FileNode extends ResourceNode implements HasAction { NodeFactory nodeFactory, NodesResources nodesResources, EventBus eventBus, - Set nodeIconProvider) { + Set nodeIconProvider, + EditorAgent editorAgent) { super(resource, nodeSettings, nodesResources, nodeFactory, eventBus, nodeIconProvider); - this.eventBus = eventBus; this.nodeIconProvider = nodeIconProvider; + this.editorAgent = editorAgent; } /** {@inheritDoc} */ @Override public void actionPerformed() { - eventBus.fireEvent(FileEvent.createOpenFileEvent(getData())); + editorAgent.openEditor(getData()); } } diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/file/UploadFilePresenter.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/file/UploadFilePresenter.java index 2926ec97f2..2b5841222b 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/file/UploadFilePresenter.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/upload/file/UploadFilePresenter.java @@ -19,10 +19,10 @@ import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.ide.CoreLocalizationConstant; -import org.eclipse.che.ide.api.event.FileEvent; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.Notification; import org.eclipse.che.ide.api.notification.NotificationListener; -import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.notification.StatusNotification; import org.eclipse.che.ide.api.resources.Container; @@ -31,7 +31,6 @@ import org.eclipse.che.ide.resource.Path; import org.eclipse.che.ide.resources.reveal.RevealResourceEvent; import static com.google.common.base.Strings.isNullOrEmpty; - import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.FLOAT_MODE; /** @@ -47,6 +46,7 @@ public class UploadFilePresenter implements UploadFileView.ActionDelegate { private final AppContext appContext; private final EventBus eventBus; private final NotificationManager notificationManager; + private final EditorAgent editorAgent; private final CoreLocalizationConstant locale; private Container container; @@ -55,12 +55,14 @@ public class UploadFilePresenter implements UploadFileView.ActionDelegate { AppContext appContext, EventBus eventBus, NotificationManager notificationManager, - CoreLocalizationConstant locale) { + CoreLocalizationConstant locale, + EditorAgent editorAgent) { this.appContext = appContext; this.eventBus = eventBus; this.view = view; this.locale = locale; this.notificationManager = notificationManager; + this.editorAgent = editorAgent; this.view.setDelegate(this); this.view.setEnabledUploadButton(false); @@ -102,7 +104,7 @@ public class UploadFilePresenter implements UploadFileView.ActionDelegate { @Override public void onClick(Notification notification) { if (!clicked) { - eventBus.fireEvent(FileEvent.createOpenFileEvent(file.get())); + editorAgent.openEditor(file.get()); clicked = true; notification.setListener(null); notification.setContent(""); diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/WorkspaceViewImpl.ui.xml b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/WorkspaceViewImpl.ui.xml index 78c3da979f..d54e9a073c 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/WorkspaceViewImpl.ui.xml +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/workspace/WorkspaceViewImpl.ui.xml @@ -44,34 +44,27 @@ - - + - - - - - - - - - - - - + + + + + + diff --git a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/xml/NewXmlFileAction.java b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/xml/NewXmlFileAction.java index 8153de4c29..9dccb83160 100644 --- a/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/xml/NewXmlFileAction.java +++ b/ide/che-core-ide-app/src/main/java/org/eclipse/che/ide/xml/NewXmlFileAction.java @@ -14,10 +14,12 @@ import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.Resources; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; @@ -38,10 +40,11 @@ public class NewXmlFileAction extends AbstractNewResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.actionNewXmlFileTitle(), localizationConstant.actionNewXmlFileDescription(), - resources.defaultFile(), dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + resources.defaultFile(), dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); } @Override diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/Core.css b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/Core.css index eec2c3e02e..6afef68e43 100644 --- a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/Core.css +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/Core.css @@ -518,6 +518,24 @@ a { background-color: keyboardSelectionBackgroundColor; } +.gwt-DisclosurePanel .header td { + color: mainFontColor; + font-size: 11px; + font-weight: bold; + font-family: textFieldFontFamily; +} + +.gwt-DisclosurePanel .header td img { + width: 12px; + height: 12px; + margin-top: 5px; +} + +.gwt-DisclosurePanel .content { + margin-left: 24px; + border: none; +} + .editorFullScreen { fill: #e7e7e7; width: 15px; @@ -779,3 +797,8 @@ a { ::-webkit-scrollbar-thumb:hover { background-color: scrollbarHoverBackgroundColor; } + +.codeassistant-highlight { + color: completionPopupItemHighlightTextColor; +} + diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/CoreLocalizationConstant.properties b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/CoreLocalizationConstant.properties index d7216da0bb..5a61082e84 100644 --- a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/CoreLocalizationConstant.properties +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/CoreLocalizationConstant.properties @@ -35,8 +35,8 @@ renameProjectDialogTitle = Rename project \"{0}\" renameDialogNewNameLabel = New name: ############## Project Explorer ###################### -projectExplorer.button.title=Explorer -projectExplorer.titleBar.text=Project Explorer +projectExplorer.button.title=Projects +projectExplorer.titleBar.text=Projects Explorer ############### Navigate To File ############### action.navigateToFile.text = Navigate to File diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/editor/EditorMessages.properties b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/editor/EditorMessages.properties new file mode 100644 index 0000000000..aae523f6aa --- /dev/null +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/editor/EditorMessages.properties @@ -0,0 +1,24 @@ +# +# 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 +# + +editor.description=Che Command Editor +editor.message.unable_save=Unable to save command +button.test.text=RUN +button.save.text=SAVE +button.cancel.text=CANCEL +page.name.title=Name +page.command_line.title=Command Line +page.goal.title=Goal +page.projects.title=Apply to +page.projects.table.header.project.label=Project +page.projects.table.header.applicable.label=Applicable +page.with_text_editor.macros=Macros +page.preview_url.title=Preview URL diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/editor/styles.css b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/editor/styles.css new file mode 100644 index 0000000000..9a8c767d2d --- /dev/null +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/editor/styles.css @@ -0,0 +1,21 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +.sectionLabel { + margin: 8px 0 8px 20px; + color: mainFontColor; + font-size: 11px; + font-weight: bold; + font-family: textFieldFontFamily; +} + +.section { + margin: 8px 0 20px 20px !important; +} diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/execute/ExecMessages.properties b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/execute/ExecMessages.properties new file mode 100644 index 0000000000..7fea81b51b --- /dev/null +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/execute/ExecMessages.properties @@ -0,0 +1,12 @@ +# +# 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 +# + +action.commands.title=Commands diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/ExplorerMessages.properties b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/ExplorerMessages.properties new file mode 100644 index 0000000000..1a3663871f --- /dev/null +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/ExplorerMessages.properties @@ -0,0 +1,19 @@ +# +# 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 +# + +explorer.part.title=Commands +explorer.part.tooltip=Manage commands +explorer.view.title=Commands Explorer +explorer.message.unable_create=Unable to create command +explorer.message.unable_duplicate=Unable to duplicate command +explorer.message.unable_remove=Unable to remove command +explorer.remove_confirmation.title=Remove +explorer.remove_confirmation.message=Remove command \"{0}\" diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/add-command-button.svg b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/add-command-button.svg similarity index 100% rename from plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/add-command-button.svg rename to ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/add-command-button.svg diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/duplicate-command-button.svg b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/duplicate-command-button.svg similarity index 100% rename from plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/duplicate-command-button.svg rename to ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/duplicate-command-button.svg diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/explorer-part.svg b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/explorer-part.svg new file mode 100644 index 0000000000..cc591560b6 --- /dev/null +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/explorer-part.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/remove-command-button.svg b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/remove-command-button.svg similarity index 100% rename from plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/remove-command-button.svg rename to ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/remove-command-button.svg diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/styles.css b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/styles.css new file mode 100644 index 0000000000..bcd0b87529 --- /dev/null +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/explorer/styles.css @@ -0,0 +1,76 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +@eval categoryHeaderButtonHoverColor org.eclipse.che.ide.api.theme.Style.theme.categoryHeaderButtonHoverColor(); +@eval categoryHeaderButtonColor org.eclipse.che.ide.api.theme.Style.theme.categoryHeaderButtonColor(); +@eval categoryElementButtonHoverColor org.eclipse.che.ide.api.theme.Style.theme.categoryElementButtonHoverColor(); +@eval categoryElementButtonColor org.eclipse.che.ide.api.theme.Style.theme.categoryElementButtonColor(); +@eval categorySelectElementBackgroundColor org.eclipse.che.ide.api.theme.Style.theme.categorySelectElementBackgroundColor(); +@eval categorySelectElementColor org.eclipse.che.ide.api.theme.Style.theme.categorySelectElementColor(); + +.commandGoalNode span:last-child, +.commandNode .commandNodeButtonsPanel > span { + display: inline-block; + height: 100%; + width: 25px; + float: right; + cursor: pointer; + text-align: center; +} + +.commandNodeText { + max-width: 65%; +} + +.commandGoalNode span:last-child svg, +.commandNode .commandNodeButtonsPanel svg { + width: 12px; + height: 12px; + vertical-align: middle; + fill: categoryHeaderButtonColor; + stroke: categoryHeaderButtonColor; +} + +.commandGoalNode span:last-child:hover svg, +.commandNode .commandNodeButtonsPanel span:hover > svg { + fill: categoryHeaderButtonHoverColor; + stroke: categoryHeaderButtonHoverColor; +} + +.commandNode { + padding-right: 1px; + line-height: 18px; + overflow: hidden; +} + +div.commandNode[selected] { + background: categorySelectElementBackgroundColor; + color: categorySelectElementColor; +} + +div.commandNode[selected] .commandNodeButtonsPanel { + display: inline; +} + +div.commandNode[selected] .commandNodeButtonsPanel svg { + opacity: 1; + fill: categoryElementButtonColor; + stroke: categoryElementButtonColor; +} + +div.commandNode[selected] .commandNodeButtonsPanel span:hover > svg { + fill: categoryElementButtonHoverColor; + stroke: categoryElementButtonHoverColor; +} + +.commandNodeButtonsPanel { + display: none; + float: right; +} diff --git a/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/goal/GoalMessages.properties b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/goal/GoalMessages.properties new file mode 100644 index 0000000000..02f26a0ab8 --- /dev/null +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/goal/GoalMessages.properties @@ -0,0 +1,12 @@ +# +# 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 +# + +message.goal_already_registered=Command goal with ID {0} is already registered diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/find-icon.svg b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/magnifier.svg similarity index 86% rename from plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/find-icon.svg rename to ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/magnifier.svg index 60c5b421a1..69db965080 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/find-icon.svg +++ b/ide/che-core-ide-app/src/main/resources/org/eclipse/che/ide/command/magnifier.svg @@ -1,4 +1,4 @@ - + + editorProvider; + + @InjectMocks + private CommandEditorProvider provider; + + @Test + public void shouldReturnId() throws Exception { + assertThat(provider.getId()).isNotNull(); + assertThat(provider.getId()).isNotEmpty(); + } + + @Test + public void shouldReturnDescriptions() throws Exception { + provider.getDescription(); + + verify(editorMessages).editorDescription(); + } + + @Test + public void shouldReturnEditor() throws Exception { + provider.getEditor(); + + verify(editorProvider).get(); + } +} diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/CommandEditorTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/CommandEditorTest.java new file mode 100644 index 0000000000..55c6af3376 --- /dev/null +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/CommandEditorTest.java @@ -0,0 +1,221 @@ +/******************************************************************************* + * 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.gwt.user.client.ui.AcceptsOneWidget; +import com.google.gwtmockito.GwtMockitoTestRunner; + +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.CoreLocalizationConstant; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandImpl.ApplicableContext; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.editor.EditorInput; +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.command.editor.page.CommandEditorPage.DirtyStateListener; +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.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.EMERGE_MODE; +import static org.eclipse.che.ide.api.notification.StatusNotification.Status.WARNING; +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** Tests for {@link CommandEditor}. */ +@RunWith(GwtMockitoTestRunner.class) +public class CommandEditorTest { + + private static final String EDITED_COMMAND_NAME = "build"; + + @Mock + private CommandEditorView view; + @Mock + private WorkspaceAgent workspaceAgent; + @Mock + private IconRegistry iconRegistry; + @Mock + private CommandManager commandManager; + @Mock + private NamePage namePage; + @Mock + private CommandLinePage commandLinePage; + @Mock + private GoalPage goalPage; + @Mock + private ProjectsPage projectsPage; + @Mock + private PreviewUrlPage previewUrlPage; + @Mock + private NotificationManager notificationManager; + @Mock + private DialogFactory dialogFactory; + @Mock + private EditorAgent editorAgent; + @Mock + private CoreLocalizationConstant localizationConstants; + @Mock + private EditorMessages editorMessages; + @Mock + private NodeFactory nodeFactory; + + @InjectMocks + private CommandEditor editor; + + @Mock + private EditorInput editorInput; + @Mock + private CommandFileNode editedCommandFile; + @Mock + private CommandImpl editedCommand; + @Mock + private EditorAgent.OpenEditorCallback openEditorCallback; + + @Mock + private Promise commandPromise; + @Captor + private ArgumentCaptor> operationCaptor; + @Captor + private ArgumentCaptor> errorOperationCaptor; + + @Before + public void setUp() throws Exception { + when(editedCommand.getName()).thenReturn(EDITED_COMMAND_NAME); + when(editedCommand.getApplicableContext()).thenReturn(mock(ApplicableContext.class)); + when(editedCommandFile.getData()).thenReturn(editedCommand); + when(editorInput.getFile()).thenReturn(editedCommandFile); + + editor.init(editorInput, openEditorCallback); + } + + @Test + public void shouldBeInitialized() throws Exception { + verify(view).setDelegate(editor); + verify(commandManager).addCommandChangedListener(editor); + + verify(commandLinePage).setDirtyStateListener(any(DirtyStateListener.class)); + verify(goalPage).setDirtyStateListener(any(DirtyStateListener.class)); + verify(projectsPage).setDirtyStateListener(any(DirtyStateListener.class)); + verify(previewUrlPage).setDirtyStateListener(any(DirtyStateListener.class)); + + verify(commandLinePage).edit(editor.editedCommand); + verify(goalPage).edit(editor.editedCommand); + verify(projectsPage).edit(editor.editedCommand); + verify(previewUrlPage).edit(editor.editedCommand); + } + + @Test + public void shouldExposeViewOnGo() throws Exception { + AcceptsOneWidget container = mock(AcceptsOneWidget.class); + editor.go(container); + + verify(container).setWidget(view); + } + + @Test + public void shouldReturnTitle() throws Exception { + editor.getTitle(); + + verify(editorInput).getName(); + } + + @Test + public void shouldReturnTitleTooltip() throws Exception { + editor.getTitleToolTip(); + + verify(editorInput).getName(); + } + + @Test + public void shouldReturnView() throws Exception { + assertEquals(view, editor.getView()); + } + + @Test + public void shouldSaveCommand() throws Exception { + when(commandManager.updateCommand(anyString(), eq(editor.editedCommand))).thenReturn(commandPromise); + when(commandPromise.then(any(Operation.class))).thenReturn(commandPromise); + + editor.doSave(); + + verify(commandManager).updateCommand(anyString(), eq(editor.editedCommand)); + } + + @Test(expected = OperationException.class) + public void shouldShowNotificationWhenFailedToSaveCommand() throws Exception { + when(commandManager.updateCommand(anyString(), eq(editor.editedCommand))).thenReturn(commandPromise); + when(commandPromise.then(any(Operation.class))).thenReturn(commandPromise); + + editor.doSave(); + + verify(commandPromise).catchError(errorOperationCaptor.capture()); + errorOperationCaptor.getValue().apply(mock(PromiseError.class)); + verify(editorMessages).editorMessageUnableToSave(); + verify(notificationManager).notify(anyString(), anyString(), WARNING, EMERGE_MODE); + } + + @Test + public void shouldCloseEditor() throws Exception { + editor.close(true); + + verify(workspaceAgent).removePart(editor); + } + + @Test + public void shouldCloseEditorWhenCancellingRequested() throws Exception { + editor.onCommandCancel(); + + verify(workspaceAgent).removePart(editor); + } + + @Test + public void shouldSaveCommandWhenSavingRequested() throws Exception { + when(commandManager.updateCommand(anyString(), eq(editor.editedCommand))).thenReturn(commandPromise); + when(commandPromise.then(any(Operation.class))).thenReturn(commandPromise); + + editor.onCommandSave(); + + verify(commandManager).updateCommand(anyString(), eq(editor.editedCommand)); + } + + @Test + public void shouldCloseEditorWhenEditedCommandRemoved() throws Exception { + CommandImpl removedCommand = mock(CommandImpl.class); + when(removedCommand.getName()).thenReturn(EDITED_COMMAND_NAME); + + editor.onCommandRemoved(removedCommand); + + verify(editorAgent).closeEditor(editor); + } +} diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageTest.java new file mode 100644 index 0000000000..3317c8a93d --- /dev/null +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/goal/GoalPageTest.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * 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.page.goal; + +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandGoalRegistry; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandImpl.ApplicableContext; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.command.editor.EditorMessages; +import org.eclipse.che.ide.command.editor.page.CommandEditorPage.DirtyStateListener; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.HashMap; +import java.util.Map; + +import static org.eclipse.che.api.workspace.shared.Constants.COMMAND_GOAL_ATTRIBUTE_NAME; +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** Tests for {@link GoalPage}. */ +@RunWith(MockitoJUnitRunner.class) +public class GoalPageTest { + + private static final String COMMAND_GOAL_ID = "build"; + + @Mock + private GoalPageView view; + @Mock + private CommandGoalRegistry goalRegistry; + @Mock + private CommandManager commandManager; + @Mock + private EditorMessages messages; + + @InjectMocks + private GoalPage page; + + @Mock + private DirtyStateListener dirtyStateListener; + @Mock + private CommandImpl editedCommand; + @Mock + private ApplicableContext editedCommandApplicableContext; + + @Before + public void setUp() throws Exception { + CommandGoal commandGoal = mock(CommandGoal.class); + when(commandGoal.getId()).thenReturn(COMMAND_GOAL_ID); + when(goalRegistry.getGoalForId(anyString())).thenReturn(commandGoal); + + when(editedCommand.getApplicableContext()).thenReturn(editedCommandApplicableContext); + + Map attributes = new HashMap<>(); + attributes.put(COMMAND_GOAL_ATTRIBUTE_NAME, COMMAND_GOAL_ID); + when(editedCommand.getAttributes()).thenReturn(attributes); + + page.setDirtyStateListener(dirtyStateListener); + page.edit(editedCommand); + } + + @Test + public void shouldSetViewDelegate() throws Exception { + verify(view).setDelegate(page); + } + + @Test + public void shouldInitializeView() throws Exception { + verify(goalRegistry).getAllPredefinedGoals(); + verify(view).setAvailableGoals(Matchers.anySet()); + verify(view).setGoal(eq(COMMAND_GOAL_ID)); + } + + @Test + public void shouldReturnView() throws Exception { + assertEquals(view, page.getView()); + } + + @Test + public void shouldNotifyListenerWhenGoalChanged() throws Exception { + page.onGoalChanged("test"); + + verify(dirtyStateListener, times(2)).onDirtyStateChanged(); + } +} diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/name/NamePageTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/name/NamePageTest.java new file mode 100644 index 0000000000..58c06004a8 --- /dev/null +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/name/NamePageTest.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * 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.page.name; + +import org.eclipse.che.ide.api.command.CommandExecutor; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.command.editor.EditorMessages; +import org.eclipse.che.ide.command.editor.page.CommandEditorPage.DirtyStateListener; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** Tests for {@link NamePage}. */ +@RunWith(MockitoJUnitRunner.class) +public class NamePageTest { + + private static final String COMMAND_NAME = "build"; + + @Mock + private NamePageView view; + @Mock + private EditorMessages messages; + @Mock + private CommandExecutor commandExecutor; + + @InjectMocks + private NamePage page; + + @Mock + private DirtyStateListener dirtyStateListener; + @Mock + private CommandImpl editedCommand; + + @Before + public void setUp() throws Exception { + when(editedCommand.getName()).thenReturn(COMMAND_NAME); + + page.setDirtyStateListener(dirtyStateListener); + page.edit(editedCommand); + } + + @Test + public void shouldSetViewDelegate() throws Exception { + verify(view).setDelegate(page); + } + + @Test + public void shouldInitializeView() throws Exception { + verify(view).setCommandName(eq(COMMAND_NAME)); + } + + @Test + public void shouldReturnView() throws Exception { + assertEquals(view, page.getView()); + } + + @Test + public void shouldNotifyListenerWhenNameChanged() throws Exception { + page.onNameChanged("mvn"); + + verify(dirtyStateListener, times(2)).onDirtyStateChanged(); + } + + @Test + public void shouldExecuteCommandWhenTestingRequested() throws Exception { + page.onCommandRun(); + + verify(commandExecutor).executeCommand(editedCommand); + } + +} diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/project/ProjectSwitcherTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/project/ProjectSwitcherTest.java new file mode 100644 index 0000000000..56f8582c10 --- /dev/null +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/project/ProjectSwitcherTest.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * 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.page.project; + +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwtmockito.GwtMockitoTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** Tests for {@link ProjectSwitcher}. */ +@RunWith(GwtMockitoTestRunner.class) +public class ProjectSwitcherTest { + + private static final String PROJECT_NAME = "p1"; + + private ProjectSwitcher switcher; + + @Before + public void setUp() throws Exception { + switcher = new ProjectSwitcher(PROJECT_NAME); + } + + @Test + public void shouldSetLabel() throws Exception { + verify(switcher.label).setText(PROJECT_NAME); + } + + @Test + public void shouldReturnValue() throws Exception { + switcher.getValue(); + + verify(switcher.switcher).getValue(); + } + + @Test + public void shouldSetValue() throws Exception { + switcher.setValue(true); + + verify(switcher.switcher).setValue(Boolean.TRUE); + } + + @Test + public void shouldSetValueAndFireEvents() throws Exception { + switcher.setValue(true, true); + + verify(switcher.switcher).setValue(Boolean.TRUE, true); + } + + @Test + public void shouldAddValueChangeHandler() throws Exception { + ValueChangeHandler valueChangeHandler = mock(ValueChangeHandler.class); + switcher.addValueChangeHandler(valueChangeHandler); + + verify(switcher.switcher).addValueChangeHandler(valueChangeHandler); + } +} diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageTest.java new file mode 100644 index 0000000000..40efab10af --- /dev/null +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/editor/page/project/ProjectsPageTest.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * 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.page.project; + +import com.google.web.bindery.event.shared.EventBus; + +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandImpl.ApplicableContext; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.command.editor.EditorMessages; +import org.eclipse.che.ide.command.editor.page.CommandEditorPage.DirtyStateListener; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** Tests for {@link ProjectsPage}. */ +@RunWith(MockitoJUnitRunner.class) +public class ProjectsPageTest { + + @Mock + private ProjectsPageView view; + @Mock + private AppContext appContext; + @Mock + private EditorMessages messages; + @Mock + private EventBus eventBus; + + @InjectMocks + private ProjectsPage page; + + @Mock + private DirtyStateListener dirtyStateListener; + @Mock + private CommandImpl editedCommand; + @Mock + private ApplicableContext editedCommandApplicableContext; + + @Before + public void setUp() throws Exception { + when(appContext.getProjects()).thenReturn(new Project[0]); + + when(editedCommand.getApplicableContext()).thenReturn(editedCommandApplicableContext); + + page.setDirtyStateListener(dirtyStateListener); + page.edit(editedCommand); + } + + @Test + public void shouldSetViewDelegate() throws Exception { + verify(view).setDelegate(page); + } + + @Test + public void shouldReturnView() throws Exception { + assertEquals(view, page.getView()); + } + + @Test + public void shouldNotifyListenerWhenApplicableProjectChanged() throws Exception { + page.onApplicableProjectChanged(mock(Project.class), true); + + verify(dirtyStateListener, times(2)).onDirtyStateChanged(); + } +} diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/explorer/CommandsExplorerPresenterTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/explorer/CommandsExplorerPresenterTest.java new file mode 100644 index 0000000000..39fa7f7d14 --- /dev/null +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/explorer/CommandsExplorerPresenterTest.java @@ -0,0 +1,356 @@ +/******************************************************************************* + * 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.explorer; + +import com.google.gwt.core.client.Callback; +import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.google.gwt.user.client.ui.IsWidget; +import com.google.gwtmockito.GwtMockitoTestRunner; + +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.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandImpl.ApplicableContext; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.command.CommandType; +import org.eclipse.che.ide.api.constraints.Constraints; +import org.eclipse.che.ide.api.dialogs.CancelCallback; +import org.eclipse.che.ide.api.dialogs.ConfirmCallback; +import org.eclipse.che.ide.api.dialogs.ConfirmDialog; +import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; +import org.eclipse.che.ide.api.notification.NotificationManager; +import org.eclipse.che.ide.api.parts.PartStackType; +import org.eclipse.che.ide.api.parts.WorkspaceAgent; +import org.eclipse.che.ide.api.resources.Project; +import org.eclipse.che.ide.command.CommandResources; +import org.eclipse.che.ide.command.node.NodeFactory; +import org.eclipse.che.ide.command.type.chooser.CommandTypeChooser; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +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.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** Tests for {@link CommandsExplorerPresenter}. */ +@RunWith(GwtMockitoTestRunner.class) +public class CommandsExplorerPresenterTest { + + @Mock + private CommandsExplorerView view; + @Mock + private CommandResources resources; + @Mock + private WorkspaceAgent workspaceAgent; + @Mock + private CommandManager commandManager; + @Mock + private NotificationManager notificationManager; + @Mock + private CommandTypeChooser commandTypeChooser; + @Mock + private ExplorerMessages messages; + @Mock + private CommandsExplorerPresenter.RefreshViewTask refreshViewTask; + @Mock + private DialogFactory dialogFactory; + @Mock + private NodeFactory nodeFactory; + @Mock + private EditorAgent editorAgent; + @Mock + private AppContext appContext; + + @InjectMocks + private CommandsExplorerPresenter presenter; + + @Mock + private Promise voidPromise; + @Mock + private Promise commandPromise; + @Mock + private Promise commandTypePromise; + @Captor + private ArgumentCaptor> errorOperationCaptor; + @Captor + private ArgumentCaptor> commandOperationCaptor; + @Captor + private ArgumentCaptor> commandTypeOperationCaptor; + + @Test + public void shouldSetViewDelegate() throws Exception { + verify(view).setDelegate(eq(presenter)); + } + + @Test + public void testStart() throws Exception { + Callback callback = mock(Callback.class); + + presenter.start(callback); + + verify(workspaceAgent).openPart(presenter, PartStackType.NAVIGATION, Constraints.LAST); + verify(commandManager).addCommandChangedListener(presenter); + verify(commandManager).addCommandLoadedListener(presenter); + verify(callback).onSuccess(presenter); + } + + @Test + public void testGo() throws Exception { + AcceptsOneWidget container = mock(AcceptsOneWidget.class); + + presenter.go(container); + + verify(refreshViewTask).delayAndSelectCommand(isNull(CommandImpl.class)); + verify(container).setWidget(view); + } + + @Test + public void shouldReturnTitle() throws Exception { + presenter.getTitle(); + + verify(messages).partTitle(); + } + + @Test + public void shouldReturnView() throws Exception { + IsWidget view = presenter.getView(); + + assertEquals(this.view, view); + } + + @Test + public void shouldReturnTitleTooltip() throws Exception { + presenter.getTitleToolTip(); + + verify(messages).partTooltip(); + } + + @Test + public void shouldReturnTitleImage() throws Exception { + presenter.getTitleImage(); + + verify(resources).explorerPart(); + } + + @Test + public void shouldCreateCommand() throws Exception { + // given + CommandType selectedCommandType = mock(CommandType.class); + String commandTypeId = "mvn"; + when(selectedCommandType.getId()).thenReturn(commandTypeId); + + CommandGoal selectedCommandGoal = mock(CommandGoal.class); + String commandGoalId = "test"; + when(selectedCommandGoal.getId()).thenReturn(commandGoalId); + + when(view.getSelectedGoal()).thenReturn(selectedCommandGoal); + when(commandTypeChooser.show(anyInt(), anyInt())).thenReturn(commandTypePromise); + when(appContext.getProjects()).thenReturn(new Project[0]); + when(commandManager.createCommand(anyString(), + anyString(), + any(ApplicableContext.class))).thenReturn(commandPromise); + when(commandPromise.then(any(Operation.class))).thenReturn(commandPromise); + when(commandPromise.catchError(any(Operation.class))).thenReturn(commandPromise); + + // when + presenter.onCommandAdd(0, 0); + + // then + verify(commandTypeChooser).show(0, 0); + verify(commandTypePromise).then(commandTypeOperationCaptor.capture()); + commandTypeOperationCaptor.getValue().apply(selectedCommandType); + + verify(view).getSelectedGoal(); + + verify(commandManager).createCommand(eq(commandGoalId), + eq(commandTypeId), + any(ApplicableContext.class)); + } + + @Test(expected = OperationException.class) + public void shouldShowNotificationWhenFailedToCreateCommand() throws Exception { + // given + CommandType selectedCommandType = mock(CommandType.class); + String commandTypeId = "mvn"; + when(selectedCommandType.getId()).thenReturn(commandTypeId); + + CommandGoal selectedCommandGoal = mock(CommandGoal.class); + String commandGoalId = "test"; + when(selectedCommandGoal.getId()).thenReturn(commandGoalId); + + when(view.getSelectedGoal()).thenReturn(selectedCommandGoal); + when(commandTypeChooser.show(anyInt(), anyInt())).thenReturn(commandTypePromise); + when(appContext.getProjects()).thenReturn(new Project[0]); + when(commandManager.createCommand(anyString(), + anyString(), + any(ApplicableContext.class))).thenReturn(commandPromise); + when(commandPromise.then(any(Operation.class))).thenReturn(commandPromise); + when(commandPromise.catchError(any(Operation.class))).thenReturn(commandPromise); + + // when + presenter.onCommandAdd(0, 0); + + // then + verify(commandTypeChooser).show(0, 0); + verify(commandTypePromise).then(commandTypeOperationCaptor.capture()); + commandTypeOperationCaptor.getValue().apply(selectedCommandType); + + verify(view).getSelectedGoal(); + + verify(commandManager).createCommand(eq(commandGoalId), + eq(commandTypeId), + any(ApplicableContext.class)); + + verify(commandPromise).catchError(errorOperationCaptor.capture()); + errorOperationCaptor.getValue().apply(mock(PromiseError.class)); + verify(messages).unableCreate(); + verify(notificationManager).notify(anyString(), anyString(), eq(FAIL), eq(EMERGE_MODE)); + } + + @Test + public void shouldDuplicateCommand() throws Exception { + CommandImpl command = mock(CommandImpl.class); + when(commandManager.createCommand(any(CommandImpl.class))).thenReturn(commandPromise); + when(commandPromise.then(any(Operation.class))).thenReturn(commandPromise); + + presenter.onCommandDuplicate(command); + + verify(commandManager).createCommand(command); + } + + @Test(expected = OperationException.class) + public void shouldShowNotificationWhenFailedToDuplicateCommand() throws Exception { + CommandImpl command = mock(CommandImpl.class); + when(commandManager.createCommand(any(CommandImpl.class))).thenReturn(commandPromise); + when(commandPromise.then(any(Operation.class))).thenReturn(commandPromise); + + presenter.onCommandDuplicate(command); + + verify(commandPromise).catchError(errorOperationCaptor.capture()); + errorOperationCaptor.getValue().apply(mock(PromiseError.class)); + verify(messages).unableDuplicate(); + verify(notificationManager).notify(anyString(), anyString(), eq(FAIL), eq(EMERGE_MODE)); + } + + @Test + public void shouldRemoveCommand() throws Exception { + // given + ConfirmDialog confirmDialog = mock(ConfirmDialog.class); + when(dialogFactory.createConfirmDialog(anyString(), + anyString(), + any(ConfirmCallback.class), + any(CancelCallback.class))).thenReturn(confirmDialog); + ArgumentCaptor confirmCallbackCaptor = ArgumentCaptor.forClass(ConfirmCallback.class); + + CommandImpl command = mock(CommandImpl.class); + String cmdName = "build"; + when(command.getName()).thenReturn(cmdName); + when(commandManager.removeCommand(anyString())).thenReturn(voidPromise); + + // when + presenter.onCommandRemove(command); + + // then + verify(dialogFactory).createConfirmDialog(anyString(), anyString(), confirmCallbackCaptor.capture(), isNull(CancelCallback.class)); + confirmCallbackCaptor.getValue().accepted(); + verify(confirmDialog).show(); + verify(commandManager).removeCommand(cmdName); + } + + @Test + public void shouldNotRemoveCommandWhenCancelled() throws Exception { + ConfirmDialog confirmDialog = mock(ConfirmDialog.class); + when(dialogFactory.createConfirmDialog(anyString(), + anyString(), + any(ConfirmCallback.class), + any(CancelCallback.class))).thenReturn(confirmDialog); + CommandImpl command = mock(CommandImpl.class); + + presenter.onCommandRemove(command); + + verify(dialogFactory).createConfirmDialog(anyString(), anyString(), any(ConfirmCallback.class), isNull(CancelCallback.class)); + verify(confirmDialog).show(); + verify(commandManager, never()).removeCommand(anyString()); + } + + @Test(expected = OperationException.class) + public void shouldShowNotificationWhenFailedToRemoveCommand() throws Exception { + // given + ConfirmDialog confirmDialog = mock(ConfirmDialog.class); + when(dialogFactory.createConfirmDialog(anyString(), + anyString(), + any(ConfirmCallback.class), + any(CancelCallback.class))).thenReturn(confirmDialog); + ArgumentCaptor confirmCallbackCaptor = ArgumentCaptor.forClass(ConfirmCallback.class); + + when(commandManager.removeCommand(anyString())).thenReturn(voidPromise); + + // when + presenter.onCommandRemove(mock(CommandImpl.class)); + + // then + verify(dialogFactory).createConfirmDialog(anyString(), anyString(), confirmCallbackCaptor.capture(), isNull(CancelCallback.class)); + confirmCallbackCaptor.getValue().accepted(); + + verify(voidPromise).catchError(errorOperationCaptor.capture()); + errorOperationCaptor.getValue().apply(mock(PromiseError.class)); + verify(messages).unableRemove(); + verify(notificationManager).notify(anyString(), anyString(), eq(FAIL), eq(EMERGE_MODE)); + } + + @Test + public void shouldRefreshViewWhenCommandsAreLoaded() throws Exception { + presenter.onCommandsLoaded(); + + verify(refreshViewTask).delayAndSelectCommand(isNull(CommandImpl.class)); + } + + @Test + public void shouldRefreshViewWhenCommandAdded() throws Exception { + CommandImpl command = mock(CommandImpl.class); + + presenter.onCommandAdded(command); + + verify(refreshViewTask).delayAndSelectCommand(isNull(CommandImpl.class)); + } + + @Test + public void shouldRefreshViewWhenCommandUpdated() throws Exception { + presenter.onCommandUpdated(mock(CommandImpl.class), mock(CommandImpl.class)); + + verify(refreshViewTask).delayAndSelectCommand(isNull(CommandImpl.class)); + } + + @Test + public void shouldRefreshViewWhenCommandRemoved() throws Exception { + presenter.onCommandRemoved(mock(CommandImpl.class)); + + verify(refreshViewTask).delayAndSelectCommand(isNull(CommandImpl.class)); + } +} diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/palette/CommandsPalettePresenterTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/palette/CommandsPalettePresenterTest.java new file mode 100644 index 0000000000..3fe5870e09 --- /dev/null +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/palette/CommandsPalettePresenterTest.java @@ -0,0 +1,160 @@ +/******************************************************************************* + * 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.palette; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.api.core.model.workspace.Workspace; +import org.eclipse.che.api.machine.shared.dto.MachineDto; +import org.eclipse.che.api.promises.client.Operation; +import org.eclipse.che.api.promises.client.Promise; +import org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandExecutor; +import org.eclipse.che.ide.api.command.CommandGoal; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.command.CommandUtils; +import org.eclipse.che.ide.machine.chooser.MachineChooser; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** Tests for {@link CommandsPalettePresenter}. */ +@RunWith(MockitoJUnitRunner.class) +public class CommandsPalettePresenterTest { + + @Mock + private CommandsPaletteView view; + + @Mock + private CommandManager commandManager; + + @Mock + private CommandExecutor commandExecutor; + + @Mock + private DialogFactory dialogFactory; + + @Mock + private AppContext appContext; + + @Mock + private MachineChooser machineChooser; + + @Mock + private CommandUtils commandUtils; + + @Mock + private PaletteMessages messages; + + @Mock + private Promise machinePromise; + + @Captor + private ArgumentCaptor> selectedMachineCaptor; + + @Captor + private ArgumentCaptor>> filteredCommandsCaptor; + + @InjectMocks + private CommandsPalettePresenter presenter; + + @Test + public void shouldSetViewDelegate() throws Exception { + verify(view).setDelegate(eq(presenter)); + } + + @Test + public void shouldShowViewAndSetCommands() throws Exception { + presenter.showDialog(); + + verify(view).show(); + verify(commandManager).getCommands(); + verify(view).setCommands(Matchers.any()); + } + + @Test + public void shouldFilterCommands() throws Exception { + // given + CommandImpl cmd1 = mock(CommandImpl.class); + when(cmd1.getName()).thenReturn("test"); + + CommandImpl cmd2 = mock(CommandImpl.class); + when(cmd2.getName()).thenReturn("run"); + + List commands = new ArrayList<>(); + commands.add(cmd1); + commands.add(cmd2); + + when(commandManager.getCommands()).thenReturn(commands); + + Map> filteredCommandsMock = new HashMap<>(); + filteredCommandsMock.put(mock(CommandGoal.class), commands); + when(commandUtils.groupCommandsByGoal(commands)).thenReturn(filteredCommandsMock); + + // when + presenter.onFilterChanged("run"); + + // then + verify(commandUtils).groupCommandsByGoal(commands); + verify(view).setCommands(filteredCommandsCaptor.capture()); + final Map> filteredCommandsValue = filteredCommandsCaptor.getValue(); + assertEquals(filteredCommandsMock, filteredCommandsValue); + } + + @Test + public void shouldExecuteCommand() throws Exception { + // given + Workspace workspace = mock(Workspace.class); + when(appContext.getWorkspace()).thenReturn(workspace); + + WorkspaceRuntimeDto workspaceRuntime = mock(WorkspaceRuntimeDto.class); + when(workspace.getRuntime()).thenReturn(workspaceRuntime); + + List machines = new ArrayList<>(1); + MachineDto chosenMachine = mock(MachineDto.class); + machines.add(chosenMachine); + when(workspaceRuntime.getMachines()).thenReturn(machines); + + when(machineChooser.show()).thenReturn(machinePromise); + + CommandImpl commandToExecute = mock(CommandImpl.class); + + // when + presenter.onCommandExecute(commandToExecute); + + // then + verify(view).close(); + verify(machineChooser).show(); + + verify(machinePromise).then(selectedMachineCaptor.capture()); + selectedMachineCaptor.getValue().apply(chosenMachine); + + verify(commandExecutor).executeCommand(eq(commandToExecute), eq(chosenMachine)); + } +} diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/palette/ShowCommandsPaletteActionTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/palette/ShowCommandsPaletteActionTest.java new file mode 100644 index 0000000000..59ef0f041d --- /dev/null +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/palette/ShowCommandsPaletteActionTest.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * 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.palette; + +import org.eclipse.che.ide.api.action.ActionEvent; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** Tests for {@link ShowCommandsPaletteAction}. */ +@RunWith(MockitoJUnitRunner.class) +public class ShowCommandsPaletteActionTest { + + @Mock + private PaletteMessages messages; + @Mock + private CommandsPalettePresenter presenter; + + @InjectMocks + private ShowCommandsPaletteAction action; + + @Test + public void shouldInitializeAction() { + verify(messages).actionShowPaletteTitle(); + verify(messages).actionShowPaletteDescription(); + } + + @Test + public void shouldShowDialog() { + action.actionPerformed(mock(ActionEvent.class)); + + verify(presenter).showDialog(); + } +} diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/toolbar/previews/PreviewUrlTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/toolbar/previews/PreviewUrlTest.java new file mode 100644 index 0000000000..3c38b7935b --- /dev/null +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/command/toolbar/previews/PreviewUrlTest.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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.toolbar.previews; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** Tests for {@link PreviewUrl}. */ +public class PreviewUrlTest { + + private static final String URL = "http://preview.com"; + private static final String DISPLAY_NAME = "dev-machine:8080"; + + private PreviewUrl previewUrl; + + @Before + public void setUp() { + previewUrl = new PreviewUrl(URL, DISPLAY_NAME); + } + + @Test + public void testGetUrl() throws Exception { + assertEquals(URL, previewUrl.getUrl()); + } + + @Test + public void testGetDisplayName() throws Exception { + assertEquals(DISPLAY_NAME, previewUrl.getDisplayName()); + } +} diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerHostNameMacroTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerHostNameMacroTest.java similarity index 90% rename from ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerHostNameMacroTest.java rename to ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerHostNameMacroTest.java index e929151bb5..f11a3fd9a6 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerHostNameMacroTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerHostNameMacroTest.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.machine.macro; +package org.eclipse.che.ide.macro; import com.google.gwtmockito.GwtMockitoTestRunner; import com.google.web.bindery.event.shared.EventBus; @@ -20,11 +20,10 @@ import org.eclipse.che.api.machine.shared.Constants; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.macro.BaseMacro; import org.eclipse.che.ide.api.macro.Macro; import org.eclipse.che.ide.api.macro.MacroRegistry; import org.eclipse.che.ide.api.machine.DevMachine; -import org.eclipse.che.ide.macro.CustomMacro; -import org.eclipse.che.ide.macro.ServerHostNameMacro; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -85,15 +84,15 @@ public class ServerHostNameMacroTest { @Test public void getMacros() throws Exception { - final Set providers = provider.getMacros(devMachine); + final Set macros = provider.getMacros(devMachine); - assertEquals(providers.size(), 2); + assertEquals(macros.size(), 2); - final Iterator iterator = providers.iterator(); + final Iterator iterator = macros.iterator(); final Macro provider1 = iterator.next(); - assertTrue(provider1 instanceof CustomMacro); + assertTrue(provider1 instanceof BaseMacro); assertEquals(provider1.getName(), ServerHostNameMacro.KEY.replace("%", WS_AGENT_PORT)); provider1.expand().then(new Operation() { @@ -105,7 +104,7 @@ public class ServerHostNameMacroTest { final Macro provider2 = iterator.next(); - assertTrue(provider2 instanceof CustomMacro); + assertTrue(provider2 instanceof BaseMacro); assertEquals(provider2.getName(), ServerHostNameMacro.KEY.replace("%", WS_AGENT_PORT.substring(0, WS_AGENT_PORT.length() - 4))); provider2.expand().then(new Operation() { diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerMacroTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerMacroTest.java similarity index 89% rename from ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerMacroTest.java rename to ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerMacroTest.java index 19879f90b5..eb47c49806 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerMacroTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerMacroTest.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.machine.macro; +package org.eclipse.che.ide.macro; import com.google.gwtmockito.GwtMockitoTestRunner; import com.google.web.bindery.event.shared.EventBus; @@ -20,11 +20,10 @@ import org.eclipse.che.api.machine.shared.Constants; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.macro.BaseMacro; import org.eclipse.che.ide.api.macro.Macro; import org.eclipse.che.ide.api.macro.MacroRegistry; import org.eclipse.che.ide.api.machine.DevMachine; -import org.eclipse.che.ide.macro.CustomMacro; -import org.eclipse.che.ide.macro.ServerMacro; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -81,15 +80,15 @@ public class ServerMacroTest { @Test public void getMacros() throws Exception { - final Set providers = provider.getMacros(devMachine); + final Set macros = provider.getMacros(devMachine); - assertEquals(providers.size(), 2); + assertEquals(macros.size(), 2); - final Iterator iterator = providers.iterator(); + final Iterator iterator = macros.iterator(); final Macro provider1 = iterator.next(); - assertTrue(provider1 instanceof CustomMacro); + assertTrue(provider1 instanceof BaseMacro); assertEquals(provider1.getName(), ServerMacro.KEY.replace("%", WS_AGENT_PORT.substring(0, WS_AGENT_PORT.length() - 4))); provider1.expand().then(new Operation() { @@ -101,7 +100,7 @@ public class ServerMacroTest { final Macro provider2 = iterator.next(); - assertTrue(provider2 instanceof CustomMacro); + assertTrue(provider2 instanceof BaseMacro); assertEquals(provider2.getName(), ServerMacro.KEY.replace("%", WS_AGENT_PORT)); provider2.expand().then(new Operation() { diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerPortMacroTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerPortMacroTest.java similarity index 85% rename from ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerPortMacroTest.java rename to ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerPortMacroTest.java index a81df8f0a5..f8e3b2cc92 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerPortMacroTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerPortMacroTest.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.machine.macro; +package org.eclipse.che.ide.macro; import com.google.gwtmockito.GwtMockitoTestRunner; import com.google.web.bindery.event.shared.EventBus; @@ -20,11 +20,10 @@ import org.eclipse.che.api.machine.shared.Constants; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.macro.BaseMacro; import org.eclipse.che.ide.api.macro.Macro; import org.eclipse.che.ide.api.macro.MacroRegistry; import org.eclipse.che.ide.api.machine.DevMachine; -import org.eclipse.che.ide.macro.CustomMacro; -import org.eclipse.che.ide.macro.ServerPortMacro; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -72,26 +71,26 @@ public class ServerPortMacroTest { @Mock private Server server; - private ServerPortMacro provider; + private ServerPortMacro macro; @Before public void setUp() throws Exception { - provider = new ServerPortMacro(macroRegistry, eventBus, appContext); + macro = new ServerPortMacro(macroRegistry, eventBus, appContext); - registerProvider(); + registerMacros(); } @Test public void getMacros() throws Exception { - final Set providers = provider.getMacros(devMachine); + final Set macros = macro.getMacros(devMachine); - assertEquals(providers.size(), 2); + assertEquals(macros.size(), 2); - final Iterator iterator = providers.iterator(); + final Iterator iterator = macros.iterator(); final Macro provider1 = iterator.next(); - assertTrue(provider1 instanceof CustomMacro); + assertTrue(provider1 instanceof BaseMacro); assertEquals(provider1.getName(), ServerPortMacro.KEY.replace("%", WS_AGENT_PORT.substring(0, WS_AGENT_PORT.length() - 4))); provider1.expand().then(new Operation() { @@ -103,7 +102,7 @@ public class ServerPortMacroTest { final Macro provider2 = iterator.next(); - assertTrue(provider2 instanceof CustomMacro); + assertTrue(provider2 instanceof BaseMacro); assertEquals(provider2.getName(), ServerPortMacro.KEY.replace("%", WS_AGENT_PORT)); provider2.expand().then(new Operation() { @@ -114,7 +113,7 @@ public class ServerPortMacroTest { }); } - protected void registerProvider() { + protected void registerMacros() { when(devMachine.getDescriptor()).thenReturn(machine); when(machine.getRuntime()).thenReturn(machineRuntimeInfo); doReturn(Collections.singletonMap(WS_AGENT_PORT, server)).when(machineRuntimeInfo).getServers(); diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerProtocolMacroTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerProtocolMacroTest.java similarity index 89% rename from ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerProtocolMacroTest.java rename to ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerProtocolMacroTest.java index c9bbedd704..a9ee5d6459 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/machine/macro/ServerProtocolMacroTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/macro/ServerProtocolMacroTest.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.machine.macro; +package org.eclipse.che.ide.macro; import com.google.gwtmockito.GwtMockitoTestRunner; import com.google.web.bindery.event.shared.EventBus; @@ -20,11 +20,10 @@ import org.eclipse.che.api.machine.shared.Constants; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.macro.BaseMacro; import org.eclipse.che.ide.api.macro.Macro; import org.eclipse.che.ide.api.macro.MacroRegistry; import org.eclipse.che.ide.api.machine.DevMachine; -import org.eclipse.che.ide.macro.CustomMacro; -import org.eclipse.che.ide.macro.ServerProtocolMacro; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -84,15 +83,15 @@ public class ServerProtocolMacroTest { @Test public void getMacros() throws Exception { - final Set providers = provider.getMacros(devMachine); + final Set macros = provider.getMacros(devMachine); - assertEquals(providers.size(), 2); + assertEquals(macros.size(), 2); - final Iterator iterator = providers.iterator(); + final Iterator iterator = macros.iterator(); final Macro provider1 = iterator.next(); - assertTrue(provider1 instanceof CustomMacro); + assertTrue(provider1 instanceof BaseMacro); assertEquals(provider1.getName(), ServerProtocolMacro.KEY.replace("%", WS_AGENT_PORT)); provider1.expand().then(new Operation() { @@ -104,7 +103,7 @@ public class ServerProtocolMacroTest { final Macro provider2 = iterator.next(); - assertTrue(provider2 instanceof CustomMacro); + assertTrue(provider2 instanceof BaseMacro); assertEquals(provider2.getName(), ServerProtocolMacro.KEY.replace("%", WS_AGENT_PORT.substring(0, WS_AGENT_PORT.length() - 4))); provider2.expand().then(new Operation() { diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/navigation/NavigateToFilePresenterTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/navigation/NavigateToFilePresenterTest.java index aba6462842..a9df87f514 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/navigation/NavigateToFilePresenterTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/navigation/NavigateToFilePresenterTest.java @@ -14,6 +14,7 @@ import com.google.common.base.Optional; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.machine.DevMachine; import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; import org.eclipse.che.api.promises.client.Promise; @@ -63,6 +64,8 @@ public class NavigateToFilePresenterTest { private Promise> optFilePromise; @Mock private AppContext appContext; + @Mock + private EditorAgent editorAgent; private NavigateToFilePresenter presenter; @@ -79,7 +82,8 @@ public class NavigateToFilePresenterTest { eventBus, dtoUnmarshallerFactory, messageBusProvider, - appContext); + appContext, + editorAgent); presenter.onWsAgentStarted(wsAgentStateEvent); } diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/AbstractNewResourceActionTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/AbstractNewResourceActionTest.java index 90cf178254..551576d52b 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/AbstractNewResourceActionTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/AbstractNewResourceActionTest.java @@ -11,6 +11,7 @@ package org.eclipse.che.ide.newresource; import com.google.gwtmockito.GwtMockitoTestRunner; +import com.google.inject.Provider; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.promises.client.Operation; @@ -18,6 +19,7 @@ import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.File; @@ -42,15 +44,17 @@ import static org.mockito.Mockito.when; public class AbstractNewResourceActionTest { @Mock - DialogFactory dialogFactory; + DialogFactory dialogFactory; @Mock CoreLocalizationConstant coreLocalizationConstant; @Mock - EventBus eventBus; + EventBus eventBus; @Mock - AppContext appContext; + AppContext appContext; @Mock - NotificationManager notificationManager; + NotificationManager notificationManager; + @Mock + Provider editorAgentProvider; @Mock Resource file; @@ -71,7 +75,8 @@ public class AbstractNewResourceActionTest { coreLocalizationConstant, eventBus, appContext, - notificationManager) { + notificationManager, + editorAgentProvider) { // }; } diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/NewFolderActionTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/NewFolderActionTest.java index bae4bb33d9..b31ed5ea62 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/NewFolderActionTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/newresource/NewFolderActionTest.java @@ -11,6 +11,7 @@ package org.eclipse.che.ide.newresource; import com.google.gwtmockito.GwtMockitoTestRunner; +import com.google.inject.Provider; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.promises.client.Operation; @@ -19,6 +20,7 @@ import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.Resources; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.Folder; @@ -45,15 +47,17 @@ public class NewFolderActionTest { @Mock CoreLocalizationConstant coreLocalizationConstant; @Mock - Resources resources; + Resources resources; @Mock - DialogFactory dialogFactory; + DialogFactory dialogFactory; @Mock - EventBus eventBus; + EventBus eventBus; @Mock - AppContext appContext; + AppContext appContext; @Mock - NotificationManager notificationManager; + NotificationManager notificationManager; + @Mock + Provider editorAgentProvider; @Mock Resource file; @@ -71,7 +75,9 @@ public class NewFolderActionTest { resources, dialogFactory, eventBus, - appContext, notificationManager); + appContext, + notificationManager, + editorAgentProvider); } @Test diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenterTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenterTest.java index 16ad382ba3..8659dce4ae 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenterTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/editor/EditorPartStackPresenterTest.java @@ -27,7 +27,6 @@ import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.EditorInput; import org.eclipse.che.ide.api.editor.EditorPartPresenter; import org.eclipse.che.ide.api.editor.EditorWithErrors; -import org.eclipse.che.ide.api.event.FileEvent; import org.eclipse.che.ide.api.parts.EditorTab; import org.eclipse.che.ide.api.parts.PartPresenter; import org.eclipse.che.ide.api.parts.PartStackView.TabItem; @@ -64,6 +63,7 @@ import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; @@ -108,6 +108,8 @@ public class EditorPartStackPresenterTest { private CloseAllTabsPaneAction closeAllTabsPaneAction; @Mock private EditorPaneMenuItemFactory editorPaneMenuItemFactory; + @Mock + private EditorAgent editorAgent; //additional mocks @Mock @@ -206,7 +208,8 @@ public class EditorPartStackPresenterTest { editorPaneMenu, actionManager, closePaneAction, - closeAllTabsPaneAction); + closeAllTabsPaneAction, + editorAgent); when(tabItemFactory.createEditorPartButton(partPresenter1, presenter)).thenReturn(editorTab1); when(tabItemFactory.createEditorPartButton(partPresenter2, presenter)).thenReturn(editorTab2); @@ -455,7 +458,7 @@ public class EditorPartStackPresenterTest { presenter.paneMenuTabItemHandler.onCloseButtonClicked(editorPaneTabMenuItem); - verify(eventBus).fireEvent(Matchers.anyObject()); + verify(editorAgent).closeEditor(any(EditorPartPresenter.class)); } } diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidgetTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidgetTest.java index 5fb76040ac..28820a9fbc 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidgetTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/part/widgets/editortab/EditorTabWidgetTest.java @@ -16,10 +16,10 @@ import com.google.gwt.user.client.Element; import com.google.gwtmockito.GwtMockitoTestRunner; import com.google.web.bindery.event.shared.EventBus; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.EditorInput; 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.parts.EditorPartStack; import org.eclipse.che.ide.api.parts.EditorTab.ActionDelegate; import org.eclipse.che.ide.api.parts.PartStackUIResources; @@ -57,8 +57,6 @@ public class EditorTabWidgetTest { @Mock private SVGResource icon; @Mock - private FileTypeRegistry fileTypeRegistry; - @Mock private SVGImage iconImage; @Mock private EditorPartPresenter editorPartPresenter; @@ -81,6 +79,8 @@ public class EditorTabWidgetTest { @Mock private EventBus eventBus; @Mock + private EditorAgent editorAgent; + @Mock private EditorInput editorInput; private EditorTabWidget tab; @@ -97,7 +97,7 @@ public class EditorTabWidgetTest { resources, editorTabContextMenuFactory, eventBus, - fileTypeRegistry); + editorAgent); tab.setDelegate(delegate); } @@ -166,14 +166,13 @@ public class EditorTabWidgetTest { FileType fileType = mock(FileType.class); when(editorPartPresenter.getEditorInput()).thenReturn(editorInput); - when(fileTypeRegistry.getFileTypeByFile(file)).thenReturn(fileType); when(fileType.getImage()).thenReturn(icon); when(editorInput.getFile()).thenReturn(file); tab.update(editorPartPresenter); verify(editorPartPresenter, times(2)).getEditorInput(); - verify(fileTypeRegistry).getFileTypeByFile(file); + verify(editorPartPresenter, times(2)).getTitleImage(); verify(tab.iconPanel).setWidget(Matchers.anyObject()); } @@ -184,7 +183,6 @@ public class EditorTabWidgetTest { VirtualFile newFile = mock(VirtualFile.class); when(editorPartPresenter.getEditorInput()).thenReturn(editorInput); - when(fileTypeRegistry.getFileTypeByFile(newFile)).thenReturn(fileType); when(fileType.getImage()).thenReturn(icon); when(editorInput.getFile()).thenReturn(newFile); diff --git a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizardTest.java b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizardTest.java index 62bf518b36..1f9a8da21f 100644 --- a/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizardTest.java +++ b/ide/che-core-ide-app/src/test/java/org/eclipse/che/ide/projecttype/wizard/ProjectWizardTest.java @@ -38,7 +38,6 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import java.util.Collections; -import java.util.Map; import static org.eclipse.che.ide.api.project.type.wizard.ProjectWizardMode.CREATE; import static org.eclipse.che.ide.api.project.type.wizard.ProjectWizardMode.IMPORT; @@ -187,7 +186,7 @@ public class ProjectWizardTest { when(promiseError.getCause()).thenReturn(exception); when(dataObject.getCommands()).thenReturn(Collections.singletonList(command)); when(command.getCommandLine()).thenReturn("echo 'Hello'"); - when(commandManager.create(any(String.class), any(String.class), any(String.class), any(Map.class))).thenReturn(createCommandPromise); + when(commandManager.createCommand(any(CommandImpl.class))).thenReturn(createCommandPromise); when(createCommandPromise.then(any(Operation.class))).thenReturn(createCommandPromise); when(createCommandPromise.catchError(any(Operation.class))).thenReturn(createCommandPromise); diff --git a/ide/che-core-ide-templates/src/main/resources/samples.json b/ide/che-core-ide-templates/src/main/resources/samples.json index e49113c787..24279e080c 100644 --- a/ide/che-core-ide-templates/src/main/resources/samples.json +++ b/ide/che-core-ide-templates/src/main/resources/samples.json @@ -26,7 +26,8 @@ "type": "mvn", "commandLine": "mvn -f ${current.project.path} clean install -DskipTests", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Build" } }, { @@ -34,23 +35,26 @@ "type": "custom", "commandLine": "$TOMCAT_HOME/bin/catalina.sh stop", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Run" } }, { "name": "build and deploy", "type": "mvn", - "commandLine": "mvn -f ${current.project.path} clean install -DskipTests && cp ${current.project.path}/target/*.war $TOMCAT_HOME/webapps/ROOT.war && $TOMCAT_HOME/bin/catalina.sh run 2>&1", + "commandLine": "mvn -f ${current.project.path} clean install -DskipTests \ncp ${current.project.path}/target/*.war $TOMCAT_HOME/webapps/ROOT.war \n$TOMCAT_HOME/bin/catalina.sh run 2>&1", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Run" } }, { "name": "debug", "type": "mvn", - "commandLine": "mvn -f ${current.project.path} clean install -DskipTests && cp ${current.project.path}/target/*.war $TOMCAT_HOME/webapps/ROOT.war && $TOMCAT_HOME/bin/catalina.sh jpda run 2>&1", + "commandLine": "mvn -f ${current.project.path} clean install -DskipTests \ncp ${current.project.path}/target/*.war $TOMCAT_HOME/webapps/ROOT.war \n$TOMCAT_HOME/bin/catalina.sh jpda run 2>&1", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Debug" } } ], @@ -129,9 +133,10 @@ { "name": "build and run", "type": "custom", - "commandLine": "cd ${current.project.path} && gcc -o Hello Hello.c && ./Hello", + "commandLine": "cd ${current.project.path} \ngcc -o Hello Hello.c \n./Hello", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Run" } } ], @@ -167,7 +172,8 @@ "type": "custom", "commandLine": "mvn -f ${current.project.path} clean install", "attributes": { - "previewUrl": "http://${server.port.6080}" + "previewUrl": "http://${server.port.6080}", + "goal": "Run" } } ], @@ -202,7 +208,8 @@ "type": "custom", "commandLine": "mvn -f ${current.project.path} clean install", "attributes": { - "previewUrl": "http://${server.port.6080}" + "previewUrl": "http://${server.port.6080}", + "goal": "Run" } } ], @@ -235,9 +242,10 @@ { "name": "run", "type": "custom", - "commandLine": "cd ${current.project.path} && go get -d && go run main.go", + "commandLine": "cd ${current.project.path} \ngo get -d \ngo run main.go", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Run" } } ], @@ -270,9 +278,10 @@ { "name": "run", "type": "custom", - "commandLine": "cd ${current.project.path} && go get -d && go run main.go", + "commandLine": "cd ${current.project.path} \ngo get -d \ngo run main.go", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Run" } } ], @@ -307,13 +316,18 @@ "type": "mvn", "commandLine": "mvn -f ${current.project.path} clean install", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Build" } }, { "name": "run", "type": "custom", - "commandLine": "cd ${current.project.path} && mvn exec:java -Dexec.mainClass='org.eclipse.che.wordcount.WordCount'" + "commandLine": "cd ${current.project.path} \nmvn exec:java -Dexec.mainClass='org.eclipse.che.wordcount.WordCount'", + "attributes": { + "previewUrl": "", + "goal": "Run" + } } ], "links": [], @@ -345,9 +359,10 @@ { "name": "run", "type": "custom", - "commandLine": "cd ${current.project.path} && python main.py", + "commandLine": "cd ${current.project.path} \npython main.py", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Run" } } ], @@ -380,9 +395,10 @@ { "name": "run", "type": "custom", - "commandLine": "cd ${current.project.path} && sudo virtualenv /env && sudo pip install -r requirements.txt && python main.py", + "commandLine": "cd ${current.project.path} \nsudo virtualenv /env \nsudo pip install -r requirements.txt \npython main.py", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Run" } } ], @@ -415,9 +431,10 @@ { "name": "run", "type": "custom", - "commandLine": "cd ${GAE} && ./dev_appserver.py 2>&1 --skip_sdk_update_check true --host=0.0.0.0 --admin_host=0.0.0.0 ${current.project.path}", + "commandLine": "cd ${GAE} \n./dev_appserver.py 2>&1 --skip_sdk_update_check true --host=0.0.0.0 --admin_host=0.0.0.0 ${current.project.path}", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Run" } } ], @@ -450,17 +467,19 @@ { "name": "install dependencies", "type": "custom", - "commandLine": "cd ${current.project.path} && bundle install", + "commandLine": "cd ${current.project.path} \nbundle install", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Build" } }, { "name": "run", "type": "custom", - "commandLine": "cd ${current.project.path} && rails server -b 0.0.0.0", + "commandLine": "cd ${current.project.path} \nrails server -b 0.0.0.0", "attributes": { - "previewUrl": "http://${server.port.3000}" + "previewUrl": "http://${server.port.3000}", + "goal": "Run" } } ], @@ -494,9 +513,10 @@ { "name": "run", "type": "custom", - "commandLine": "cd ${current.project.path} && ruby main.rb", + "commandLine": "cd ${current.project.path} \nruby main.rb", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Run" } } ], @@ -531,9 +551,10 @@ { "name": "run", "type": "custom", - "commandLine": "cd ${current.project.path} && node app/app.js", + "commandLine": "cd ${current.project.path} \nnode app/app.js", "attributes": { - "previewUrl": "http://${server.port.3000}" + "previewUrl": "http://${server.port.3000}", + "goal": "Run" } } ], @@ -543,51 +564,53 @@ "Node.JS" ] }, - { - "name": "angular-patternfly-starter", - "displayName": "angular-patternfly-starter", - "path": "/angular-patternfly-starter", - "description": "Angular PatternFly Starter Project.", - "projectType": "node-js", - "mixins": [], - "attributes": { - "language": [ - "javascript" - ] - }, - "modules": [], - "problems": [], - "source": { - "type": "git", - "location": "https://github.com/patternfly/angular-patternfly-demo-app.git", - "parameters": {} - }, - "commands": [ - { - "name": "install dependencies", - "type": "custom", - "commandLine": "cd ${current.project.path} && npm install --no-bin-links && bower install", - "attributes": { - "previewUrl": "" - } - }, - { - "name": "run", - "type": "custom", - "commandLine": "cd ${current.project.path} && grunt server", - "attributes": { - "previewUrl": "http://${server.port.8003}" - } - } - ], - "links": [], - "category": "Samples", - "tags": [ - "nodejs", - "patternfly", - "javascript", - "Node.JS" - ] + { + "name": "angular-patternfly-starter", + "displayName": "angular-patternfly-starter", + "path": "/angular-patternfly-starter", + "description": "Angular PatternFly Starter Project.", + "projectType": "node-js", + "mixins": [], + "attributes": { + "language": [ + "javascript" + ] + }, + "modules": [], + "problems": [], + "source": { + "type": "git", + "location": "https://github.com/patternfly/angular-patternfly-demo-app.git", + "parameters": {} + }, + "commands": [ + { + "name": "install dependencies", + "type": "custom", + "commandLine": "cd ${current.project.path} \nnpm install --no-bin-links \nbower install", + "attributes": { + "previewUrl": "", + "goal": "Build" + } + }, + { + "name": "run", + "type": "custom", + "commandLine": "cd ${current.project.path} \ngrunt server", + "attributes": { + "previewUrl": "http://${server.port.8003}", + "goal": "Run" + } + } + ], + "links": [], + "category": "Samples", + "tags": [ + "nodejs", + "patternfly", + "javascript", + "Node.JS" + ] }, { "name": "web-java-spring", @@ -612,9 +635,10 @@ { "name": "build", "type": "mvn", - "commandLine": "mvn -f ${current.project.path} clean install && cp ${current.project.path}/target/*.war $TOMCAT_HOME/webapps/ROOT.war", + "commandLine": "mvn -f ${current.project.path} clean install \ncp ${current.project.path}/target/*.war $TOMCAT_HOME/webapps/ROOT.war", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Build" } }, { @@ -622,7 +646,8 @@ "type": "custom", "commandLine": "$TOMCAT_HOME/bin/catalina.sh run 2>&1", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Run" } }, { @@ -630,23 +655,26 @@ "type": "custom", "commandLine": "$TOMCAT_HOME/bin/catalina.sh stop", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Run" } }, { "name": "build and run", "type": "mvn", - "commandLine": "mvn -f ${current.project.path} clean install && cp ${current.project.path}/target/*.war $TOMCAT_HOME/webapps/ROOT.war && $TOMCAT_HOME/bin/catalina.sh run 2>&1", + "commandLine": "mvn -f ${current.project.path} clean install \ncp ${current.project.path}/target/*.war $TOMCAT_HOME/webapps/ROOT.war \n$TOMCAT_HOME/bin/catalina.sh run 2>&1", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Run" } }, { "name": "debug", "type": "mvn", - "commandLine": "mvn -f ${current.project.path} clean install && cp ${current.project.path}/target/*.war $TOMCAT_HOME/webapps/ROOT.war && $TOMCAT_HOME/bin/catalina.sh jpda run 2>&1", + "commandLine": "mvn -f ${current.project.path} clean install \ncp ${current.project.path}/target/*.war $TOMCAT_HOME/webapps/ROOT.war \n$TOMCAT_HOME/bin/catalina.sh jpda run 2>&1", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Debug" } } ], @@ -681,9 +709,10 @@ { "name": "build and run", "type": "custom", - "commandLine": "cd ${current.project.path} && make && ./a.out", + "commandLine": "cd ${current.project.path} \nmake \n./a.out", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Run" } } ], @@ -717,17 +746,19 @@ { "name": "install dependencies", "type": "custom", - "commandLine": "cd ${current.project.path} && npm install && bower install", + "commandLine": "cd ${current.project.path} \nnpm install \nbower install", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Build" } }, { "name": "run", "type": "custom", - "commandLine": "cd ${current.project.path} && grunt serve", + "commandLine": "cd ${current.project.path} \ngrunt serve", "attributes": { - "previewUrl": "http://${server.port.9000}" + "previewUrl": "http://${server.port.9000}", + "goal": "Run" } } ], @@ -760,9 +791,10 @@ { "name": "start apache", "type": "custom", - "commandLine": "sudo service apache2 start && sudo tail -f /var/log/apache2/access.log -f /var/log/apache2/error.log", + "commandLine": "sudo service apache2 start \nsudo tail -f /var/log/apache2/access.log -f /var/log/apache2/error.log", "attributes": { - "previewUrl": "http://${server.port.80}/${current.project.relpath}" + "previewUrl": "http://${server.port.80}/${current.project.relpath}", + "goal": "Run" } }, { @@ -770,7 +802,8 @@ "type": "custom", "commandLine": "sudo service apache2 stop", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Run" } }, { @@ -778,7 +811,8 @@ "type": "custom", "commandLine": "sudo service apache2 restart", "attributes": { - "previewUrl": "http://${server.port.80}/${current.project.relpath}" + "previewUrl": "http://${server.port.80}/${current.project.relpath}", + "goal": "Run" } } ], @@ -812,9 +846,10 @@ { "name": "run", "type": "custom", - "commandLine": "cd ${GAE} && ./dev_appserver.py 2>&1 --php_executable_path=/usr/bin/php5-cgi --skip_sdk_update_check true --host=0.0.0.0 --admin_host=0.0.0.0 ${current.project.path}", + "commandLine": "cd ${GAE} \n./dev_appserver.py 2>&1 --php_executable_path=/usr/bin/php5-cgi --skip_sdk_update_check true --host=0.0.0.0 --admin_host=0.0.0.0 ${current.project.path}", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Run" } } ], @@ -849,15 +884,17 @@ "type": "mvn", "commandLine": "mvn -f ${current.project.path} clean install", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Build" } }, { "name": "run", "type": "mvn", - "commandLine": "mvn -f ${current.project.path} clean install && java -jar ${current.project.path}/target/*.jar", + "commandLine": "mvn -f ${current.project.path} clean install \njava -jar ${current.project.path}/target/*.jar", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Run" } } ], @@ -891,17 +928,19 @@ { "name": "update dependencies", "type": "custom", - "commandLine": "cd ${current.project.path} && dotnet restore", + "commandLine": "cd ${current.project.path} \ndotnet restore", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Build" } }, { "name": "run", "type": "custom", - "commandLine": "cd ${current.project.path} && dotnet run", + "commandLine": "cd ${current.project.path} \ndotnet run", "attributes": { - "previewUrl": "http://${server.port.5000}" + "previewUrl": "http://${server.port.5000}", + "goal": "Run" } } ], @@ -934,9 +973,10 @@ { "name": "build", "type": "mvn", - "commandLine": "mvn -f ${current.project.path} clean install && cp ${current.project.path}/target/*.war $TOMEE_HOME/webapps/ROOT.war", + "commandLine": "mvn -f ${current.project.path} clean install \ncp ${current.project.path}/target/*.war $TOMEE_HOME/webapps/ROOT.war", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Build" } }, { @@ -944,7 +984,8 @@ "type": "custom", "commandLine": "$TOMEE_HOME/bin/catalina.sh run 2>&1", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Run" } }, { @@ -952,23 +993,26 @@ "type": "custom", "commandLine": "$TOMEE_HOME/bin/catalina.sh stop", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Run" } }, { "name": "build and run", "type": "mvn", - "commandLine": "mvn -f ${current.project.path} clean install && cp ${current.project.path}/target/*.war $TOMEE_HOME/webapps/ROOT.war && $TOMEE_HOME/bin/catalina.sh run 2>&1", + "commandLine": "mvn -f ${current.project.path} clean install \ncp ${current.project.path}/target/*.war $TOMEE_HOME/webapps/ROOT.war \n$TOMEE_HOME/bin/catalina.sh run 2>&1", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Run" } }, { "name": "debug", "type": "mvn", - "commandLine": "mvn -f ${current.project.path} clean install && cp ${current.project.path}/target/*.war $TOMEE_HOME/webapps/ROOT.war && $TOMEE_HOME/bin/catalina.sh jpda run 2>&1", + "commandLine": "mvn -f ${current.project.path} clean install \ncp ${current.project.path}/target/*.war $TOMEE_HOME/webapps/ROOT.war \n$TOMEE_HOME/bin/catalina.sh jpda run 2>&1", "attributes": { - "previewUrl": "http://${server.port.8080}" + "previewUrl": "http://${server.port.8080}", + "goal": "Debug" } } ], @@ -1003,17 +1047,19 @@ { "name": "1. Create and run project", "type": "custom", - "commandLine": "print-help && cd ${current.project.path} && npm install express@4.13.4 && express -f . && cp -rn /bitnami/mongodb/conf ${current.project.path} && npm install mongodb@2.1.18 --save && npm install && counter=0; until nc -z localhost 27017; do counter=$((counter+1)); if [ $counter == 10 ]; then echo \"Error: Couldn't connect to MongoDB.\"; exit 1; fi; echo \"Trying to connect to MongoDB at localhost. Attempt $counter.\"; sleep 5; done; echo \"Connected to MongoDB database. Starting application server.\" && npm start", + "commandLine": "print-help \ncd ${current.project.path} \nnpm install express@4.13.4 \nexpress -f . \ncp -rn /bitnami/mongodb/conf ${current.project.path} \nnpm install mongodb@2.1.18 --save \nnpm install \ncounter=0; until nc -z localhost 27017; do counter=$((counter+1)); if [ $counter == 10 ]; then echo \"Error: Couldn't connect to MongoDB.\"; exit 1; fi; echo \"Trying to connect to MongoDB at localhost. Attempt $counter.\"; sleep 5; done; echo \"Connected to MongoDB database. Starting application server.\" \nnpm start", "attributes": { - "previewUrl": "http://${server.port.3000}" + "previewUrl": "http://${server.port.3000}", + "goal": "Run" } }, { "name": "2. Run", "type": "custom", - "commandLine": "print-help && cd ${current.project.path} && npm start", + "commandLine": "print-help \ncd ${current.project.path} \nnpm start", "attributes": { - "previewUrl": "http://${server.port.3000}" + "previewUrl": "http://${server.port.3000}", + "goal": "Run" } } ], @@ -1048,14 +1094,20 @@ { "name": "1. Create project", "type": "custom", - "commandLine": "print-help && mkdir ${current.project.path}/app_template && cd ${current.project.path}/app_template && swift-package init --type executable 2>&1 | grep -v \"no version information available\"; swift build 2>&1 | grep -v \"no version information available\"; echo \"Project built successfully.\"", - "attributes": {} + "commandLine": "print-help \nmkdir ${current.project.path}/app_template \ncd ${current.project.path}/app_template \nswift-package init --type executable 2>&1 | grep -v \"no version information available\"; swift build 2>&1 | grep -v \"no version information available\"; echo \"Project built successfully.\"", + "attributes": { + "previewUrl": "", + "goal": "Run" + } }, { "name": "2. Run", "type": "custom", - "commandLine": "print-help && cd ${current.project.path}/app_template && swift build 2>&1 | grep -v \"no version information available\"; ./.build/debug/app_template", - "attributes": {} + "commandLine": "print-help \ncd ${current.project.path}/app_template \nswift build 2>&1 | grep -v \"no version information available\"; ./.build/debug/app_template", + "attributes": { + "previewUrl": "", + "goal": "Run" + } } ], "links": [], @@ -1089,17 +1141,19 @@ { "name": "1. Create and run project", "type": "custom", - "commandLine": "print-help && sudo HOME=/root /opt/bitnami/nami/bin/nami start mariadb && cp -an /tmp/laravel-sample/. ${current.project.path} && cd ${current.project.path} && composer update && php artisan migrate && php artisan serve --host=0.0.0.0 --port=3000", + "commandLine": "print-help \nsudo HOME=/root /opt/bitnami/nami/bin/nami start mariadb \ncp -an /tmp/laravel-sample/. ${current.project.path} \ncd ${current.project.path} \ncomposer update \nphp artisan migrate \nphp artisan serve --host=0.0.0.0 --port=3000", "attributes": { - "previewUrl": "http://${server.port.3000}/" + "previewUrl": "http://${server.port.3000}/", + "goal": "Run" } }, { "name": "2. Run", "type": "custom", - "commandLine": "print-help && sudo HOME=/root /opt/bitnami/nami/bin/nami start mariadb && cd ${current.project.path} && php artisan serve --host=0.0.0.0 --port=3000", + "commandLine": "print-help \nsudo HOME=/root /opt/bitnami/nami/bin/nami start mariadb \ncd ${current.project.path} \nphp artisan serve --host=0.0.0.0 --port=3000", "attributes": { - "previewUrl": "http://${server.port.3000}/" + "previewUrl": "http://${server.port.3000}/", + "goal": "Run" } } ], @@ -1134,17 +1188,19 @@ { "name": "1. Create and run project", "type": "custom", - "commandLine": "print-help && sudo HOME=/root /opt/bitnami/nami/bin/nami start mariadb && cd ${current.project.path} && mv README.md README-CHE.md && rails new . --skip-bundle --database mysql && sed -Ei 's/\\s*#\\s*gem(.*)therubyracer/gem\\1therubyracer/' Gemfile && bundle install && bundle exec rails db:create && bundle exec rails db:migrate && bundle exec rails server -b 0.0.0.0 -p 3000", + "commandLine": "print-help \nsudo HOME=/root /opt/bitnami/nami/bin/nami start mariadb \ncd ${current.project.path} \nmv README.md README-CHE.md \nrails new . --skip-bundle --database mysql \nsed -Ei 's/\\s*#\\s*gem(.*)therubyracer/gem\\1therubyracer/' Gemfile \nbundle install \nbundle exec rails db:create \nbundle exec rails db:migrate \nbundle exec rails server -b 0.0.0.0 -p 3000", "attributes": { - "previewUrl": "http://${server.port.3000}/" + "previewUrl": "http://${server.port.3000}/", + "goal": "Run" } }, { "name": "2. Run", "type": "custom", - "commandLine": "print-help && cd ${current.project.path} && bundle exec rails server -b 0.0.0.0 -p 3000", + "commandLine": "print-help \ncd ${current.project.path} \nbundle exec rails server -b 0.0.0.0 -p 3000", "attributes": { - "previewUrl": "http://${server.port.3000}/" + "previewUrl": "http://${server.port.3000}/", + "goal": "Run" } } ], @@ -1179,17 +1235,19 @@ { "name": "1. Create and run project", "type": "custom", - "commandLine": "print-help && sudo HOME=/root /opt/bitnami/nami/bin/nami execute codeigniter createProject --force $(basename ${current.project.path}) | grep -v undefined && php -S 0.0.0.0:8000 -t ${current.project.path}", + "commandLine": "print-help \nsudo HOME=/root /opt/bitnami/nami/bin/nami execute codeigniter createProject --force $(basename ${current.project.path}) | grep -v undefined \nphp -S 0.0.0.0:8000 -t ${current.project.path}", "attributes": { - "previewUrl": "http://${server.port.8000}/" + "previewUrl": "http://${server.port.8000}/", + "goal": "Run" } }, { "name": "2. Run", "type": "custom", - "commandLine": "print-help && php -S 0.0.0.0:8000 -t ${current.project.path}", + "commandLine": "print-help \nphp -S 0.0.0.0:8000 -t ${current.project.path}", "attributes": { - "previewUrl": "http://${server.port.8000}/" + "previewUrl": "http://${server.port.8000}/", + "goal": "Run" } } ], @@ -1224,17 +1282,19 @@ { "name": "1. Create and run project", "type": "custom", - "commandLine": "print-help && sudo HOME=/root nami execute symfony createProject --force $(basename ${current.project.path}) | grep -v undefined && ln -fs ${current.project.path}/web/app.php ${current.project.path}/web/index.php && php -S 0.0.0.0:8000 -t ${current.project.path}/web", + "commandLine": "print-help \nsudo HOME=/root nami execute symfony createProject --force $(basename ${current.project.path}) | grep -v undefined \nln -fs ${current.project.path}/web/app.php ${current.project.path}/web/index.php \nphp -S 0.0.0.0:8000 -t ${current.project.path}/web", "attributes": { - "previewUrl": "http://${server.port.8000}/" + "previewUrl": "http://${server.port.8000}/", + "goal": "Run" } }, { "name": "2. Run", "type": "custom", - "commandLine": "print-help && php -S 0.0.0.0:8000 -t ${current.project.path}/web", + "commandLine": "print-help \nphp -S 0.0.0.0:8000 -t ${current.project.path}/web", "attributes": { - "previewUrl": "http://${server.port.8000}/" + "previewUrl": "http://${server.port.8000}/", + "goal": "Run" } } ], @@ -1269,17 +1329,19 @@ { "name": "1. Create and run project", "type": "custom", - "commandLine": "print-help && sudo HOME=/root /opt/bitnami/nami/bin/nami execute activator createProject --force $(basename ${current.project.path}) play-java | grep -v undefined && cd ${current.project.path} && /opt/bitnami/activator/bin/activator -Dsbt.log.noformat=true -Doffline=true -Dhttp.host=0.0.0.0 -Dhttp.port=9000 ~run", + "commandLine": "print-help \nsudo HOME=/root /opt/bitnami/nami/bin/nami execute activator createProject --force $(basename ${current.project.path}) play-java | grep -v undefined \ncd ${current.project.path} \n/opt/bitnami/activator/bin/activator -Dsbt.log.noformat=true -Doffline=true -Dhttp.host=0.0.0.0 -Dhttp.port=9000 ~run", "attributes": { - "previewUrl": "http://${server.port.9000}/" + "previewUrl": "http://${server.port.9000}/", + "goal": "Run" } }, { "name": "2. Run", "type": "custom", - "commandLine": "print-help && cd ${current.project.path} && /opt/bitnami/activator/bin/activator -Doffline=true -Dhttp.host=0.0.0.0 -Dhttp.port=9000 -Dsbt.log.noformat=true ~run", + "commandLine": "print-help \ncd ${current.project.path} \n/opt/bitnami/activator/bin/activator -Doffline=true -Dhttp.host=0.0.0.0 -Dhttp.port=9000 -Dsbt.log.noformat=true ~run", "attributes": { - "previewUrl": "http://${server.port.9000}/" + "previewUrl": "http://${server.port.9000}/", + "goal": "Run" } } ], @@ -1312,17 +1374,19 @@ { "name": "configure", "type": "custom", - "commandLine": "chmod 777 ${current.project.path}/data; echo \"\n DocumentRoot ${current.project.path}/public\n SetEnv APPLICATION_ENV 'development'\n \n DirectoryIndex index.php\n AllowOverride All\n Require all granted\n \n\" | sudo tee /etc/apache2/sites-available/000-default.conf; cp /usr/local/zend/etc/php.ini /tmp/update-php.ini && grep -q 'extension=pcntl.so' /tmp/update-php.ini || echo \"\nextension=pcntl.so\" | sudo tee -a /tmp/update-php.ini && php -c /tmp/update-php.ini ${current.project.path}/bin/update.php && rm /tmp/update-php.ini", + "commandLine": "chmod 777 ${current.project.path}/data; echo \"\n DocumentRoot ${current.project.path}/public\n SetEnv APPLICATION_ENV 'development'\n \n DirectoryIndex index.php\n AllowOverride All\n Require all granted\n \n\" | sudo tee /etc/apache2/sites-available/000-default.conf; cp /usr/local/zend/etc/php.ini /tmp/update-php.ini \ngrep -q 'extension=pcntl.so' /tmp/update-php.ini || echo \"\nextension=pcntl.so\" | sudo tee -a /tmp/update-php.ini \nphp -c /tmp/update-php.ini ${current.project.path}/bin/update.php \nrm /tmp/update-php.ini", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Common" } }, { "name": "update images", "type": "custom", - "commandLine": "cp /usr/local/zend/etc/php.ini /tmp/update-php.ini && grep -q 'extension=pcntl.so' /tmp/update-php.ini || echo \"\nextension=pcntl.so\" | sudo tee -a /tmp/update-php.ini && php -c /tmp/update-php.ini ${current.project.path}/bin/update.php && rm /tmp/update-php.ini", + "commandLine": "cp /usr/local/zend/etc/php.ini /tmp/update-php.ini \ngrep -q 'extension=pcntl.so' /tmp/update-php.ini || echo \"\nextension=pcntl.so\" | sudo tee -a /tmp/update-php.ini \nphp -c /tmp/update-php.ini ${current.project.path}/bin/update.php \nrm /tmp/update-php.ini", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Common" } }, { @@ -1330,7 +1394,8 @@ "type": "custom", "commandLine": "sudo rm -rf ${current.project.path}/data/doctrine-cache", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Common" } } ], @@ -1364,7 +1429,8 @@ "type": "custom", "commandLine": "chmod 777 ${current.project.path}/data/cache; echo \"\n DocumentRoot ${current.project.path}/public\n SetEnv APPLICATION_ENV 'development'\n \n DirectoryIndex index.php\n AllowOverride All\n Require all granted\n \n\" | sudo tee /etc/apache2/sites-available/000-default.conf", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Common" } } ], @@ -1398,7 +1464,8 @@ "type": "custom", "commandLine": "chmod 777 ${current.project.path}/data/cache; echo \"\n DocumentRoot ${current.project.path}/public\n SetEnv APPLICATION_ENV 'development'\n \n DirectoryIndex index.php\n AllowOverride All\n Require all granted\n \n\" | sudo tee /etc/apache2/sites-available/000-default.conf", "attributes": { - "previewUrl": "" + "previewUrl": "", + "goal": "Common" } } ], @@ -1431,9 +1498,7 @@ "convertToTopLevelProject": "true" } }, - "commands": [ - - ], + "commands": [], "links": [], "category": "Samples", "tags": [ @@ -1463,9 +1528,7 @@ "convertToTopLevelProject": "true" } }, - "commands": [ - - ], + "commands": [], "links": [], "category": "Samples", "tags": [ @@ -1495,9 +1558,7 @@ "convertToTopLevelProject": "true" } }, - "commands": [ - - ], + "commands": [], "links": [], "category": "Samples", "tags": [ diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/choice/ChoiceDialogViewImpl.ui.xml b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/choice/ChoiceDialogViewImpl.ui.xml index 30b8eb3bd7..9503ff484c 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/choice/ChoiceDialogViewImpl.ui.xml +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/choice/ChoiceDialogViewImpl.ui.xml @@ -38,7 +38,7 @@ } - + \ No newline at end of file diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/confirm/ConfirmDialogViewImpl.ui.xml b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/confirm/ConfirmDialogViewImpl.ui.xml index 1389f3ac85..a915cf6474 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/confirm/ConfirmDialogViewImpl.ui.xml +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/confirm/ConfirmDialogViewImpl.ui.xml @@ -45,7 +45,7 @@ } - + \ No newline at end of file diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/input/InputDialogViewImpl.ui.xml b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/input/InputDialogViewImpl.ui.xml index bb6bde4834..ab70447da6 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/input/InputDialogViewImpl.ui.xml +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/input/InputDialogViewImpl.ui.xml @@ -32,7 +32,7 @@ color: red; } - + diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/message/MessageDialogViewImpl.ui.xml b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/message/MessageDialogViewImpl.ui.xml index 9ad86e9886..725f23fc4a 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/message/MessageDialogViewImpl.ui.xml +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dialogs/message/MessageDialogViewImpl.ui.xml @@ -34,7 +34,7 @@ - + \ No newline at end of file diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/BaseListItem.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/BaseListItem.java new file mode 100644 index 0000000000..8ef3c9ab07 --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/BaseListItem.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * 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.ui.dropdown; + +/** + * Base implementation of {@link DropdownListItem} which + * represents some value in a {@link DropdownList}. + * + * @param + * type of the value that this item represents + * @see StringItemRenderer + */ +public class BaseListItem implements DropdownListItem { + + private final T value; + + /** + * Creates a new item that represents the given {@code value}. + * + * @param value + * value to represent in a {@link DropdownList}. + */ + public BaseListItem(T value) { + this.value = value; + } + + /** + * Returns the represented value. + * + * @return value this item represents + */ + public T getValue() { + return value; + } +} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownListFactory.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownListFactory.java deleted file mode 100644 index 0d4567ee11..0000000000 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownListFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * 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.ui.dropdown; - -import javax.validation.constraints.NotNull; - -/** - * The factory for creating drop down list. - * - * @author Valeriy Svydenko - */ -public interface DropDownListFactory { - - /** - * Create an instance of {@link DropDownWidget} managing action group registered in action manager. - * - * @param actionGroupId - * identifier of {@link org.eclipse.che.ide.api.action.ActionGroup} registered in action manager - * - * @return - * an instance of {@link DropDownWidget} - */ - @NotNull - DropDownWidget createDropDown(@NotNull String actionGroupId); - -} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownWidget.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownWidget.java deleted file mode 100644 index d8f899b783..0000000000 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownWidget.java +++ /dev/null @@ -1,70 +0,0 @@ -/******************************************************************************* - * 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.ui.dropdown; - -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.ide.api.action.Action; - -/** - * Provides methods which allow change visual representation of header of the list. - * - * @author Valeriy Svydenko - * @author Oleksii Orel - * @author Vitaliy Gulily - */ -public interface DropDownWidget { - - /** - * Returns name of the selected element. - * - * @return - * name of the selected element - */ - @Nullable - String getSelectedName(); - - /** - * Returns id of the selected element. - * - * @return - * selected element identifier - */ - @Nullable - String getSelectedId(); - - /** - * Sets id and name of selected element. - * - * @param id - * id of the selected element - * @param name - * name of the selected element - */ - void selectElement(@Nullable String id, @Nullable String name); - - /** - * Creates an instance of element action with given name and id for displaying it. - * - * @param id - * id of element - * @param name - * name of element - * - * @return an instance of selector action - */ - Action createAction(String id, String name); - - /** - * Updates popup elements in drop down part of widget. - */ - void updatePopup(); - -} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownWidgetImpl.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownWidgetImpl.java deleted file mode 100644 index 43a56e8db6..0000000000 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownWidgetImpl.java +++ /dev/null @@ -1,298 +0,0 @@ -/******************************************************************************* - * 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.ui.dropdown; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.logical.shared.ResizeEvent; -import com.google.gwt.event.logical.shared.ResizeHandler; -import com.google.gwt.resources.client.ClientBundle; -import com.google.gwt.resources.client.CssResource; -import com.google.gwt.uibinder.client.UiBinder; -import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.ui.Composite; -import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.Label; -import com.google.gwt.user.client.ui.Widget; -import com.google.inject.Provider; -import com.google.inject.assistedinject.Assisted; -import com.google.inject.assistedinject.AssistedInject; - -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.ide.api.action.Action; -import org.eclipse.che.ide.api.action.ActionEvent; -import org.eclipse.che.ide.api.action.ActionGroup; -import org.eclipse.che.ide.api.action.ActionManager; -import org.eclipse.che.ide.api.action.ActionSelectedHandler; -import org.eclipse.che.ide.api.action.DefaultActionGroup; -import org.eclipse.che.ide.api.action.Presentation; -import org.eclipse.che.ide.api.keybinding.KeyBindingAgent; -import org.eclipse.che.ide.api.parts.PerspectiveManager; -import org.eclipse.che.ide.ui.Tooltip; -import org.eclipse.che.ide.ui.toolbar.MenuLockLayer; -import org.eclipse.che.ide.ui.toolbar.PopupMenu; -import org.eclipse.che.ide.ui.toolbar.PresentationFactory; -import org.vectomatic.dom.svg.ui.SVGResource; - -import javax.validation.constraints.NotNull; - -import static com.google.gwt.dom.client.Style.Unit.PX; -import static org.eclipse.che.ide.ui.menu.PositionController.HorizontalAlign.MIDDLE; -import static org.eclipse.che.ide.ui.menu.PositionController.VerticalAlign.BOTTOM; - -/** - * Class provides general view representation for header of drop down list. - * - * @author Valeriy Svydenko - * @author Oleksii Orel - * @author Vitaliy Guliy - */ -public class DropDownWidgetImpl extends Composite implements ActionSelectedHandler, ClickHandler, DropDownWidget { - - interface DropDownWidgetImplUiBinder extends UiBinder { - } - - private static final DropDownWidgetImplUiBinder UI_BINDER = GWT.create(DropDownWidgetImplUiBinder.class); - - @UiField - FlowPanel marker; - - @UiField - Label selectedElementName; - - @UiField - FlowPanel selectedElement; - - @UiField - FlowPanel listHeader; - - private final String actionGroupId; - - private final Resources resources; - private final ActionManager actionManager; - private final KeyBindingAgent keyBindingAgent; - private final PresentationFactory presentationFactory; - private final DefaultActionGroup actions; - private final Provider managerProvider; - - private String selectedId; - private String selectedName; - private PopupMenu popupMenu; - private MenuLockLayer lockLayer; - private Tooltip tooltip; - - - @AssistedInject - public DropDownWidgetImpl(Resources resources, - ActionManager actionManager, - KeyBindingAgent keyBindingAgent, - Provider managerProvider, - @NotNull @Assisted String actionGroupId) { - this.resources = resources; - this.actionGroupId = actionGroupId; - - initWidget(UI_BINDER.createAndBindUi(this)); - - resources.dropdownListCss().ensureInjected(); - - listHeader.setStyleName(resources.dropdownListCss().menuElement()); - - marker.getElement().appendChild(resources.expansionImage().getSvg().getElement()); - marker.addStyleName(resources.dropdownListCss().expandedImage()); - - addDomHandler(this, ClickEvent.getType()); - - this.actionManager = actionManager; - this.keyBindingAgent = keyBindingAgent; - this.managerProvider = managerProvider; - - presentationFactory = new PresentationFactory(); - actions = new DefaultActionGroup(actionManager); - - Window.addResizeHandler(new ResizeHandler() { - @Override - public void onResize(ResizeEvent event) { - updatePopup(); - } - }); - } - - /** {@inheritDoc} */ - @Override - public void selectElement(String id, String name) { - selectedId = id; - selectedName = name; - selectedElementName.setText(name == null ? "---" : name); - tooltip = Tooltip.create((elemental.dom.Element)listHeader.getElement(), BOTTOM, MIDDLE, name); - } - - /** {@inheritDoc} */ - @Nullable - @Override - public String getSelectedName() { - return selectedName; - } - - public String getSelectedId() { - return selectedId; - } - - /** {@inheritDoc} */ - @Override - public void onClick(ClickEvent event) { - int left = getAbsoluteLeft(); - int top = getAbsoluteTop() + listHeader.getOffsetHeight(); - int width = listHeader.getOffsetWidth(); - show(left, top, width); - } - - /** {@inheritDoc} */ - @Override - public void updatePopup() { - if (popupMenu == null || !popupMenu.isAttached()) { - return; - } - this.hide(); - int top = getAbsoluteTop() + listHeader.getOffsetHeight(); - show(getAbsoluteLeft(), top, listHeader.getOffsetWidth()); - } - - /** {@inheritDoc} */ - @Override - public Action createAction(String id, String name) { - return new SimpleListElementAction(id, name); - } - - /** {@inheritDoc} */ - @Override - public void onActionSelected(Action action) { - this.hide(); - } - - /** - * Shows a content menu and moves it to specified position. - * - * @param left - * horizontal position - * @param top - * vertical position - * @param width - * header width - */ - private void show(int left, int top, int width) { - hide(); - updateActions(); - - lockLayer = new MenuLockLayer(); - popupMenu = new PopupMenu(actions, - actionManager, - managerProvider, - presentationFactory, - lockLayer, - this, - keyBindingAgent, - actionGroupId, true); - popupMenu.addStyleName(resources.dropdownListCss().dropDownListMenu()); - popupMenu.getElement().getStyle().setTop(top, PX); - popupMenu.getElement().getStyle().setLeft(left, PX); - popupMenu.getElement().getStyle().setWidth(width, PX); - - lockLayer.add(popupMenu); - } - - /** - * Refresh the list of visible actions. - */ - private void updateActions() { - actions.removeAll(); - - ActionGroup mainActionGroup = (ActionGroup)actionManager.getAction(actionGroupId); - if (mainActionGroup == null) { - return; - } - - Action[] children = mainActionGroup.getChildren(null); - for (Action action : children) { - Presentation presentation = presentationFactory.getPresentation(action); - ActionEvent e = new ActionEvent(presentation, actionManager, managerProvider.get()); - - action.update(e); - if (presentation.isVisible()) { - actions.add(action); - } - } - } - - /** Hides opened content menu. */ - private void hide() { - if (popupMenu != null) { - popupMenu.removeFromParent(); - popupMenu = null; - } - - if (lockLayer != null) { - lockLayer.removeFromParent(); - lockLayer = null; - } - } - - /** - * The action which describes simple element of the custom drop down list. - */ - private class SimpleListElementAction extends Action { - private final String id; - private final String name; - - public SimpleListElementAction(String id, String name) { - super(name); - this.id = id; - this.name = name; - } - - /** {@inheritDoc} */ - @Override - public void actionPerformed(ActionEvent e) { - selectElement(id, name); - } - - /** @return the id of the element */ - @NotNull - public String getId() { - return id; - } - - /** @return the title of the element */ - @NotNull - public String getName() { - return name; - } - } - - /** Item style selectors for a categories list item. */ - public interface DropdownCss extends CssResource { - String expandedImage(); - - String menuElement(); - - String dropDownListMenu(); - } - - public interface Resources extends ClientBundle { - @Source({"DropdownList.css", "org/eclipse/che/ide/api/ui/style.css"}) - DropdownCss dropdownListCss(); - - @Source("expansionIcon.svg") - SVGResource expansionImage(); - } - -} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownWidgetImpl.ui.xml b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownWidgetImpl.ui.xml deleted file mode 100644 index 3d972b08fa..0000000000 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropDownWidgetImpl.ui.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - .widget { - display: inline-block; - } - - .selectedElementName { - color: inherit; - font-size: inherit; - overflow: hidden; - text-overflow: ellipsis; - } - - .imagePanel { - float: right; - } - - .container { - float: left; - width: 130px; - } - - - - - - - - - - - diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownList.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownList.java new file mode 100644 index 0000000000..0cd42f4bad --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownList.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * 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.ui.dropdown; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.PopupPanel; +import com.google.gwt.user.client.ui.ScrollPanel; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.Widget; + +import org.eclipse.che.commons.annotation.Nullable; + +import java.util.HashMap; +import java.util.Map; + +import static com.google.gwt.user.client.ui.PopupPanel.AnimationType.ROLL_DOWN; + +/** Dropdown list widget. */ +public class DropdownList extends Composite { + + private static final DropdownListUiBinder UI_BINDER = GWT.create(DropdownListUiBinder.class); + private static final DropdownListResources RESOURCES = GWT.create(DropdownListResources.class); + + /** Maximum amount of items that should visible in dropdown list without scrolling. */ + private static final int MAX_VISIBLE_ITEMS = 7; + /** Amount of pixels reserved for displaying one item in the dropdown list. */ + private static final int ITEM_WIDGET_HEIGHT = 22; + + private static final int DEFAULT_WIDGET_WIDTH_PX = 200; + + private final PopupPanel dropdownPopupPanel; + private final FlowPanel dropdownContentPanel; + private final Widget emptyStateWidget; + + private final Map itemListWidgets; + private final Map itemHeaderWidgets; + + @UiField + SimplePanel selectedItemPanel; + @UiField + SimplePanel dropButtonPanel; + + private SelectionHandler selectionHandler; + private DropdownListItem selectedItem; + + /** Stores true if dropdown panels's width should be always synchronized with the list header's width. */ + private boolean widthsSynced; + + /** Creates new dropdown widget. */ + public DropdownList() { + this(new Label("---")); + } + + /** + * Creates new dropdown widget. + * Uses the given {@code emptyStateText} for displaying an empty list's state. + */ + public DropdownList(String emptyStateText) { + this(new Label(emptyStateText)); + } + + /** + * Creates new dropdown widget. + * Uses the given {@code emptyStateWidget} for displaying an empty list's state. + */ + public DropdownList(Widget emptyStateWidget) { + itemListWidgets = new HashMap<>(); + itemHeaderWidgets = new HashMap<>(); + + this.emptyStateWidget = emptyStateWidget; + + initWidget(UI_BINDER.createAndBindUi(this)); + + dropButtonPanel.getElement().appendChild(RESOURCES.expansionImage().getSvg().getElement()); + + dropdownContentPanel = new FlowPanel(); + dropdownContentPanel.ensureDebugId("dropdown-list-content-panel"); + + dropdownPopupPanel = new PopupPanel(true); + dropdownPopupPanel.removeStyleName("gwt-PopupPanel"); + dropdownPopupPanel.addStyleName(RESOURCES.dropdownListCss().itemsPanel()); + dropdownPopupPanel.setAnimationEnabled(true); + dropdownPopupPanel.addAutoHidePartner(getElement()); + dropdownPopupPanel.setAnimationType(ROLL_DOWN); + dropdownPopupPanel.add(new ScrollPanel(dropdownContentPanel)); + + attachEventHandlers(); + setSelectedItem(null); + + setWidth(DEFAULT_WIDGET_WIDTH_PX + "px"); + } + + /** + * {@inheritDoc} + *

Note: this method sets the list header's width only. + * Use {@link #setDropdownPanelWidth(String)} to set the dropdown panels's width. + * + * @see #setDropdownPanelWidth(String) + */ + @Override + public void setWidth(String width) { + super.setWidth(width); + } + + /** + * Sets the dropdown panels's width. + * If it's not set explicitly then it will be calculated depending on the children width. + * + * @param width + * the dropdown panels's new width, in CSS units (e.g. "10px", "1em") + * @see #setWidth(String) + */ + public void setDropdownPanelWidth(String width) { + dropdownPopupPanel.setWidth(width); + } + + /** Set the dropdown panels's width should be always synchronized with the list header's width. */ + public void syncWidths() { + widthsSynced = true; + Window.addResizeHandler(e -> setDropdownPanelWidth(getElement().getClientWidth() + "px")); + } + + /** Adapts dropdown panel's height depending on the amount of child items. */ + private void adaptDropDownPanelHeight() { + final int visibleRowsCount = Math.min(MAX_VISIBLE_ITEMS, itemListWidgets.size()); + final int dropdownPanelHeight = ITEM_WIDGET_HEIGHT * visibleRowsCount; + + dropdownPopupPanel.setHeight(dropdownPanelHeight + "px"); + } + + private void attachEventHandlers() { + selectedItemPanel.addDomHandler(e -> toggleListVisibility(), ClickEvent.getType()); + emptyStateWidget.addDomHandler(e -> toggleListVisibility(), ClickEvent.getType()); + dropButtonPanel.addDomHandler(e -> toggleListVisibility(), ClickEvent.getType()); + } + + private void toggleListVisibility() { + if (dropdownPopupPanel.isShowing()) { + dropdownPopupPanel.hide(); + } else { + dropdownPopupPanel.showRelativeTo(this); + + if (widthsSynced) { + setDropdownPanelWidth(getElement().getClientWidth() + "px"); + } + } + } + + private void checkListEmptiness() { + if (itemListWidgets.isEmpty()) { + setSelectedItem(null); + } + } + + /** Sets the given {@code handler} to notify it about changing selected item. */ + public void setSelectionHandler(SelectionHandler handler) { + selectionHandler = handler; + } + + /** Returns the currently selected item or {@code null} if none. */ + @Nullable + public DropdownListItem getSelectedItem() { + return selectedItem; + } + + /** Set the given item as currently selected. Sets empty state widget if {@code null} were provided. */ + private void setSelectedItem(@Nullable DropdownListItem item) { + selectedItem = item; + selectedItemPanel.setWidget(item != null ? itemHeaderWidgets.get(item) : emptyStateWidget); + } + + /** + * Add the given {@code item} to the top of the list. + * + * @param item + * item to add to the list + * @param renderer + * renderer provides widgets for representing the given {@code item} in the list + */ + public void addItem(DropdownListItem item, DropdownListItemRenderer renderer) { + final Widget headerWidget = renderer.renderHeaderWidget(); + final Widget listWidget = new SimplePanel(renderer.renderListWidget()); + + itemHeaderWidgets.put(item, headerWidget); + itemListWidgets.put(item, listWidget); + + headerWidget.addHandler(e -> toggleListVisibility(), ClickEvent.getType()); + + listWidget.addStyleName(RESOURCES.dropdownListCss().listItem()); + listWidget.addDomHandler(e -> { + setSelectedItem(item); + dropdownPopupPanel.hide(); + + if (selectionHandler != null) { + selectionHandler.onItemSelected(item); + } + }, ClickEvent.getType()); + + dropdownContentPanel.insert(listWidget, 0); + adaptDropDownPanelHeight(); + setSelectedItem(item); + } + + /** + * Short for quick adding text value to the list. + * + * @param value + * text value to add to the list + * @return added item which wraps the given {@code value} + */ + public BaseListItem addItem(String value) { + BaseListItem item = new BaseListItem<>(value); + + addItem(item, new StringItemRenderer(item)); + + return item; + } + + /** Remove item from the list. */ + public void removeItem(DropdownListItem item) { + final Widget widget = itemListWidgets.remove(item); + + if (widget != null) { + dropdownContentPanel.remove(widget); + } + + itemHeaderWidgets.remove(item); + + if (!itemListWidgets.isEmpty()) { + // set any available item as currently selected + setSelectedItem(itemListWidgets.entrySet().iterator().next().getKey()); + } else { + checkListEmptiness(); + } + + adaptDropDownPanelHeight(); + } + + /** Clear the list. */ + public void clear() { + itemListWidgets.clear(); + itemHeaderWidgets.clear(); + dropdownContentPanel.clear(); + + adaptDropDownPanelHeight(); + checkListEmptiness(); + } + + interface DropdownListUiBinder extends UiBinder { + } + + public interface SelectionHandler { + /** + * Called when currently selected item has been changed. + * + * @param item + * currently selected item + */ + void onItemSelected(DropdownListItem item); + } + + static { + RESOURCES.dropdownListCss().ensureInjected(); + } +} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownList.ui.xml b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownList.ui.xml new file mode 100644 index 0000000000..861df3bbd5 --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownList.ui.xml @@ -0,0 +1,72 @@ + + + + + @eval selectCommandActionColor org.eclipse.che.ide.api.theme.Style.getSelectCommandActionColor(); + @eval selectCommandActionHoverColor org.eclipse.che.ide.api.theme.Style.getSelectCommandActionHoverColor(); + + .widget { + height: 22px; + display: inline-block; + cursor: pointer; + background-color: #33373b; + background-image: linear-gradient(to bottom, #444444, #343434 98%); + border: solid 0.6px #454545; + } + + .widget:hover { + color: #53a2ff; + background-image: linear-gradient(to bottom, #3d3d3d, #1d1d1d 98%); + } + + .widget:active { + color: #235c9e; + background-image: linear-gradient(to bottom, #3d3d3d, #1d1d1d); + } + + .selectedItemPanel { + float: left; + width: literal("calc(100% - 27px)"); + padding-left: 5px; + color: inherit; + font-size: inherit; + overflow: hidden; + text-overflow: ellipsis; + line-height: 21px; + } + + .dropButton { + float: right; + padding-top: 2px; + padding-right: 3px; + padding-left: 7px; + } + + .dropButton svg { + width: 10px; + height: 7px; + fill: selectCommandActionColor; + } + + .dropButton:hover svg { + fill: selectCommandActionHoverColor; + } + + + + + + + diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownListItem.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownListItem.java new file mode 100644 index 0000000000..3d5d52a14f --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownListItem.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * 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.ui.dropdown; + +/** + * Interface for the {@link DropdownList}'s item. + * + * @see BaseListItem + */ +public interface DropdownListItem { +} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownListItemRenderer.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownListItemRenderer.java new file mode 100644 index 0000000000..f3bce7665c --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownListItemRenderer.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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.ui.dropdown; + +import com.google.gwt.user.client.ui.Widget; + +/** + * Interface for specifying an arbitrary renderer for {@link DropdownList}'s items. + *

Important: {@link #renderHeaderWidget()} and + * {@link #renderListWidget()} mustn't return the same instance. + * + * @see StringItemRenderer + */ +public interface DropdownListItemRenderer { + + /** Returns widget for representing the {@link DropdownListItem} in the list's header (chosen item). */ + Widget renderHeaderWidget(); + + /** Returns widget for representing the {@link DropdownListItem} in the list. */ + Widget renderListWidget(); +} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownListResources.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownListResources.java new file mode 100644 index 0000000000..894b4ea487 --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/DropdownListResources.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * 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.ui.dropdown; + +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; + +import org.vectomatic.dom.svg.ui.SVGResource; + +/** Client bundle for {@link DropdownList}. */ +public interface DropdownListResources extends ClientBundle { + + @Source({"styles.css", "org/eclipse/che/ide/api/ui/style.css"}) + DropdownCss dropdownListCss(); + + @Source("expansionIcon.svg") + SVGResource expansionImage(); + + interface DropdownCss extends CssResource { + + String itemsPanel(); + + String listItem(); + } +} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/StringItemRenderer.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/StringItemRenderer.java new file mode 100644 index 0000000000..d65177e101 --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/dropdown/StringItemRenderer.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.ui.dropdown; + +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.Widget; + +import static com.google.gwt.dom.client.Style.Unit.PX; + +/** + * Renders the given {@link BaseListItem} as {@link Label}. + * + * @see BaseListItem + */ +public class StringItemRenderer implements DropdownListItemRenderer { + + private final BaseListItem item; + + private Widget headerWidget; + private Widget listWidget; + + public StringItemRenderer(BaseListItem item) { + this.item = item; + } + + @Override + public Widget renderHeaderWidget() { + if (headerWidget == null) { + headerWidget = new Label(item.getValue()); + } + + return headerWidget; + } + + @Override + public Widget renderListWidget() { + if (listWidget == null) { + listWidget = new Label(item.getValue()); + listWidget.getElement().getStyle().setMarginBottom(0, PX); + } + + return listWidget; + } +} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/ActionHandler.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/ActionHandler.java new file mode 100644 index 0000000000..96e1f97d4f --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/ActionHandler.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * 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.ui.menubutton; + +/** Action handler for {@link MenuPopupButton}. */ +public interface ActionHandler { + + /** + * Called when action (mouse click) on the {@code item}has been performed. + * + * @param item + * the item on which action has been performed + */ + void onAction(PopupItem item); +} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/MenuPopupButton.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/MenuPopupButton.java new file mode 100644 index 0000000000..431942d5de --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/MenuPopupButton.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * 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.ui.menubutton; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.event.dom.client.MouseDownEvent; +import com.google.gwt.event.dom.client.MouseOutEvent; +import com.google.gwt.event.dom.client.MouseUpEvent; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.ButtonBase; +import com.google.gwt.user.client.ui.FlowPanel; + +import org.vectomatic.dom.svg.ui.SVGResource; + +import java.util.Optional; + +/** Button with popup menu opened by long click. */ +public class MenuPopupButton extends ButtonBase { + + private static final Resources RESOURCES; + + protected final MenuPopupItemDataProvider dataProvider; + private final Timer showMenuTimer; + + private ActionHandler actionHandler; + + private FlowPanel marker = new FlowPanel(); + private PopupItemList popupItemList; + + public MenuPopupButton(SafeHtml content, MenuPopupItemDataProvider dataProvider) { + super(Document.get().createDivElement()); + + this.dataProvider = dataProvider; + + getElement().setInnerSafeHtml(content); + + showMenuTimer = new Timer() { + @Override + public void run() { + showMenu(); + } + }; + + addStyleName(RESOURCES.css().button()); + attachEventHandlers(); + + dataProvider.setItemDataChangedHandler(this::updateButton); + } + + private void attachEventHandlers() { + addDomHandler(event -> showMenuTimer.cancel(), MouseOutEvent.getType()); + + addDomHandler(event -> { + if (event.getNativeButton() == NativeEvent.BUTTON_LEFT) { + showMenuTimer.schedule(1000); + } else { + showMenuTimer.cancel(); + } + }, MouseDownEvent.getType()); + + addDomHandler(event -> showMenuTimer.cancel(), MouseUpEvent.getType()); + + addClickHandler(event -> { + if (popupItemList != null && popupItemList.isShowing()) { + return; + } + + final PopupItem defaultItem = dataProvider.getDefaultItem(); + + if (defaultItem != null) { + getActionHandler().ifPresent(actionHandler -> actionHandler.onAction(defaultItem)); + } else { + showMenu(); + } + }); + } + + public Optional getActionHandler() { + return Optional.ofNullable(actionHandler); + } + + public void setActionHandler(ActionHandler actionHandler) { + this.actionHandler = actionHandler; + } + + /** Shows or hides 'Open Menu' button. */ + private void updateButton() { + if (dataProvider.getItems().isEmpty()) { + marker.removeFromParent(); + } else { + marker = new FlowPanel(); + marker.getElement().appendChild(RESOURCES.expansionImage().getSvg().getElement()); + marker.addStyleName(RESOURCES.css().expandedImage()); + getElement().appendChild(marker.getElement()); + } + } + + private void showMenu() { + popupItemList = new PopupItemList(dataProvider.getItems(), dataProvider, RESOURCES, null); + getActionHandler().ifPresent(actionHandler -> popupItemList.setActionHandler(actionHandler)); + popupItemList.setPopupPosition(getAbsoluteLeft(), getAbsoluteTop() + getOffsetHeight()); + popupItemList.show(); + } + + public interface Resources extends ClientBundle { + + @Source("expansionIcon.svg") + SVGResource expansionImage(); + + @Source({"button.css", "org/eclipse/che/ide/api/ui/style.css"}) + Css css(); + } + + public interface Css extends CssResource { + + String button(); + + String popupPanel(); + + String expandedImage(); + + String popupItem(); + + String popupItemOver(); + + String arrow(); + + String label(); + } + + static { + RESOURCES = GWT.create(Resources.class); + RESOURCES.css().ensureInjected(); + } +} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/MenuPopupItemDataProvider.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/MenuPopupItemDataProvider.java new file mode 100644 index 0000000000..ba3f9fe919 --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/MenuPopupItemDataProvider.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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.ui.menubutton; + +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.util.Pair; + +import java.util.List; + +/** Data provider for {@link MenuPopupButton}. */ +public interface MenuPopupItemDataProvider { + + /** Returns the default item, used when user click on button. */ + @Nullable + PopupItem getDefaultItem(); + + /** Returns top level items. */ + List getItems(); + + /** + * Checks whether the given {@code item} is a group. + * Group item cannot be selected. + */ + boolean isGroup(PopupItem item); + + /** Returns the pair of the given {@code parent} children and their labels. */ + @Nullable + Pair, String> getChildren(PopupItem parent); + + /** Sets the {@link ItemDataChangeHandler}. */ + void setItemDataChangedHandler(ItemDataChangeHandler handler); + + interface ItemDataChangeHandler { + /** Should be called when {@link MenuPopupItemDataProvider}'s data has been changed. */ + void onItemDataChanged(); + } +} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/PopupItem.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/PopupItem.java new file mode 100644 index 0000000000..e8f2f40afd --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/PopupItem.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * 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.ui.menubutton; + +/** Item for {@link MenuPopupButton}. */ +public interface PopupItem { + + String getName(); + + boolean isDisabled(); +} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/PopupItemList.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/PopupItemList.java new file mode 100644 index 0000000000..b8340c3e80 --- /dev/null +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/menubutton/PopupItemList.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * 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.ui.menubutton; + +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.Style; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.MouseOverEvent; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.PopupPanel; + +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.FontAwesome; +import org.eclipse.che.ide.util.Pair; + +import java.util.List; +import java.util.Optional; + +/** Popup list for {@link MenuPopupButton}. */ +class PopupItemList extends PopupPanel { + + private final MenuPopupItemDataProvider dataProvider; + private final MenuPopupButton.Resources resources; + + private ActionHandler actionHandler; + private PopupItemList childList; + + private ItemWidget overItem; + + PopupItemList(List children, + MenuPopupItemDataProvider dataProvider, + MenuPopupButton.Resources resources, + @Nullable String title) { + super(true, false); + + this.dataProvider = dataProvider; + this.resources = resources; + + setAnimationEnabled(true); + setAnimationType(AnimationType.ROLL_DOWN); + addStyleName(resources.css().popupPanel()); + + final FlowPanel content = new FlowPanel(); + add(content); + + if (title != null) { + Label label = new Label(title); + label.setStyleName(resources.css().label()); + content.add(label); + } + + children.forEach(child -> content.add(new ItemWidget(child))); + + addCloseHandler(event -> { + if (childList != null && childList.isShowing()) { + childList.hide(false); + } + }); + } + + Optional getActionHandler() { + return Optional.ofNullable(actionHandler); + } + + void setActionHandler(ActionHandler actionHandler) { + this.actionHandler = actionHandler; + } + + private class ItemWidget extends FlowPanel { + + private final PopupItem item; + + ItemWidget(PopupItem item) { + this.item = item; + + addStyleName(resources.css().popupItem()); + + final Element itemLabel = Document.get().createDivElement(); + itemLabel.setInnerText(item.getName()); + itemLabel.getStyle().setFloat(Style.Float.LEFT); + + getElement().appendChild(itemLabel); + + if (dataProvider.isGroup(item)) { + DivElement arrow = Document.get().createDivElement(); + arrow.setInnerHTML(FontAwesome.PLAY); + arrow.addClassName(resources.css().arrow()); + getElement().appendChild(arrow); + } + + attachEventHandlers(); + } + + private void attachEventHandlers() { + addDomHandler(event -> { + if (overItem != null) { + overItem.removeStyleName(resources.css().popupItemOver()); + } + overItem = ItemWidget.this; + addStyleName(resources.css().popupItemOver()); + if (childList != null) { + childList.hide(); + } + + if (dataProvider.isGroup(item)) { + Pair, String> children = dataProvider.getChildren(item); + createChildPopup(children); + } + }, MouseOverEvent.getType()); + + addDomHandler(event -> { + if (dataProvider.isGroup(item)) { + return; + } + + hide(true); + + getActionHandler().ifPresent(actionHandler -> actionHandler.onAction(item)); + }, ClickEvent.getType()); + } + + private void createChildPopup(Pair, String> children) { + childList = new PopupItemList(children.first, dataProvider, resources, "Execute on:"); + getActionHandler().ifPresent(actionHandler -> childList.setActionHandler(actionHandler)); + childList.setPopupPosition(getAbsoluteLeft() + getOffsetWidth(), getAbsoluteTop()); + childList.show(); + childList.setAutoHideEnabled(false); + childList.setAnimationEnabled(false); + childList.addCloseHandler(event -> { + if (event.isAutoClosed()) { + hide(); + } + }); + } + } +} diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/SubPanel.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/SubPanel.java index a3a1108786..78576c7135 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/SubPanel.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/multisplitpanel/SubPanel.java @@ -105,7 +105,5 @@ public interface SubPanel { /** Invoked when a {@code widget} on a {@code panel} was double clicked. */ void onDoubleClicked(SubPanel panel, IsWidget widget); - } - } diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/radiobuttongroup/RadioButtonGroup.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/radiobuttongroup/RadioButtonGroup.java index 6a8e453315..ced96b379b 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/radiobuttongroup/RadioButtonGroup.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/radiobuttongroup/RadioButtonGroup.java @@ -15,18 +15,22 @@ import com.google.gwt.dom.client.Node; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.CssResource; +import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.RadioButton; +import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.util.UUID; import org.vectomatic.dom.svg.ui.SVGImage; import org.vectomatic.dom.svg.ui.SVGResource; -import org.eclipse.che.commons.annotation.Nullable; import java.util.ArrayList; import java.util.List; +import static com.google.gwt.dom.client.Element.as; +import static com.google.gwt.dom.client.Style.Unit.PX; + /** * Represents mutually-exclusion set of buttons. * Turning on one of those buttons turns off all other buttons in the group. @@ -38,10 +42,6 @@ public class RadioButtonGroup extends Composite { private static final Resources resources = GWT.create(Resources.class); - static { - resources.getCSS().ensureInjected(); - } - private final String GROUP_NAME; private List buttons; @@ -50,6 +50,7 @@ public class RadioButtonGroup extends Composite { /** Creates new mutually-exclusion group of buttons. */ public RadioButtonGroup() { GROUP_NAME = "buttons-group-" + UUID.uuid(); + buttons = new ArrayList<>(); mainPanel = new FlowPanel(); mainPanel.setStyleName(resources.getCSS().mainPanel()); @@ -58,14 +59,14 @@ public class RadioButtonGroup extends Composite { } /** - * Adds the new button to the group. + * Adds the new radio button to the group. * * @param label - * button's label + * radio button's label * @param title - * button's tooltip + * radio button's tooltip * @param icon - * button's icon + * radio button's icon * @param clickHandler * click handler */ @@ -75,14 +76,17 @@ public class RadioButtonGroup extends Composite { radioButton.setStyleName(resources.getCSS().button()); radioButton.addClickHandler(clickHandler); - final Node child = radioButton.getElement().getLastChild(); + final Element radioButtonElement = radioButton.getElement(); + final Node labelNode = radioButtonElement.getLastChild(); if (icon != null) { - final SVGImage svgImage = new SVGImage(icon); - child.insertFirst(svgImage.getElement()); + labelNode.insertFirst(new SVGImage(icon).getElement()); + } else { + radioButtonElement.getStyle().setWidth(90, PX); + as(labelNode).getStyle().setWidth(90, PX); } - mainPanel.add(radioButton); + mainPanel.add(radioButton); buttons.add(radioButton); } @@ -111,4 +115,8 @@ public class RadioButtonGroup extends Composite { String button(); } } + + static { + resources.getCSS().ensureInjected(); + } } diff --git a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/switcher/Switcher.java b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/switcher/Switcher.java index 9cd504524a..0d4f4190e9 100644 --- a/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/switcher/Switcher.java +++ b/ide/che-core-ide-ui/src/main/java/org/eclipse/che/ide/ui/switcher/Switcher.java @@ -30,16 +30,69 @@ import com.google.gwt.user.client.ui.SimpleCheckBox; * @author Ann Shumilova */ public class Switcher extends Composite implements HasValue { - private static final Resources resources = GWT.create(Resources.class); - static { - resources.switcherCSS().ensureInjected(); - } + private static final Resources RESOURCES = GWT.create(Resources.class); SimpleCheckBox checkbox; + public Switcher() { + FlowPanel mainPanel = new FlowPanel(); + mainPanel.setStyleName(RESOURCES.switcherCSS().onoffswitch()); + + final String elementId = DOM.createUniqueId(); + + checkbox = new SimpleCheckBox(); + checkbox.getElement().setId(elementId); + checkbox.setName("onoffswitch"); + checkbox.setStyleName(RESOURCES.switcherCSS().onoffswitchCheckbox()); + mainPanel.add(checkbox); + + Element label = DOM.createLabel(); + label.setClassName(RESOURCES.switcherCSS().onoffswitchLabel()); + label.setAttribute("for", elementId); + + Element inner = DOM.createDiv(); + inner.setClassName(RESOURCES.switcherCSS().onoffswitchInner()); + label.appendChild(inner); + + Element sw = DOM.createDiv(); + sw.setClassName(RESOURCES.switcherCSS().onoffswitchSwitch()); + label.appendChild(sw); + + mainPanel.getElement().appendChild(label); + + initWidget(mainPanel); + } + + @Override + public HandlerRegistration addValueChangeHandler(ValueChangeHandler handler) { + return checkbox.addValueChangeHandler(handler); + } + + @Override + public Boolean getValue() { + return checkbox.getValue(); + } + + @Override + public void setValue(Boolean value) { + checkbox.setValue(value); + } + + @Override + public void setValue(Boolean value, boolean fireEvents) { + checkbox.setValue(value); + + if (fireEvents) { + ValueChangeEvent.fire(this, value); + } + } + public interface Resources extends ClientBundle { - public interface SwitcherCSS extends CssResource { + @Source({"switcher.css", "org/eclipse/che/ide/api/ui/style.css"}) + SwitcherCSS switcherCSS(); + + interface SwitcherCSS extends CssResource { String onoffswitchInner(); String onoffswitch(); @@ -49,69 +102,10 @@ public class Switcher extends Composite implements HasValue { String onoffswitchLabel(); String onoffswitchCheckbox(); - - } - - @Source({"switcher.css", "org/eclipse/che/ide/api/ui/style.css"}) - SwitcherCSS switcherCSS(); - } - - - public Switcher() { - FlowPanel mainPanel = new FlowPanel(); - mainPanel.setStyleName(resources.switcherCSS().onoffswitch()); - - checkbox = new SimpleCheckBox(); - checkbox.getElement().setId("switcher"); - checkbox.setName("onoffswitch"); - checkbox.setStyleName(resources.switcherCSS().onoffswitchCheckbox()); - mainPanel.add(checkbox); - - Element label = DOM.createLabel(); - label.setClassName(resources.switcherCSS().onoffswitchLabel()); - label.setAttribute("for", "switcher"); - - Element inner = DOM.createDiv(); - inner.setClassName(resources.switcherCSS().onoffswitchInner()); - label.appendChild(inner); - - Element sw = DOM.createDiv(); - sw.setClassName(resources.switcherCSS().onoffswitchSwitch()); - label.appendChild(sw); - - mainPanel.getElement().appendChild(label); - - initWidget(mainPanel); - } - - /** {@inheritDoc} */ - @Override - public HandlerRegistration addValueChangeHandler(ValueChangeHandler handler) { - return checkbox.addValueChangeHandler(handler); - } - - - /** {@inheritDoc} */ - @Override - public Boolean getValue() { - return checkbox.getValue(); - } - - - /** {@inheritDoc} */ - @Override - public void setValue(Boolean value) { - checkbox.setValue(value); - } - - - /** {@inheritDoc} */ - @Override - public void setValue(Boolean value, boolean fireEvents) { - checkbox.setValue(value); - if (fireEvents) { - ValueChangeEvent.fire(this, value); } } + static { + RESOURCES.switcherCSS().ensureInjected(); + } } diff --git a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/dropdown/DropdownList.css b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/dropdown/DropdownList.css deleted file mode 100644 index d0d761caeb..0000000000 --- a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/dropdown/DropdownList.css +++ /dev/null @@ -1,68 +0,0 @@ -/******************************************************************************* - * 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 - *******************************************************************************/ -.expandedImage { - transform: scaleY(0.5) rotate(90deg); - margin-left: 3px; - margin-top: 1px; -} - -.expandedImage svg { - width: 12px; - height: 12px; - fill: selectCommandActionColor; -} - -.expandedImage:hover svg { - fill: selectCommandActionHoverColor; -} - -.menuElement { - height: 100%; - color: selectCommandActionColor; -} - -.menuElement:hover { - color: selectCommandActionHoverColor; -} - -.menuElement:focus { - color: selectCommandActionHoverColor; - background-color: hoverBackgroundColor; -} - -.dropDownListMenu { - max-height: 300px; - overflow-x: hidden; - overflow-y: auto; - transition: opacity 0.2s; -} - -.dropDownListMenu > table { - min-width: 25px; - width: inherit; -} - -.dropDownListMenu > table > tbody > tr > td { - padding: 0; -} - -.dropDownListMenu > table > tbody > tr > td > div { - margin-left: 10px; - text-transform: uppercase; -} - -.dropDownListMenu > table > tbody > tr > td:first-child { - width: 16px; -} - -.dropDownListMenu > table > tbody > tr > td:last-child { - width: 0; -} diff --git a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/dropdown/expansionIcon.svg b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/dropdown/expansionIcon.svg index 527260974f..16d1440fd2 100644 --- a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/dropdown/expansionIcon.svg +++ b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/dropdown/expansionIcon.svg @@ -12,7 +12,7 @@ --> - - + + diff --git a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/dropdown/styles.css b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/dropdown/styles.css new file mode 100644 index 0000000000..d7572f57bf --- /dev/null +++ b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/dropdown/styles.css @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +.itemsPanel { + background-color: openedFilesDropdownListBackgroundColor; + border: 1px solid openedFilesDropdownListBorderColor; + box-shadow: 0 2px 2px 0 openedFilesDropdownListShadowColor; + border-radius: 0 0 3px 3px; +} + +.listItem { + width: literal("calc(100% - 27px)"); + height: 22px; + padding: 0 22px 0 5px; + cursor: pointer; + line-height: 22px; +} + +.listItem:hover { + background-color: hoverBackgroundColor; +} diff --git a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/menubutton/button.css b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/menubutton/button.css new file mode 100644 index 0000000000..db5efc6c7b --- /dev/null +++ b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/menubutton/button.css @@ -0,0 +1,94 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ +.button { + width: 32px; + height: 22px; + color: #4990e2; + background-image: linear-gradient(to bottom, #444444, #343434 98%); + border: solid 0.6px #454545; + font-size: 17px; + font-weight: normal; + font-style: normal; + font-stretch: normal; + text-align: center; + cursor: pointer; +} + +.button:focus { + outline: none; +} + +.button:hover { + color: #53a2ff; + background-image: linear-gradient(to bottom, #3d3d3d, #1d1d1d 98%); +} + +.button:active { + color: #235c9e; + background-image: linear-gradient(to bottom, #3d3d3d, #1d1d1d); +} + +.popupPanel { + background-color: #212325; + box-shadow: 0 1px 3px 0 #202020; + border: solid 1px #161819; + font-size: 10px; + font-weight: normal; + font-style: normal; + font-stretch: normal; + line-height: 16px;; + color: #dddddd; + padding: 0; +} + +.expandedImage { + transform: scaleY(0.6) rotate(90deg); + margin-left: 1px; + margin-top: 6px; + float: right; +} + +.expandedImage svg { + width: 9px; + height: 9px; + fill: selectCommandActionColor; +} + +.expandedImage:hover svg { + fill: selectCommandActionHoverColor; +} + +.popupItem { + height: 20px; + line-height: 20px; + padding: 0 10px; + cursor: default; +} + +.popupItemOver { + background-color: #2e3945; + color: #4eabff; +} + +.arrow { + float: right; + margin-left: 10px; + color: #dddddd; +} + +.label { + padding-left: 7px; + font-size: 10px; + font-weight: normal; + font-style: normal; + font-stretch: normal; + color: #919191; +} \ No newline at end of file diff --git a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/menubutton/expansionIcon.svg b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/menubutton/expansionIcon.svg new file mode 100644 index 0000000000..527260974f --- /dev/null +++ b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/menubutton/expansionIcon.svg @@ -0,0 +1,18 @@ + + + + + + diff --git a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/radiobuttongroup/radio-button-group.css b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/radiobuttongroup/radio-button-group.css index 8b78856c72..a22b7d8833 100644 --- a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/radiobuttongroup/radio-button-group.css +++ b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/radiobuttongroup/radio-button-group.css @@ -30,6 +30,9 @@ background: inherit; display: inline-block; vertical-align: middle; + color: #aaaaaa; + font-size: buttonFontSize; + font-family: mainFontFamily; } .mx-button label svg { @@ -42,6 +45,10 @@ filter: drop-shadow(0 0.5px 0 rgba(0, 0, 0, 0.3)); } +.mx-button label:hover { + color: toolbarHoverIconColor; +} + .mx-button label:hover svg { fill: toolbarHoverIconColor; } @@ -53,6 +60,7 @@ .mx-button input:checked + label { background: perspectiveSwitcherBackgroundColor; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.5); + color: #eeeeee; } .mx-button:first-child label { diff --git a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/switcher/switcher.css b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/switcher/switcher.css index 8e66d098cc..6156122b72 100644 --- a/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/switcher/switcher.css +++ b/ide/che-core-ide-ui/src/main/resources/org/eclipse/che/ide/ui/switcher/switcher.css @@ -8,6 +8,11 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ +@eval primaryButtonBackground org.eclipse.che.ide.api.theme.Style.theme.getPrimaryButtonBackground(); +@eval buttonBackground org.eclipse.che.ide.api.theme.Style.theme.getButtonBackground(); +@eval partBackground org.eclipse.che.ide.api.theme.Style.theme.partBackground(); +@eval outputBackgroundColor org.eclipse.che.ide.api.theme.Style.theme.outputBackgroundColor(); + .onoffswitch { position: relative; width: 50px; @@ -24,17 +29,15 @@ display: block; overflow: hidden; cursor: pointer; - border: 2px solid #5E5E5E; - border-radius: 13px; + width: 55px; + height: 18px; + background-color: outputBackgroundColor; } .onoffswitchInner { width: 200%; margin-left: -100%; - -moz-transition: margin 0.3s ease-in 0s; - -webkit-transition: margin 0.3s ease-in 0s; - -o-transition: margin 0.3s ease-in 0s; - transition: margin 0.3s ease-in 0s; + transition: margin 0.2s ease-in; } .onoffswitchInner:before, .onoffswitchInner:after { @@ -53,34 +56,27 @@ } .onoffswitchInner:before { - content: "ON"; + content: "YES"; padding-left: 5px; - background-color: #3E6CA5; - color: #FFFFFF; + color: primaryButtonBackground; } .onoffswitchInner:after { - content: "OFF"; - padding-right: 3px; - background-color: #EEEEEE; + content: "NO"; + padding-right: 8px; color: #999999; text-align: right; } .onoffswitchSwitch { width: 21px; + height: 12px; margin: -0.5px; - background: #DDDDDD; - border: 2px solid #5E5E5E; - border-radius: 13px; + background: buttonBackground; position: absolute; - top: 0; - bottom: 0; + top: 3px; right: 26px; - -moz-transition: all 0.3s ease-in 0s; - -webkit-transition: all 0.3s ease-in 0s; - -o-transition: all 0.3s ease-in 0s; - transition: all 0.3s ease-in 0s; + transition: all 0.2s ease-in; } .onoffswitchCheckbox:checked + .onoffswitchLabel .onoffswitchInner { @@ -89,4 +85,5 @@ .onoffswitchCheckbox:checked + .onoffswitchLabel .onoffswitchSwitch { right: 0px; -} \ No newline at end of file + background: primaryButtonBackground; +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/api/promises/client/js/Promises.java b/ide/commons-gwt/src/main/java/org/eclipse/che/api/promises/client/js/Promises.java index fba7803404..b3b80515fc 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/api/promises/client/js/Promises.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/api/promises/client/js/Promises.java @@ -18,6 +18,7 @@ import com.google.gwt.core.client.JsArrayMixed; import org.eclipse.che.api.promises.client.Promise; import org.eclipse.che.api.promises.client.PromiseError; +import org.eclipse.che.api.promises.client.PromiseProvider; /** * A smattering of useful methods to work with Promises. @@ -65,12 +66,18 @@ public final class Promises { * @param promises * the included promises * @return a promise with an array of unit values as fulfillment value + * @deprecated use {@link PromiseProvider#all(ArrayOf)} */ + @Deprecated public static final native JsPromise all(ArrayOf> promises) /*-{ return Promise.all(promises); }-*/; - /** @see #all(ArrayOf) */ + /** + * @see #all(ArrayOf) + * @deprecated use {@link PromiseProvider#all2(Promise[])} + */ + @Deprecated public static final JsPromise all(final Promise... promises) { final JsArrayOf> promisesArray = JavaScriptObject.createArray().cast(); for (final Promise promise : promises) { @@ -87,7 +94,9 @@ public final class Promises { * @param * the type of the returned promise * @return + * @deprecated use {@link PromiseProvider#reject(PromiseError)} */ + @Deprecated public static final native JsPromise reject(PromiseError reason) /*-{ return Promise.reject(reason); }-*/; @@ -100,7 +109,9 @@ public final class Promises { * @param * the type of the returned promise * @return a promise that is resolved with the specified value + * @deprecated use {@link PromiseProvider#resolve(U)} */ + @Deprecated public static final native JsPromise resolve(U value) /*-{ return Promise.resolve(value); }-*/; diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/FontAwesome.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/FontAwesome.java index 3874d8ea03..fb422dcd24 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/FontAwesome.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/FontAwesome.java @@ -147,4 +147,43 @@ public class FontAwesome { */ public static final String PAUSE = ""; + /** + * http://fontawesome.io/icon/play/ + */ + public static final String PLAY = ""; + + /** + * http://fontawesome.io/icon/repeat/ + */ + public static final String REPEAT = ""; + + /** + * http://fontawesome.io/icon/stop/ + */ + public static final String STOP = ""; + + /** + * http://fontawesome.io/icon/bug/ + */ + public static final String BUG = ""; + + /** + * http://fontawesome.io/icon/bullseye/ + */ + public static final String BULLSEYE = ""; + + /** + * http://fontawesome.io/icon/list/ + */ + public static final String LIST = ""; + + /** + * http://fontawesome.io/icon/arrow-up/ + */ + public static final String ARROW_UP = ""; + + /** + * http://fontawesome.io/icon/arrow-down/ + */ + public static final String ARROW_DOWN = ""; } diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/filters/FuzzyMatches.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/filters/FuzzyMatches.java similarity index 98% rename from plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/filters/FuzzyMatches.java rename to ide/commons-gwt/src/main/java/org/eclipse/che/ide/filters/FuzzyMatches.java index 8a5daf9c5b..f1dcddd0b0 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/filters/FuzzyMatches.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/filters/FuzzyMatches.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.plugin.languageserver.ide.filters; +package org.eclipse.che.ide.filters; import com.google.gwt.regexp.shared.MatchResult; import com.google.gwt.regexp.shared.RegExp; @@ -20,9 +20,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import static org.eclipse.che.plugin.languageserver.ide.filters.Matcher.MatcherUtil.*; +import static org.eclipse.che.ide.filters.Matcher.MatcherUtil.or; + /** + * Fuzzy logic to match some string + * * @author Evgen Vidolob */ @Singleton diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/filters/Match.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/filters/Match.java similarity index 87% rename from plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/filters/Match.java rename to ide/commons-gwt/src/main/java/org/eclipse/che/ide/filters/Match.java index 0fcc47c9e2..61d6bc91af 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/filters/Match.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/filters/Match.java @@ -8,9 +8,11 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.plugin.languageserver.ide.filters; +package org.eclipse.che.ide.filters; /** + * Result of {@link Matcher#match(String, String)}, contains start and end offset in matched string. + * * @author Evgen Vidolob */ public class Match { diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/filters/Matcher.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/filters/Matcher.java similarity index 95% rename from plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/filters/Matcher.java rename to ide/commons-gwt/src/main/java/org/eclipse/che/ide/filters/Matcher.java index 87da77afee..e8984d8426 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/filters/Matcher.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/filters/Matcher.java @@ -8,7 +8,7 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.plugin.languageserver.ide.filters; +package org.eclipse.che.ide.filters; import org.eclipse.che.commons.annotation.Nullable; @@ -16,6 +16,8 @@ import java.util.ArrayList; import java.util.List; /** + * Matcher the wey to match some string. + * S * @author Evgen Vidolob */ public interface Matcher { diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/ui/listbox/CustomComboBox.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/ui/listbox/CustomComboBox.java index 7e9ead1f45..b0cc219b61 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/ui/listbox/CustomComboBox.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/ui/listbox/CustomComboBox.java @@ -83,6 +83,7 @@ public class CustomComboBox extends FocusWidget implements HasChangeHandlers { comboBoxElement.appendChild(RESOURCES.arrow().getSvg().getElement()); optionsPanel.setVisible(false); + optionsPanel.ensureDebugId("custom-combobox-content-panel"); addDomHandler(new BlurHandler() { @Override diff --git a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateCSourceFileAction.java b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateCSourceFileAction.java index cb397f8395..c5b2814bbf 100644 --- a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateCSourceFileAction.java +++ b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateCSourceFileAction.java @@ -11,12 +11,14 @@ package org.eclipse.che.plugin.cpp.ide.action; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.plugin.cpp.ide.CppLocalizationConstant; import org.eclipse.che.plugin.cpp.ide.CppResources; @@ -45,7 +47,8 @@ public class CreateCSourceFileAction extends NewClikeResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.createCFileActionTitle(), localizationConstant.createCFileActionDescription(), cppResources.cFile(), @@ -53,7 +56,8 @@ public class CreateCSourceFileAction extends NewClikeResourceAction { coreLocalizationConstant, eventBus, appContext, - notificationManager); + notificationManager, + editorAgentProvider); } @Override diff --git a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateCppSourceFileAction.java b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateCppSourceFileAction.java index 61889cb6e9..9077e294aa 100644 --- a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateCppSourceFileAction.java +++ b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateCppSourceFileAction.java @@ -11,12 +11,14 @@ package org.eclipse.che.plugin.cpp.ide.action; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.plugin.cpp.ide.CppLocalizationConstant; import org.eclipse.che.plugin.cpp.ide.CppResources; @@ -47,10 +49,11 @@ public class CreateCppSourceFileAction extends NewClikeResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.createCppFileActionTitle(), localizationConstant.createCppFileActionDescription(), - cppResources.cppFile(), dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + cppResources.cppFile(), dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); } @Override diff --git a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateHeaderSourceFileAction.java b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateHeaderSourceFileAction.java index d12897602a..12592050ba 100644 --- a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateHeaderSourceFileAction.java +++ b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/CreateHeaderSourceFileAction.java @@ -11,12 +11,14 @@ package org.eclipse.che.plugin.cpp.ide.action; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.plugin.cpp.ide.CppLocalizationConstant; import org.eclipse.che.plugin.cpp.ide.CppResources; @@ -43,11 +45,12 @@ public class CreateHeaderSourceFileAction extends NewClikeResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.createCHeaderFileActionTitle(), localizationConstant.createCHeaderFileActionDescription(), cppResources.cHeaderFile(), - dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); } @Override diff --git a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/NewClikeResourceAction.java b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/NewClikeResourceAction.java index 9d5aa29756..eda0e416c0 100644 --- a/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/NewClikeResourceAction.java +++ b/plugins/plugin-cpp/che-plugin-cpp-lang-ide/src/main/java/org/eclipse/che/plugin/cpp/ide/action/NewClikeResourceAction.java @@ -10,11 +10,13 @@ *******************************************************************************/ package org.eclipse.che.plugin.cpp.ide.action; +import com.google.inject.Provider; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import org.vectomatic.dom.svg.ui.SVGResource; @@ -44,8 +46,9 @@ public abstract class NewClikeResourceAction extends AbstractNewResourceAction CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { - super(title, description, svgIcon, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + NotificationManager notificationManager, + Provider editorAgentProvider) { + super(title, description, svgIcon, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); this.appContext = appContext; } } diff --git a/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/java/org/eclipse/che/plugin/csharp/ide/action/CreateCSharpSourceFileAction.java b/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/java/org/eclipse/che/plugin/csharp/ide/action/CreateCSharpSourceFileAction.java index 5eacaf2249..3f19094286 100644 --- a/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/java/org/eclipse/che/plugin/csharp/ide/action/CreateCSharpSourceFileAction.java +++ b/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/java/org/eclipse/che/plugin/csharp/ide/action/CreateCSharpSourceFileAction.java @@ -11,12 +11,14 @@ package org.eclipse.che.plugin.csharp.ide.action; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.plugin.csharp.ide.CSharpLocalizationConstant; import org.eclipse.che.plugin.csharp.ide.CSharpResources; @@ -52,7 +54,8 @@ public class CreateCSharpSourceFileAction extends NewCSharplikeResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.createCSharpFileActionTitle(), localizationConstant.createCSharpFileActionDescription(), resources.csharpFile(), @@ -60,7 +63,8 @@ public class CreateCSharpSourceFileAction extends NewCSharplikeResourceAction { coreLocalizationConstant, eventBus, appContext, - notificationManager); + notificationManager, + editorAgentProvider); } @Override diff --git a/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/java/org/eclipse/che/plugin/csharp/ide/action/NewCSharplikeResourceAction.java b/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/java/org/eclipse/che/plugin/csharp/ide/action/NewCSharplikeResourceAction.java index 774944c1a7..960bcbbf70 100644 --- a/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/java/org/eclipse/che/plugin/csharp/ide/action/NewCSharplikeResourceAction.java +++ b/plugins/plugin-csharp/che-plugin-csharp-lang-ide/src/main/java/org/eclipse/che/plugin/csharp/ide/action/NewCSharplikeResourceAction.java @@ -10,11 +10,13 @@ *******************************************************************************/ package org.eclipse.che.plugin.csharp.ide.action; +import com.google.inject.Provider; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import org.vectomatic.dom.svg.ui.SVGResource; @@ -46,8 +48,9 @@ public abstract class NewCSharplikeResourceAction extends AbstractNewResourceAct CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { - super(title, description, svgIcon, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + NotificationManager notificationManager, + Provider editorAgentProvider) { + super(title, description, svgIcon, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); this.appContext = appContext; } } diff --git a/plugins/plugin-dashboard/che-plugin-ext-dashboard/src/main/resources/org/eclipse/che/ide/ext/dashboard/client/Dashboard.css b/plugins/plugin-dashboard/che-plugin-ext-dashboard/src/main/resources/org/eclipse/che/ide/ext/dashboard/client/Dashboard.css index 2a44452ce9..7b8adf0a53 100644 --- a/plugins/plugin-dashboard/che-plugin-ext-dashboard/src/main/resources/org/eclipse/che/ide/ext/dashboard/client/Dashboard.css +++ b/plugins/plugin-dashboard/che-plugin-ext-dashboard/src/main/resources/org/eclipse/che/ide/ext/dashboard/client/Dashboard.css @@ -14,7 +14,7 @@ outline: none; width: 24px; height: 16px; - top: 4px; + top: 9px; background-color: #525c86; color: #f1f1f1!important; font-size: 8px; diff --git a/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/src/main/java/org/eclipse/che/ide/ext/gwt/client/command/GwtCommandType.java b/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/src/main/java/org/eclipse/che/ide/ext/gwt/client/command/GwtCommandType.java index 6f24efe965..4b88982256 100644 --- a/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/src/main/java/org/eclipse/che/ide/ext/gwt/client/command/GwtCommandType.java +++ b/plugins/plugin-gwt/che-plugin-gwt-ext-gwt/src/main/java/org/eclipse/che/ide/ext/gwt/client/command/GwtCommandType.java @@ -52,7 +52,7 @@ public class GwtCommandType implements CommandType { pages = new LinkedList<>(); pages.add(page); - iconRegistry.registerIcon(new Icon(ID + ".commands.category.icon", resources.gwtCommandType())); + iconRegistry.registerIcon(new Icon("command.type." + ID, resources.gwtCommandType())); } @Override diff --git a/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/src/main/java/org/eclipse/che/plugin/jdb/ide/debug/JavaDebuggerFileHandler.java b/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/src/main/java/org/eclipse/che/plugin/jdb/ide/debug/JavaDebuggerFileHandler.java index 68aab01436..88474d2957 100644 --- a/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/src/main/java/org/eclipse/che/plugin/jdb/ide/debug/JavaDebuggerFileHandler.java +++ b/plugins/plugin-java-debugger/che-plugin-java-debugger-ide/src/main/java/org/eclipse/che/plugin/jdb/ide/debug/JavaDebuggerFileHandler.java @@ -94,7 +94,7 @@ public class JavaDebuggerFileHandler implements ActiveFileHandler { public void apply(Optional file) throws OperationException { if (file.isPresent()) { handleActivatedFile(file.get(), callback, location.getLineNumber()); - eventBus.fireEvent(FileEvent.createOpenFileEvent(file.get())); + editorAgent.openEditor(file.get()); } else { callback.onFailure(new IllegalStateException("File is undefined")); } @@ -134,7 +134,7 @@ public class JavaDebuggerFileHandler implements ActiveFileHandler { }; handleActivatedFile(file, downloadSourceCallback, location.getLineNumber()); - eventBus.fireEvent(FileEvent.createOpenFileEvent(file)); + editorAgent.openEditor(file); } }) .catchError(new Operation() { diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/CurrentClassFQN_Macro.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/CurrentClassFQN_Macro.java index 3aaf5c08ed..9cca0d107b 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/CurrentClassFQN_Macro.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/CurrentClassFQN_Macro.java @@ -58,7 +58,7 @@ public class CurrentClassFQN_Macro implements Macro { public Promise expand() { final Resource[] resources = appContext.getResources(); - if (resources == null || resources.length > 1) { + if (resources == null || resources.length != 1) { return Promises.resolve(""); } diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/action/NewPackageAction.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/action/NewPackageAction.java index 1ef894201b..64579460e0 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/action/NewPackageAction.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/action/NewPackageAction.java @@ -12,6 +12,7 @@ package org.eclipse.che.ide.ext.java.client.action; import com.google.common.base.Optional; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; @@ -23,6 +24,7 @@ import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.Folder; @@ -61,10 +63,11 @@ public class NewPackageAction extends AbstractNewResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.actionNewPackageTitle(), localizationConstant.actionNewPackageDescription(), - javaResources.packageItem(), dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + javaResources.packageItem(), dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); } @Override diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/command/JavaCommandType.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/command/JavaCommandType.java index f9d5e02f90..1deca3931f 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/command/JavaCommandType.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/command/JavaCommandType.java @@ -61,7 +61,7 @@ public class JavaCommandType implements CommandType { pages = new LinkedList<>(); pages.add(page); - iconRegistry.registerIcon(new Icon(ID + ".commands.category.icon", resources.javaCategoryIcon())); + iconRegistry.registerIcon(new Icon("command.type." + ID, resources.javaCategoryIcon())); } @Override @@ -86,12 +86,13 @@ public class JavaCommandType implements CommandType { @Override public String getCommandLineTemplate() { + return "cd " + currentProjectPathMacro.getName() + - " && javac -classpath " + classpathMacro.getName() + + "\njavac -classpath " + classpathMacro.getName() + " -sourcepath " + sourcepathMacro.getName() + " -d " + outputDirMacro.getName() + " src/Main.java" + - " && java -classpath " + classpathMacro.getName() + outputDirMacro.getName() + + "\njava -classpath " + classpathMacro.getName() + outputDirMacro.getName() + " Main"; } diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/newsourcefile/NewJavaSourceFilePresenter.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/newsourcefile/NewJavaSourceFilePresenter.java index 87f4786366..45daacf52f 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/newsourcefile/NewJavaSourceFilePresenter.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/newsourcefile/NewJavaSourceFilePresenter.java @@ -15,7 +15,7 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.ide.api.event.FileEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.resources.Container; import org.eclipse.che.ide.api.resources.Resource; import org.eclipse.che.ide.ext.java.client.JavaLocalizationConstant; @@ -48,13 +48,16 @@ public class NewJavaSourceFilePresenter implements NewJavaSourceFileView.ActionD private final NewJavaSourceFileView view; private final List sourceFileTypes; private final JavaLocalizationConstant locale; - private final EventBus eventBus; + private final EventBus eventBus; + private final EditorAgent editorAgent; private Container parent; @Inject - public NewJavaSourceFilePresenter(NewJavaSourceFileView view, JavaLocalizationConstant locale, EventBus eventBus) { + public NewJavaSourceFilePresenter(NewJavaSourceFileView view, JavaLocalizationConstant locale, EventBus eventBus, + EditorAgent editorAgent) { this.locale = locale; this.eventBus = eventBus; + this.editorAgent = editorAgent; sourceFileTypes = Arrays.asList(CLASS, INTERFACE, ENUM, ANNOTATION); this.view = view; this.view.setDelegate(this); @@ -189,13 +192,13 @@ public class NewJavaSourceFilePresenter implements NewJavaSourceFileView.ActionD if (!isNullOrEmpty(packageFragment)) { parent.newFolder(packageFragment.replace('.', '/')).then(pkg -> { pkg.newFile(nameWithoutExtension + ".java", content).then(file -> { - eventBus.fireEvent(FileEvent.createOpenFileEvent(file)); + editorAgent.openEditor(file); eventBus.fireEvent(new RevealResourceEvent(file)); }); }); } else { parent.newFile(nameWithoutExtension + ".java", content).then(file -> { - eventBus.fireEvent(FileEvent.createOpenFileEvent(file)); + editorAgent.openEditor(file); eventBus.fireEvent(new RevealResourceEvent(file)); }); } diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/tree/library/JarFileNode.java b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/tree/library/JarFileNode.java index 9fa33abfd3..9672bd9cc0 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/tree/library/JarFileNode.java +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/java/org/eclipse/che/ide/ext/java/client/tree/library/JarFileNode.java @@ -13,7 +13,6 @@ package org.eclipse.che.ide.ext.java.client.tree.library; import com.google.common.annotations.Beta; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; -import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.api.promises.client.Function; import org.eclipse.che.api.promises.client.FunctionException; @@ -22,7 +21,7 @@ import org.eclipse.che.api.promises.client.js.Promises; import org.eclipse.che.ide.api.data.tree.HasAction; import org.eclipse.che.ide.api.data.tree.Node; import org.eclipse.che.ide.api.data.tree.settings.NodeSettings; -import org.eclipse.che.ide.api.event.FileEvent; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.resources.VirtualFile; import org.eclipse.che.ide.api.theme.Style; import org.eclipse.che.ide.ext.java.client.JavaResources; @@ -50,10 +49,10 @@ public class JarFileNode extends SyntheticNode implements VirtualFile, private final int libId; private final Path project; - private final EventBus eventBus; private final JavaResources javaResources; private final NodesResources nodesResources; private final JavaNavigationService service; + private final EditorAgent editorAgent; private boolean contentGenerated; @Inject @@ -61,17 +60,17 @@ public class JarFileNode extends SyntheticNode implements VirtualFile, @Assisted int libId, @Assisted Path project, @Assisted NodeSettings nodeSettings, - EventBus eventBus, JavaResources javaResources, NodesResources nodesResources, - JavaNavigationService service) { + JavaNavigationService service, + EditorAgent editorAgent) { super(jarEntry, nodeSettings); this.libId = libId; this.project = project; - this.eventBus = eventBus; this.javaResources = javaResources; this.nodesResources = nodesResources; this.service = service; + this.editorAgent = editorAgent; getAttributes().put(CUSTOM_BACKGROUND_FILL, singletonList(Style.theme.projectExplorerReadonlyItemBackground())); } @@ -86,7 +85,7 @@ public class JarFileNode extends SyntheticNode implements VirtualFile, /** {@inheritDoc} */ @Override public void actionPerformed() { - eventBus.fireEvent(FileEvent.createOpenFileEvent(this)); + editorAgent.openEditor(this); } /** {@inheritDoc} */ diff --git a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/resources/org/eclipse/che/ide/ext/java/client/svg/category/java.svg b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/resources/org/eclipse/che/ide/ext/java/client/svg/category/java.svg index b66a2ea09c..81b3a2f08b 100644 --- a/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/resources/org/eclipse/che/ide/ext/java/client/svg/category/java.svg +++ b/plugins/plugin-java/che-plugin-java-ext-lang-client/src/main/resources/org/eclipse/che/ide/ext/java/client/svg/category/java.svg @@ -13,7 +13,7 @@ --> - + diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml b/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml index 457857fd25..3b4b20a6ab 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/pom.xml @@ -62,10 +62,6 @@ org.eclipse.che.core che-core-api-languageserver-shared - - org.eclipse.che.core - che-core-commons-annotations - org.eclipse.che.core che-core-commons-gwt diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java index 9b850ec97e..faa74d311f 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/CompletionItemBasedCompletionProposal.java @@ -10,15 +10,13 @@ *******************************************************************************/ package org.eclipse.che.plugin.languageserver.ide.editor.codeassist; -import io.typefox.lsapi.ServerCapabilities; - import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.Widget; - +import io.typefox.lsapi.ServerCapabilities; import org.eclipse.che.api.languageserver.shared.lsapi.CompletionItemDTO; import org.eclipse.che.api.languageserver.shared.lsapi.RangeDTO; import org.eclipse.che.api.languageserver.shared.lsapi.TextDocumentIdentifierDTO; @@ -32,8 +30,8 @@ import org.eclipse.che.ide.api.editor.document.Document; import org.eclipse.che.ide.api.editor.text.LinearRange; import org.eclipse.che.ide.api.editor.text.TextPosition; import org.eclipse.che.ide.api.icon.Icon; +import org.eclipse.che.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.LanguageServerResources; -import org.eclipse.che.plugin.languageserver.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.service.TextDocumentServiceClient; import java.util.List; diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java index e3e50c4964..f649116666 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/editor/codeassist/LanguageServerCodeAssistProcessor.java @@ -10,11 +10,9 @@ *******************************************************************************/ package org.eclipse.che.plugin.languageserver.ide.editor.codeassist; -import io.typefox.lsapi.ServerCapabilities; - import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; - +import io.typefox.lsapi.ServerCapabilities; import org.eclipse.che.api.languageserver.shared.lsapi.CompletionItemDTO; import org.eclipse.che.api.languageserver.shared.lsapi.CompletionListDTO; import org.eclipse.che.api.languageserver.shared.lsapi.TextDocumentIdentifierDTO; @@ -26,9 +24,9 @@ import org.eclipse.che.ide.api.editor.codeassist.CodeAssistCallback; import org.eclipse.che.ide.api.editor.codeassist.CodeAssistProcessor; import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal; import org.eclipse.che.ide.api.editor.texteditor.TextEditor; +import org.eclipse.che.ide.filters.FuzzyMatches; +import org.eclipse.che.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.LanguageServerResources; -import org.eclipse.che.plugin.languageserver.ide.filters.FuzzyMatches; -import org.eclipse.che.plugin.languageserver.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.service.TextDocumentServiceClient; import org.eclipse.che.plugin.languageserver.ide.util.DtoBuildHelper; diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/symbol/GoToSymbolAction.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/symbol/GoToSymbolAction.java index 62836ed28e..ada8a2aeb6 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/symbol/GoToSymbolAction.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/symbol/GoToSymbolAction.java @@ -10,11 +10,9 @@ *******************************************************************************/ package org.eclipse.che.plugin.languageserver.ide.navigation.symbol; -import io.typefox.lsapi.ServerCapabilities; - import com.google.inject.Inject; import com.google.inject.Singleton; - +import io.typefox.lsapi.ServerCapabilities; import org.eclipse.che.api.languageserver.shared.lsapi.DocumentSymbolParamsDTO; import org.eclipse.che.api.languageserver.shared.lsapi.RangeDTO; import org.eclipse.che.api.languageserver.shared.lsapi.SymbolInformationDTO; @@ -36,10 +34,10 @@ import org.eclipse.che.ide.api.editor.texteditor.TextEditor; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.notification.StatusNotification; import org.eclipse.che.ide.dto.DtoFactory; +import org.eclipse.che.ide.filters.FuzzyMatches; +import org.eclipse.che.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.LanguageServerLocalization; import org.eclipse.che.plugin.languageserver.ide.editor.LanguageServerEditorConfiguration; -import org.eclipse.che.plugin.languageserver.ide.filters.FuzzyMatches; -import org.eclipse.che.plugin.languageserver.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.quickopen.QuickOpenModel; import org.eclipse.che.plugin.languageserver.ide.quickopen.QuickOpenPresenter; import org.eclipse.che.plugin.languageserver.ide.service.TextDocumentServiceClient; @@ -68,7 +66,7 @@ public class GoToSymbolAction extends AbstractPerspectiveAction implements Quick private final EditorAgent editorAgent; private final DtoFactory dtoFactory; private final NotificationManager notificationManager; - private final FuzzyMatches fuzzyMatches; + private final FuzzyMatches fuzzyMatches; private final SymbolKindHelper symbolKindHelper; private QuickOpenPresenter presenter; private List cachedItems; diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/symbol/SymbolEntry.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/symbol/SymbolEntry.java index f879b81944..c2138ee297 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/symbol/SymbolEntry.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/symbol/SymbolEntry.java @@ -13,7 +13,7 @@ package org.eclipse.che.plugin.languageserver.ide.navigation.symbol; import org.eclipse.che.ide.api.editor.text.TextPosition; import org.eclipse.che.ide.api.editor.text.TextRange; import org.eclipse.che.ide.api.editor.texteditor.TextEditor; -import org.eclipse.che.plugin.languageserver.ide.filters.Match; +import org.eclipse.che.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.quickopen.QuickOpenEntryGroup; import org.vectomatic.dom.svg.ui.SVGResource; diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/workspace/FindSymbolAction.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/workspace/FindSymbolAction.java index 2000e40feb..6d3a97d65d 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/workspace/FindSymbolAction.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/workspace/FindSymbolAction.java @@ -14,7 +14,6 @@ import com.google.common.base.Strings; import com.google.common.collect.Sets; import com.google.inject.Inject; import com.google.inject.Singleton; - import org.eclipse.che.api.languageserver.shared.lsapi.LocationDTO; import org.eclipse.che.api.languageserver.shared.lsapi.RangeDTO; import org.eclipse.che.api.languageserver.shared.lsapi.SymbolInformationDTO; @@ -31,9 +30,9 @@ import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.editor.text.TextPosition; import org.eclipse.che.ide.api.editor.text.TextRange; import org.eclipse.che.ide.dto.DtoFactory; +import org.eclipse.che.ide.filters.FuzzyMatches; +import org.eclipse.che.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.LanguageServerLocalization; -import org.eclipse.che.plugin.languageserver.ide.filters.FuzzyMatches; -import org.eclipse.che.plugin.languageserver.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.navigation.symbol.SymbolKindHelper; import org.eclipse.che.plugin.languageserver.ide.quickopen.QuickOpenModel; import org.eclipse.che.plugin.languageserver.ide.quickopen.QuickOpenPresenter; @@ -64,7 +63,7 @@ public class FindSymbolAction extends AbstractPerspectiveAction implements Quick private final DtoFactory dtoFactory; private final EditorAgent editorAgent; private final SymbolKindHelper symbolKindHelper; - private final FuzzyMatches fuzzyMatches; + private final FuzzyMatches fuzzyMatches; private final ThrottledDelayer> delayer; @Inject diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/workspace/SymbolEntry.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/workspace/SymbolEntry.java index f9fadcdf9a..85ae8dcf31 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/workspace/SymbolEntry.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/navigation/workspace/SymbolEntry.java @@ -11,9 +11,9 @@ package org.eclipse.che.plugin.languageserver.ide.navigation.workspace; import org.eclipse.che.ide.api.editor.text.TextRange; -import org.eclipse.che.plugin.languageserver.ide.filters.Match; -import org.eclipse.che.plugin.languageserver.ide.util.OpenFileInEditorHelper; +import org.eclipse.che.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.quickopen.EditorQuickOpenEntry; +import org.eclipse.che.plugin.languageserver.ide.util.OpenFileInEditorHelper; import org.vectomatic.dom.svg.ui.SVGResource; import java.util.List; diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenEntry.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenEntry.java index 50e55312da..239eb30e9c 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenEntry.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenEntry.java @@ -11,7 +11,7 @@ package org.eclipse.che.plugin.languageserver.ide.quickopen; -import org.eclipse.che.plugin.languageserver.ide.filters.Match; +import org.eclipse.che.ide.filters.Match; import org.vectomatic.dom.svg.ui.SVGResource; import java.util.Collections; diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenEntryGroup.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenEntryGroup.java index 1f6ba9b7d6..2ab20a297c 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenEntryGroup.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenEntryGroup.java @@ -10,7 +10,7 @@ *******************************************************************************/ package org.eclipse.che.plugin.languageserver.ide.quickopen; -import org.eclipse.che.plugin.languageserver.ide.filters.Match; +import org.eclipse.che.ide.filters.Match; import org.vectomatic.dom.svg.ui.SVGResource; import java.util.List; diff --git a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenViewImpl.java b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenViewImpl.java index 770e15ef5c..11befabcfe 100644 --- a/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenViewImpl.java +++ b/plugins/plugin-languageserver/che-plugin-languageserver-ide/src/main/java/org/eclipse/che/plugin/languageserver/ide/quickopen/QuickOpenViewImpl.java @@ -10,9 +10,6 @@ *******************************************************************************/ package org.eclipse.che.plugin.languageserver.ide.quickopen; -import elemental.dom.Element; -import elemental.html.SpanElement; - import com.google.gwt.core.client.Scheduler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyDownEvent; @@ -30,13 +27,14 @@ import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.TextBox; import com.google.inject.Inject; - +import elemental.dom.Element; +import elemental.html.SpanElement; import org.eclipse.che.ide.Resources; import org.eclipse.che.ide.api.autocomplete.AutoCompleteResources; +import org.eclipse.che.ide.filters.Match; import org.eclipse.che.ide.ui.list.SimpleList; import org.eclipse.che.ide.util.dom.Elements; import org.eclipse.che.plugin.languageserver.ide.LanguageServerResources; -import org.eclipse.che.plugin.languageserver.ide.filters.Match; import org.eclipse.che.plugin.languageserver.ide.quickopen.QuickOpenEntry.Mode; import org.vectomatic.dom.svg.ui.SVGImage; diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml b/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml index 607ce8a55c..3d956ca319 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/pom.xml @@ -61,6 +61,10 @@ org.eclipse.che.core che-core-api-model + + org.eclipse.che.core + che-core-api-project-shared + org.eclipse.che.core che-core-api-ssh-shared @@ -140,11 +144,6 @@ che-core-api-dto test - - org.eclipse.che.core - che-core-api-project-shared - test - org.hamcrest hamcrest-core diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java index dc16d99faa..2542f712f2 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineExtension.java @@ -38,13 +38,9 @@ import org.eclipse.che.ide.api.parts.Perspective; import org.eclipse.che.ide.api.parts.PerspectiveManager; import org.eclipse.che.ide.api.workspace.event.WorkspaceStartingEvent; import org.eclipse.che.ide.api.workspace.event.WorkspaceStoppedEvent; -import org.eclipse.che.ide.extension.machine.client.actions.EditCommandsAction; -import org.eclipse.che.ide.extension.machine.client.actions.ExecuteSelectedCommandAction; import org.eclipse.che.ide.extension.machine.client.actions.RunCommandAction; -import org.eclipse.che.ide.extension.machine.client.actions.SelectCommandComboBox; import org.eclipse.che.ide.extension.machine.client.actions.ShowConsoleTreeAction; -import org.eclipse.che.ide.extension.machine.client.actions.SwitchPerspectiveAction; -import org.eclipse.che.ide.extension.machine.client.command.macros.ServerPortProvider; +import org.eclipse.che.ide.extension.machine.client.command.macros.ServerAddressMacroRegistrar; import org.eclipse.che.ide.extension.machine.client.machine.MachineStatusHandler; import org.eclipse.che.ide.extension.machine.client.perspective.terminal.TerminalInitializePromiseHolder; import org.eclipse.che.ide.extension.machine.client.processes.NewTerminalAction; @@ -56,9 +52,6 @@ import org.eclipse.che.ide.terminal.client.TerminalResources; import org.eclipse.che.ide.util.input.KeyCodeMap; import org.eclipse.che.plugin.requirejs.ide.RequireJsLoader; -import javax.inject.Named; - -import static org.eclipse.che.ide.api.action.IdeActions.GROUP_CENTER_TOOLBAR; import static org.eclipse.che.ide.api.action.IdeActions.GROUP_CONSOLES_TREE_CONTEXT_MENU; import static org.eclipse.che.ide.api.action.IdeActions.GROUP_RUN; import static org.eclipse.che.ide.api.action.IdeActions.GROUP_WORKSPACE; @@ -74,30 +67,13 @@ import static org.eclipse.che.ide.api.constraints.Constraints.FIRST; @Extension(title = "Machine", version = "1.0.0") public class MachineExtension { - public static final String GROUP_MACHINE_TOOLBAR = "MachineGroupToolbar"; - public static final String GROUP_COMMANDS_DROPDOWN = "CommandsSelector"; - public static final String GROUP_COMMANDS_LIST = "CommandsListGroup"; - public static final String GROUP_MACHINES_DROPDOWN = "MachinesSelector"; - public static final String GROUP_MACHINES_LIST = "MachinesListGroup"; - private final PerspectiveManager perspectiveManager; - /** - * Controls central toolbar action group visibility. Use for example next snippet: - * - * bindConstant().annotatedWith(Names.named("machine.extension.central.toolbar.visibility")).to(false); - * - * to define a constant. If no constant defined than default value is used - true. - */ - @Inject(optional = true) - @Named("central.toolbar.visibility") - boolean centralToolbarVisible = true; - @Inject public MachineExtension(final MachineResources machineResources, final TerminalResources terminalResources, final EventBus eventBus, - final Provider machinePortProvider, + final Provider machinePortProvider, final PerspectiveManager perspectiveManager, final Provider machineStatusHandlerProvider, final AppContext appContext, @@ -189,14 +165,9 @@ public class MachineExtension { } @Inject - private void prepareActions(MachineLocalizationConstant localizationConstant, - ActionManager actionManager, + private void prepareActions(ActionManager actionManager, KeyBindingAgent keyBinding, - ExecuteSelectedCommandAction executeSelectedCommandAction, - SelectCommandComboBox selectCommandAction, - EditCommandsAction editCommandsAction, StopWorkspaceAction stopWorkspaceAction, - SwitchPerspectiveAction switchPerspectiveAction, RunCommandAction runCommandAction, NewTerminalAction newTerminalAction, EditTargetsAction editTargetsAction, @@ -209,11 +180,6 @@ public class MachineExtension { final DefaultActionGroup workspaceMenu = (DefaultActionGroup)actionManager.getAction(GROUP_WORKSPACE); final DefaultActionGroup runMenu = (DefaultActionGroup)actionManager.getAction(GROUP_RUN); - // register actions - actionManager.registerAction("editCommands", editCommandsAction); - actionManager.registerAction("selectCommandAction", selectCommandAction); - actionManager.registerAction("executeSelectedCommand", executeSelectedCommandAction); - actionManager.registerAction("editTargets", editTargetsAction); actionManager.registerAction("stopWorkspace", stopWorkspaceAction); @@ -223,34 +189,10 @@ public class MachineExtension { // add actions in main menu runMenu.add(newTerminalAction, FIRST); runMenu.addSeparator(); - runMenu.add(editCommandsAction); runMenu.add(editTargetsAction); workspaceMenu.add(stopWorkspaceAction); - - if (centralToolbarVisible) { - // add actions on center part of toolbar - final DefaultActionGroup centerToolbarGroup = (DefaultActionGroup)actionManager.getAction(GROUP_CENTER_TOOLBAR); - final DefaultActionGroup machineToolbarGroup = new DefaultActionGroup(GROUP_MACHINE_TOOLBAR, false, actionManager); - actionManager.registerAction(GROUP_MACHINE_TOOLBAR, machineToolbarGroup); - centerToolbarGroup.add(machineToolbarGroup, FIRST); - machineToolbarGroup.add(selectCommandAction); - final DefaultActionGroup executeToolbarGroup = new DefaultActionGroup(actionManager); - executeToolbarGroup.add(executeSelectedCommandAction); - machineToolbarGroup.add(executeToolbarGroup); - } - - // add group for list of machines - final DefaultActionGroup machinesList = new DefaultActionGroup(GROUP_MACHINES_DROPDOWN, true, actionManager); - actionManager.registerAction(GROUP_MACHINES_LIST, machinesList); - machinesList.add(editTargetsAction, FIRST); - - // add group for list of commands - final DefaultActionGroup commandList = new DefaultActionGroup(GROUP_COMMANDS_DROPDOWN, true, actionManager); - actionManager.registerAction(GROUP_COMMANDS_LIST, commandList); - commandList.add(editCommandsAction, FIRST); - // Consoles tree context menu group DefaultActionGroup consolesTreeContextMenu = (DefaultActionGroup)actionManager.getAction(GROUP_CONSOLES_TREE_CONTEXT_MENU); consolesTreeContextMenu.add(reRunProcessAction); diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineLocalizationConstant.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineLocalizationConstant.java index c7967463f6..05a82383c1 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineLocalizationConstant.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineLocalizationConstant.java @@ -34,30 +34,12 @@ public interface MachineLocalizationConstant extends Messages { @Key("control.devMachine.category") String devMachineCategory(); - @Key("control.selectCommand.text") - String selectCommandControlTitle(); - - @Key("control.selectCommand.description") - String selectCommandControlDescription(); - - @Key("control.runSelectedCommand.text") - String executeSelectedCommandControlTitle(); - - @Key("control.runSelectedCommand.description") - String executeSelectedCommandControlDescription(); - @Key("control.runCommand.empty.params") String runCommandEmptyParamsMessage(); @Key("control.runCommand.empty.name") String runCommandEmptyNameMessage(); - @Key("control.editCommands.text") - String editCommandsControlTitle(); - - @Key("control.editCommands.description") - String editCommandsControlDescription(); - @Key("control.editTargets") String editTargets(); @@ -189,38 +171,6 @@ public interface MachineLocalizationConstant extends Messages { @Key("view.createMachine.findByTags") String viewCreateMachineFindByTags(); - - /* EditCommandsView */ - @Key("view.editCommands.placeholder") - String editCommandsViewPlaceholder(); - - @Key("view.editCommands.title") - String editCommandsViewTitle(); - - @Key("view.editCommands.hint") - String editCommandsViewHint(); - - @Key("view.editCommands.name.text") - String editCommandsViewNameText(); - - @Key("view.editCommands.remove.title") - String editCommandsViewRemoveTitle(); - - @Key("view.editCommands.remove.confirmation") - String editCommandsRemoveConfirmation(String commandName); - - @Key("view.editCommands.execute.message") - String editCommandsExecuteMessage(); - - @Key("view.editCommands.saveChanges.title") - String editCommandsSaveChangesTitle(); - - @Key("view.editCommands.saveChanges.text") - String editCommandsSaveChangesConfirmation(String commandName); - - @Key("view.editCommands.saveChanges.discard") - String editCommandsSaveChangesDiscard(); - /* Targets view */ @Key("view.targets.category.ssh") String targetsViewCategorySsh(); diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineResources.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineResources.java index 82e215b065..0f83645d74 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineResources.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/MachineResources.java @@ -28,14 +28,6 @@ public interface MachineResources extends ClientBundle { @Source("images/console/clear-logs.svg") SVGResource clear(); - /** Returns the icon for 'Execute Selected Command' action. */ - @Source("images/execute.svg") - SVGResource execute(); - - /** Returns the new icon for command bar. */ - @Source("images/cmd-icon.svg") - SVGResource cmdIcon(); - /** Returns the new icon for devmachine. */ @Source("images/cube.svg") SVGResource devMachine(); @@ -139,10 +131,6 @@ public interface MachineResources extends ClientBundle { String unSelectRecipe(); - String selectCommandBox(); - - String selectCommandBoxIconPanel(); - String processTree(); String processTreeNode(); diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/EditCommandsAction.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/EditCommandsAction.java deleted file mode 100644 index 9ef85b3c58..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/EditCommandsAction.java +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************************* - * 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.extension.machine.client.actions; - -import com.google.inject.Inject; -import com.google.inject.Singleton; - -import org.eclipse.che.ide.api.action.AbstractPerspectiveAction; -import org.eclipse.che.ide.api.action.ActionEvent; -import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; -import org.eclipse.che.ide.extension.machine.client.MachineResources; -import org.eclipse.che.ide.extension.machine.client.command.edit.EditCommandsPresenter; - -import javax.validation.constraints.NotNull; -import java.util.Collections; - -import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; - -/** - * Action for editing commands. - * - * @author Artem Zatsarynnyi - */ -@Singleton -public class EditCommandsAction extends AbstractPerspectiveAction { - - private final EditCommandsPresenter editCommandsPresenter; - - @Inject - public EditCommandsAction(EditCommandsPresenter editCommandsPresenter, - MachineLocalizationConstant localizationConstant, - MachineResources resources) { - super(Collections.singletonList(PROJECT_PERSPECTIVE_ID), - localizationConstant.editCommandsControlTitle(), - localizationConstant.editCommandsControlDescription(), - null, - resources.editCommands()); - - this.editCommandsPresenter = editCommandsPresenter; - } - - @Override - public void updateInPerspective(@NotNull ActionEvent e) { - } - - @Override - public void actionPerformed(ActionEvent e) { - editCommandsPresenter.show(); - } - -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/ExecuteSelectedCommandAction.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/ExecuteSelectedCommandAction.java deleted file mode 100644 index 1f8f2e1320..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/ExecuteSelectedCommandAction.java +++ /dev/null @@ -1,69 +0,0 @@ -/******************************************************************************* - * 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.extension.machine.client.actions; - -import com.google.inject.Inject; -import com.google.inject.Singleton; - -import org.eclipse.che.api.core.model.machine.Machine; -import org.eclipse.che.ide.api.action.AbstractPerspectiveAction; -import org.eclipse.che.ide.api.action.ActionEvent; -import org.eclipse.che.ide.api.command.CommandImpl; -import org.eclipse.che.ide.api.command.CommandManager; -import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; -import org.eclipse.che.ide.extension.machine.client.MachineResources; - -import java.util.Collections; - -import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; - -/** - * Action to execute command which is selected in drop-down list. - * - * @author Artem Zatsarynnyi - */ -@Singleton -public class ExecuteSelectedCommandAction extends AbstractPerspectiveAction { - - private final SelectCommandComboBox selectCommandAction; - private final CommandManager commandManager; - - @Inject - public ExecuteSelectedCommandAction(MachineLocalizationConstant localizationConstant, - MachineResources resources, - SelectCommandComboBox selectCommandAction, - CommandManager commandManager) { - super(Collections.singletonList(PROJECT_PERSPECTIVE_ID), - localizationConstant.executeSelectedCommandControlTitle(), - localizationConstant.executeSelectedCommandControlDescription(), - null, - resources.execute()); - - this.selectCommandAction = selectCommandAction; - this.commandManager = commandManager; - } - - @Override - public void updateInPerspective(ActionEvent event) { - event.getPresentation().setVisible(selectCommandAction.getSelectedMachine() != null - && selectCommandAction.getSelectedCommand() != null); - } - - @Override - public void actionPerformed(ActionEvent e) { - CommandImpl command = selectCommandAction.getSelectedCommand(); - Machine machine = selectCommandAction.getSelectedMachine(); - - if (command != null && machine != null) { - commandManager.executeCommand(command, machine); - } - } -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/RunCommandAction.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/RunCommandAction.java index aa1817436e..dd0fb52d1b 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/RunCommandAction.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/RunCommandAction.java @@ -15,9 +15,9 @@ import com.google.inject.Inject; import org.eclipse.che.ide.api.action.Action; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; +import org.eclipse.che.ide.api.command.CommandExecutor; import org.eclipse.che.ide.api.command.CommandManager; -import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; import org.eclipse.che.ide.util.loging.Log; @@ -30,19 +30,19 @@ public class RunCommandAction extends Action { public static final String NAME_PARAM_ID = "name"; - private final SelectCommandComboBox selectCommandAction; private final CommandManager commandManager; + private final CommandExecutor commandExecutor; private final AppContext appContext; private final MachineLocalizationConstant localizationConstant; @Inject - public RunCommandAction(SelectCommandComboBox selectCommandAction, + public RunCommandAction(CommandManager commandManager, MachineLocalizationConstant localizationConstant, - CommandManager commandManager, + CommandExecutor commandExecutor, AppContext appContext) { - this.selectCommandAction = selectCommandAction; - this.localizationConstant = localizationConstant; this.commandManager = commandManager; + this.localizationConstant = localizationConstant; + this.commandExecutor = commandExecutor; this.appContext = appContext; } @@ -53,16 +53,14 @@ public class RunCommandAction extends Action { return; } - String name = event.getParameters().get(NAME_PARAM_ID); + final String name = event.getParameters().get(NAME_PARAM_ID); if (name == null) { Log.error(getClass(), localizationConstant.runCommandEmptyNameMessage()); return; } - final CommandImpl command = selectCommandAction.getCommandByName(name); - if (command != null) { - commandManager.executeCommand(command, appContext.getDevMachine().getDescriptor()); - } + commandManager.getCommand(name) + .ifPresent(command -> commandExecutor.executeCommand(command, + appContext.getDevMachine().getDescriptor())); } - } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/SelectCommandComboBox.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/SelectCommandComboBox.java deleted file mode 100644 index c5f5e206d6..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/actions/SelectCommandComboBox.java +++ /dev/null @@ -1,466 +0,0 @@ -/******************************************************************************* - * 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.extension.machine.client.actions; - -import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.Widget; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import com.google.web.bindery.event.shared.EventBus; - -import org.eclipse.che.api.core.model.machine.Machine; -import org.eclipse.che.api.core.model.machine.MachineConfig; -import org.eclipse.che.api.core.model.workspace.Workspace; -import org.eclipse.che.api.core.model.workspace.WorkspaceRuntime; -import org.eclipse.che.api.machine.shared.dto.MachineDto; -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.ide.api.action.AbstractPerspectiveAction; -import org.eclipse.che.ide.api.action.ActionEvent; -import org.eclipse.che.ide.api.action.ActionManager; -import org.eclipse.che.ide.api.action.CustomComponentAction; -import org.eclipse.che.ide.api.action.DefaultActionGroup; -import org.eclipse.che.ide.api.action.Presentation; -import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.command.CommandImpl; -import org.eclipse.che.ide.api.command.CommandManager; -import org.eclipse.che.ide.api.command.CommandType; -import org.eclipse.che.ide.api.command.CommandTypeRegistry; -import org.eclipse.che.ide.api.machine.MachineEntity; -import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; -import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; -import org.eclipse.che.ide.api.workspace.event.WorkspaceStartedEvent; -import org.eclipse.che.ide.api.workspace.event.WorkspaceStoppedEvent; -import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; -import org.eclipse.che.ide.extension.machine.client.MachineResources; -import org.eclipse.che.ide.extension.machine.client.inject.factories.EntityFactory; -import org.eclipse.che.ide.api.machine.events.MachineStateEvent; -import org.eclipse.che.ide.ui.dropdown.DropDownListFactory; -import org.eclipse.che.ide.ui.dropdown.DropDownWidget; -import org.vectomatic.dom.svg.ui.SVGImage; - -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import static java.util.Collections.emptyList; -import static org.eclipse.che.ide.extension.machine.client.MachineExtension.GROUP_COMMANDS_LIST; -import static org.eclipse.che.ide.extension.machine.client.MachineExtension.GROUP_MACHINES_LIST; -import static org.eclipse.che.ide.workspace.perspectives.project.ProjectPerspective.PROJECT_PERSPECTIVE_ID; - -/** - * Action allows user to select target machine and command to execute. - * - * @author Artem Zatsarynnyi - * @author Oleksii Orel - */ -@Singleton -public class SelectCommandComboBox extends AbstractPerspectiveAction implements CustomComponentAction, - CommandManager.CommandChangedListener, - WsAgentStateHandler, - MachineStateEvent.Handler, - WorkspaceStartedEvent.Handler, - WorkspaceStoppedEvent.Handler { - - public static final String GROUP_COMMANDS = "CommandsGroup"; - public static final String GROUP_MACHINES = "MachinesGroup"; - - private final MachineLocalizationConstant locale; - private final MachineResources resources; - private final Map registeredMachineMap; - private final ActionManager actionManager; - private final EntityFactory entityFactory; - private final CommandManager commandManager; - private final CommandTypeRegistry commandTypeRegistry; - private final AppContext appContext; - private final DropDownWidget commandsListWidget; - private final DropDownWidget machinesListWidget; - private final List commands; - private final DefaultActionGroup commandActions; - private final DefaultActionGroup machinesActions; - - private boolean workspaceRunning = false; - - @Inject - public SelectCommandComboBox(MachineLocalizationConstant locale, - MachineResources resources, - ActionManager actionManager, - EventBus eventBus, - EntityFactory entityFactory, - DropDownListFactory dropDownListFactory, - CommandManager commandManager, - CommandTypeRegistry commandTypeRegistry, - AppContext appContext) { - super(Collections.singletonList(PROJECT_PERSPECTIVE_ID), - locale.selectCommandControlTitle(), - locale.selectCommandControlDescription(), - null, null); - - this.locale = locale; - this.resources = resources; - this.actionManager = actionManager; - this.commandManager = commandManager; - this.entityFactory = entityFactory; - this.commandTypeRegistry = commandTypeRegistry; - this.appContext = appContext; - - this.registeredMachineMap = new HashMap<>(); - this.commands = new ArrayList<>(); - - this.machinesListWidget = dropDownListFactory.createDropDown(GROUP_MACHINES); - this.commandsListWidget = dropDownListFactory.createDropDown(GROUP_COMMANDS); - - commandManager.addCommandChangedListener(this); - - commandActions = new DefaultActionGroup(GROUP_COMMANDS, false, actionManager); - actionManager.registerAction(GROUP_COMMANDS, commandActions); - - machinesActions = new DefaultActionGroup(GROUP_MACHINES, false, actionManager); - actionManager.registerAction(GROUP_MACHINES, machinesActions); - - eventBus.addHandler(WsAgentStateEvent.TYPE, this); - eventBus.addHandler(MachineStateEvent.TYPE, this); - eventBus.addHandler(WorkspaceStartedEvent.TYPE, this); - eventBus.addHandler(WorkspaceStoppedEvent.TYPE, this); - } - - @Override - public void updateInPerspective(@NotNull ActionEvent event) { - event.getPresentation().setVisible(workspaceRunning); - } - - @Override - public void actionPerformed(ActionEvent e) { - } - - @Override - public Widget createCustomComponent(Presentation presentation) { - // Create widgets for custom component 'select command'. - FlowPanel customComponentHeader = new FlowPanel(); - FlowPanel devMachineIconPanel = new FlowPanel(); - FlowPanel commandIconPanel = new FlowPanel(); - - customComponentHeader.setStyleName(resources.getCss().selectCommandBox()); - devMachineIconPanel.setStyleName(resources.getCss().selectCommandBoxIconPanel()); - devMachineIconPanel.add(new SVGImage(resources.devMachine())); - customComponentHeader.add(devMachineIconPanel); - customComponentHeader.add((Widget)machinesListWidget); - commandIconPanel.setStyleName(resources.getCss().selectCommandBoxIconPanel()); - commandIconPanel.add(new SVGImage(resources.cmdIcon())); - customComponentHeader.add(commandIconPanel); - customComponentHeader.add((Widget)commandsListWidget); - - return customComponentHeader; - } - - /** Returns selected command. */ - @Nullable - public CommandImpl getSelectedCommand() { - if (commands.isEmpty()) { - return null; - } - - final String selectedCommandName = commandsListWidget.getSelectedName(); - - for (CommandImpl command : commands) { - if (command.getName().equals(selectedCommandName)) { - return command; - } - } - return null; - } - - public void setSelectedCommand(CommandImpl command) { - commandsListWidget.selectElement(command.getName(), command.getName()); - } - - /** Returns command by it's name. */ - @Nullable - public CommandImpl getCommandByName(String name) { - if (commands.isEmpty()) { - return null; - } - - for (CommandImpl command : commands) { - if (command.getName().equals(name)) { - return command; - } - } - return null; - } - - /** - * Load all commands to the widget. - * - * @param commandToSelect - * command that should be selected after loading all commands - */ - private void loadCommands(@Nullable final CommandImpl commandToSelect) { - setCommands(commandManager.getCommands(), commandToSelect); - } - - /** - * Sets commands to the widget. - * - * @param commands - * commands to set - * @param commandToSelect - * command that should be selected or {@code null} if none - */ - private void setCommands(List commands, @Nullable CommandImpl commandToSelect) { - this.commands.clear(); - - commandActions.removeAll(); - - final DefaultActionGroup commandsList = (DefaultActionGroup)actionManager.getAction(GROUP_COMMANDS_LIST); - if (commandsList != null) { - commandActions.addAll(commandsList); - } - - Collections.sort(commands, new Comparator() { - @Override - public int compare(CommandImpl o1, CommandImpl o2) { - return o1.getType().compareTo(o2.getType()); - } - }); - - CommandImpl prevCommand = null; - for (CommandImpl command : commands) { - if (prevCommand == null || !command.getType().equals(prevCommand.getType())) { - CommandType commandType = commandTypeRegistry.getCommandTypeById(command.getType()); - commandActions.addSeparator(commandType.getDisplayName()); - } - - commandActions.add(commandsListWidget.createAction(command.getName(), command.getName())); - prevCommand = command; - } - - this.commands.addAll(commands); - - if (commandToSelect != null) { - setSelectedCommand(commandToSelect); - } else { - selectLastUsedCommand(); - } - } - - /** Selects last used command. */ - private void selectLastUsedCommand() { - if (commands.isEmpty()) { - setEmptyCommand(); - } else { - // for now, we always select first command - final CommandImpl command = commands.get(0); - commandsListWidget.selectElement(command.getName(), command.getName()); - } - } - - @Nullable - Machine getSelectedMachine() { - if (machinesListWidget.getSelectedId() == null) { - return null; - } - - return registeredMachineMap.get(machinesListWidget.getSelectedId()); - } - - /** Clears the selected element in the 'Select Command' menu. */ - private void setEmptyCommand() { - commandsListWidget.selectElement(null, null); - } - - @Override - public void onCommandAdded(CommandImpl command) { - loadCommands(null); - } - - @Override - public void onCommandUpdated(CommandImpl command) { - loadCommands(command); - } - - @Override - public void onCommandRemoved(CommandImpl command) { - loadCommands(null); - } - - /** Load all machines to the widget. */ - private void loadMachines() { - List machines = getMachines(appContext.getWorkspace()); - if (!machines.isEmpty()) { - addMachineActions(machines); - } - } - - private List getMachines(Workspace workspace) { - WorkspaceRuntime workspaceRuntime = workspace.getRuntime(); - if (workspaceRuntime == null) { - return emptyList(); - } - - List runtimeMachines = workspaceRuntime.getMachines(); - List machines = new ArrayList<>(runtimeMachines.size()); - for (Machine machine : runtimeMachines) { - if (machine instanceof MachineDto) { - MachineEntity machineEntity = entityFactory.createMachine((MachineDto)machine); - machines.add(machineEntity); - } - - } - return machines; - } - - @Override - public void onWsAgentStarted(WsAgentStateEvent event) { - workspaceRunning = true; - loadCommands(null); - loadMachines(); - } - - @Override - public void onWsAgentStopped(WsAgentStateEvent event) { - } - - @Override - public void onMachineCreating(MachineStateEvent event) { - } - - @Override - public void onMachineRunning(MachineStateEvent event) { - Machine machine = event.getMachine(); - - addMachineAction(machine); - } - - @Override - public void onMachineDestroyed(MachineStateEvent event) { - Machine machine = event.getMachine(); - - final String machineId = machine.getId(); - - if (registeredMachineMap.remove(machineId) == null) { - return; - } - - if (machine.getConfig().getName().equals(machinesListWidget.getSelectedName())) { - machinesListWidget.selectElement(null, null); - } - - updateMachineActions(); - } - - private void addMachineActions(List machines) { - for (MachineEntity machine : machines) { - registeredMachineMap.put(machine.getId(), machine); - } - - updateMachineActions(); - } - - private void addMachineAction(Machine machine) { - registeredMachineMap.put(machine.getId(), machine); - updateMachineActions(); - - machinesListWidget.selectElement(machine.getId(), machine.getConfig().getName()); - } - - private void updateMachineActions() { - machinesActions.removeAll(); - final DefaultActionGroup actionList = (DefaultActionGroup)actionManager.getAction(GROUP_MACHINES_LIST); - if (actionList != null) { - machinesActions.addAll(actionList); - } - - if (registeredMachineMap.isEmpty()) { - return; - } - - final List> machineEntryList = new LinkedList(registeredMachineMap.entrySet()); - // defined MachineDto Comparator here - Collections.sort(machineEntryList, new MachineListEntryComparator()); - - String machineCategory = null; - for (Map.Entry machineEntry : machineEntryList) { - final Machine machine = machineEntry.getValue(); - final MachineConfig machineConfig = machine.getConfig(); - - if (!this.getMachineCategory(machineConfig).equals(machineCategory)) { - machineCategory = this.getMachineCategory(machineConfig); - machinesActions.addSeparator(machineCategory); - } - machinesActions.add(machinesListWidget.createAction(machine.getId(), machineConfig.getName())); - } - - machinesListWidget.updatePopup(); - - if (machinesListWidget.getSelectedName() == null && machinesActions.getChildrenCount() > 0) { - Machine firstMachine = machineEntryList.get(0).getValue(); - if (firstMachine == null) { - return; - } - machinesListWidget.selectElement(firstMachine.getId(), firstMachine.getConfig().getName()); - } - } - - private String getMachineCategory(MachineConfig machineConfig) { - if (machineConfig.isDev()) { - return locale.devMachineCategory(); - } - return machineConfig.getType(); - } - - @Override - public void onWorkspaceStarted(WorkspaceStartedEvent event) { - workspaceRunning = true; - } - - @Override - public void onWorkspaceStopped(WorkspaceStoppedEvent event) { - machinesListWidget.selectElement(null, null); - registeredMachineMap.clear(); - workspaceRunning = false; - } - - private class MachineListEntryComparator implements Comparator> { - @Override - public int compare(Map.Entry o1, Map.Entry o2) { - final Machine firstMachine = o1.getValue(); - final Machine secondMachine = o2.getValue(); - - if (firstMachine == null) { - return -1; - } - if (secondMachine == null) { - return 1; - } - - final MachineConfig firstMachineConfig = firstMachine.getConfig(); - final MachineConfig secondMachineConfig = secondMachine.getConfig(); - - if (firstMachineConfig.isDev()) { - return -1; - } - if (secondMachineConfig.isDev()) { - return 1; - } - - if (firstMachineConfig.getType().equalsIgnoreCase(secondMachineConfig.getType())) { - return (firstMachineConfig.getName()).compareToIgnoreCase(secondMachineConfig.getName()); - } - - return (getMachineCategory(firstMachineConfig)).compareToIgnoreCase(getMachineCategory(secondMachineConfig)); - } - } -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/CommandExecutorImpl.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/CommandExecutorImpl.java new file mode 100644 index 0000000000..a83eb50a7b --- /dev/null +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/CommandExecutorImpl.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * 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.extension.machine.client.command; + +import com.google.inject.Inject; + +import org.eclipse.che.api.core.model.machine.Command; +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.command.CommandExecutor; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.machine.ExecAgentCommandManager; +import org.eclipse.che.ide.api.macro.MacroProcessor; +import org.eclipse.che.ide.api.selection.Selection; +import org.eclipse.che.ide.api.selection.SelectionAgent; +import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandConsoleFactory; +import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandOutputConsole; +import org.eclipse.che.ide.extension.machine.client.processes.panel.ProcessesPanelPresenter; +import org.eclipse.che.ide.machine.chooser.MachineChooser; + +import java.util.Map; + +/** Implementation of {@link CommandExecutor}. */ +public class CommandExecutorImpl implements CommandExecutor { + + private final MacroProcessor macroProcessor; + private final CommandConsoleFactory commandConsoleFactory; + private final ProcessesPanelPresenter processesPanelPresenter; + private final ExecAgentCommandManager execAgentClient; + private final MachineChooser machineChooser; + private final SelectionAgent selectionAgent; + + @Inject + public CommandExecutorImpl(MacroProcessor macroProcessor, + CommandConsoleFactory commandConsoleFactory, + ProcessesPanelPresenter processesPanelPresenter, + ExecAgentCommandManager execAgentClient, + MachineChooser machineChooser, + SelectionAgent selectionAgent) { + this.macroProcessor = macroProcessor; + this.commandConsoleFactory = commandConsoleFactory; + this.processesPanelPresenter = processesPanelPresenter; + this.execAgentClient = execAgentClient; + this.machineChooser = machineChooser; + this.selectionAgent = selectionAgent; + } + + @Override + public void executeCommand(Command command, Machine machine) { + final String name = command.getName(); + final String type = command.getType(); + final String commandLine = command.getCommandLine(); + final Map attributes = command.getAttributes(); + + macroProcessor.expandMacros(commandLine).then(expandedCommandLine -> { + final CommandImpl expandedCommand = new CommandImpl(name, expandedCommandLine, type, attributes); + final CommandOutputConsole console = commandConsoleFactory.create(expandedCommand, machine); + final String machineId = machine.getId(); + + processesPanelPresenter.addCommandOutput(machineId, console); + + execAgentClient.startProcess(machineId, expandedCommand) + .thenIfProcessStartedEvent(console.getProcessStartedOperation()) + .thenIfProcessDiedEvent(console.getProcessDiedOperation()) + .thenIfProcessStdOutEvent(console.getStdOutOperation()) + .thenIfProcessStdErrEvent(console.getStdErrOperation()); + }); + } + + @Override + public void executeCommand(CommandImpl command) { + final Machine selectedMachine = getSelectedMachine(); + + if (selectedMachine != null) { + executeCommand(command, selectedMachine); + } else { + machineChooser.show().then(machine -> { + executeCommand(command, machine); + }); + } + } + + /** Returns the currently selected machine or {@code null} if none. */ + @Nullable + private Machine getSelectedMachine() { + final Selection selection = selectionAgent.getSelection(); + + if (selection != null && !selection.isEmpty() && selection.isSingleSelection()) { + final Object possibleNode = selection.getHeadElement(); + + if (possibleNode instanceof Machine) { + return (Machine)possibleNode; + } + } + + return null; + } +} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/CommandManagerImpl.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/CommandManagerImpl.java deleted file mode 100644 index 70da8ae8d4..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/CommandManagerImpl.java +++ /dev/null @@ -1,293 +0,0 @@ -/******************************************************************************* - * 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.extension.machine.client.command; - -import com.google.inject.Inject; - -import org.eclipse.che.api.core.model.machine.Command; -import org.eclipse.che.api.core.model.machine.Machine; -import org.eclipse.che.api.machine.shared.dto.CommandDto; -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.workspace.shared.dto.WorkspaceDto; -import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.command.CommandImpl; -import org.eclipse.che.ide.api.command.CommandManager; -import org.eclipse.che.ide.api.command.CommandPage; -import org.eclipse.che.ide.api.command.CommandType; -import org.eclipse.che.ide.api.command.CommandTypeRegistry; -import org.eclipse.che.ide.api.machine.ExecAgentCommandManager; -import org.eclipse.che.ide.api.macro.MacroProcessor; -import org.eclipse.che.ide.api.workspace.WorkspaceServiceClient; -import org.eclipse.che.ide.dto.DtoFactory; -import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandConsoleFactory; -import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandOutputConsole; -import org.eclipse.che.ide.extension.machine.client.processes.panel.ProcessesPanelPresenter; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Implementation of {@link CommandManager}. - * - * @author Artem Zatsarynnyi - */ -public class CommandManagerImpl implements CommandManager { - - public static final String PREVIEW_URL_ATTR = "previewUrl"; - - private final CommandTypeRegistry commandTypeRegistry; - private final AppContext appContext; - private final WorkspaceServiceClient workspaceServiceClient; - private final DtoFactory dtoFactory; - private final MacroProcessor macroProcessor; - private final CommandConsoleFactory commandConsoleFactory; - private final ProcessesPanelPresenter processesPanelPresenter; - private final ExecAgentCommandManager execAgentCommandManager; - - private final Map commands; - private final Set commandChangedListeners; - - @Inject - public CommandManagerImpl(CommandTypeRegistry commandTypeRegistry, - AppContext appContext, - WorkspaceServiceClient workspaceServiceClient, - DtoFactory dtoFactory, - MacroProcessor macroProcessor, - CommandConsoleFactory commandConsoleFactory, - ProcessesPanelPresenter processesPanelPresenter, - ExecAgentCommandManager execAgentCommandManager) { - this.commandTypeRegistry = commandTypeRegistry; - this.appContext = appContext; - this.workspaceServiceClient = workspaceServiceClient; - this.dtoFactory = dtoFactory; - this.macroProcessor = macroProcessor; - this.commandConsoleFactory = commandConsoleFactory; - this.processesPanelPresenter = processesPanelPresenter; - this.execAgentCommandManager = execAgentCommandManager; - - commands = new HashMap<>(); - commandChangedListeners = new HashSet<>(); - retrieveAllCommands(); - } - - private void retrieveAllCommands() { - workspaceServiceClient.getCommands(appContext.getWorkspaceId()).then(new Operation>() { - @Override - public void apply(List arg) throws OperationException { - for (Command command : arg) { - commands.put(command.getName(), new CommandImpl(command)); - } - } - }); - } - - @Override - public List getCommands() { - // return copy of the commands in order to prevent it modification directly - List list = new ArrayList<>(commands.size()); - for (CommandImpl command : commands.values()) { - list.add(new CommandImpl(command)); - } - - return list; - } - - @Override - public Promise create(String type) { - final CommandType commandType = commandTypeRegistry.getCommandTypeById(type); - - Map attributes = new HashMap(); - attributes.put(PREVIEW_URL_ATTR, commandType.getPreviewUrlTemplate()); - - final CommandImpl command = new CommandImpl(getUniqueCommandName(type, null), - commandType.getCommandLineTemplate(), - type, - attributes); - return add(command); - } - - @Override - public Promise create(String desirableName, String commandLine, String type, Map attributes) { - final CommandType commandType = commandTypeRegistry.getCommandTypeById(type); - - Map attr = (attributes != null) ? attributes : new HashMap(); - attr.put(PREVIEW_URL_ATTR, commandType.getPreviewUrlTemplate()); - - final CommandImpl command = new CommandImpl(getUniqueCommandName(type, desirableName), - commandLine != null ? commandLine : commandType.getCommandLineTemplate(), - type, - attr); - return add(command); - } - - private Promise add(final CommandImpl command) { - final CommandDto commandDto = dtoFactory.createDto(CommandDto.class) - .withName(getUniqueCommandName(command.getType(), command.getName())) - .withCommandLine(command.getCommandLine()) - .withType(command.getType()) - .withAttributes(command.getAttributes()); - - return workspaceServiceClient.addCommand(appContext.getWorkspaceId(), commandDto).then(new Function() { - @Override - public CommandImpl apply(WorkspaceDto arg) throws FunctionException { - final CommandImpl newCommand = new CommandImpl(command); - newCommand.setName(commandDto.getName()); - - commands.put(newCommand.getName(), newCommand); - - fireCommandAdded(newCommand); - - return newCommand; - } - }); - } - - @Override - public Promise update(final String commandName, final CommandImpl command) { - final String name; - if (commandName.equals(command.getName())) { - name = commandName; - } else { - name = getUniqueCommandName(command.getType(), command.getName()); - } - - final CommandDto commandDto = dtoFactory.createDto(CommandDto.class) - .withName(name) - .withCommandLine(command.getCommandLine()) - .withType(command.getType()) - .withAttributes(command.getAttributes()); - - return workspaceServiceClient.updateCommand(appContext.getWorkspaceId(), commandName, commandDto) - .then(new Function() { - @Override - public CommandImpl apply(WorkspaceDto arg) throws FunctionException { - final CommandImpl updatedCommand = new CommandImpl(commandDto.getName(), - command.getCommandLine(), - command.getType(), - command.getAttributes()); - commands.remove(commandName); - commands.put(updatedCommand.getName(), updatedCommand); - - fireCommandUpdated(updatedCommand); - - return updatedCommand; - } - }); - } - - @Override - public Promise remove(final String name) { - return workspaceServiceClient.deleteCommand(appContext.getWorkspaceId(), name).then(new Function() { - @Override - public Void apply(WorkspaceDto arg) throws FunctionException { - fireCommandRemoved(commands.remove(name)); - return null; - } - }); - } - - @Override - public List getPages(String type) { - CommandType commandType = commandTypeRegistry.getCommandTypeById(type); - return commandType != null ? commandType.getPages() : Collections.emptyList(); - } - - @Override - public void executeCommand(final CommandImpl command, final Machine machine) { - final String name = command.getName(); - final String type = command.getType(); - final String commandLine = command.getCommandLine(); - final Map attributes = command.getAttributes(); - - macroProcessor.expandMacros(commandLine).then(new Operation() { - @Override - public void apply(String expandedCommandLine) throws OperationException { - CommandImpl expandedCommand = new CommandImpl(name, expandedCommandLine, type, attributes); - - final CommandOutputConsole console = commandConsoleFactory.create(expandedCommand, machine); - final String machineId = machine.getId(); - - processesPanelPresenter.addCommandOutput(machineId, console); - - execAgentCommandManager.startProcess(machineId, expandedCommand) - .thenIfProcessStartedEvent(console.getProcessStartedOperation()) - .thenIfProcessDiedEvent(console.getProcessDiedOperation()) - .thenIfProcessStdOutEvent(console.getStdOutOperation()) - .thenIfProcessStdErrEvent(console.getStdErrOperation()); - } - }); - } - - @Override - public void addCommandChangedListener(CommandChangedListener listener) { - commandChangedListeners.add(listener); - } - - @Override - public void removeCommandChangedListener(CommandChangedListener listener) { - commandChangedListeners.remove(listener); - } - - private void fireCommandAdded(CommandImpl command) { - for (CommandChangedListener listener : commandChangedListeners) { - listener.onCommandAdded(command); - } - } - - private void fireCommandRemoved(CommandImpl command) { - for (CommandChangedListener listener : commandChangedListeners) { - listener.onCommandRemoved(command); - } - } - - private void fireCommandUpdated(CommandImpl command) { - for (CommandChangedListener listener : commandChangedListeners) { - listener.onCommandUpdated(command); - } - } - - private String getUniqueCommandName(String customType, String customName) { - final CommandType commandType = commandTypeRegistry.getCommandTypeById(customType); - final Set commandNames = commands.keySet(); - - final String newCommandName; - - if (customName == null || customName.isEmpty()) { - newCommandName = "new" + commandType.getDisplayName(); - } else { - if (!commandNames.contains(customName)) { - return customName; - } - newCommandName = customName + " copy"; - } - - if (!commandNames.contains(newCommandName)) { - return newCommandName; - } - - for (int count = 1; count < 1000; count++) { - if (!commandNames.contains(newCommandName + "-" + count)) { - return newCommandName + "-" + count; - } - } - - return newCommandName; - } -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/custom/CustomCommandType.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/custom/CustomCommandType.java index 61dffedb31..4733ed56ed 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/custom/CustomCommandType.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/custom/CustomCommandType.java @@ -40,7 +40,7 @@ public class CustomCommandType implements CommandType { pages = new LinkedList<>(); pages.add(page); - iconRegistry.registerIcon(new Icon(ID + ".commands.category.icon", resources.customCommandType())); + iconRegistry.registerIcon(new Icon("command.type." + ID, resources.customCommandType())); } @Override diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsPresenter.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsPresenter.java deleted file mode 100644 index 88ba1abd2e..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsPresenter.java +++ /dev/null @@ -1,444 +0,0 @@ -/******************************************************************************* - * 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.extension.machine.client.command.edit; - -import com.google.common.base.Strings; -import com.google.inject.Inject; -import com.google.inject.Singleton; - -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.CoreLocalizationConstant; -import org.eclipse.che.ide.api.command.CommandImpl; -import org.eclipse.che.ide.api.command.CommandManager; -import org.eclipse.che.ide.api.command.CommandPage; -import org.eclipse.che.ide.api.command.CommandPage.DirtyStateListener; -import org.eclipse.che.ide.api.command.CommandPage.FieldStateActionDelegate; -import org.eclipse.che.ide.api.command.CommandType; -import org.eclipse.che.ide.api.command.CommandTypeRegistry; -import org.eclipse.che.ide.api.dialogs.ChoiceDialog; -import org.eclipse.che.ide.api.dialogs.ConfirmCallback; -import org.eclipse.che.ide.api.dialogs.ConfirmDialog; -import org.eclipse.che.ide.api.dialogs.DialogFactory; -import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Presenter for managing commands. - * - * @author Artem Zatsarynnyi - * @author Oleksii Orel - * @author Valeriy Svydenko - */ -@Singleton -public class EditCommandsPresenter implements EditCommandsView.ActionDelegate, FieldStateActionDelegate { - - public static final String PREVIEW_URL_ATTR = "previewUrl"; - - private final EditCommandsView view; - private final CommandManager commandManager; - private final CommandTypeRegistry commandTypeRegistry; - private final DialogFactory dialogFactory; - private final MachineLocalizationConstant machineLocale; - private final CoreLocalizationConstant coreLocale; - - private final Comparator commandsComparator; - - // initial name of the currently edited command - String editedCommandNameInitial; - // initial preview URL of the currently edited command - String editedCommandPreviewUrlInitial; - - CommandProcessingCallback commandProcessingCallback; - - private CommandPage editedPage; - // command that being edited - private CommandImpl editedCommand; - - @Inject - protected EditCommandsPresenter(EditCommandsView view, - CommandManager commandManager, - CommandTypeRegistry commandTypeRegistry, - DialogFactory dialogFactory, - MachineLocalizationConstant machineLocale, - CoreLocalizationConstant coreLocale) { - this.view = view; - this.commandManager = commandManager; - this.commandTypeRegistry = commandTypeRegistry; - this.dialogFactory = dialogFactory; - this.machineLocale = machineLocale; - this.coreLocale = coreLocale; - this.view.setDelegate(this); - - commandsComparator = new Comparator() { - @Override - public int compare(CommandImpl o1, CommandImpl o2) { - return o1.getName().compareTo(o2.getName()); - } - }; - } - - @Override - public void onCloseClicked() { - onNameChanged(); - - final CommandImpl selectedCommand = view.getSelectedCommand(); - if (selectedCommand != null && isViewModified()) { - onCommandSelected(selectedCommand); - } - - view.close(); - } - - @Override - public void onSaveClicked() { - final CommandImpl selectedCommand = view.getSelectedCommand(); - if (selectedCommand == null) { - return; - } - - updateCommand(selectedCommand).then(new Operation() { - @Override - public void apply(CommandImpl arg) throws OperationException { - commandProcessingCallback = getCommandProcessingCallback(); - refreshView(); - } - }); - } - - private Promise updateCommand(final CommandImpl command) { - return commandManager.update(editedCommandNameInitial, command) - .then(new Operation() { - @Override - public void apply(CommandImpl updatedCommand) throws OperationException { - editedPage.onSave(); - - if (!command.getName().equals(updatedCommand.getName())) { - onNameChanged(); - } - } - }) - .catchError(new Operation() { - @Override - public void apply(PromiseError arg) throws OperationException { - dialogFactory.createMessageDialog("Error", arg.getMessage(), null).show(); - } - }); - } - - @Override - public void onCancelClicked() { - commandProcessingCallback = getCommandProcessingCallback(); - refreshView(); - } - - @Override - public void onAddClicked() { - final String selectedType = view.getSelectedCommandType(); - - if (selectedType != null) { - createNewCommand(selectedType, null, null, null); - } - } - - @Override - public void onDuplicateClicked() { - final CommandImpl selectedCommand = view.getSelectedCommand(); - - if (selectedCommand != null) { - createNewCommand(selectedCommand.getType(), - selectedCommand.getCommandLine(), - selectedCommand.getName(), - selectedCommand.getAttributes()); - } - } - - private void createNewCommand(final String type, - final String commandLine, - final String name, - final Map attributes) { - if (!isViewModified()) { - createCommand(type, commandLine, name, attributes); - return; - } - - final ConfirmCallback saveCallback = new ConfirmCallback() { - @Override - public void accepted() { - updateCommand(editedCommand).then(new Operation() { - @Override - public void apply(CommandImpl arg) throws OperationException { - createCommand(type, commandLine, name, attributes); - } - }); - } - }; - - final ConfirmCallback discardCallback = new ConfirmCallback() { - @Override - public void accepted() { - refreshView(); - createCommand(type, commandLine, name, attributes); - } - }; - - ChoiceDialog dialog = dialogFactory.createChoiceDialog( - machineLocale.editCommandsSaveChangesTitle(), - machineLocale.editCommandsSaveChangesConfirmation(editedCommand.getName()), - coreLocale.save(), - machineLocale.editCommandsSaveChangesDiscard(), - saveCallback, discardCallback); - dialog.show(); - } - - private void createCommand(String type, String commandLine, String name, Map attributes) { - commandManager.create(name, commandLine, type, attributes).then(new Operation() { - @Override - public void apply(CommandImpl command) throws OperationException { - view.selectCommand(command); - refreshView(); - } - }); - } - - @Override - public void onRemoveClicked() { - final CommandImpl selectedCommand = view.getSelectedCommand(); - if (selectedCommand == null) { - return; - } - - final ConfirmCallback confirmCallback = new ConfirmCallback() { - @Override - public void accepted() { - commandManager.remove(selectedCommand.getName()).then(new Operation() { - @Override - public void apply(Void arg) throws OperationException { - view.selectNeighborCommand(selectedCommand); - commandProcessingCallback = getCommandProcessingCallback(); - refreshView(); - } - }).catchError(new Operation() { - @Override - public void apply(PromiseError arg) throws OperationException { - dialogFactory.createMessageDialog("Error", arg.getMessage(), null).show(); - } - }); - } - }; - - ConfirmDialog confirmDialog = dialogFactory.createConfirmDialog( - machineLocale.editCommandsViewRemoveTitle(), - machineLocale.editCommandsRemoveConfirmation(selectedCommand.getName()), - confirmCallback, null); - confirmDialog.show(); - } - - @Override - public void onEnterClicked() { - if (view.isCancelButtonInFocus()) { - onCancelClicked(); - return; - } - - if (view.isCloseButtonInFocus()) { - onCloseClicked(); - return; - } - - onSaveClicked(); - } - - @Override - public void onCommandSelected(final CommandImpl command) { - if (!isViewModified()) { - handleCommandSelection(command); - return; - } - - final ConfirmCallback saveCallback = new ConfirmCallback() { - @Override - public void accepted() { - updateCommand(editedCommand).then(new Operation() { - @Override - public void apply(CommandImpl arg) throws OperationException { - refreshView(); - handleCommandSelection(command); - } - }); - } - }; - - final ConfirmCallback discardCallback = new ConfirmCallback() { - @Override - public void accepted() { - refreshView(); - handleCommandSelection(command); - } - }; - - ChoiceDialog dialog = dialogFactory.createChoiceDialog( - machineLocale.editCommandsSaveChangesTitle(), - machineLocale.editCommandsSaveChangesConfirmation(editedCommand.getName()), - coreLocale.save(), - machineLocale.editCommandsSaveChangesDiscard(), - saveCallback, - discardCallback); - - dialog.show(); - } - - private void handleCommandSelection(CommandImpl command) { - editedCommand = command; - editedCommandNameInitial = command.getName(); - editedCommandPreviewUrlInitial = getPreviewUrlOrNull(command); - - view.setCommandName(command.getName()); - view.setCommandPreviewUrl(getPreviewUrlOrNull(command)); - - final List pages = commandManager.getPages(command.getType()); - if (!pages.isEmpty()) { - editedPage = pages.get(0); // for now, show only the 1'st page - - editedPage.setFieldStateActionDelegate(this); - - editedPage.setDirtyStateListener(new DirtyStateListener() { - @Override - public void onDirtyStateChanged() { - view.setCancelButtonState(isViewModified()); - view.setSaveButtonState(isViewModified()); - } - }); - - editedPage.resetFrom(command); - editedPage.go(view.getCommandPageContainer()); - } - } - - private String getPreviewUrlOrNull(CommandImpl command) { - if (command.getAttributes() != null && command.getAttributes().containsKey(PREVIEW_URL_ATTR)) { - return command.getAttributes().get(PREVIEW_URL_ATTR); - } - return null; - } - - @Override - public void onNameChanged() { - final CommandImpl selectedCommand = view.getSelectedCommand(); - if (selectedCommand == null || !selectedCommand.equals(editedCommand)) { - return; - } - - selectedCommand.setName(view.getCommandName()); - - view.setCancelButtonState(isViewModified()); - view.setSaveButtonState(isViewModified()); - } - - @Override - public void onPreviewUrlChanged() { - final CommandImpl selectedCommand = view.getSelectedCommand(); - if (selectedCommand == null || !selectedCommand.equals(editedCommand)) { - return; - } - - selectedCommand.getAttributes().put(PREVIEW_URL_ATTR, view.getCommandPreviewUrl()); - - view.setCancelButtonState(isViewModified()); - view.setSaveButtonState(isViewModified()); - } - - /** Show dialog. */ - public void show() { - view.show(); - - refreshView(); - } - - private void refreshView() { - reset(); - - List allCommands = commandManager.getCommands(); - Map> typeToCommands = new HashMap<>(); - - for (CommandType type : commandTypeRegistry.getCommandTypes()) { - final List commandsOfType = new ArrayList<>(); - - for (CommandImpl command : allCommands) { - if (type.getId().equals(command.getType())) { - commandsOfType.add(command); - } - } - - Collections.sort(commandsOfType, commandsComparator); - typeToCommands.put(type, commandsOfType); - } - - view.setData(typeToCommands); - view.setFilterState(!allCommands.isEmpty()); - - if (commandProcessingCallback != null) { - commandProcessingCallback.onCompleted(); - commandProcessingCallback = null; - } - } - - private void reset() { - editedCommand = null; - editedCommandNameInitial = null; - editedCommandPreviewUrlInitial = null; - editedPage = null; - - view.setCommandName(""); - view.clearCommandPageContainer(); - view.setCommandPreviewUrl(""); - - view.setCancelButtonState(false); - view.setSaveButtonState(false); - } - - private boolean isViewModified() { - if (editedCommand == null || editedPage == null) { - return false; - } - - return editedPage.isDirty() - || !editedCommandNameInitial.equals(view.getCommandName()) - || !Strings.nullToEmpty(editedCommandPreviewUrlInitial).equals(Strings.nullToEmpty(view.getCommandPreviewUrl())); - } - - private CommandProcessingCallback getCommandProcessingCallback() { - return new CommandProcessingCallback() { - @Override - public void onCompleted() { - view.setCloseButtonInFocus(); - } - }; - } - - @Override - public void updatePreviewURLState(boolean isVisible) { - view.setPreviewUrlState(isVisible); - } - - interface CommandProcessingCallback { - /** Called when handling of command is completed successfully. */ - void onCompleted(); - } -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsView.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsView.java deleted file mode 100644 index 7cf6450c5b..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsView.java +++ /dev/null @@ -1,135 +0,0 @@ -/******************************************************************************* - * 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.extension.machine.client.command.edit; - -import com.google.gwt.user.client.ui.AcceptsOneWidget; - -import org.eclipse.che.commons.annotation.Nullable; -import org.eclipse.che.ide.api.command.CommandImpl; -import org.eclipse.che.ide.api.command.CommandType; -import org.eclipse.che.ide.api.mvp.View; - -import java.util.List; -import java.util.Map; - -/** - * The view of {@link EditCommandsPresenter}. - * - * @author Artem Zatsarynnyi - */ -public interface EditCommandsView extends View { - - /** Show view. */ - void show(); - - /** Close view. */ - void close(); - - /** Select the neighbor command of the same type that the current command. */ - void selectNeighborCommand(CommandImpl command); - - /** Returns the container for displaying page for editing command. */ - AcceptsOneWidget getCommandPageContainer(); - - /** Clear the container for displaying page for editing command. */ - void clearCommandPageContainer(); - - /** Select the specified command. */ - void selectCommand(CommandImpl command); - - /** - * Sets commands grouped by types to display in the view. - * - * @param commandsByTypes - * available commands grouped by types - */ - void setData(Map> commandsByTypes); - - /** Returns command name. */ - String getCommandName(); - - /** Sets command name. */ - void setCommandName(String name); - - /** Returns preview Url. */ - String getCommandPreviewUrl(); - - /** Sets preview Url. */ - void setCommandPreviewUrl(String previewUrl); - - /** Sets visible state of the 'Preview URL' panel. */ - void setPreviewUrlState(boolean enabled); - - /** Sets enabled state of the 'Cancel' button. */ - void setCancelButtonState(boolean enabled); - - /** Sets enabled state of the 'Apply' button. */ - void setSaveButtonState(boolean enabled); - - /** Sets enabled state of the filter input field. */ - void setFilterState(boolean enabled); - - /** Returns type of the selected command or {@code null} if no command is selected. */ - @Nullable - String getSelectedCommandType(); - - /** Returns the command which is currently selected. */ - @Nullable - CommandImpl getSelectedCommand(); - - /** Sets the focus on the 'Close' button. */ - void setCloseButtonInFocus(); - - /** Returns {@code true} if cancel button is in the focus and {@code false} - otherwise. */ - boolean isCancelButtonInFocus(); - - /** Returns {@code true} if close button is in the focus and {@code false} - otherwise. */ - boolean isCloseButtonInFocus(); - - /** Action handler for the view actions/controls. */ - interface ActionDelegate { - - /** Called when 'Ok' button is clicked. */ - void onCloseClicked(); - - /** Called when 'Apply' button is clicked. */ - void onSaveClicked(); - - /** Called when 'Cancel' button is clicked. */ - void onCancelClicked(); - - /** Called when 'Add' button is clicked. */ - void onAddClicked(); - - /** Called when 'Duplicate' button is clicked. */ - void onDuplicateClicked(); - - /** Called when 'Remove' button is clicked. */ - void onRemoveClicked(); - - /** Called when 'Enter' key pressed. */ - void onEnterClicked(); - - /** - * Called when some command has been selected. - * - * @param command - * selected command - */ - void onCommandSelected(CommandImpl command); - - /** Called when command name has been changed. */ - void onNameChanged(); - - /** Called when preview url has been changed. */ - void onPreviewUrlChanged(); - } -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsViewImpl.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsViewImpl.java deleted file mode 100644 index f88ec69738..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsViewImpl.java +++ /dev/null @@ -1,550 +0,0 @@ -/******************************************************************************* - * 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.extension.machine.client.command.edit; - -import elemental.events.KeyboardEvent; - -import com.google.gwt.core.client.GWT; -import com.google.gwt.dom.client.Document; -import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.SpanElement; -import com.google.gwt.dom.client.Style; -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.KeyDownEvent; -import com.google.gwt.event.dom.client.KeyDownHandler; -import com.google.gwt.event.dom.client.KeyUpEvent; -import com.google.gwt.uibinder.client.UiBinder; -import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.uibinder.client.UiHandler; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Event; -import com.google.gwt.user.client.EventListener; -import com.google.gwt.user.client.ui.AcceptsOneWidget; -import com.google.gwt.user.client.ui.Button; -import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.Label; -import com.google.gwt.user.client.ui.SimplePanel; -import com.google.gwt.user.client.ui.TextBox; -import com.google.gwt.user.client.ui.UIObject; -import com.google.gwt.user.client.ui.Widget; -import com.google.inject.Inject; -import com.google.inject.Singleton; - -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.CommandType; -import org.eclipse.che.ide.api.icon.Icon; -import org.eclipse.che.ide.api.icon.IconRegistry; -import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; -import org.eclipse.che.ide.ui.list.CategoriesList; -import org.eclipse.che.ide.ui.list.Category; -import org.eclipse.che.ide.ui.list.CategoryRenderer; -import org.eclipse.che.ide.ui.window.Window; -import org.vectomatic.dom.svg.ui.SVGImage; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * The implementation of {@link EditCommandsView}. - * - * @author Artem Zatsarynnyi - * @author Oleksii Orel - */ -@Singleton -public class EditCommandsViewImpl extends Window implements EditCommandsView { - - private static final EditCommandsViewImplUiBinder UI_BINDER = GWT.create(EditCommandsViewImplUiBinder.class); - - private final EditCommandResources commandResources; - private final CoreLocalizationConstant coreLocale; - private final IconRegistry iconRegistry; - - private final Label hintLabel; - - private final CategoryRenderer commandRenderer; - private final Category.CategoryEventDelegate commandEventDelegate; - - @UiField(provided = true) - MachineLocalizationConstant machineLocale; - @UiField - TextBox filterInputField; - @UiField - SimplePanel categoriesPanel; - @UiField - FlowPanel namePanel; - @UiField - TextBox commandName; - @UiField - SimplePanel commandPageContainer; - @UiField - FlowPanel previewUrlPanel; - @UiField - TextBox commandPreviewUrl; - @UiField - FlowPanel buttonsPanel; - - private Button cancelButton; - private Button saveButton; - private Button closeButton; - - private ActionDelegate delegate; - - private CategoriesList categoriesList; - private Map> categories; - - private String selectedType; - private CommandImpl selectedCommand; - - private String filterTextValue; - - @Inject - protected EditCommandsViewImpl(org.eclipse.che.ide.Resources resources, - final EditCommandResources commandResources, - MachineLocalizationConstant machineLocale, - CoreLocalizationConstant coreLocale, - IconRegistry iconRegistry) { - this.commandResources = commandResources; - this.machineLocale = machineLocale; - this.coreLocale = coreLocale; - this.iconRegistry = iconRegistry; - - commandRenderer = new CategoryRenderer() { - @Override - public void renderElement(Element element, CommandImpl data) { - UIObject.ensureDebugId(element, "commandsManager-type-" + data.getType()); - - element.addClassName(commandResources.getCss().categorySubElementHeader()); - element.setInnerText(data.getName().trim().isEmpty() ? "" : data.getName()); - element.appendChild(createCommandButtons()); - } - - @Override - public SpanElement renderCategory(Category category) { - return createCategoryHeaderForCommandType(category.getTitle()); - } - }; - - commandEventDelegate = new Category.CategoryEventDelegate() { - @Override - public void onListItemClicked(Element listItemBase, CommandImpl itemData) { - onCommandSelected(itemData); - } - }; - - categories = new HashMap<>(); - - commandResources.getCss().ensureInjected(); - - setWidget(UI_BINDER.createAndBindUi(this)); - setTitle(machineLocale.editCommandsViewTitle()); - getWidget().getElement().setId("commandsManagerView"); - - hintLabel = new Label(machineLocale.editCommandsViewHint()); - hintLabel.addStyleName(commandResources.getCss().hintLabel()); - - filterInputField.getElement().setAttribute("placeholder", machineLocale.editCommandsViewPlaceholder()); - filterInputField.getElement().addClassName(commandResources.getCss().filterPlaceholder()); - - categoriesList = new CategoriesList(resources); - categoriesList.addDomHandler(new KeyDownHandler() { - @Override - public void onKeyDown(KeyDownEvent event) { - switch (event.getNativeKeyCode()) { - case KeyboardEvent.KeyCode.INSERT: - delegate.onAddClicked(); - resetFilter(); - break; - case KeyboardEvent.KeyCode.DELETE: - delegate.onRemoveClicked(); - break; - } - } - }, KeyDownEvent.getType()); - categoriesPanel.add(categoriesList); - - createButtons(); - - getWidget().getElement().getStyle().setPadding(0, Style.Unit.PX); - } - - /** Creates and returns buttons for duplicating and removing command. */ - private SpanElement createCommandButtons() { - final SpanElement removeCommandButton = Document.get().createSpanElement(); - removeCommandButton.appendChild(commandResources.removeCommandButton().getSvg().getElement()); - Event.sinkEvents(removeCommandButton, Event.ONCLICK); - Event.setEventListener(removeCommandButton, new EventListener() { - @Override - public void onBrowserEvent(Event event) { - if (Event.ONCLICK == event.getTypeInt()) { - event.stopPropagation(); - onCommandSelected(selectedCommand); - delegate.onRemoveClicked(); - } - } - }); - - final SpanElement duplicateCommandButton = Document.get().createSpanElement(); - duplicateCommandButton.appendChild(commandResources.duplicateCommandButton().getSvg().getElement()); - Event.sinkEvents(duplicateCommandButton, Event.ONCLICK); - Event.setEventListener(duplicateCommandButton, new EventListener() { - @Override - public void onBrowserEvent(Event event) { - if (Event.ONCLICK == event.getTypeInt()) { - event.stopPropagation(); - delegate.onDuplicateClicked(); - } - } - }); - - final SpanElement buttonsPanel = Document.get().createSpanElement(); - buttonsPanel.setClassName(commandResources.getCss().buttonArea()); - - buttonsPanel.appendChild(removeCommandButton); - buttonsPanel.appendChild(duplicateCommandButton); - - return buttonsPanel; - } - - private SpanElement createCategoryHeaderForCommandType(final String commandTypeId) { - final SpanElement categoryHeaderElement = Document.get().createSpanElement(); - categoryHeaderElement.setClassName(commandResources.getCss().categoryHeader()); - - final SpanElement iconElement = Document.get().createSpanElement(); - categoryHeaderElement.appendChild(iconElement); - - final SpanElement nameElement = Document.get().createSpanElement(); - categoryHeaderElement.appendChild(nameElement); - final CommandType currentCommandType = getTypeById(commandTypeId); - nameElement.setInnerText(currentCommandType != null ? currentCommandType.getDisplayName() : commandTypeId); - - final SpanElement buttonElement = Document.get().createSpanElement(); - buttonElement.appendChild(commandResources.addCommandButton().getSvg().getElement()); - categoryHeaderElement.appendChild(buttonElement); - - Event.sinkEvents(buttonElement, Event.ONCLICK); - Event.setEventListener(buttonElement, new EventListener() { - @Override - public void onBrowserEvent(Event event) { - if (Event.ONCLICK == event.getTypeInt()) { - event.stopPropagation(); - namePanel.setVisible(true); - previewUrlPanel.setVisible(true); - selectedType = commandTypeId; - delegate.onAddClicked(); - resetFilter(); - } - } - }); - - final Icon icon = iconRegistry.getIconIfExist(commandTypeId + ".commands.category.icon"); - if (icon != null) { - final SVGImage iconSVG = icon.getSVGImage(); - if (iconSVG != null) { - iconElement.appendChild(iconSVG.getElement()); - return categoryHeaderElement; - } - } - - return categoryHeaderElement; - } - - private void createButtons() { - saveButton = createButton(coreLocale.save(), "window-edit-commands-save", new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - delegate.onSaveClicked(); - } - }); - saveButton.addStyleName(Window.resources.windowCss().primaryButton()); - buttonsPanel.add(saveButton); - - cancelButton = createButton(coreLocale.cancel(), "window-edit-commands-cancel", new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - delegate.onCancelClicked(); - } - }); - buttonsPanel.add(cancelButton); - - closeButton = createButton(coreLocale.close(), "window-edit-commands-close", - new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - delegate.onCloseClicked(); - } - }); - closeButton.addDomHandler(new BlurHandler() { - @Override - public void onBlur(BlurEvent blurEvent) { - //set default focus - selectText(filterInputField.getElement()); - } - }, BlurEvent.getType()); - - addButtonToFooter(closeButton); - - Element dummyFocusElement = DOM.createSpan(); - dummyFocusElement.setTabIndex(0); - getFooter().getElement().appendChild(dummyFocusElement); - } - - private void resetFilter() { - filterInputField.setText(""); - filterTextValue = ""; - } - - private CommandType getTypeById(String commandId) { - for (CommandType type : categories.keySet()) { - if (type.getId().equals(commandId)) { - return type; - } - } - - return null; - } - - /** - * Render the commands list. - * It also takes into account the name filter and restores the selected command. - */ - private void renderCategoriesList(Map> categories) { - final List> categoriesToRender = new ArrayList<>(); - - for (CommandType type : categories.keySet()) { - List commands = new ArrayList<>(); - if (filterTextValue.isEmpty()) { - commands = categories.get(type); - } else { // filtering List - for (final CommandImpl command : categories.get(type)) { - if (command.getName().contains(filterTextValue)) { - commands.add(command); - } - } - } - - Category category = new Category<>(type.getId(), commandRenderer, commands, commandEventDelegate); - categoriesToRender.add(category); - } - - categoriesList.clear(); - categoriesList.render(categoriesToRender, true); - - if (selectedCommand != null) { - categoriesList.selectElement(selectedCommand); - if (filterTextValue.isEmpty()) { - selectText(commandName.getElement()); - } - } else { - resetView(); - } - } - - @Override - public void selectNeighborCommand(CommandImpl command) { - final CommandImpl commandToSelect; - final List commandsOfType = categories.get(getTypeById(command.getType())); - - int selectedCommandIndex = commandsOfType.indexOf(command); - if (commandsOfType.size() < 2 || selectedCommandIndex == -1) { - commandToSelect = null; - } else { - if (selectedCommandIndex > 0) { - selectedCommandIndex--; - } else { - selectedCommandIndex++; - } - commandToSelect = commandsOfType.get(selectedCommandIndex); - } - - if (commandToSelect != null) { - selectCommand(commandToSelect); - } else { - resetView(); - } - } - - /** Set the given command selected in the categories list. */ - @Override - public void selectCommand(CommandImpl command) { - selectedCommand = command; - selectedType = command.getType(); - - categoriesList.selectElement(command); - } - - @Override - public void setData(Map> commandsByTypes) { - this.categories = commandsByTypes; - - renderCategoriesList(commandsByTypes); - } - - /** Select all text in the given inputElement. */ - private native void selectText(Element inputElement) /*-{ - inputElement.focus(); - inputElement.setSelectionRange(0, inputElement.value.length); - }-*/; - - @Override - public void setDelegate(ActionDelegate delegate) { - this.delegate = delegate; - } - - @Override - public void show() { - super.show(); - - resetView(); - resetFilter(); - } - - /** Reset view's state to default. */ - private void resetView() { - selectedCommand = null; - selectedType = null; - - commandName.setText(""); - commandPreviewUrl.setText(""); - - namePanel.setVisible(false); - previewUrlPanel.setVisible(false); - - commandPageContainer.clear(); - commandPageContainer.add(hintLabel); - } - - @Override - public void close() { - this.hide(); - } - - @Override - public AcceptsOneWidget getCommandPageContainer() { - return commandPageContainer; - } - - @Override - public void clearCommandPageContainer() { - commandPageContainer.clear(); - } - - public String getCommandName() { - return commandName.getText().trim(); - } - - public void setCommandName(String name) { - commandName.setText(name); - } - - @Override - public String getCommandPreviewUrl() { - return commandPreviewUrl.getText().trim(); - } - - public void setCommandPreviewUrl(String commandPreviewUrl) { - this.commandPreviewUrl.setText(commandPreviewUrl); - } - - @Override - public void setPreviewUrlState(boolean enabled) { - previewUrlPanel.setVisible(enabled); - } - - @Override - public void setCancelButtonState(boolean enabled) { - cancelButton.setEnabled(enabled); - } - - @Override - public void setSaveButtonState(boolean enabled) { - saveButton.setEnabled(enabled); - } - - @Override - public void setFilterState(boolean enabled) { - filterInputField.setEnabled(enabled); - } - - @Nullable - @Override - public String getSelectedCommandType() { - return selectedType; - } - - @Nullable - @Override - public CommandImpl getSelectedCommand() { - return selectedCommand; - } - - private void onCommandSelected(CommandImpl command) { - selectedType = command.getType(); - selectedCommand = command; - - namePanel.setVisible(true); - previewUrlPanel.setVisible(true); - - delegate.onCommandSelected(command); - } - - @Override - public void setCloseButtonInFocus() { - closeButton.setFocus(true); - } - - @UiHandler("commandName") - public void onNameKeyUp(KeyUpEvent event) { - delegate.onNameChanged(); - } - - @UiHandler("commandPreviewUrl") - public void onPreviewUrlKeyUp(KeyUpEvent event) { - delegate.onPreviewUrlChanged(); - } - - @UiHandler("filterInputField") - public void onFilterKeyUp(KeyUpEvent event) { - if (!filterTextValue.equals(filterInputField.getText())) { - filterTextValue = filterInputField.getText(); - renderCategoriesList(categories); - } - } - - @Override - protected void onEnterClicked() { - delegate.onEnterClicked(); - } - - @Override - protected void onClose() { - delegate.onCloseClicked(); - } - - @Override - public boolean isCancelButtonInFocus() { - return isWidgetFocused(cancelButton); - } - - @Override - public boolean isCloseButtonInFocus() { - return isWidgetFocused(closeButton); - } - - interface EditCommandsViewImplUiBinder extends UiBinder { - } -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsViewImpl.ui.xml b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsViewImpl.ui.xml deleted file mode 100644 index 55cd568fbb..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsViewImpl.ui.xml +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - .commandPanel > div:first-child + div { - border-right: 1px solid popupBorderColor; - } - - .commandDefinitionHeader input, - .commandDefinitionBody input, - .commandDefinitionBody textarea { - font-size: 12px; - box-shadow: none; - border-radius: 0; - padding-left: 5px; - padding-right: 5px; - border-color: textFieldBorderColor !important; - width: literal("calc(100% - 12px)") !important; - } - - .commandDefinitionHeader input, - .commandDefinitionBody input { - margin-bottom: 15px; - height: 20px; - } - - .commandDefinitionHeader { - min-height: 60px; - width: 100%; - } - - .commandDefinitionBody > div { - margin: 0; - } - - .commandDefinitionBody > div div { - display: inline-block; - line-height: inherit; - width: 100%; - } - - .title { - font-size: 14px; - margin-bottom: 15px; - } - - .title, - .label { - margin-top: 0; - margin-left: 0; - } - - .leftPart { - border: 1px solid popupBorderColor; - margin: 12px 10px 10px 10px; - -moz-user-select: none; - -webkit-user-select: none; - user-select: none; - } - - .rightPart { - margin: 10px; - } - - .categories { - border-top: 1px solid popupBorderColor; - } - - .categories div > span { - float: none; - } - - .categories div > span + div { - float: left; - width: inherit; - } - - .categories div > span + div svg { - height: 9px; - width: 9px; - } - - .filter { - line-height: 29px; - text-align: end; - } - - .filter input { - border-color: textFieldBorderColor !important; - min-height: 20px; - margin: 0 3px 0 3px; - width: literal("calc(100% - 18px)"); - -moz-user-select: text; - -webkit-user-select: text; - user-select: text; - } - - .buttonsPanel { - float: right; - position: absolute; - bottom: 0; - right: 0; - } - - .buttonsPanel button { - margin-right: 6px; - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/macros/ServerAddressMacroRegistrar.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/macros/ServerAddressMacroRegistrar.java new file mode 100644 index 0000000000..5283f30183 --- /dev/null +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/macros/ServerAddressMacroRegistrar.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * 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.extension.machine.client.command.macros; + +import com.google.common.collect.Sets; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.web.bindery.event.shared.EventBus; + +import org.eclipse.che.api.core.model.machine.Machine; +import org.eclipse.che.api.core.model.machine.Server; +import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; +import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; +import org.eclipse.che.ide.api.macro.BaseMacro; +import org.eclipse.che.ide.api.macro.Macro; +import org.eclipse.che.ide.api.macro.MacroRegistry; + +import java.util.Map; +import java.util.Set; + +/** + * For every server in WsAgent's machine registers a {@link Macro} that + * returns server's external address in form hostname:port. + * + * @author Vlad Zhukovskiy + */ +@Singleton +public class ServerAddressMacroRegistrar implements WsAgentStateHandler { + + public static final String MACRO_NAME_TEMPLATE = "${server.port.%}"; + + private final MacroRegistry macroRegistry; + private final AppContext appContext; + + private Set macros; + + @Inject + public ServerAddressMacroRegistrar(EventBus eventBus, + MacroRegistry macroRegistry, + AppContext appContext) { + this.macroRegistry = macroRegistry; + this.appContext = appContext; + + eventBus.addHandler(WsAgentStateEvent.TYPE, this); + + registerMacros(); + } + + private void registerMacros() { + Machine devMachine = appContext.getDevMachine(); + if (devMachine != null) { + macros = getMacros(devMachine); + macroRegistry.register(macros); + } + } + + private Set getMacros(Machine machine) { + Set macros = Sets.newHashSet(); + for (Map.Entry entry : machine.getRuntime().getServers().entrySet()) { + macros.add(new ServerAddressMacro(entry.getKey(), + entry.getValue().getAddress())); + + if (entry.getKey().endsWith("/tcp")) { + macros.add(new ServerAddressMacro(entry.getKey().substring(0, entry.getKey().length() - 4), + entry.getValue().getAddress())); + } + } + + return macros; + } + + @Override + public void onWsAgentStarted(WsAgentStateEvent event) { + registerMacros(); + } + + @Override + public void onWsAgentStopped(WsAgentStateEvent event) { + for (Macro provider : macros) { + macroRegistry.unregister(provider); + } + + macros.clear(); + } + + private class ServerAddressMacro extends BaseMacro { + ServerAddressMacro(String internalPort, String externalAddress) { + super(MACRO_NAME_TEMPLATE.replaceAll("%", internalPort), + externalAddress, + "Returns external address of the server running on port " + internalPort); + } + } +} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/macros/ServerPortProvider.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/macros/ServerPortProvider.java deleted file mode 100644 index c089c14db0..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/macros/ServerPortProvider.java +++ /dev/null @@ -1,123 +0,0 @@ -/******************************************************************************* - * 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.extension.machine.client.command.macros; - -import com.google.common.collect.Sets; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import com.google.web.bindery.event.shared.EventBus; - -import org.eclipse.che.api.core.model.machine.Machine; -import org.eclipse.che.api.core.model.machine.Server; -import org.eclipse.che.api.promises.client.Promise; -import org.eclipse.che.api.promises.client.js.Promises; -import org.eclipse.che.ide.api.app.AppContext; -import org.eclipse.che.ide.api.macro.Macro; -import org.eclipse.che.ide.api.macro.MacroRegistry; -import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; -import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; - -import java.util.Map; -import java.util.Set; - -/** - * Provide mapping internal port, i.e. ${server.port.8080} to 127.0.0.1:21212. - * - * @author Vlad Zhukovskiy - */ -@Singleton -public class ServerPortProvider implements WsAgentStateHandler { - - public static final String KEY_TEMPLATE = "${server.port.%}"; - - private final MacroRegistry commandPropertyRegistry; - private final AppContext appContext; - - private Set providers; - - @Inject - public ServerPortProvider(EventBus eventBus, - MacroRegistry commandPropertyRegistry, - AppContext appContext) { - this.commandPropertyRegistry = commandPropertyRegistry; - this.appContext = appContext; - - eventBus.addHandler(WsAgentStateEvent.TYPE, this); - - registerProviders(); - } - - private void registerProviders() { - Machine devMachine = appContext.getDevMachine(); - if (devMachine != null) { - providers = getProviders(devMachine); - commandPropertyRegistry.register(providers); - } - } - - private Set getProviders(Machine machine) { - Set providers = Sets.newHashSet(); - for (Map.Entry entry : machine.getRuntime().getServers().entrySet()) { - providers.add(new AddressMacro(entry.getKey(), - entry.getValue().getAddress(), - entry.getKey())); - - if (entry.getKey().endsWith("/tcp")) { - providers.add(new AddressMacro(entry.getKey().substring(0, entry.getKey().length() - 4), - entry.getValue().getAddress(), entry.getKey())); - } - } - - return providers; - } - - @Override - public void onWsAgentStarted(WsAgentStateEvent event) { - registerProviders(); - } - - @Override - public void onWsAgentStopped(WsAgentStateEvent event) { - for (Macro provider : providers) { - commandPropertyRegistry.unregister(provider); - } - - providers.clear(); - } - - private class AddressMacro implements Macro { - - String variable; - String address; - String description; - - AddressMacro(String internalPort, String address, String description) { - this.variable = KEY_TEMPLATE.replaceAll("%", internalPort); - this.address = address; - this.description = description; - } - - @Override - public String getName() { - return variable; - } - - @Override - public String getDescription() { - return description; - } - - @Override - public Promise expand() { - return Promises.resolve(address); - } - } -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/inject/MachineGinModule.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/inject/MachineGinModule.java index 5bffcc4f04..4ac56a0774 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/inject/MachineGinModule.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/inject/MachineGinModule.java @@ -17,7 +17,7 @@ import com.google.inject.Singleton; import com.google.inject.name.Names; import org.eclipse.che.api.machine.shared.Constants; -import org.eclipse.che.ide.api.command.CommandManager; +import org.eclipse.che.ide.api.command.CommandExecutor; import org.eclipse.che.ide.api.command.CommandType; import org.eclipse.che.ide.api.extension.ExtensionGinModule; import org.eclipse.che.ide.api.machine.MachineEntity; @@ -25,10 +25,8 @@ import org.eclipse.che.ide.api.macro.Macro; import org.eclipse.che.ide.api.outputconsole.OutputConsole; import org.eclipse.che.ide.extension.machine.client.RecipeScriptDownloadServiceClient; import org.eclipse.che.ide.extension.machine.client.RecipeScriptDownloadServiceClientImpl; -import org.eclipse.che.ide.extension.machine.client.command.CommandManagerImpl; +import org.eclipse.che.ide.extension.machine.client.command.CommandExecutorImpl; import org.eclipse.che.ide.extension.machine.client.command.custom.CustomCommandType; -import org.eclipse.che.ide.extension.machine.client.command.edit.EditCommandsView; -import org.eclipse.che.ide.extension.machine.client.command.edit.EditCommandsViewImpl; import org.eclipse.che.ide.extension.machine.client.command.macros.CurrentProjectPathMacro; import org.eclipse.che.ide.extension.machine.client.command.macros.CurrentProjectRelativePathMacro; import org.eclipse.che.ide.extension.machine.client.command.macros.DevMachineHostNameMacro; @@ -86,8 +84,7 @@ public class MachineGinModule extends AbstractGinModule { bind(ProcessesPanelView.class).to(ProcessesPanelViewImpl.class).in(Singleton.class); - bind(CommandManager.class).to(CommandManagerImpl.class).in(Singleton.class); - bind(EditCommandsView.class).to(EditCommandsViewImpl.class).in(Singleton.class); + bind(CommandExecutor.class).to(CommandExecutorImpl.class).in(Singleton.class); bind(TargetsView.class).to(TargetsViewImpl.class).in(Singleton.class); diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsole.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsole.java index 507c776e80..10cc893d3e 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsole.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsole.java @@ -33,6 +33,9 @@ public interface CommandOutputConsole extends OutputConsole { */ CommandImpl getCommand(); + /** Returns PID of the associated process or 0 if none was associated. */ + int getPid(); + /** * Start listening to the output on the given WebSocket channel. */ diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsolePresenter.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsolePresenter.java index 2ee84242c7..c736116ff7 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsolePresenter.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/outputspanel/console/CommandOutputConsolePresenter.java @@ -25,19 +25,21 @@ import org.eclipse.che.api.machine.shared.dto.execagent.event.ProcessStdErrEvent import org.eclipse.che.api.machine.shared.dto.execagent.event.ProcessStdOutEventDto; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; +import org.eclipse.che.commons.annotation.Nullable; +import org.eclipse.che.ide.api.command.CommandExecutor; import org.eclipse.che.ide.api.command.CommandImpl; -import org.eclipse.che.ide.api.command.CommandManager; import org.eclipse.che.ide.api.machine.ExecAgentCommandManager; +import org.eclipse.che.ide.api.machine.events.ProcessStartedEvent; import org.eclipse.che.ide.api.macro.MacroProcessor; import org.eclipse.che.ide.extension.machine.client.MachineResources; -import org.eclipse.che.ide.extension.machine.client.processes.ProcessFinishedEvent; +import org.eclipse.che.ide.api.machine.events.ProcessFinishedEvent; import org.vectomatic.dom.svg.ui.SVGResource; import java.util.ArrayList; import java.util.List; import static com.google.common.base.Strings.isNullOrEmpty; -import static org.eclipse.che.ide.extension.machine.client.command.edit.EditCommandsPresenter.PREVIEW_URL_ATTR; +import static org.eclipse.che.api.workspace.shared.Constants.COMMAND_PREVIEW_URL_ATTRIBUTE_NAME; /** * Console for command output. @@ -51,7 +53,7 @@ public class CommandOutputConsolePresenter implements CommandOutputConsole, Outp private final CommandImpl command; private final EventBus eventBus; private final Machine machine; - private final CommandManager commandManager; + private final CommandExecutor commandExecutor; private final ExecAgentCommandManager execAgentCommandManager; private int pid; @@ -68,7 +70,7 @@ public class CommandOutputConsolePresenter implements CommandOutputConsole, Outp @Inject public CommandOutputConsolePresenter(final OutputConsoleView view, MachineResources resources, - CommandManager commandManager, + CommandExecutor commandExecutor, MacroProcessor macroProcessor, EventBus eventBus, ExecAgentCommandManager execAgentCommandManager, @@ -80,11 +82,11 @@ public class CommandOutputConsolePresenter implements CommandOutputConsole, Outp this.command = command; this.machine = machine; this.eventBus = eventBus; - this.commandManager = commandManager; + this.commandExecutor = commandExecutor; view.setDelegate(this); - final String previewUrl = command.getAttributes().get(PREVIEW_URL_ATTR); + final String previewUrl = command.getAttributes().get(COMMAND_PREVIEW_URL_ATTRIBUTE_NAME); if (!isNullOrEmpty(previewUrl)) { macroProcessor.expandMacros(previewUrl).then(new Operation() { @Override @@ -109,6 +111,12 @@ public class CommandOutputConsolePresenter implements CommandOutputConsole, Outp return command; } + @Nullable + @Override + public int getPid() { + return pid; + } + @Override public String getTitle() { return command.getName(); @@ -171,6 +179,8 @@ public class CommandOutputConsolePresenter implements CommandOutputConsole, Outp view.toggleScrollToEndButton(true); pid = event.getPid(); + + eventBus.fireEvent(new ProcessStartedEvent(pid, machine)); } }; } @@ -184,7 +194,7 @@ public class CommandOutputConsolePresenter implements CommandOutputConsole, Outp view.enableStopButton(false); view.toggleScrollToEndButton(false); - eventBus.fireEvent(new ProcessFinishedEvent(pid)); + eventBus.fireEvent(new ProcessFinishedEvent(pid, machine)); } }; } @@ -227,12 +237,12 @@ public class CommandOutputConsolePresenter implements CommandOutputConsole, Outp @Override public void reRunProcessButtonClicked() { if (isFinished()) { - commandManager.executeCommand(command, machine); + commandExecutor.executeCommand(command, machine); } else { execAgentCommandManager.killProcess(machine.getId(), pid).then(new Operation() { @Override public void apply(ProcessKillResponseDto arg) throws OperationException { - commandManager.executeCommand(command, machine); + commandExecutor.executeCommand(command, machine); } }); } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java index 8339772e3d..056b4fee32 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenter.java @@ -44,6 +44,7 @@ import org.eclipse.che.ide.api.dialogs.DialogFactory; import org.eclipse.che.ide.api.machine.ExecAgentCommandManager; import org.eclipse.che.ide.api.machine.MachineEntity; import org.eclipse.che.ide.api.machine.events.MachineStateEvent; +import org.eclipse.che.ide.api.machine.events.ProcessFinishedEvent; import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; import org.eclipse.che.ide.api.macro.MacroProcessor; @@ -54,10 +55,13 @@ import org.eclipse.che.ide.api.parts.PartStackStateChangedEvent; import org.eclipse.che.ide.api.parts.PartStackType; import org.eclipse.che.ide.api.parts.WorkspaceAgent; import org.eclipse.che.ide.api.parts.base.BasePresenter; +import org.eclipse.che.ide.api.selection.Selection; import org.eclipse.che.ide.api.ssh.SshServiceClient; import org.eclipse.che.ide.api.workspace.event.EnvironmentOutputEvent; import org.eclipse.che.ide.api.workspace.event.WorkspaceStartedEvent; import org.eclipse.che.ide.api.workspace.event.WorkspaceStoppedEvent; +import org.eclipse.che.ide.command.toolbar.processes.ActivateProcessOutputEvent; +import org.eclipse.che.ide.command.toolbar.processes.ProcessOutputClosedEvent; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; import org.eclipse.che.ide.extension.machine.client.MachineResources; @@ -69,7 +73,6 @@ import org.eclipse.che.ide.extension.machine.client.outputspanel.console.Command import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandOutputConsolePresenter; import org.eclipse.che.ide.extension.machine.client.outputspanel.console.DefaultOutputConsole; import org.eclipse.che.ide.extension.machine.client.perspective.terminal.TerminalPresenter; -import org.eclipse.che.ide.extension.machine.client.processes.ProcessFinishedEvent; import org.eclipse.che.ide.extension.machine.client.processes.ProcessTreeNode; import org.eclipse.che.ide.extension.machine.client.processes.ProcessTreeNodeSelectedEvent; import org.eclipse.che.ide.extension.machine.client.processes.actions.ConsoleTreeContextMenu; @@ -205,6 +208,7 @@ public class ProcessesPanelPresenter extends BasePresenter implements ProcessesP eventBus.addHandler(EnvironmentOutputEvent.TYPE, this); eventBus.addHandler(DownloadWorkspaceOutputEvent.TYPE, this); eventBus.addHandler(PartStackStateChangedEvent.TYPE, this); + eventBus.addHandler(ActivateProcessOutputEvent.TYPE, event -> setActiveProcessOutput(event.getPid())); final PartStack partStack = checkNotNull(workspaceAgent.getPartStack(PartStackType.INFORMATION), "Information part stack should not be a null"); @@ -399,6 +403,26 @@ public class ProcessesPanelPresenter extends BasePresenter implements ProcessesP } } + /** Set active output of the process with the given PID. */ + private void setActiveProcessOutput(int pid) { + ProcessTreeNode processNode = null; + + for (Map.Entry entry : consoles.entrySet()) { + final OutputConsole console = entry.getValue(); + if (console instanceof CommandOutputConsole) { + final int consolePid = ((CommandOutputConsole)console).getPid(); + if (pid == consolePid) { + final String commandId = consoleCommands.get(console); + processNode = findTreeNodeById(commandId); + } + } + } + + if (processNode != null) { + view.selectNode(processNode); + } + } + /** * Adds new terminal to the processes panel * @@ -452,7 +476,7 @@ public class ProcessesPanelPresenter extends BasePresenter implements ProcessesP @Override public void onPreviewSsh(String machineId) { - ProcessTreeNode machineTreeNode = findProcessTreeNodeById(machineId); + ProcessTreeNode machineTreeNode = findTreeNodeById(machineId); if (machineTreeNode == null) { return; } @@ -512,8 +536,15 @@ public class ProcessesPanelPresenter extends BasePresenter implements ProcessesP @Override public void onTreeNodeSelected(final ProcessTreeNode node) { + setSelection(new Selection.NoSelectionProvided()); + if (node != null) { if (ProcessTreeNode.ProcessNodeType.MACHINE_NODE == node.getType()) { + final MachineEntity machine = getMachine(node.getId()); + if (machine != null) { + setSelection(new Selection<>(machine)); + } + view.showProcessOutput(node.getName()); } else { view.showProcessOutput(node.getId()); @@ -546,7 +577,7 @@ public class ProcessesPanelPresenter extends BasePresenter implements ProcessesP * the console for command output */ public void addCommandOutput(String machineId, OutputConsole outputConsole) { - ProcessTreeNode machineTreeNode = findProcessTreeNodeById(machineId); + ProcessTreeNode machineTreeNode = findTreeNodeById(machineId); if (machineTreeNode == null) { notificationManager.notify(localizationConstant.failedToExecuteCommand(), localizationConstant.machineNotFound(machineId), FAIL, FLOAT_MODE); @@ -670,6 +701,10 @@ public class ProcessesPanelPresenter extends BasePresenter implements ProcessesP removeCallback.remove(); + if (console instanceof CommandOutputConsole) { + eventBus.fireEvent(new ProcessOutputClosedEvent(((CommandOutputConsole)console).getPid())); + } + return; } @@ -693,6 +728,10 @@ public class ProcessesPanelPresenter extends BasePresenter implements ProcessesP consoleCommands.remove(console); removeCallback.remove(); + + if (console instanceof CommandOutputConsole) { + eventBus.fireEvent(new ProcessOutputClosedEvent(((CommandOutputConsole)console).getPid())); + } } }; } @@ -753,12 +792,23 @@ public class ProcessesPanelPresenter extends BasePresenter implements ProcessesP view.setProcessesData(rootNode); } - private ProcessTreeNode findProcessTreeNodeById(String id) { - for (ProcessTreeNode processTreeNode : rootNode.getChildren()) { - if (id.equals(processTreeNode.getId())) { - return processTreeNode; + @Nullable + private ProcessTreeNode findTreeNodeById(String nodeId) { + for (ProcessTreeNode machineTreeNode : rootNode.getChildren()) { + if (nodeId.equals(machineTreeNode.getId())) { + return machineTreeNode; + } else { + final Collection machineProcesses = machineTreeNode.getChildren(); + if (machineProcesses != null) { + for (ProcessTreeNode processTreeNode : machineProcesses) { + if (nodeId.equals(processTreeNode.getId())) { + return processTreeNode; + } + } + } } } + return null; } @@ -832,7 +882,7 @@ public class ProcessesPanelPresenter extends BasePresenter implements ProcessesP */ private ProcessTreeNode provideMachineNode(@NotNull MachineEntity machine, boolean replace) { final String machineId = machine.getId(); - final ProcessTreeNode existedMachineNode = findProcessTreeNodeById(machineId); + final ProcessTreeNode existedMachineNode = findTreeNodeById(machineId); if (!replace && existedMachineNode != null) { return existedMachineNode; } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandResources.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/targets/TargetsResources.java similarity index 62% rename from plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandResources.java rename to plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/targets/TargetsResources.java index fddfe1cd36..bdcd0b74a7 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandResources.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/targets/TargetsResources.java @@ -8,50 +8,38 @@ * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ -package org.eclipse.che.ide.extension.machine.client.command.edit; +package org.eclipse.che.ide.extension.machine.client.targets; import com.google.gwt.resources.client.ClientBundle; import com.google.gwt.resources.client.CssResource; -import com.google.gwt.resources.client.DataResource; import org.vectomatic.dom.svg.ui.SVGResource; /** - * Class contains references to resources which need to correct displaying of command wizard dialog. + * Class contains references to resources which need to correct displaying of targets dialog. * * @author Oleksii Orel */ -public interface EditCommandResources extends ClientBundle { +public interface TargetsResources extends ClientBundle { - interface EditCommandStyles extends CssResource { + interface EditTargetsStyles extends CssResource { String categoryHeader(); String categorySubElementHeader(); - String hintLabel(); - String buttonArea(); String running(); - - String filterPlaceholder(); } - @Source({"CommandRenderer.css", "org/eclipse/che/ide/api/ui/style.css"}) - EditCommandStyles getCss(); - - @DataResource.MimeType("image/svg+xml") - @Source("find-icon.svg") - DataResource findIcon(); + @Source({"TargetRenderer.css", "org/eclipse/che/ide/api/ui/style.css"}) + EditTargetsStyles getCss(); @Source("add-command-button.svg") SVGResource addCommandButton(); - @Source("duplicate-command-button.svg") - SVGResource duplicateCommandButton(); - @Source("remove-command-button.svg") SVGResource removeCommandButton(); } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/targets/TargetsViewImpl.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/targets/TargetsViewImpl.java index 8ab7cfe3c3..3ef23ee352 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/targets/TargetsViewImpl.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/java/org/eclipse/che/ide/extension/machine/client/targets/TargetsViewImpl.java @@ -38,7 +38,6 @@ import org.eclipse.che.ide.api.icon.Icon; import org.eclipse.che.ide.api.icon.IconRegistry; import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; import org.eclipse.che.ide.extension.machine.client.MachineResources; -import org.eclipse.che.ide.extension.machine.client.command.edit.EditCommandResources; import org.eclipse.che.ide.ui.Tooltip; import org.eclipse.che.ide.ui.list.CategoriesList; import org.eclipse.che.ide.ui.list.Category; @@ -69,9 +68,9 @@ public class TargetsViewImpl extends Window implements TargetsView { interface TargetsViewImplUiBinder extends UiBinder { } - private EditCommandResources commandResources; - private MachineResources machineResources; - private IconRegistry iconRegistry; + private TargetsResources commandResources; + private MachineResources machineResources; + private IconRegistry iconRegistry; private ActionDelegate delegate; @@ -96,7 +95,7 @@ public class TargetsViewImpl extends Window implements TargetsView { MachineLocalizationConstant machineLocale, MachineResources machineResources, CoreLocalizationConstant coreLocale, - EditCommandResources commandResources, + TargetsResources commandResources, IconRegistry iconRegistry, TargetsViewImplUiBinder uiBinder) { this.machineLocale = machineLocale; diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/MachineLocalizationConstant.properties b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/MachineLocalizationConstant.properties index a1c8d88289..768f551c1d 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/MachineLocalizationConstant.properties +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/MachineLocalizationConstant.properties @@ -17,15 +17,9 @@ downloadOutputs = Download outputs ##### Actions ##### main.menu.machine = Machine -control.selectCommand.text = Select Command -control.selectCommand.description = Select command to execute control.devMachine.category = development -control.runSelectedCommand.text = Execute Selected Command -control.runSelectedCommand.description = Execute selected command in developer machine control.runCommand.empty.params = Cannot run command without params control.runCommand.empty.name = Cannot run command without name specified -control.editCommands.text = Edit Commands... -control.editCommands.description = Edit commands control.editTargets = Edit Targets... control.editTargets.description = Open dialog to edit targets... control.clearMachineConsole.text = Clear Console @@ -101,18 +95,6 @@ view.createMachine.name = Name: view.createMachine.recipeURL = Recipe URL: view.createMachine.findByTags = Find by tags: -##### EditCommandsView ##### -view.editCommands.placeholder = Filter -view.editCommands.title = Commands -view.editCommands.hint = Press the ''+'' button to create a new command -view.editCommands.name.text = Name -view.editCommands.remove.title = Delete Command -view.editCommands.execute.message = First, you need to apply your changes -view.editCommands.remove.confirmation = Do you want to remove the {0} command? -view.editCommands.saveChanges.title = Unsaved changes -view.editCommands.saveChanges.text = Command {0} has been changed.
Do you want to save it? -view.editCommands.saveChanges.discard = Discard changes - ##### TargetsView ##### view.targets.category.ssh = ssh view.targets.category.docker = docker diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/images/execute.svg b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/images/execute.svg deleted file mode 100644 index 1ddc72c15f..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/images/execute.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/machine.css b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/machine.css index 154cfaa119..a1370bd82f 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/machine.css +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/machine.css @@ -140,56 +140,6 @@ text-shadow: 0 1px 0 rgba(0, 0, 0, 1); } -.selectCommandBox:first-child > .selectCommandBoxIconPanel:first-child { - border-top-left-radius: 2px; - border-bottom-left-radius: 2px; -} - -.selectCommandBox:first-child > .selectCommandBoxIconPanel:first-child + div { - font-family: textFieldFontFamily; - color: selectCommandActionColor; - font-size: textFieldFontSize; -} - -.selectCommandBox:first-child > .selectCommandBoxIconPanel:first-child + div:hover { - color: selectCommandActionHoverColor; -} - -.selectCommandBox { - height: 100%; - min-width: 336px; - white-space: nowrap; - margin: 0 !important; - display: inline-block; -} - -.selectCommandBoxIconPanel { - float: left; - width: 40px; - height: 100%; - margin-top: auto; - line-height: 24px; - background-color: selectCommandActionIconBackgroundColor; -} - -.selectCommandBox .selectCommandBoxIconPanel + div { - float: left; - text-align: left; - width: 150px; - padding: 0 5px 0 5px; - display: inline-block; -} - -.selectCommandBoxIconPanel svg { - max-width: 22px; - max-height: 22px; - fill: selectCommandActionIconColor; -} - -.selectCommandBoxIconPanel svg path { - fill: selectCommandActionIconColor !important; -} - .processTree { font-family: mainFontFamily; font-size: fontSize; diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/CommandRenderer.css b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/targets/TargetRenderer.css similarity index 82% rename from plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/CommandRenderer.css rename to plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/targets/TargetRenderer.css index 1c65ab5c74..e4b2e33cf6 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/command/edit/CommandRenderer.css +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/targets/TargetRenderer.css @@ -16,12 +16,6 @@ @eval categorySelectElementBackgroundColor org.eclipse.che.ide.api.theme.Style.theme.categorySelectElementBackgroundColor(); @eval categorySelectElementColor org.eclipse.che.ide.api.theme.Style.theme.categorySelectElementColor(); -.hintLabel { - color: textFieldColor; - font-size: largeLabel; - font-weight: bold; -} - .categoryHeader svg { width: 15px; height: 15px; @@ -118,23 +112,3 @@ div.categorySubElementHeader[selected] .buttonArea span:hover > svg { left: 30px; top: 4px; } - -input.filterPlaceholder::-webkit-input-placeholder { - font-weight: bold; - padding-left: literal("calc(50% - 15px)"); - color: placeholderColor; - background-image: findIcon; - background-repeat: no-repeat; - background-position: literal("calc(50% - 25px)") center; - background-size: contain; -} - -input.filterPlaceholder::-moz-placeholder { - font-weight: bold; - text-align: center; - color: placeholderColor; - background-image: findIcon; - background-repeat: no-repeat; - background-position: literal("calc(50% - 25px)") center; - background-size: contain; -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/images/cmd-icon.svg b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/targets/add-command-button.svg similarity index 57% rename from plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/images/cmd-icon.svg rename to plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/targets/add-command-button.svg index c4cf6372a0..f1fa87a6ec 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/images/cmd-icon.svg +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/targets/add-command-button.svg @@ -11,7 +11,10 @@ Codenvy, S.A. - initial API and implementation --> - - CMD + + + + + + diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/targets/remove-command-button.svg b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/targets/remove-command-button.svg new file mode 100644 index 0000000000..35695a0c37 --- /dev/null +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/main/resources/org/eclipse/che/ide/extension/machine/client/targets/remove-command-button.svg @@ -0,0 +1,22 @@ + + + + + + + + + diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/actions/EditCommandsActionTest.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/actions/EditCommandsActionTest.java deleted file mode 100644 index 5ffb06087a..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/actions/EditCommandsActionTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/******************************************************************************* - * 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.extension.machine.client.actions; - -import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.ide.api.action.ActionEvent; -import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; -import org.eclipse.che.ide.extension.machine.client.MachineResources; -import org.eclipse.che.ide.extension.machine.client.command.edit.EditCommandsPresenter; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.mockito.Mockito.verify; - -/** @author Artem Zatsarynnyi */ -@RunWith(MockitoJUnitRunner.class) -public class EditCommandsActionTest { - - @Mock - private MachineLocalizationConstant localizationConstants; - @Mock - private MachineResources resources; - @Mock - private EditCommandsPresenter editCommandsPresenter; - @Mock - private ActionEvent event; - @Mock - private EventBus eventBus; - - @InjectMocks - private EditCommandsAction action; - - @Test - public void constructorShouldBeVerified() throws Exception{ - verify(localizationConstants).editCommandsControlTitle(); - verify(localizationConstants).editCommandsControlDescription(); -// verify(resources).recipe(); //Temporary commented due to new icon will be provided - } - - @Test - public void actionShouldBePerformed() throws Exception { - action.actionPerformed(event); - - verify(editCommandsPresenter).show(); - } -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/actions/ExecuteSelectedCommandActionTest.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/actions/ExecuteSelectedCommandActionTest.java deleted file mode 100644 index 31d69e34d5..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/actions/ExecuteSelectedCommandActionTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/******************************************************************************* - * 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.extension.machine.client.actions; - -import com.google.web.bindery.event.shared.EventBus; -import org.eclipse.che.api.machine.shared.dto.MachineDto; -import org.eclipse.che.ide.api.action.ActionEvent; -import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; -import org.eclipse.che.ide.extension.machine.client.MachineResources; -import org.eclipse.che.ide.api.command.CommandManager; -import org.eclipse.che.ide.api.command.CommandImpl; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** @author Artem Zatsarynnyi */ -@RunWith(MockitoJUnitRunner.class) -public class ExecuteSelectedCommandActionTest { - - @Mock - private MachineLocalizationConstant localizationConstants; - @Mock - private MachineResources resources; - @Mock - private SelectCommandComboBox selectCommandAction; - @Mock - private CommandManager commandManager; - @Mock - private ActionEvent event; - @Mock - private EventBus eventBus; - - @Mock - private CommandImpl command; - @Mock - private MachineDto machine; - - @InjectMocks - private ExecuteSelectedCommandAction action; - - @Before - public void setUp() throws Exception { - when(selectCommandAction.getSelectedCommand()).thenReturn(command); - when(selectCommandAction.getSelectedMachine()).thenReturn(machine); - } - - @Test - public void constructorShouldBeVerified() throws Exception { - verify(localizationConstants).executeSelectedCommandControlTitle(); - verify(localizationConstants).executeSelectedCommandControlDescription(); - verify(resources).execute(); - } - - @Test - public void actionShouldBePerformed() throws Exception { - action.actionPerformed(event); - - verify(commandManager).executeCommand(command, machine); - } - -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/actions/RunCommandActionTest.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/actions/RunCommandActionTest.java index fc84f7c7af..47795144f7 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/actions/RunCommandActionTest.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/actions/RunCommandActionTest.java @@ -13,10 +13,11 @@ package org.eclipse.che.ide.extension.machine.client.actions; import org.eclipse.che.api.core.model.machine.Machine; import org.eclipse.che.ide.api.action.ActionEvent; import org.eclipse.che.ide.api.app.AppContext; +import org.eclipse.che.ide.api.command.CommandExecutor; +import org.eclipse.che.ide.api.command.CommandImpl; +import org.eclipse.che.ide.api.command.CommandManager; import org.eclipse.che.ide.api.machine.DevMachine; import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; -import org.eclipse.che.ide.api.command.CommandManager; -import org.eclipse.che.ide.api.command.CommandImpl; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,6 +26,7 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import java.util.Collections; +import java.util.Optional; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; @@ -43,9 +45,9 @@ public class RunCommandActionTest { //constructors mocks @Mock - SelectCommandComboBox selectCommandAction; + CommandManager commandManager; @Mock - private CommandManager commandManager; + private CommandExecutor commandExecutor; @Mock private MachineLocalizationConstant locale; @Mock @@ -61,7 +63,7 @@ public class RunCommandActionTest { @Before public void setUp() throws Exception { - when(selectCommandAction.getCommandByName(anyString())).thenReturn(command); + when(commandManager.getCommand(anyString())).thenReturn(Optional.of(command)); } @Test @@ -69,7 +71,7 @@ public class RunCommandActionTest { when(event.getParameters()).thenReturn(Collections.singletonMap("otherParam", "MCI")); action.actionPerformed(event); - verify(commandManager, never()).executeCommand(any(CommandImpl.class), any(Machine.class)); + verify(commandExecutor, never()).executeCommand(any(CommandImpl.class), any(Machine.class)); } @Test @@ -82,7 +84,7 @@ public class RunCommandActionTest { action.actionPerformed(event); - verify(commandManager).executeCommand(eq(command), any(Machine.class)); + verify(commandExecutor).executeCommand(eq(command), any(Machine.class)); } } diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsPresenterTest.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsPresenterTest.java deleted file mode 100644 index e91ec755b0..0000000000 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/command/edit/EditCommandsPresenterTest.java +++ /dev/null @@ -1,157 +0,0 @@ -/******************************************************************************* - * 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.extension.machine.client.command.edit; - -import org.eclipse.che.api.machine.shared.dto.CommandDto; -import org.eclipse.che.api.promises.client.Function; -import org.eclipse.che.api.promises.client.Operation; -import org.eclipse.che.api.promises.client.Promise; -import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto; -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.CommandType; -import org.eclipse.che.ide.api.command.CommandTypeRegistry; -import org.eclipse.che.ide.api.dialogs.DialogFactory; -import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; - -import java.util.ArrayList; -import java.util.List; - -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -/** @author Roman Nikitenko */ -@RunWith(MockitoJUnitRunner.class) -public class EditCommandsPresenterTest { - - private static String COMMAND_NAME = "commandName"; - private static String COMMAND_TYPE = "commandType"; - - @Mock - private EditCommandsView view; - @Mock - private CommandManager commandManager; - @Mock - private CommandTypeRegistry commandTypeRegistry; - @Mock - private DialogFactory dialogFactory; - @Mock - private MachineLocalizationConstant machineLocale; - @Mock - private CoreLocalizationConstant coreLocale; - - @Mock - private CommandImpl command; - - @Mock - private Promise> commandsPromise; - @Mock - private Promise commandPromise; - @Captor - private ArgumentCaptor, List>> commandsCaptor; - @Captor - private ArgumentCaptor> commandCaptor; - @Captor - private ArgumentCaptor> workspaceCaptor; - - @InjectMocks - private EditCommandsPresenter presenter; - - @Before - public void setUp() { - presenter.editedCommandNameInitial = COMMAND_NAME; - - when(commandManager.update(anyString(), anyObject())).thenReturn(commandPromise); - - CommandType commandType = mock(CommandType.class); - when(commandType.getId()).thenReturn(COMMAND_TYPE); - List commandTypes = new ArrayList<>(1); - commandTypes.add(commandType); - when(commandTypeRegistry.getCommandTypes()).thenReturn(commandTypes); - - when(command.getType()).thenReturn(COMMAND_TYPE); - when(command.getName()).thenReturn(COMMAND_NAME); - List commands = new ArrayList<>(1); - commands.add(command); - when(commandManager.getCommands()).thenReturn(commands); - } - - @Test - public void onEnterClickedWhenCancelButtonInFocus() throws Exception { - when(view.isCancelButtonInFocus()).thenReturn(true); - - presenter.onEnterClicked(); - - verify(view).setCancelButtonState(false); - verify(view).setSaveButtonState(false); - verify(commandManager).getCommands(); - verify(view).setData(anyObject()); - verify(view).setFilterState(anyBoolean()); - verify(view).setCloseButtonInFocus(); - verify(view, never()).close(); - verify(commandManager, never()).update(anyString(), anyObject()); - verify(commandManager, never()).remove(anyString()); - } - - @Test - public void onEnterClickedWhenCloseButtonInFocus() throws Exception { - when(view.isCloseButtonInFocus()).thenReturn(true); - - presenter.onEnterClicked(); - - verify(view).close(); - verify(commandManager, never()).getCommands(); - verify(commandManager, never()).update(anyString(), anyObject()); - verify(commandManager, never()).remove(anyString()); - } - - @Test - public void onEnterClickedWhenSaveButtonInFocus() throws Exception { - when(view.isCancelButtonInFocus()).thenReturn(false); - when(view.isCloseButtonInFocus()).thenReturn(false); - - when(view.getSelectedCommand()).thenReturn(command); - - when(commandPromise.then((Operation)anyObject())).thenReturn(commandPromise); - when(commandPromise.catchError((Operation)anyObject())).thenReturn(commandPromise); - - presenter.onEnterClicked(); - - verify(commandManager).update(anyString(), eq(command)); - - verify(commandPromise, times(2)).then(commandCaptor.capture()); - commandCaptor.getValue().apply(command); - - verify(view).setCancelButtonState(false); - verify(view).setSaveButtonState(false); - verify(commandManager).getCommands(); - verify(view).setData(anyObject()); - verify(view).setFilterState(anyBoolean()); - verify(view).setCloseButtonInFocus(); - verify(view, never()).close(); - } -} diff --git a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenterTest.java b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenterTest.java index 46124b43d9..459cd7b10b 100644 --- a/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenterTest.java +++ b/plugins/plugin-machine/che-plugin-machine-ext-client/src/test/java/org/eclipse/che/ide/extension/machine/client/processes/panel/ProcessesPanelPresenterTest.java @@ -16,6 +16,7 @@ import com.google.gwt.user.client.ui.Widget; import com.google.gwtmockito.GwtMockitoTestRunner; import com.google.web.bindery.event.shared.EventBus; +import org.eclipse.che.api.core.model.machine.Machine; import org.eclipse.che.api.core.model.machine.MachineStatus; import org.eclipse.che.api.machine.shared.dto.MachineConfigDto; import org.eclipse.che.api.machine.shared.dto.MachineDto; @@ -53,7 +54,7 @@ import org.eclipse.che.ide.extension.machine.client.inject.factories.TerminalFac import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandConsoleFactory; import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandOutputConsole; import org.eclipse.che.ide.extension.machine.client.perspective.terminal.TerminalPresenter; -import org.eclipse.che.ide.extension.machine.client.processes.ProcessFinishedEvent; +import org.eclipse.che.ide.api.machine.events.ProcessFinishedEvent; import org.eclipse.che.ide.extension.machine.client.processes.ProcessTreeNode; import org.eclipse.che.ide.extension.machine.client.processes.actions.ConsoleTreeContextMenuFactory; import org.junit.Before; @@ -203,7 +204,7 @@ public class ProcessesPanelPresenterTest { MachineStateEvent machineStateEvent = mock(MachineStateEvent.class); when(machineStateEvent.getMachine()).thenReturn(machine); - verify(eventBus, times(8)).addHandler(anyObject(), machineStateHandlerCaptor.capture()); + verify(eventBus, times(9)).addHandler(anyObject(), machineStateHandlerCaptor.capture()); MachineStateEvent.Handler machineStateHandler = machineStateHandlerCaptor.getAllValues().get(0); machineStateHandler.onMachineCreating(machineStateEvent); @@ -468,7 +469,7 @@ public class ProcessesPanelPresenterTest { when(outputConsole.isFinished()).thenReturn(true); presenter.consoles.put(PROCESS_ID, outputConsole); - presenter.onProcessFinished(new ProcessFinishedEvent(PID)); + presenter.onProcessFinished(new ProcessFinishedEvent(PID, mock(Machine.class))); verify(view).setStopButtonVisibility(PROCESS_ID, false); } diff --git a/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/command/MavenCommandType.java b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/command/MavenCommandType.java index 44940759d4..f974a648d3 100644 --- a/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/command/MavenCommandType.java +++ b/plugins/plugin-maven/che-plugin-maven-ide/src/main/java/org/eclipse/che/plugin/maven/client/command/MavenCommandType.java @@ -19,7 +19,7 @@ import org.eclipse.che.ide.api.icon.Icon; import org.eclipse.che.ide.api.icon.IconRegistry; import org.eclipse.che.ide.extension.machine.client.command.macros.CurrentProjectPathMacro; import org.eclipse.che.ide.extension.machine.client.command.macros.CurrentProjectRelativePathMacro; -import org.eclipse.che.ide.extension.machine.client.command.macros.ServerPortProvider; +import org.eclipse.che.ide.extension.machine.client.command.macros.ServerAddressMacroRegistrar; import org.eclipse.che.plugin.maven.client.MavenResources; import java.util.LinkedList; @@ -53,7 +53,7 @@ public class MavenCommandType implements CommandType { pages = new LinkedList<>(); pages.add(page); - iconRegistry.registerIcon(new Icon(ID + ".commands.category.icon", resources.maven())); + iconRegistry.registerIcon(new Icon("command.type." + ID, resources.maven())); } @Override @@ -84,7 +84,7 @@ public class MavenCommandType implements CommandType { @Override public String getPreviewUrlTemplate() { //TODO: hardcode http after switching WS Master to https - return "http://" + ServerPortProvider.KEY_TEMPLATE.replace("%", DEF_PORT) + "/" + + return "http://" + ServerAddressMacroRegistrar.MACRO_NAME_TEMPLATE.replace("%", DEF_PORT) + "/" + currentProjectRelativePathMacro.getName(); } } diff --git a/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/src/main/java/org/eclipse/che/plugin/nodejs/ide/action/NewNodeJsFileAction.java b/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/src/main/java/org/eclipse/che/plugin/nodejs/ide/action/NewNodeJsFileAction.java index 4127d005af..2c8f8cd973 100644 --- a/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/src/main/java/org/eclipse/che/plugin/nodejs/ide/action/NewNodeJsFileAction.java +++ b/plugins/plugin-nodejs/che-plugin-nodejs-lang-ide/src/main/java/org/eclipse/che/plugin/nodejs/ide/action/NewNodeJsFileAction.java @@ -11,11 +11,13 @@ package org.eclipse.che.plugin.nodejs.ide.action; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import org.eclipse.che.plugin.nodejs.ide.NodeJsLocalizationConstant; @@ -36,7 +38,8 @@ public class NewNodeJsFileAction extends AbstractNewResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(locale.newNodeJsFileTitle(), locale.newNodeJsFileDescription(), resources.jsIcon(), @@ -44,7 +47,8 @@ public class NewNodeJsFileAction extends AbstractNewResourceAction { coreLocalizationConstant, eventBus, appContext, - notificationManager); + notificationManager, + editorAgentProvider); } @Override diff --git a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/ContentAssistWidget.java b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/ContentAssistWidget.java index ce996efbd7..c5b8bec68e 100644 --- a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/ContentAssistWidget.java +++ b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/ContentAssistWidget.java @@ -10,6 +10,16 @@ *******************************************************************************/ package org.eclipse.che.ide.editor.orion.client; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.dom.client.Style; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.assistedinject.Assisted; +import com.google.inject.assistedinject.AssistedInject; import elemental.dom.Element; import elemental.dom.Node; import elemental.events.CustomEvent; @@ -21,18 +31,6 @@ import elemental.events.MouseEvent; import elemental.html.HTMLCollection; import elemental.html.SpanElement; import elemental.html.Window; - -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.dom.client.Style; -import com.google.gwt.event.dom.client.KeyCodes; -import com.google.gwt.user.client.Timer; -import com.google.gwt.user.client.rpc.AsyncCallback; -import com.google.gwt.user.client.ui.FlowPanel; -import com.google.gwt.user.client.ui.RootPanel; -import com.google.gwt.user.client.ui.Widget; -import com.google.inject.assistedinject.Assisted; -import com.google.inject.assistedinject.AssistedInject; - import org.eclipse.che.ide.api.editor.codeassist.Completion; import org.eclipse.che.ide.api.editor.codeassist.CompletionProposal; import org.eclipse.che.ide.api.editor.codeassist.CompletionProposalExtension; @@ -665,13 +663,15 @@ public class ContentAssistWidget implements EventListener { private void applyProposal(CompletionProposal proposal) { CompletionProposal.CompletionCallback callback = this::applyCompletion; + hide(); + if (proposal instanceof CompletionProposalExtension) { ((CompletionProposalExtension)proposal).getCompletion(insert, callback); } else { proposal.getCompletion(callback); } - hide(); + } private void applyCompletion(Completion completion) { diff --git a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorWidget.java b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorWidget.java index c1552a2d30..f37fcdba70 100644 --- a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorWidget.java +++ b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/OrionEditorWidget.java @@ -286,6 +286,26 @@ public class OrionEditorWidget extends Composite implements EditorWidget, editorViewOverlay.updateSettings(properties.getJavaScriptObject()); } + @Override + public void setAnnotationRulerVisible(boolean show) { + editorOverlay.setAnnotationRulerVisible(show); + } + + @Override + public void setFoldingRulerVisible(boolean show) { + editorOverlay.setFoldingRulerVisible(show); + } + + @Override + public void setZoomRulerVisible(boolean show) { + editorOverlay.setZoomRulerVisible(show); + } + + @Override + public void setOverviewRulerVisible(boolean show) { + editorOverlay.setOverviewRulerVisible(show); + } + @Override public boolean isDirty() { return this.editorOverlay.isDirty(); diff --git a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/jso/OrionEditorOverlay.java b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/jso/OrionEditorOverlay.java index d0012a420a..0db3e7035d 100644 --- a/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/jso/OrionEditorOverlay.java +++ b/plugins/plugin-orion/che-plugin-orion-editor/src/main/java/org/eclipse/che/ide/editor/orion/client/jso/OrionEditorOverlay.java @@ -187,10 +187,22 @@ public class OrionEditorOverlay extends JavaScriptObject { return this.getAnnotationModel(); }-*/; + public final native void setAnnotationRulerVisible(boolean visible) /*-{ + this.setAnnotationRulerVisible(visible); + }-*/; + + public final native void setFoldingRulerVisible(boolean visible) /*-{ + this.setFoldingRulerVisible(visible); + }-*/; + public final native void setZoomRulerVisible(boolean visible) /*-{ this.setZoomRulerVisible(visible); }-*/; + public final native void setOverviewRulerVisible(boolean visible) /*-{ + this.setOverviewRulerVisible(visible); + }-*/; + public final native void showProblems(JsArray problems) /*-{ this.showProblems(problems); }-*/; diff --git a/plugins/plugin-php/che-plugin-php-lang-ide/src/main/java/org/eclipse/che/plugin/php/ide/action/CreatePhpSourceFileAction.java b/plugins/plugin-php/che-plugin-php-lang-ide/src/main/java/org/eclipse/che/plugin/php/ide/action/CreatePhpSourceFileAction.java index 96750d376e..161939c563 100644 --- a/plugins/plugin-php/che-plugin-php-lang-ide/src/main/java/org/eclipse/che/plugin/php/ide/action/CreatePhpSourceFileAction.java +++ b/plugins/plugin-php/che-plugin-php-lang-ide/src/main/java/org/eclipse/che/plugin/php/ide/action/CreatePhpSourceFileAction.java @@ -11,12 +11,14 @@ package org.eclipse.che.plugin.php.ide.action; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.plugin.php.ide.PhpLocalizationConstant; import org.eclipse.che.plugin.php.ide.PhpResources; @@ -41,7 +43,8 @@ public class CreatePhpSourceFileAction extends NewPhplikeResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.createPhpFileActionTitle(), localizationConstant.createPhpFileActionDescription(), resources.phpFile(), @@ -49,7 +52,8 @@ public class CreatePhpSourceFileAction extends NewPhplikeResourceAction { coreLocalizationConstant, eventBus, appContext, - notificationManager); + notificationManager, + editorAgentProvider); } @Override diff --git a/plugins/plugin-php/che-plugin-php-lang-ide/src/main/java/org/eclipse/che/plugin/php/ide/action/NewPhplikeResourceAction.java b/plugins/plugin-php/che-plugin-php-lang-ide/src/main/java/org/eclipse/che/plugin/php/ide/action/NewPhplikeResourceAction.java index 88a765a750..09cee09f5f 100644 --- a/plugins/plugin-php/che-plugin-php-lang-ide/src/main/java/org/eclipse/che/plugin/php/ide/action/NewPhplikeResourceAction.java +++ b/plugins/plugin-php/che-plugin-php-lang-ide/src/main/java/org/eclipse/che/plugin/php/ide/action/NewPhplikeResourceAction.java @@ -10,11 +10,13 @@ *******************************************************************************/ package org.eclipse.che.plugin.php.ide.action; +import com.google.inject.Provider; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import org.vectomatic.dom.svg.ui.SVGResource; @@ -46,8 +48,9 @@ public abstract class NewPhplikeResourceAction extends AbstractNewResourceAction CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { - super(title, description, svgIcon, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + NotificationManager notificationManager, + Provider editorAgentProvider) { + super(title, description, svgIcon, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); this.appContext = appContext; } } diff --git a/plugins/plugin-python/che-plugin-python-lang-ide/src/main/java/org/eclipse/che/plugin/python/ide/action/CreatePythonFileAction.java b/plugins/plugin-python/che-plugin-python-lang-ide/src/main/java/org/eclipse/che/plugin/python/ide/action/CreatePythonFileAction.java index 2e623f8602..fde21f7707 100644 --- a/plugins/plugin-python/che-plugin-python-lang-ide/src/main/java/org/eclipse/che/plugin/python/ide/action/CreatePythonFileAction.java +++ b/plugins/plugin-python/che-plugin-python-lang-ide/src/main/java/org/eclipse/che/plugin/python/ide/action/CreatePythonFileAction.java @@ -11,12 +11,14 @@ package org.eclipse.che.plugin.python.ide.action; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import org.eclipse.che.plugin.python.ide.PythonLocalizationConstant; @@ -39,10 +41,11 @@ public class CreatePythonFileAction extends AbstractNewResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.createPythonFileActionTitle(), localizationConstant.createPythonFileActionDescription(), - pythonResources.pythonFile(), dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + pythonResources.pythonFile(), dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); } @Override diff --git a/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/src/main/java/org/eclipse/che/ide/ext/plugins/client/command/GwtCheCommandType.java b/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/src/main/java/org/eclipse/che/ide/ext/plugins/client/command/GwtCheCommandType.java index 5cba973da1..a5942161c0 100644 --- a/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/src/main/java/org/eclipse/che/ide/ext/plugins/client/command/GwtCheCommandType.java +++ b/plugins/plugin-sdk/che-plugin-sdk-ext-plugins/src/main/java/org/eclipse/che/ide/ext/plugins/client/command/GwtCheCommandType.java @@ -47,7 +47,7 @@ public class GwtCheCommandType implements CommandType { pages = new LinkedList<>(); pages.add(page); - iconRegistry.registerIcon(new Icon(ID + ".commands.category.icon", resources.gwtCheCommandType())); + iconRegistry.registerIcon(new Icon("command.type." + ID, resources.gwtCheCommandType())); } @Override diff --git a/plugins/plugin-testing/che-plugin-testing-ide/pom.xml b/plugins/plugin-testing/che-plugin-testing-ide/pom.xml index db35e05f26..c684500f3a 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/pom.xml +++ b/plugins/plugin-testing/che-plugin-testing-ide/pom.xml @@ -72,6 +72,10 @@ org.eclipse.che.core che-core-ide-api + + org.eclipse.che.core + che-core-ide-app + org.eclipse.che.core che-core-ide-ui diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java index 7bbe588a68..6a857ccc70 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/TestServiceClient.java @@ -33,6 +33,7 @@ import org.eclipse.che.ide.api.command.CommandManager; import org.eclipse.che.ide.api.machine.ExecAgentCommandManager; import org.eclipse.che.ide.api.macro.MacroProcessor; import org.eclipse.che.ide.api.notification.StatusNotification; +import org.eclipse.che.ide.command.goal.TestGoal; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandConsoleFactory; import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandOutputConsole; @@ -79,6 +80,7 @@ public class TestServiceClient { private final MacroProcessor macroProcessor; private final CommandConsoleFactory commandConsoleFactory; private final ProcessesPanelPresenter processesPanelPresenter; + private final TestGoal testGoal; @Inject @@ -91,7 +93,8 @@ public class TestServiceClient { PromiseProvider promiseProvider, MacroProcessor macroProcessor, CommandConsoleFactory commandConsoleFactory, - ProcessesPanelPresenter processesPanelPresenter) { + ProcessesPanelPresenter processesPanelPresenter, + TestGoal testGoal) { this.appContext = appContext; this.asyncRequestFactory = asyncRequestFactory; this.dtoUnmarshallerFactory = dtoUnmarshallerFactory; @@ -101,6 +104,7 @@ public class TestServiceClient { this.macroProcessor = macroProcessor; this.commandConsoleFactory = commandConsoleFactory; this.processesPanelPresenter = processesPanelPresenter; + this.testGoal = testGoal; } public Promise getOrCreateTestCompileCommand() { @@ -116,7 +120,7 @@ public class TestServiceClient { MatchResult result = mavenCleanBuildPattern.exec(commandLine); if (result != null) { String testCompileCommandLine = mavenCleanBuildPattern.replace(commandLine, "$1mvn test-compile $2"); - return commandManager.create("test-compile", testCompileCommandLine, "mvn", new HashMap()); + return commandManager.createCommand(testGoal.getId(), "mvn", "test-compile", testCompileCommandLine, new HashMap()); } } } diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view/TestResultViewImpl.java b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view/TestResultViewImpl.java index 99adad5d95..fc2d84f889 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view/TestResultViewImpl.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/main/java/org/eclipse/che/plugin/testing/ide/view/TestResultViewImpl.java @@ -19,6 +19,20 @@ import java.util.List; import java.util.Map; import javax.validation.constraints.NotNull; +import com.google.common.base.Optional; +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Style; +import com.google.gwt.event.logical.shared.SelectionEvent; +import com.google.gwt.event.logical.shared.SelectionHandler; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.SplitLayoutPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; +import com.google.inject.Singleton; import org.eclipse.che.api.promises.client.Operation; import org.eclipse.che.api.promises.client.OperationException; @@ -33,7 +47,6 @@ import org.eclipse.che.ide.api.editor.EditorPartPresenter; import org.eclipse.che.ide.api.editor.document.Document; import org.eclipse.che.ide.api.editor.text.TextPosition; import org.eclipse.che.ide.api.editor.texteditor.TextEditor; -import org.eclipse.che.ide.api.event.FileEvent; import org.eclipse.che.ide.api.parts.PartStackUIResources; import org.eclipse.che.ide.api.parts.base.BaseView; import org.eclipse.che.ide.api.resources.File; @@ -81,7 +94,6 @@ public class TestResultViewImpl extends BaseView private final AppContext appContext; private final EditorAgent editorAgent; - private final EventBus eventBus; private final TestResultNodeFactory nodeFactory; private TestResult lastTestResult; private Tree resultTree; @@ -97,15 +109,13 @@ public class TestResultViewImpl extends BaseView FlowPanel navigationPanel; @Inject - public TestResultViewImpl(PartStackUIResources resources, + public TestResultViewImpl(PartStackUIResources resources, EditorAgent editorAgent, AppContext appContext, - EventBus eventBus, TestResultNodeFactory nodeFactory) { super(resources); this.editorAgent = editorAgent; this.appContext = appContext; - this.eventBus = eventBus; this.nodeFactory = nodeFactory; splitLayoutPanel = new SplitLayoutPanel(1); setContentWidget(UI_BINDER.createAndBindUi(this)); @@ -183,7 +193,8 @@ public class TestResultViewImpl extends BaseView @Override public void apply(Optional file) throws OperationException { if (file.isPresent()) { - eventBus.fireEvent(FileEvent.createOpenFileEvent(file.get())); + + editorAgent.openEditor(file.get()); Timer t = new Timer() { @Override public void run() { diff --git a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/TestServiceClientTest.java b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/TestServiceClientTest.java index df472c25b7..3737934f91 100644 --- a/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/TestServiceClientTest.java +++ b/plugins/plugin-testing/che-plugin-testing-ide/src/test/java/org/eclipse/che/plugin/testing/ide/TestServiceClientTest.java @@ -10,25 +10,7 @@ *******************************************************************************/ package org.eclipse.che.plugin.testing.ide; -import static java.util.Arrays.asList; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyMapOf; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import com.google.gwtmockito.GwtMockitoTestRunner; import org.eclipse.che.api.core.model.machine.Command; import org.eclipse.che.api.core.model.machine.Machine; @@ -53,6 +35,7 @@ import org.eclipse.che.ide.api.machine.ExecAgentCommandManager; import org.eclipse.che.ide.api.machine.execagent.ExecAgentPromise; import org.eclipse.che.ide.api.macro.MacroProcessor; import org.eclipse.che.ide.api.notification.StatusNotification; +import org.eclipse.che.ide.command.goal.TestGoal; import org.eclipse.che.ide.dto.DtoFactory; import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandConsoleFactory; import org.eclipse.che.ide.extension.machine.client.outputspanel.console.CommandOutputConsole; @@ -68,7 +51,24 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; -import com.google.gwtmockito.GwtMockitoTestRunner; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.util.Arrays.asList; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyMapOf; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; /** * Test for the TestServiceClient class. @@ -100,6 +100,8 @@ public class TestServiceClientTest implements MockitoPrinter { private ProcessesPanelPresenter processesPanelPresenter; @Mock private DtoFactory dtoFactory; + @Mock + private TestGoal testGoal; @Mock private StatusNotification statusNotification; @@ -129,7 +131,7 @@ public class TestServiceClientTest implements MockitoPrinter { testServiceClient = spy(new TestServiceClient(appContext, asyncRequestFactory, dtoUnmarshallerFactory, dtoFactory, commandManager, execAgentCommandManager, promiseProvider, macroProcessor, commandConsoleFactory, - processesPanelPresenter)); + processesPanelPresenter, testGoal)); doReturn(new PromiseMocker().getPromise()).when(testServiceClient).sendTests(anyString(), anyString(), anyMapOf(String.class, String.class)); @@ -206,6 +208,8 @@ public class TestServiceClientTest implements MockitoPrinter { return execAgentPromise; }); operationsOnProcessEvents.clear(); + + when(testGoal.getId()).thenReturn("Test"); } @SuppressWarnings("unchecked") @@ -232,10 +236,11 @@ public class TestServiceClientTest implements MockitoPrinter { "mvn clean install -f ${current.project.path}", "mvn"))); testServiceClient.getOrCreateTestCompileCommand(); - verify(commandManager).create("test-compile", - "mvn test-compile -f ${current.project.path}", - "mvn", - Collections.emptyMap()); + verify(commandManager).createCommand("Test", + "mvn", + "test-compile", + "mvn test-compile -f ${current.project.path}", + Collections.emptyMap()); } @Test @@ -244,10 +249,11 @@ public class TestServiceClientTest implements MockitoPrinter { "scl enable rh-maven33 'mvn clean install -f ${current.project.path}'", "mvn"))); testServiceClient.getOrCreateTestCompileCommand(); - verify(commandManager).create("test-compile", - "scl enable rh-maven33 'mvn test-compile -f ${current.project.path}'", - "mvn", - Collections.emptyMap()); + verify(commandManager).createCommand("Test", + "mvn", + "test-compile", + "scl enable rh-maven33 'mvn test-compile -f ${current.project.path}'", + Collections.emptyMap()); } @Test diff --git a/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/css/NewCssFileAction.java b/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/css/NewCssFileAction.java index 9efb97ca9d..ceace0f351 100644 --- a/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/css/NewCssFileAction.java +++ b/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/css/NewCssFileAction.java @@ -13,11 +13,13 @@ package org.eclipse.che.ide.ext.web.css; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.ext.web.WebLocalizationConstant; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; @@ -37,10 +39,11 @@ public class NewCssFileAction extends AbstractNewResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.newCssFileActionTitle(), localizationConstant.newCssFileActionDescription(), - null, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + null, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); } @Override diff --git a/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/css/NewLessFileAction.java b/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/css/NewLessFileAction.java index 7442a54925..cf88c7d90d 100644 --- a/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/css/NewLessFileAction.java +++ b/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/css/NewLessFileAction.java @@ -13,11 +13,13 @@ package org.eclipse.che.ide.ext.web.css; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.ext.web.WebLocalizationConstant; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; @@ -37,10 +39,11 @@ public class NewLessFileAction extends AbstractNewResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.newLessFileActionTitle(), localizationConstant.newLessFileActionDescription(), - null, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + null, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); } @Override diff --git a/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/html/NewHtmlFileAction.java b/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/html/NewHtmlFileAction.java index 19a28ff715..9eaadb1f9d 100644 --- a/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/html/NewHtmlFileAction.java +++ b/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/html/NewHtmlFileAction.java @@ -13,11 +13,13 @@ package org.eclipse.che.ide.ext.web.html; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.ext.web.WebLocalizationConstant; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; @@ -45,10 +47,11 @@ public class NewHtmlFileAction extends AbstractNewResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.newHtmlFileActionTitle(), localizationConstant.newHtmlFileActionDescription(), - null, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + null, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); } @Override diff --git a/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/js/NewJavaScriptFileAction.java b/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/js/NewJavaScriptFileAction.java index ce6d3a191f..ec21424421 100644 --- a/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/js/NewJavaScriptFileAction.java +++ b/plugins/plugin-web/che-plugin-web-ext-web/src/main/java/org/eclipse/che/ide/ext/web/js/NewJavaScriptFileAction.java @@ -13,11 +13,13 @@ package org.eclipse.che.ide.ext.web.js; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.ext.web.WebLocalizationConstant; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; import com.google.web.bindery.event.shared.EventBus; @@ -36,10 +38,11 @@ public class NewJavaScriptFileAction extends AbstractNewResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super(localizationConstant.newJavaScriptFileActionTitle(), localizationConstant.newJavaScriptFileActionDescription(), - null, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager); + null, dialogFactory, coreLocalizationConstant, eventBus, appContext, notificationManager, editorAgentProvider); } @Override diff --git a/samples/sample-plugin-actions/che-sample-plugin-actions-ide/src/main/java/org/eclipse/che/plugin/sampleactions/ide/action/NewMyFileAction.java b/samples/sample-plugin-actions/che-sample-plugin-actions-ide/src/main/java/org/eclipse/che/plugin/sampleactions/ide/action/NewMyFileAction.java index 11c3e7ae31..8f177b91be 100644 --- a/samples/sample-plugin-actions/che-sample-plugin-actions-ide/src/main/java/org/eclipse/che/plugin/sampleactions/ide/action/NewMyFileAction.java +++ b/samples/sample-plugin-actions/che-sample-plugin-actions-ide/src/main/java/org/eclipse/che/plugin/sampleactions/ide/action/NewMyFileAction.java @@ -12,10 +12,12 @@ package org.eclipse.che.plugin.sampleactions.ide.action; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import org.eclipse.che.plugin.sampleactions.ide.SampleActionsResources; @@ -34,14 +36,16 @@ public class NewMyFileAction extends AbstractNewResourceAction { CoreLocalizationConstant coreLocalizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super("Create my file", "Create a new file", resources.icon(), dialogFactory, coreLocalizationConstant, eventBus, appContext, - notificationManager); + notificationManager, + editorAgentProvider); } @Override diff --git a/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/src/main/java/org/eclipse/che/plugin/filetype/ide/action/CreateMyFileAction.java b/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/src/main/java/org/eclipse/che/plugin/filetype/ide/action/CreateMyFileAction.java index 6ce80df2fb..e36778384b 100644 --- a/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/src/main/java/org/eclipse/che/plugin/filetype/ide/action/CreateMyFileAction.java +++ b/samples/sample-plugin-filetype/che-sample-plugin-filetype-ide/src/main/java/org/eclipse/che/plugin/filetype/ide/action/CreateMyFileAction.java @@ -11,11 +11,13 @@ package org.eclipse.che.plugin.filetype.ide.action; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.web.bindery.event.shared.EventBus; import org.eclipse.che.ide.CoreLocalizationConstant; import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.dialogs.DialogFactory; +import org.eclipse.che.ide.api.editor.EditorAgent; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.newresource.AbstractNewResourceAction; import org.eclipse.che.plugin.filetype.ide.MyResources; @@ -33,14 +35,16 @@ public class CreateMyFileAction extends AbstractNewResourceAction { CoreLocalizationConstant localizationConstant, EventBus eventBus, AppContext appContext, - NotificationManager notificationManager) { + NotificationManager notificationManager, + Provider editorAgentProvider) { super("Create my File", "Create a new file ", myResources.icon(), dialogFactory, localizationConstant, eventBus, appContext, - notificationManager); + notificationManager, + editorAgentProvider); } @Override diff --git a/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java b/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java index 41dd3d9882..9b1a0ebe59 100644 --- a/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java +++ b/wsagent/che-core-api-project-shared/src/main/java/org/eclipse/che/api/project/shared/Constants.java @@ -34,6 +34,9 @@ public class Constants { public static final String CHE_DIR = ".che"; + public static final String COMMANDS_ATTRIBUTE_NAME = "commands"; + public static final String COMMANDS_ATTRIBUTE_DESCRIPTION = "Project-related commands"; + private Constants() { } } diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectTypes.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectTypes.java index 49230bebcd..c8c81ebf47 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectTypes.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/ProjectTypes.java @@ -111,13 +111,15 @@ public class ProjectTypes { // detect duplicated attributes for (Attribute attr : mixin.getAttributes()) { final String attrName = attr.getName(); - if (attributeDefs.containsKey(attrName)) { + final Attribute attribute = attributeDefs.get(attrName); + if (attribute != null && !attribute.getProjectType().equals(attr.getProjectType())) { this.problems.add(new Problem(ATTRIBUTE_NAME_PROBLEM, format("Attribute name conflict. Duplicated attributes detected for %s. " + "Attribute %s declared in %s already declared in %s. Skipped.", - projectPath, attrName, mixin.getId(), attributeDefs.get(attrName).getProjectType()))); + projectPath, attrName, mixin.getId(), attribute.getProjectType()))); continue; } + attributeDefs.put(attrName, attr); } @@ -190,11 +192,15 @@ public class ProjectTypes { mixins.put(pt.getId(), pt); for (Attribute attr : pt.getAttributes()) { final String attrName = attr.getName(); - if (attributeDefs.containsKey(attrName)) { + final Attribute attribute = attributeDefs.get(attr.getName()); + // If attr from mixin is going to be added but we already have some attribute with the same name, + // check whether it's the same attribute that comes from the common parent PT, e.g. from Base PT. + if (attribute != null && !attribute.getProjectType().equals(attr.getProjectType())) { problems.add(new Problem(ATTRIBUTE_NAME_PROBLEM, format("Attribute name conflict. Duplicated attributes detected for %s. " + "Attribute %s declared in %s already declared in %s. Skipped.", - projectPath, attrName, pt.getId(), attributeDefs.get(attrName).getProjectType()))); + projectPath, attrName, pt.getId(), attribute.getProjectType()))); + continue; } attributeDefs.put(attrName, attr); diff --git a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/BaseProjectType.java b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/BaseProjectType.java index 7a6e3ed947..31d71b797a 100644 --- a/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/BaseProjectType.java +++ b/wsagent/che-core-api-project/src/main/java/org/eclipse/che/api/project/server/type/BaseProjectType.java @@ -12,6 +12,9 @@ package org.eclipse.che.api.project.server.type; import javax.inject.Singleton; +import static org.eclipse.che.api.project.shared.Constants.COMMANDS_ATTRIBUTE_DESCRIPTION; +import static org.eclipse.che.api.project.shared.Constants.COMMANDS_ATTRIBUTE_NAME; + /** * @author gazarenkov */ @@ -22,5 +25,7 @@ public class BaseProjectType extends ProjectTypeDef { public BaseProjectType() { super(ID, "Blank", true, false); + + addVariableDefinition(COMMANDS_ATTRIBUTE_NAME, COMMANDS_ATTRIBUTE_DESCRIPTION, false); } } diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java index 1b981ed873..c0fe2403c8 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/ProjectServiceTest.java @@ -31,6 +31,7 @@ import org.eclipse.che.api.project.server.handlers.ProjectHandlerRegistry; import org.eclipse.che.api.project.server.importer.ProjectImporter; import org.eclipse.che.api.project.server.importer.ProjectImporterRegistry; import org.eclipse.che.api.project.server.type.AttributeValue; +import org.eclipse.che.api.project.server.type.Constant; import org.eclipse.che.api.project.server.type.ProjectTypeConstraintException; import org.eclipse.che.api.project.server.type.ProjectTypeDef; import org.eclipse.che.api.project.server.type.ProjectTypeRegistry; @@ -324,7 +325,9 @@ public class ProjectServiceTest { Map> attr = new HashMap<>(); for (Attribute attribute : myProjectType.getAttributes()) { - attr.put(attribute.getName(), attribute.getValue().getList()); + if (attribute instanceof Constant) { + attr.put(attribute.getName(), attribute.getValue().getList()); + } } when(testProjectConfigMock.getAttributes()).thenReturn(attr); diff --git a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/type/ProjectTypeTest.java b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/type/ProjectTypeTest.java index d00946894a..5fcbfc3434 100644 --- a/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/type/ProjectTypeTest.java +++ b/wsagent/che-core-api-project/src/test/java/org/eclipse/che/api/project/server/type/ProjectTypeTest.java @@ -106,8 +106,10 @@ public class ProjectTypeTest { assertEquals(3, reg.getProjectTypes().size()); assertEquals(1, child.getParents().size()); assertEquals(2, child.getAncestors().size()); - assertEquals(2, reg.getProjectType("child").getAttributes().size()); - assertEquals(1, reg.getProjectType("parent").getAttributes().size()); + assertEquals(2 + reg.getProjectType(BaseProjectType.ID).getAttributes().size(), + reg.getProjectType("child").getAttributes().size()); + assertEquals(1 + reg.getProjectType(BaseProjectType.ID).getAttributes().size(), + reg.getProjectType("parent").getAttributes().size()); Assert.assertTrue(reg.getProjectType("child").isTypeOf("parent")); } @@ -174,7 +176,8 @@ public class ProjectTypeTest { ProjectTypeRegistry reg = new ProjectTypeRegistry(pts); assertEquals(2, child.getParents().size()); - assertEquals(3, reg.getProjectType("child").getAttributes().size()); + assertEquals(3 + reg.getProjectType(BaseProjectType.ID).getAttributes().size(), + reg.getProjectType("child").getAttributes().size()); } @Test diff --git a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java index e682cf5acf..e2a5967b8d 100644 --- a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java +++ b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/Constants.java @@ -46,11 +46,14 @@ public final class Constants { public static final String LINK_REL_GET_WORKSPACE_EVENTS_CHANNEL = "get workspace events channel"; - public static final String WS_AGENT_PROCESS_NAME = "CheWsAgent"; + public static final String WS_AGENT_PROCESS_NAME = "CheWsAgent"; public static final String CHE_WORKSPACE_AUTO_SNAPSHOT = "che.workspace.auto_snapshot"; public static final String CHE_WORKSPACE_AUTO_RESTORE = "che.workspace.auto_restore"; public static final String CHE_WORKSPACE_AUTO_START = "che.workspace.auto_start"; + public static final String COMMAND_PREVIEW_URL_ATTRIBUTE_NAME = "previewUrl"; + public static final String COMMAND_GOAL_ATTRIBUTE_NAME = "goal"; + private Constants() {} }