/******************************************************************************* * 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.multisplitpanel.panel; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; 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.DeckLayoutPanel; import com.google.gwt.user.client.ui.DockLayoutPanel; 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.assistedinject.Assisted; import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.ide.api.action.Action; import org.eclipse.che.ide.ui.multisplitpanel.SubPanel; import org.eclipse.che.ide.ui.multisplitpanel.WidgetToShow; import org.eclipse.che.ide.ui.multisplitpanel.actions.ClosePaneAction; import org.eclipse.che.ide.ui.multisplitpanel.actions.RemoveAllWidgetsInPaneAction; import org.eclipse.che.ide.ui.multisplitpanel.actions.SplitHorizontallyAction; import org.eclipse.che.ide.ui.multisplitpanel.actions.SplitVerticallyAction; import org.eclipse.che.ide.ui.multisplitpanel.menu.Menu; import org.eclipse.che.ide.ui.multisplitpanel.menu.MenuItem; import org.eclipse.che.ide.ui.multisplitpanel.menu.MenuItemActionWidget; import org.eclipse.che.ide.ui.multisplitpanel.menu.MenuItemWidget; import org.eclipse.che.ide.ui.multisplitpanel.tab.Tab; import org.eclipse.che.ide.ui.multisplitpanel.tab.TabItemFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import static com.google.gwt.user.client.ui.DockLayoutPanel.Direction.CENTER; /** * Implementation of {@link SubPanelView}. * * @author Artem Zatsarynnyi */ public class SubPanelViewImpl extends Composite implements SubPanelView, Menu.ActionDelegate, Tab.ActionDelegate, RequiresResize { private final TabItemFactory tabItemFactory; private final Menu menu; private final Map<Tab, WidgetToShow> tabs2Widgets; private final Map<WidgetToShow, Tab> widgets2Tabs; private final Map<WidgetToShow, MenuItemWidget> widgets2ListItems; private final MenuItem closePaneMenuItem; @UiField(provided = true) SplitLayoutPanel splitLayoutPanel; @UiField DockLayoutPanel mainPanel; @UiField FlowPanel tabsPanel; @UiField DeckLayoutPanel widgetsPanel; private ActionDelegate delegate; private SubPanelView parentPanel; private List<SubPanelView> eastSubPanels; private List<SubPanelView> southSubPanels; @Inject public SubPanelViewImpl(SubPanelViewImplUiBinder uiBinder, TabItemFactory tabItemFactory, Menu menu, @Assisted ClosePaneAction closePaneAction, @Assisted RemoveAllWidgetsInPaneAction removeAllWidgetsInPaneAction, @Assisted SplitHorizontallyAction splitHorizontallyAction, @Assisted SplitVerticallyAction splitVerticallyAction) { this.tabItemFactory = tabItemFactory; this.menu = menu; closePaneMenuItem = new MenuItemActionWidget(closePaneAction); menu.addListItem(closePaneMenuItem); menu.addListItem(new MenuItemActionWidget(removeAllWidgetsInPaneAction)); menu.addListItem(new MenuItemActionWidget(splitHorizontallyAction)); menu.addListItem(new MenuItemActionWidget(splitVerticallyAction)); menu.setDelegate(this); tabs2Widgets = new HashMap<>(); widgets2Tabs = new HashMap<>(); widgets2ListItems = new HashMap<>(); eastSubPanels = new ArrayList<>(); southSubPanels = new ArrayList<>(); splitLayoutPanel = new SplitLayoutPanel(3); initWidget(uiBinder.createAndBindUi(this)); tabsPanel.add(menu); widgetsPanel.ensureDebugId("process-output-panel-holder"); widgetsPanel.addDomHandler(event -> delegate.onWidgetFocused(widgetsPanel.getVisibleWidget()), ClickEvent.getType()); } @Override public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; } @Override public void splitHorizontally(SubPanelView subPanelView) { southSubPanels.add(0, subPanelView); final int height = mainPanel.getOffsetHeight() / 2; splitLayoutPanel.remove(mainPanel); splitLayoutPanel.addSouth(subPanelView, height); splitLayoutPanel.add(mainPanel); onResize(); } @Override public void splitVertically(SubPanelView subPanelView) { eastSubPanels.add(0, subPanelView); final int width = mainPanel.getOffsetWidth() / 2; splitLayoutPanel.remove(mainPanel); splitLayoutPanel.addEast(subPanelView, width); splitLayoutPanel.add(mainPanel); onResize(); } @Override public void addWidget(WidgetToShow widget, boolean removable) { final Tab tab = tabItemFactory.createTabItem(widget.getTitle(), widget.getIcon(), removable); tab.setDelegate(this); tabs2Widgets.put(tab, widget); widgets2Tabs.put(widget, tab); tabsPanel.add(tab); widgetsPanel.setWidget(widget.getWidget()); // add item to drop-down menu final MenuItemWidget listItemWidget = new MenuItemWidget(tab, removable); menu.addListItem(listItemWidget); widgets2ListItems.put(widget, listItemWidget); } @Override public void activateWidget(WidgetToShow widget) { final Tab tab = widgets2Tabs.get(widget); if (tab != null) { selectTab(tab); } widgetsPanel.showWidget(widget.getWidget().asWidget()); // add 'active' attribute for active widget for testing purpose for (WidgetToShow widgetToShow : widgets2Tabs.keySet()) { widgetToShow.getWidget().asWidget().getElement().removeAttribute("active"); } widget.getWidget().asWidget().getElement().setAttribute("active", ""); } @Override public void removeWidget(WidgetToShow widget) { final Tab tab = widgets2Tabs.get(widget); if (tab != null) { closeTab(tab); } } private void closeTab(Tab tab) { final WidgetToShow widget = tabs2Widgets.get(tab); if (widget != null) { delegate.onWidgetRemoving(widget.getWidget(), new SubPanel.RemoveCallback() { @Override public void remove() { removeWidgetFromUI(widget); } }); } } private void removeWidgetFromUI(WidgetToShow widget) { final Tab tab = widgets2Tabs.remove(widget); if (tab != null) { tabsPanel.remove(tab); widgetsPanel.remove(widget.getWidget()); tabs2Widgets.remove(tab); // remove item from drop-down menu final MenuItemWidget listItemWidget = widgets2ListItems.remove(widget); if (listItemWidget != null) { menu.removeListItem(listItemWidget); } } } @Override public void closePanel() { if (parentPanel == null) { // do not allow to close root panel return; } if (splitLayoutPanel.getWidgetCount() == 1 && !isInTheCenterOfTheParent()) { // this panel doesn't have any child sub-panels // so just remove it from it's parent ((SubPanelViewImpl)parentPanel).removeWidgetFromSplitPanel(this); return; } if (isInTheCenterOfTheParent()) { ((SubPanelViewImpl)parentPanel).removeChildSubPanel(this); } else { removeChildSubPanel(mainPanel); } } /** Checks whether this panel is in the central part of it's parent. */ private boolean isInTheCenterOfTheParent() { return ((SubPanelViewImpl)parentPanel).splitLayoutPanel.getWidgetDirection(this) == CENTER; } private void removeChildSubPanel(Widget widget) { removeWidgetFromSplitPanel(widget.asWidget()); IsWidget lastWidget = null; if (!southSubPanels.isEmpty()) { lastWidget = southSubPanels.get(0); } else if (!eastSubPanels.isEmpty()) { lastWidget = eastSubPanels.get(0); } if (lastWidget != null) { removeWidgetFromSplitPanel(lastWidget.asWidget()); splitLayoutPanel.add(lastWidget); } else { ((SubPanelViewImpl)parentPanel).removeWidgetFromSplitPanel(this); } } private void removeWidgetFromSplitPanel(Widget widget) { if (splitLayoutPanel.getWidgetDirection(widget) != CENTER) { // collapse east/south part in order to maximize central part splitLayoutPanel.setWidgetSize(widget, 0); } splitLayoutPanel.remove(widget); southSubPanels.remove(widget); eastSubPanels.remove(widget); } @Override public void setParentPanel(@Nullable SubPanelView parentPanel) { this.parentPanel = parentPanel; if (parentPanel == null) { // do not allow to remove root panel (if it doesn't have parent) menu.removeListItem(closePaneMenuItem); } } @Override public void onMenuItemSelected(MenuItem menuItem) { final Object data = menuItem.getData(); if (data instanceof Tab) { final WidgetToShow widget = tabs2Widgets.get(data); if (widget != null) { activateWidget(widget); delegate.onWidgetFocused(widget.getWidget()); } } else if (data instanceof Action) { ((Action)data).actionPerformed(null); } } @Override public void onMenuItemClosing(MenuItem menuItem) { Object data = menuItem.getData(); if (data instanceof Tab) { closeTab((Tab) data); } } @Override public void onTabClicked(Tab tab) { final WidgetToShow widget = tabs2Widgets.get(tab); if (widget != null) { activateWidget(widget); delegate.onWidgetFocused(widget.getWidget()); } } @Override public void onTabDoubleClicked(Tab tab) { final WidgetToShow widget = tabs2Widgets.get(tab); if (widget != null) { activateWidget(widget); delegate.onWidgetDoubleClicked(widget.getWidget()); } } private void selectTab(Tab tab) { for (Tab tabItem : tabs2Widgets.keySet()) { tabItem.unSelect(); } tab.select(); } @Override public void onTabClosing(Tab tab) { closeTab(tab); } @Override public void onResize() { for (WidgetToShow widgetToShow : widgets2Tabs.keySet()) { if (widgetToShow.getWidget() instanceof RequiresResize) { ((RequiresResize)widgetToShow.getWidget()).onResize(); } } } interface SubPanelViewImplUiBinder extends UiBinder<Widget, SubPanelViewImpl> { } }