/******************************************************************************* * 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.events.KeyboardEvent; import elemental.events.MouseEvent; 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.Node; import com.google.gwt.dom.client.NodeList; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.DeckLayoutPanel; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.RequiresResize; 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.commons.annotation.Nullable; import org.eclipse.che.ide.api.parts.PartStackUIResources; import org.eclipse.che.ide.api.parts.base.BaseView; import org.eclipse.che.ide.api.theme.Style; import org.eclipse.che.ide.extension.machine.client.MachineResources; import org.eclipse.che.ide.ui.tree.SelectionModel; import org.eclipse.che.ide.ui.tree.Tree; import org.eclipse.che.ide.ui.tree.TreeNodeElement; import org.eclipse.che.ide.util.input.SignalEvent; import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Implementation of {@link ConsolesPanelView}. * * @author Anna Shumilova * @author Roman Nikitenko */ @Singleton public class ConsolesPanelViewImpl extends BaseView<ConsolesPanelView.ActionDelegate> implements ConsolesPanelView, RequiresResize { @UiField(provided = true) MachineResources machineResources; @UiField(provided = true) Tree<ProcessTreeNode> processTree; @UiField(provided = true) SplitLayoutPanel splitLayoutPanel; @UiField DeckLayoutPanel outputPanel; @UiField FlowPanel navigationPanel; private Map<String, IsWidget> processWidgets; private List<ProcessTreeNode> processNodes; @Inject public ConsolesPanelViewImpl(org.eclipse.che.ide.Resources resources, MachineResources machineResources, PartStackUIResources partStackUIResources, ProcessesViewImplUiBinder uiBinder, ProcessTreeRenderer renderer, ProcessDataAdapter adapter) { super(partStackUIResources); this.machineResources = machineResources; this.processWidgets = new HashMap<>(); this.processNodes = new ArrayList<>(); splitLayoutPanel = new SplitLayoutPanel(1); renderer.setAddTerminalClickHandler(new AddTerminalClickHandler() { @Override public void onAddTerminalClick(@NotNull String machineId) { delegate.onAddTerminal(machineId); } }); renderer.setPreviewSshClickHandler(new PreviewSshClickHandler() { @Override public void onPreviewSshClick(@NotNull String machineId) { delegate.onPreviewSsh(machineId); } }); renderer.setStopProcessHandler(new StopProcessHandler() { @Override public void onStopProcessClick(@NotNull ProcessTreeNode node) { delegate.onStopCommandProcess(node); } @Override public void onCloseProcessOutputClick(@NotNull ProcessTreeNode node) { ProcessTreeNode.ProcessNodeType type = node.getType(); switch (type) { case COMMAND_NODE: delegate.onCloseCommandOutputClick(node); break; case TERMINAL_NODE: delegate.onCloseTerminal(node); break; } } }); processTree = Tree.create(resources, adapter, renderer); processTree.asWidget().addStyleName(this.machineResources.getCss().processTree()); processTree.setTreeEventHandler(new Tree.Listener<ProcessTreeNode>() { @Override public void onNodeAction(TreeNodeElement<ProcessTreeNode> node) { } @Override public void onNodeClosed(TreeNodeElement<ProcessTreeNode> node) { } @Override public void onNodeContextMenu(int mouseX, int mouseY, TreeNodeElement<ProcessTreeNode> node) { } @Override public void onNodeDragStart(TreeNodeElement<ProcessTreeNode> node, MouseEvent event) { } @Override public void onNodeDragDrop(TreeNodeElement<ProcessTreeNode> node, MouseEvent event) { } @Override public void onNodeExpanded(TreeNodeElement<ProcessTreeNode> node) { } @Override public void onNodeSelected(TreeNodeElement<ProcessTreeNode> node, SignalEvent event) { ProcessTreeNode.ProcessNodeType type = node.getData().getType(); switch (type) { case COMMAND_NODE: delegate.onCommandSelected(node.getData().getId()); break; case TERMINAL_NODE: delegate.onTerminalSelected(node.getData().getId()); break; } } @Override public void onRootContextMenu(int mouseX, int mouseY) { } @Override public void onRootDragDrop(MouseEvent event) { } @Override public void onKeyboard(KeyboardEvent event) { } }); setContentWidget(uiBinder.createAndBindUi(this)); navigationPanel.getElement().setTabIndex(0); minimizeButton.ensureDebugId("consoles-minimizeButton"); tuneSplitter(); } /** * Improves splitter visibility. */ private void tuneSplitter() { NodeList<Node> nodes = splitLayoutPanel.getElement().getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.getItem(i); if (node.hasChildNodes()) { com.google.gwt.dom.client.Element el = node.getFirstChild().cast(); if ("gwt-SplitLayoutPanel-HDragger".equals(el.getClassName())) { tuneSplitter(el); return; } } } } /** * Tunes splitter. Makes it wider and adds double border to seem rich. * * @param el * element to tune */ private void tuneSplitter(Element el) { /** Add Z-Index to move the splitter on the top and make content visible */ el.getParentElement().getStyle().setProperty("zIndex", "1000"); el.getParentElement().getStyle().setProperty("overflow", "visible"); /** Tune splitter catch panel */ el.getStyle().setProperty("boxSizing", "border-box"); el.getStyle().setProperty("width", "5px"); el.getStyle().setProperty("overflow", "hidden"); el.getStyle().setProperty("marginLeft", "-3px"); el.getStyle().setProperty("backgroundColor", "transparent"); /** Add small border */ DivElement smallBorder = Document.get().createDivElement(); smallBorder.getStyle().setProperty("position", "absolute"); smallBorder.getStyle().setProperty("width", "1px"); smallBorder.getStyle().setProperty("height", "100%"); smallBorder.getStyle().setProperty("left", "3px"); smallBorder.getStyle().setProperty("top", "0px"); smallBorder.getStyle().setProperty("backgroundColor", Style.getSplitterSmallBorderColor()); el.appendChild(smallBorder); /** Add large border */ DivElement largeBorder = Document.get().createDivElement(); largeBorder.getStyle().setProperty("position", "absolute"); largeBorder.getStyle().setProperty("width", "2px"); largeBorder.getStyle().setProperty("height", "100%"); largeBorder.getStyle().setProperty("left", "1px"); largeBorder.getStyle().setProperty("top", "0px"); largeBorder.getStyle().setProperty("opacity", "0.4"); largeBorder.getStyle().setProperty("backgroundColor", Style.getSplitterLargeBorderColor()); el.appendChild(largeBorder); } @Override protected void focusView() { getElement().focus(); } @Override public void addProcessWidget(String processId, IsWidget widget) { processWidgets.put(processId, widget); outputPanel.add(widget); showProcessOutput(processId); } @Override public void addProcessNode(@NotNull ProcessTreeNode node) { processNodes.add(node); } @Override public void removeProcessNode(@NotNull ProcessTreeNode node) { processNodes.remove(node); } @Override public void setProcessesData(@NotNull ProcessTreeNode root) { processTree.asWidget().setVisible(true); processTree.getModel().setRoot(root); processTree.renderTree(-1); } @Override public void selectNode(@NotNull ProcessTreeNode node) { SelectionModel<ProcessTreeNode> selectionModel = processTree.getSelectionModel(); selectionModel.setTreeActive(true); selectionModel.clearSelections(); selectionModel.selectSingleNode(node); node.getTreeNodeElement().scrollIntoView(); } @Override public void showProcessOutput(String processId) { if (processWidgets.containsKey(processId)) { onResize(); outputPanel.showWidget(processWidgets.get(processId).asWidget()); } } @Override public void hideProcessOutput(String processId) { IsWidget widget = processWidgets.get(processId); outputPanel.remove(widget); processWidgets.remove(processId); } @Override public int getNodeIndex(String processId) { for (ProcessTreeNode node : processNodes) { if (processId.equals(node.getId())) { return processNodes.indexOf(node); } } return -1; } @Override @Nullable public ProcessTreeNode getNodeByIndex(@NotNull int index) { if (index < 0 || index >= processNodes.size()) { return null; } return processNodes.get(index); } @Override @Nullable public ProcessTreeNode getNodeById(@NotNull String nodeId) { for (ProcessTreeNode node : processNodes) { if (nodeId.equals(node.getId())) { return node; } } return null; } @Override public void setStopButtonVisibility(String nodeId, boolean visible) { for (ProcessTreeNode node : processNodes) { if (!nodeId.equals(node.getId())) { continue; } if (visible) { node.getTreeNodeElement().getClassList().remove(machineResources.getCss().hideStopButton()); } else { node.getTreeNodeElement().getClassList().add(machineResources.getCss().hideStopButton()); } } } @Override public void onResize() { for (int i = 0; i < outputPanel.getWidgetCount(); i++) { Widget widget = outputPanel.getWidget(i); if (widget instanceof RequiresResize) { ((RequiresResize)widget).onResize(); } } } interface ProcessesViewImplUiBinder extends UiBinder<Widget, ConsolesPanelViewImpl> { } }