/******************************************************************************* * 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.core.client.Callback; 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.ide.Resources; 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.app.AppContext; import org.eclipse.che.ide.api.command.CommandProducer; import org.eclipse.che.ide.api.component.Component; import org.eclipse.che.ide.api.constraints.Constraints; import org.eclipse.che.ide.api.machine.ActiveRuntime; import org.eclipse.che.ide.api.machine.events.MachineStateEvent; import org.eclipse.che.ide.api.machine.events.WsAgentStateEvent; import org.eclipse.che.ide.api.machine.events.WsAgentStateHandler; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; 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; 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 commands. * <p>Manager gets all registered {@link CommandProducer}s and creates related actions in context menus. * <p>Manager listens all machines's state (running/destroyed) in order to * create/remove actions for the related {@link CommandProducer}s in case * they are applicable only for the certain machine types. * * @author Artem Zatsarynnyi * @see CommandProducer */ @Singleton 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<Machine> machines; private final Set<CommandProducer> commandProducers; private final Map<Action, DefaultActionGroup> actionsToActionGroups; private final Map<Machine, List<Action>> actionsByMachines; private final Map<CommandProducer, DefaultActionGroup> producersToActionGroups; private DefaultActionGroup commandActionsPopUpGroup; @Inject public CommandProducerActionManager(EventBus eventBus, ActionManager actionManager, CommandProducerActionFactory commandProducerActionFactory, AppContext appContext, 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<>(); actionsToActionGroups = new HashMap<>(); actionsByMachines = new HashMap<>(); producersToActionGroups = new HashMap<>(); eventBus.addHandler(MachineStateEvent.TYPE, this); eventBus.addHandler(WsAgentStateEvent.TYPE, this); } @Inject(optional = true) private void start(Set<CommandProducer> commandProducers) { this.commandProducers.addAll(commandProducers); commandActionsPopUpGroup = new DefaultActionGroup(messages.actionCommandsTitle(), true, actionManager); actionManager.registerAction("commandActionsPopUpGroup", commandActionsPopUpGroup); commandActionsPopUpGroup.getTemplatePresentation().setSVGResource(resources.compile()); commandActionsPopUpGroup.getTemplatePresentation().setDescription(messages.actionCommandsDescription()); DefaultActionGroup mainContextMenu = (DefaultActionGroup)actionManager.getAction(GROUP_MAIN_CONTEXT_MENU); mainContextMenu.add(commandActionsPopUpGroup); DefaultActionGroup editorTabContextMenu = (DefaultActionGroup)actionManager.getAction(GROUP_EDITOR_TAB_CONTEXT_MENU); editorTabContextMenu.add(commandActionsPopUpGroup); // add 'Commands' pop-up group to the main toolbar DefaultActionGroup commandActionsToolbarGroup = new CommandActionsToolbarGroup(actionManager); commandActionsToolbarGroup.add(commandActionsPopUpGroup); DefaultActionGroup mainToolbarGroup = (DefaultActionGroup)actionManager.getAction(GROUP_MAIN_TOOLBAR); mainToolbarGroup.add(commandActionsToolbarGroup, new Constraints(AFTER, "changeResourceGroup")); } @Override public void start(final Callback<Component, Exception> callback) { ActiveRuntime activeRuntime = appContext.getActiveRuntime(); if (activeRuntime != null) { machines.addAll(activeRuntime.getMachines()); } callback.onSuccess(this); } @Override public void onMachineCreating(MachineStateEvent event) { } @Override public void onMachineRunning(MachineStateEvent event) { machines.add(event.getMachine()); createActionsForMachine(event.getMachine()); } @Override public void onMachineDestroyed(MachineStateEvent event) { machines.remove(event.getMachine()); removeActionsForMachine(event.getMachine()); } @Override public void onWsAgentStarted(WsAgentStateEvent event) { for (CommandProducer commandProducer : commandProducers) { createActionsForProducer(commandProducer); } } @Override public void onWsAgentStopped(WsAgentStateEvent event) { } /** Creates actions for the given {@link CommandProducer}. */ private void createActionsForProducer(CommandProducer producer) { Action action; if (producer.getMachineTypes().isEmpty()) { action = commandProducerActionFactory.create(producer.getName(), producer, appContext.getDevMachine().getDescriptor()); actionManager.registerAction(producer.getName(), action); } else { action = new DefaultActionGroup(producer.getName(), true, actionManager); producersToActionGroups.put(producer, (DefaultActionGroup)action); actionManager.registerAction(producer.getName(), action); for (Machine machine : machines) { createActionsForMachine(machine); } } commandActionsPopUpGroup.add(action); } /** * Creates actions for that {@link CommandProducer}s * which are applicable for the given machine's type. */ private void createActionsForMachine(Machine machine) { for (CommandProducer commandProducer : commandProducers) { if (commandProducer.getMachineTypes().contains(machine.getConfig().getType())) { CommandProducerAction machineAction = commandProducerActionFactory.create(machine.getConfig().getName(), commandProducer, machine); final List<Action> actionList = actionsByMachines.computeIfAbsent(machine, key -> new ArrayList<>()); actionList.add(machineAction); actionManager.registerAction(machine.getConfig().getName(), machineAction); DefaultActionGroup actionGroup = producersToActionGroups.get(commandProducer); if (actionGroup != null) { actionGroup.add(machineAction); actionsToActionGroups.put(machineAction, actionGroup); } } } } private void removeActionsForMachine(Machine machine) { List<Action> actions = actionsByMachines.remove(machine); if (actions != null) { for (Action action : actions) { DefaultActionGroup actionGroup = actionsToActionGroups.remove(action); if (actionGroup != null) { actionGroup.remove(action); String id = actionManager.getId(action); if (id != null) { actionManager.unregisterAction(id); } } } } } /** * Action group for placing {@link CommandProducerAction}s on the toolbar. * It's visible when at least one {@link CommandProducerAction} exists. */ private class CommandActionsToolbarGroup extends DefaultActionGroup { CommandActionsToolbarGroup(ActionManager actionManager) { super(actionManager); } @Override public void update(ActionEvent e) { e.getPresentation().setEnabledAndVisible(commandActionsPopUpGroup.getChildrenCount() != 0); } } }