/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.ide.extension.machine.client.processes; import elemental.dom.Element; import elemental.dom.Node; import elemental.events.Event; import elemental.events.EventListener; import elemental.html.SpanElement; import com.google.inject.Inject; import org.eclipse.che.api.machine.shared.dto.MachineDto; import org.eclipse.che.ide.api.parts.PartStackUIResources; import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant; import org.eclipse.che.ide.extension.machine.client.MachineResources; import org.eclipse.che.ide.ui.Tooltip; import static org.eclipse.che.ide.extension.machine.client.processes.ConsolesPanelPresenter.SSH_PORT; import static org.eclipse.che.ide.ui.menu.PositionController.HorizontalAlign.MIDDLE; import static org.eclipse.che.ide.ui.menu.PositionController.VerticalAlign.BOTTOM; import org.eclipse.che.ide.ui.tree.NodeRenderer; import org.eclipse.che.ide.ui.tree.TreeNodeElement; import org.eclipse.che.ide.util.dom.Elements; import org.vectomatic.dom.svg.ui.SVGImage; import org.vectomatic.dom.svg.ui.SVGResource; /** * Renderer for {@ProcessTreeNode} UI presentation. * * @author Anna Shumilova * @author Roman Nikitenko */ public class ProcessTreeRenderer implements NodeRenderer<ProcessTreeNode> { private final MachineResources resources; private final MachineLocalizationConstant locale; private final PartStackUIResources partStackUIResources; private AddTerminalClickHandler addTerminalClickHandler; private PreviewSshClickHandler previewSshClickHandler; private StopProcessHandler stopProcessHandler; @Inject public ProcessTreeRenderer(MachineResources resources, MachineLocalizationConstant locale, PartStackUIResources partStackUIResources) { this.resources = resources; this.locale = locale; this.partStackUIResources = partStackUIResources; } @Override public Element getNodeKeyTextContainer(SpanElement treeNodeLabel) { return (Element)treeNodeLabel.getChildNodes().item(1); } @Override public SpanElement renderNodeContents(ProcessTreeNode node) { ProcessTreeNode.ProcessNodeType type = node.getType(); switch (type) { case MACHINE_NODE: return createMachineElement((MachineDto)node.getData()); case COMMAND_NODE: return createCommandElement(node); case TERMINAL_NODE: return createTerminalElement(node); default: return Elements.createSpanElement(); } } private SpanElement createMachineElement(final MachineDto machine) { SpanElement root = Elements.createSpanElement(); if (machine.isDev()) { SpanElement devLabel = Elements.createSpanElement(resources.getCss().devMachineLabel()); devLabel.setTextContent(locale.viewProcessesDevTitle()); root.appendChild(devLabel); } SpanElement newTerminalButton = Elements.createSpanElement(resources.getCss().processButton()); newTerminalButton.setTextContent("+"); root.appendChild(newTerminalButton); Tooltip.create((elemental.dom.Element)newTerminalButton, BOTTOM, MIDDLE, locale.viewNewTerminalTooltip()); Element statusElement = Elements.createSpanElement(resources.getCss().machineStatus()); root.appendChild(statusElement); Tooltip.create((elemental.dom.Element) statusElement, BOTTOM, MIDDLE, locale.viewMachineRunningTooltip()); if (machine.getMetadata().getServers().containsKey(SSH_PORT)) { SpanElement sshButton = Elements.createSpanElement(resources.getCss().sshButton()); sshButton.setTextContent("SSH"); root.appendChild(sshButton); sshButton.addEventListener(Event.CLICK, new EventListener() { @Override public void handleEvent(Event event) { if (previewSshClickHandler != null) { previewSshClickHandler.onPreviewSshClick(machine.getId()); } } }, true); } newTerminalButton.addEventListener(Event.CLICK, new EventListener() { @Override public void handleEvent(Event event) { event.stopPropagation(); event.preventDefault(); if (addTerminalClickHandler != null) { addTerminalClickHandler.onAddTerminalClick(machine.getId()); } } }, true); /** * This listener cancels mouse events on '+' button and prevents the jitter of the selection in the tree. */ EventListener blockMouseListener = new EventListener() { @Override public void handleEvent(Event event) { event.stopPropagation(); event.preventDefault(); } }; /** * Prevent jitter when pressing mouse on '+' button. */ newTerminalButton.addEventListener(Event.MOUSEDOWN, blockMouseListener, true); newTerminalButton.addEventListener(Event.MOUSEUP, blockMouseListener, true); newTerminalButton.addEventListener(Event.CLICK, blockMouseListener, true); newTerminalButton.addEventListener(Event.DBLCLICK, blockMouseListener, true); Element nameElement = Elements.createSpanElement(resources.getCss().machineLabel()); nameElement.setTextContent(machine.getName()); root.appendChild(nameElement); return root; } private SpanElement createCommandElement(ProcessTreeNode node) { SpanElement root = Elements.createSpanElement(); root.appendChild(createCloseElement(node)); root.appendChild(createStopProcessElement(node)); SVGResource icon = node.getTitleIcon(); if (icon != null) { SpanElement iconElement = Elements.createSpanElement(resources.getCss().processIcon()); iconElement.appendChild((Node)new SVGImage(icon).getElement()); iconElement.setClassName(resources.getCss().processIcon()); root.appendChild(iconElement); } Element nameElement = Elements.createSpanElement(); nameElement.setTextContent(node.getName()); root.appendChild(nameElement); return root; } private SpanElement createTerminalElement(ProcessTreeNode node) { SpanElement root = Elements.createSpanElement(); SVGResource icon = node.getTitleIcon(); if (icon != null) { SpanElement iconElement = Elements.createSpanElement(); iconElement.appendChild((Node)new SVGImage(icon).getElement()); iconElement.setClassName(resources.getCss().processIcon()); root.appendChild(iconElement); } root.appendChild(createCloseElement(node)); Element nameElement = Elements.createSpanElement(); nameElement.setTextContent(node.getName()); root.appendChild(nameElement); return root; } private SpanElement createCloseElement(final ProcessTreeNode node) { SpanElement closeButton = Elements.createSpanElement(resources.getCss().processesPanelCloseButtonForProcess()); SVGImage icon = new SVGImage(partStackUIResources.closeIcon()); closeButton.appendChild((Node) icon.getElement()); Tooltip.create((elemental.dom.Element)closeButton, BOTTOM, MIDDLE, locale.viewCloseProcessOutputTooltip()); closeButton.addEventListener(Event.CLICK, new EventListener() { @Override public void handleEvent(Event event) { if (stopProcessHandler != null) { stopProcessHandler.onCloseProcessOutputClick(node); } } }, true); return closeButton; } private SpanElement createStopProcessElement(final ProcessTreeNode node) { SpanElement stopProcessButton = Elements.createSpanElement(resources.getCss().processesPanelStopButtonForProcess()); Tooltip.create((elemental.dom.Element) stopProcessButton, BOTTOM, MIDDLE, locale.viewStropProcessTooltip()); stopProcessButton.addEventListener(Event.CLICK, new EventListener() { @Override public void handleEvent(Event event) { if (stopProcessHandler != null) { stopProcessHandler.onStopProcessClick(node); } } }, true); return stopProcessButton; } @Override public void updateNodeContents(TreeNodeElement<ProcessTreeNode> treeNode) { } public void setAddTerminalClickHandler(AddTerminalClickHandler addTerminalClickHandler) { this.addTerminalClickHandler = addTerminalClickHandler; } public void setPreviewSshClickHandler(PreviewSshClickHandler previewSshClickHandler) { this.previewSshClickHandler = previewSshClickHandler; } public void setStopProcessHandler(StopProcessHandler stopProcessHandler) { this.stopProcessHandler = stopProcessHandler; } }