CHE-5735 Provide consistent "new tab" behaviour (#6156)
* CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour * CHE-5735 Provide consistent "new tab" behaviour6.19.x
parent
1ec08d1cff
commit
dcdab14f73
|
|
@ -875,6 +875,13 @@ public interface Theme {
|
|||
*/
|
||||
String getMainMenuBkgColor();
|
||||
|
||||
/**
|
||||
* Delimiter background color of main menu
|
||||
*
|
||||
* @return the color
|
||||
*/
|
||||
String mainMenuDelimiterBackground();
|
||||
|
||||
/**
|
||||
* Background color of selected menu items
|
||||
*
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@
|
|||
|
||||
/*Main Menu*/
|
||||
@eval mainMenuBkgColor org.eclipse.che.ide.api.theme.Style.getMainMenuBkgColor();
|
||||
@eval mainMenuDelimiterBackground org.eclipse.che.ide.api.theme.Style.theme.mainMenuDelimiterBackground();
|
||||
@eval mainMenuSelectedBkgColor org.eclipse.che.ide.api.theme.Style.getMainMenuSelectedBkgColor();
|
||||
@eval mainMenuSelectedBorderColor org.eclipse.che.ide.api.theme.Style.getMainMenuSelectedBorderColor();
|
||||
@eval mainMenuFontColor org.eclipse.che.ide.api.theme.Style.getMainMenuFontColor();
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ public class ToolbarControllerViewImpl extends Composite implements ToolbarContr
|
|||
* @return element left position
|
||||
*/
|
||||
private native int getAbsoluteLeft(JavaScriptObject element) /*-{
|
||||
return element.getBoundingClientRect().left;
|
||||
}-*/;
|
||||
return element.getBoundingClientRect().left;
|
||||
}-*/;
|
||||
|
||||
/**
|
||||
* Returns absolute top position of the element.
|
||||
|
|
@ -60,8 +60,8 @@ public class ToolbarControllerViewImpl extends Composite implements ToolbarContr
|
|||
* @return element top position
|
||||
*/
|
||||
private native int getAbsoluteTop(JavaScriptObject element) /*-{
|
||||
return element.getBoundingClientRect().top;
|
||||
}-*/;
|
||||
return element.getBoundingClientRect().top;
|
||||
}-*/;
|
||||
|
||||
@Override
|
||||
public void setDelegate(ActionDelegate delegate) {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import org.eclipse.che.ide.editor.synchronization.workingCopy.EditorWorkingCopyS
|
|||
import org.eclipse.che.ide.editor.synchronization.workingCopy.EditorWorkingCopySynchronizerImpl;
|
||||
import org.eclipse.che.ide.editor.texteditor.TextEditorPartViewImpl;
|
||||
import org.eclipse.che.ide.editor.texteditor.infopanel.InfoPanel;
|
||||
import org.eclipse.che.ide.part.editor.AddEditorTabMenuFactory;
|
||||
import org.eclipse.che.ide.part.editor.EditorPartStackView;
|
||||
import org.eclipse.che.ide.part.editor.EditorTabContextMenuFactory;
|
||||
import org.eclipse.che.ide.part.editor.recent.RecentFileActionFactory;
|
||||
|
|
@ -115,6 +116,7 @@ public class EditorApiModule extends AbstractGinModule {
|
|||
install(new GinFactoryModuleBuilder().build(QuickAssistWidgetFactory.class));
|
||||
|
||||
install(new GinFactoryModuleBuilder().build(EditorTabContextMenuFactory.class));
|
||||
install(new GinFactoryModuleBuilder().build(AddEditorTabMenuFactory.class));
|
||||
|
||||
install(new GinFactoryModuleBuilder().build(RecentFileActionFactory.class));
|
||||
bind(RecentFileList.class).to(RecentFileStore.class).in(Singleton.class);
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ import org.eclipse.che.ide.ui.toolbar.PresentationFactory;
|
|||
@Singleton
|
||||
public class ContextMenu implements CloseMenuHandler, ActionSelectedHandler {
|
||||
|
||||
private final ActionManager actionManager;
|
||||
private final KeyBindingAgent keyBindingAgent;
|
||||
private final Provider<PerspectiveManager> managerProvider;
|
||||
protected final ActionManager actionManager;
|
||||
protected final KeyBindingAgent keyBindingAgent;
|
||||
protected final Provider<PerspectiveManager> managerProvider;
|
||||
|
||||
private PopupMenu popupMenu;
|
||||
private MenuLockLayer lockLayer;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2017 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.ide.part.editor;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import org.eclipse.che.ide.api.action.Action;
|
||||
import org.eclipse.che.ide.api.action.ActionGroup;
|
||||
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.keybinding.KeyBindingAgent;
|
||||
import org.eclipse.che.ide.api.parts.PerspectiveManager;
|
||||
import org.eclipse.che.ide.menu.ContextMenu;
|
||||
|
||||
/** Menu appeared after clicking on Add editor tab button. */
|
||||
public class AddEditorTabMenu extends ContextMenu {
|
||||
|
||||
@Inject
|
||||
public AddEditorTabMenu(
|
||||
ActionManager actionManager,
|
||||
KeyBindingAgent keyBindingAgent,
|
||||
Provider<PerspectiveManager> managerProvider) {
|
||||
super(actionManager, keyBindingAgent, managerProvider);
|
||||
}
|
||||
|
||||
protected ActionGroup updateActions() {
|
||||
DefaultActionGroup defaultGroup = new DefaultActionGroup(actionManager);
|
||||
|
||||
final ActionGroup actionGroup =
|
||||
(ActionGroup) actionManager.getAction(IdeActions.GROUP_FILE_NEW);
|
||||
|
||||
for (Action action : actionGroup.getChildren(null)) {
|
||||
defaultGroup.add(action);
|
||||
}
|
||||
|
||||
return defaultGroup;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2017 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.ide.part.editor;
|
||||
|
||||
/** Factory for creating instances of {@link AddEditorTabMenu} */
|
||||
public interface AddEditorTabMenuFactory {
|
||||
|
||||
/**
|
||||
* Creates new Add editor tab menu.
|
||||
*
|
||||
* @return editor tab menu
|
||||
*/
|
||||
AddEditorTabMenu newAddEditorTabMenu();
|
||||
}
|
||||
|
|
@ -84,7 +84,9 @@ public class EditorPartStackPresenter extends PartStackPresenter
|
|||
implements EditorPartStack,
|
||||
EditorTab.ActionDelegate,
|
||||
CloseNonPinnedEditorsHandler,
|
||||
ResourceChangedHandler {
|
||||
ResourceChangedHandler,
|
||||
EditorPartStackView.AddTabButtonClickListener {
|
||||
|
||||
private final PresentationFactory presentationFactory;
|
||||
private final AppContext appContext;
|
||||
private final EditorPaneMenuItemFactory editorPaneMenuItemFactory;
|
||||
|
|
@ -95,6 +97,7 @@ public class EditorPartStackPresenter extends PartStackPresenter
|
|||
private final CloseAllTabsPaneAction closeAllTabsPaneAction;
|
||||
private final EditorAgent editorAgent;
|
||||
private final Map<EditorPaneMenuItem, TabItem> items;
|
||||
private final AddEditorTabMenuFactory addEditorTabMenuFactory;
|
||||
|
||||
//this list need to save order of added parts
|
||||
private final LinkedList<EditorPartPresenter> partsOrder;
|
||||
|
|
@ -121,7 +124,8 @@ public class EditorPartStackPresenter extends PartStackPresenter
|
|||
ActionManager actionManager,
|
||||
ClosePaneAction closePaneAction,
|
||||
CloseAllTabsPaneAction closeAllTabsPaneAction,
|
||||
EditorAgent editorAgent) {
|
||||
EditorAgent editorAgent,
|
||||
AddEditorTabMenuFactory addEditorTabMenuFactory) {
|
||||
super(eventBus, partMenu, partStackEventHandler, tabItemFactory, partsComparator, view, null);
|
||||
this.appContext = appContext;
|
||||
this.editorPaneMenuItemFactory = editorPaneMenuItemFactory;
|
||||
|
|
@ -136,7 +140,9 @@ public class EditorPartStackPresenter extends PartStackPresenter
|
|||
this.items = new HashMap<>();
|
||||
this.partsOrder = new LinkedList<>();
|
||||
this.closedParts = new LinkedList<>();
|
||||
this.addEditorTabMenuFactory = addEditorTabMenuFactory;
|
||||
|
||||
view.setAddTabButtonClickListener(this);
|
||||
initializePaneMenu();
|
||||
view.addPaneMenuButton(editorPaneMenu);
|
||||
}
|
||||
|
|
@ -322,6 +328,18 @@ public class EditorPartStackPresenter extends PartStackPresenter
|
|||
eventBus.fireEvent(new MaximizePartEvent(parts.get(tab)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddTabButtonClicked(final int mouseX, final int mouseY) {
|
||||
Scheduler.get()
|
||||
.scheduleDeferred(
|
||||
new Scheduler.ScheduledCommand() {
|
||||
@Override
|
||||
public void execute() {
|
||||
addEditorTabMenuFactory.newAddEditorTabMenu().show(mouseX, mouseY);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void removePart(PartPresenter part) {
|
||||
|
|
|
|||
|
|
@ -11,16 +11,18 @@
|
|||
package org.eclipse.che.ide.part.editor;
|
||||
|
||||
import static com.google.gwt.dom.client.Style.Display.BLOCK;
|
||||
import static com.google.gwt.dom.client.Style.Display.NONE;
|
||||
import static com.google.gwt.dom.client.Style.Unit.PCT;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
import com.google.gwt.dom.client.Style;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.event.dom.client.MouseDownEvent;
|
||||
import com.google.gwt.event.dom.client.MouseDownHandler;
|
||||
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.AcceptsOneWidget;
|
||||
import com.google.gwt.user.client.ui.DeckLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
|
|
@ -33,6 +35,7 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import org.eclipse.che.ide.FontAwesome;
|
||||
import org.eclipse.che.ide.api.editor.texteditor.TextEditor;
|
||||
import org.eclipse.che.ide.api.parts.PartPresenter;
|
||||
import org.eclipse.che.ide.api.parts.PartStackView;
|
||||
|
|
@ -48,21 +51,42 @@ public class EditorPartStackView extends ResizeComposite
|
|||
|
||||
interface PartStackUiBinder extends UiBinder<Widget, EditorPartStackView> {}
|
||||
|
||||
/** Listener to handle clicking on Add tab button. */
|
||||
interface AddTabButtonClickListener {
|
||||
|
||||
/**
|
||||
* Called when clicking on Add tab button.
|
||||
*
|
||||
* @param mouseX absolute mouse left
|
||||
* @param mouseY absolute mouse top
|
||||
*/
|
||||
void onAddTabButtonClicked(int mouseX, int mouseY);
|
||||
}
|
||||
|
||||
private static final PartStackUiBinder UI_BINDER = GWT.create(PartStackUiBinder.class);
|
||||
|
||||
private static final int POPUP_OFFSET = 15;
|
||||
|
||||
@UiField DockLayoutPanel parent;
|
||||
|
||||
@UiField FlowPanel tabsPanel;
|
||||
|
||||
@UiField FlowPanel plusPanel;
|
||||
|
||||
@UiField DeckLayoutPanel contentPanel;
|
||||
|
||||
@UiField FlowPanel menuPanel;
|
||||
|
||||
private final Map<PartPresenter, TabItem> tabs;
|
||||
private final AcceptsOneWidget partViewContainer;
|
||||
private final LinkedList<PartPresenter> contents;
|
||||
|
||||
private int tabsPanelWidth = 0;
|
||||
|
||||
private ActionDelegate delegate;
|
||||
private EditorPaneMenu editorPaneMenu;
|
||||
private TabItem activeTab;
|
||||
private AddTabButtonClickListener addTabButtonClickListener;
|
||||
|
||||
public EditorPartStackView() {
|
||||
this.tabs = new HashMap<>();
|
||||
|
|
@ -70,6 +94,20 @@ public class EditorPartStackView extends ResizeComposite
|
|||
|
||||
initWidget(UI_BINDER.createAndBindUi(this));
|
||||
|
||||
plusPanel.getElement().setInnerHTML(FontAwesome.PLUS);
|
||||
plusPanel.addDomHandler(
|
||||
new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent clickEvent) {
|
||||
if (addTabButtonClickListener != null) {
|
||||
addTabButtonClickListener.onAddTabButtonClicked(
|
||||
getAbsoluteLeft(plusPanel.getElement()) + POPUP_OFFSET,
|
||||
getAbsoluteTop(plusPanel.getElement()) + POPUP_OFFSET);
|
||||
}
|
||||
}
|
||||
},
|
||||
ClickEvent.getType());
|
||||
|
||||
partViewContainer =
|
||||
new AcceptsOneWidget() {
|
||||
@Override
|
||||
|
|
@ -83,6 +121,30 @@ public class EditorPartStackView extends ResizeComposite
|
|||
setMaximized(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns absolute left position of the element.
|
||||
*
|
||||
* @param element element
|
||||
* @return element left position
|
||||
*/
|
||||
private native int getAbsoluteLeft(JavaScriptObject element) /*-{
|
||||
return element.getBoundingClientRect().left;
|
||||
}-*/;
|
||||
|
||||
/**
|
||||
* Returns absolute top position of the element.
|
||||
*
|
||||
* @param element element
|
||||
* @return element top position
|
||||
*/
|
||||
private native int getAbsoluteTop(JavaScriptObject element) /*-{
|
||||
return element.getBoundingClientRect().top;
|
||||
}-*/;
|
||||
|
||||
public void setAddTabButtonClickListener(AddTabButtonClickListener listener) {
|
||||
addTabButtonClickListener = listener;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected void onAttach() {
|
||||
|
|
@ -124,7 +186,7 @@ public class EditorPartStackView extends ResizeComposite
|
|||
}
|
||||
|
||||
/** Add editor tab to tab panel */
|
||||
tabsPanel.add(tabItem.getView());
|
||||
tabsPanel.insert(tabItem.getView(), tabsPanel.getWidgetIndex(plusPanel));
|
||||
|
||||
/** Process added editor tab */
|
||||
tabs.put(partPresenter, tabItem);
|
||||
|
|
@ -132,30 +194,106 @@ public class EditorPartStackView extends ResizeComposite
|
|||
partPresenter.go(partViewContainer);
|
||||
}
|
||||
|
||||
/** Makes active tab visible. */
|
||||
/** Ensures active tab and plus button are visible. */
|
||||
private void ensureActiveTabVisible() {
|
||||
// do nothing if selected tab is null
|
||||
if (activeTab == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < tabsPanel.getWidgetCount(); i++) {
|
||||
if (editorPaneMenu != null && editorPaneMenu != tabsPanel.getWidget(i)) {
|
||||
tabsPanel.getWidget(i).setVisible(true);
|
||||
}
|
||||
// do nothing if selected tab is visible and plus button is visible
|
||||
if (getAbsoluteTop(activeTab.getView().asWidget().getElement())
|
||||
== getAbsoluteTop(tabsPanel.getElement())
|
||||
&& getAbsoluteTop(plusPanel.getElement()) == getAbsoluteTop(tabsPanel.getElement())
|
||||
&& tabsPanelWidth == tabsPanel.getOffsetWidth()) {
|
||||
return;
|
||||
}
|
||||
|
||||
tabsPanelWidth = tabsPanel.getOffsetWidth();
|
||||
|
||||
// determine whether all widgets are visible
|
||||
boolean allWidgetVisible = true;
|
||||
for (int i = 0; i < tabsPanel.getWidgetCount(); i++) {
|
||||
Widget currentWidget = tabsPanel.getWidget(i);
|
||||
Widget activeTabWidget = activeTab.getView().asWidget();
|
||||
if (editorPaneMenu != null && editorPaneMenu == currentWidget) {
|
||||
Widget w = tabsPanel.getWidget(i);
|
||||
if (plusPanel == w) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (activeTabWidget.getAbsoluteTop() > tabsPanel.getAbsoluteTop()
|
||||
&& activeTabWidget != currentWidget) {
|
||||
currentWidget.setVisible(false);
|
||||
if (!w.isVisible()) {
|
||||
allWidgetVisible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// do nothing if all widgets are visible and sum of children width less then panel width
|
||||
if (allWidgetVisible) {
|
||||
int childrenWidth = 0;
|
||||
for (int i = 0; i < tabsPanel.getWidgetCount(); i++) {
|
||||
Widget w = tabsPanel.getWidget(i);
|
||||
childrenWidth += w.getOffsetWidth();
|
||||
}
|
||||
|
||||
if (childrenWidth < tabsPanelWidth) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// hide all widgets except plus button
|
||||
for (int i = 0; i < tabsPanel.getWidgetCount(); i++) {
|
||||
Widget w = tabsPanel.getWidget(i);
|
||||
if (plusPanel == w) {
|
||||
continue;
|
||||
}
|
||||
|
||||
w.setVisible(false);
|
||||
}
|
||||
|
||||
// determine selected tab index
|
||||
int selectedTabIndex = tabsPanel.getWidgetIndex(activeTab.getView().asWidget());
|
||||
|
||||
// show all possible tabs before selected tab
|
||||
for (int i = selectedTabIndex; i >= 0; i--) {
|
||||
Widget w = tabsPanel.getWidget(i);
|
||||
|
||||
// skip for plus button
|
||||
if (plusPanel == w) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// set tab visible
|
||||
w.setVisible(true);
|
||||
|
||||
// continue cycle if plus button visible
|
||||
if (getAbsoluteTop(plusPanel.getElement()) == getAbsoluteTop(tabsPanel.getElement())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// otherwise hide tab and break
|
||||
w.setVisible(false);
|
||||
break;
|
||||
}
|
||||
|
||||
// show all possible tabs after selected tab
|
||||
for (int i = selectedTabIndex + 1; i < tabsPanel.getWidgetCount(); i++) {
|
||||
Widget w = tabsPanel.getWidget(i);
|
||||
|
||||
// skip for plus button
|
||||
if (plusPanel == w) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// set tab visible
|
||||
w.setVisible(true);
|
||||
|
||||
// continue cycle if plus button visible
|
||||
if (getAbsoluteTop(plusPanel.getElement()) == getAbsoluteTop(tabsPanel.getElement())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// otherwise hide tab and break
|
||||
w.setVisible(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
|
@ -171,11 +309,6 @@ public class EditorPartStackView extends ResizeComposite
|
|||
if (!contents.isEmpty()) {
|
||||
selectTab(contents.getLast());
|
||||
}
|
||||
|
||||
//this hack need to force redraw dom element to apply correct styles
|
||||
tabsPanel.getElement().getStyle().setDisplay(NONE);
|
||||
tabsPanel.getElement().getOffsetHeight();
|
||||
tabsPanel.getElement().getStyle().setDisplay(BLOCK);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
|
@ -221,7 +354,9 @@ public class EditorPartStackView extends ResizeComposite
|
|||
|
||||
delegate.onRequestFocus();
|
||||
|
||||
Scheduler.get().scheduleDeferred(this::ensureActiveTabVisible);
|
||||
// reset timer and schedule it again
|
||||
ensureActiveTabVisibleTimer.cancel();
|
||||
ensureActiveTabVisibleTimer.schedule(200);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
|
@ -260,13 +395,21 @@ public class EditorPartStackView extends ResizeComposite
|
|||
@Override
|
||||
public void onResize() {
|
||||
super.onResize();
|
||||
Scheduler.get()
|
||||
.scheduleDeferred(
|
||||
new Scheduler.ScheduledCommand() {
|
||||
@Override
|
||||
public void execute() {
|
||||
ensureActiveTabVisible();
|
||||
}
|
||||
});
|
||||
|
||||
// reset timer and schedule it again
|
||||
ensureActiveTabVisibleTimer.cancel();
|
||||
ensureActiveTabVisibleTimer.schedule(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer to prevent updating tabs visibility while resizing. It needs to update tabs once when
|
||||
* resizing has stopped.
|
||||
*/
|
||||
private Timer ensureActiveTabVisibleTimer =
|
||||
new Timer() {
|
||||
@Override
|
||||
public void run() {
|
||||
ensureActiveTabVisible();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,25 +14,70 @@
|
|||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
|
||||
xmlns:g="urn:import:com.google.gwt.user.client.ui">
|
||||
|
||||
<ui:style>
|
||||
<ui:style src="org/eclipse/che/ide/api/ui/style.css">
|
||||
|
||||
@eval editorPanelBackgroundColor org.eclipse.che.ide.api.theme.Style.theme.editorPanelBackgroundColor();
|
||||
@eval editorPanelBorderColor org.eclipse.che.ide.api.theme.Style.theme.editorPanelBorderColor();
|
||||
|
||||
.tabsPanel {
|
||||
.topPanel {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
background-color: editorPanelBackgroundColor;
|
||||
border-bottom: 1px solid editorPanelBorderColor;
|
||||
overflow: hidden;
|
||||
background-color: editorPanelBackgroundColor;
|
||||
}
|
||||
|
||||
.tabsPanel {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
height: 23px;
|
||||
left: 0px;
|
||||
right: 34px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tabsPanel > div {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.plusPanel {
|
||||
float: left;
|
||||
width: 23px;
|
||||
height: 23px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
line-height: 23px;
|
||||
text-align: center;
|
||||
font-size: 10px;
|
||||
opacity: 0.6;
|
||||
color: editorTabIconColor;
|
||||
}
|
||||
|
||||
.plusPanel:HOVER {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.menuPanel {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
height: 23px;
|
||||
right: 0px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.menuPanel > div {
|
||||
position: absolute;
|
||||
|
||||
}
|
||||
|
||||
</ui:style>
|
||||
|
||||
<g:DockLayoutPanel ui:field="parent" width="100%" height="100%">
|
||||
<g:north size="23">
|
||||
<g:FlowPanel ui:field="tabsPanel" addStyleNames="{style.tabsPanel}" debugId="editorPartStack-tabsPanel"/>
|
||||
<g:FlowPanel styleName="{style.topPanel}">
|
||||
<g:FlowPanel ui:field="tabsPanel" styleName="{style.tabsPanel}" debugId="multiSplitPanel-tabsPanel">
|
||||
<g:FlowPanel ui:field="plusPanel" styleName="{style.plusPanel}" debugId="plusPanel"></g:FlowPanel>
|
||||
</g:FlowPanel>
|
||||
<g:FlowPanel ui:field="menuPanel" styleName="{style.menuPanel}"></g:FlowPanel>
|
||||
</g:FlowPanel>
|
||||
</g:north>
|
||||
<g:center>
|
||||
<g:DeckLayoutPanel ui:field="contentPanel" debugId="editorPartStack-contentPanel"/>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ 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.processes.actions.AddTabMenuFactory;
|
||||
import org.eclipse.che.ide.processes.actions.ConsoleTreeContextMenuFactory;
|
||||
import org.eclipse.che.ide.processes.panel.ProcessesPanelView;
|
||||
import org.eclipse.che.ide.processes.panel.ProcessesPanelViewImpl;
|
||||
|
|
@ -28,6 +29,7 @@ public class ProcessesGinModule extends AbstractGinModule {
|
|||
protected void configure() {
|
||||
bind(ProcessesPanelView.class).to(ProcessesPanelViewImpl.class).in(Singleton.class);
|
||||
install(new GinFactoryModuleBuilder().build(ConsoleTreeContextMenuFactory.class));
|
||||
install(new GinFactoryModuleBuilder().build(AddTabMenuFactory.class));
|
||||
|
||||
GinMapBinder.newMapBinder(binder(), String.class, ProcessTreeNodeRenderStrategy.class)
|
||||
.addBinding(COMMAND_NODE.getStringValue())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2017 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.ide.processes.actions;
|
||||
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.SERVER_SSH_REFERENCE;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.SERVER_TERMINAL_REFERENCE;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Map;
|
||||
import org.eclipse.che.ide.CoreLocalizationConstant;
|
||||
import org.eclipse.che.ide.FontAwesome;
|
||||
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.DefaultActionGroup;
|
||||
import org.eclipse.che.ide.api.action.IdeActions;
|
||||
import org.eclipse.che.ide.api.action.Separator;
|
||||
import org.eclipse.che.ide.api.app.AppContext;
|
||||
import org.eclipse.che.ide.api.keybinding.KeyBindingAgent;
|
||||
import org.eclipse.che.ide.api.parts.PerspectiveManager;
|
||||
import org.eclipse.che.ide.api.workspace.model.MachineImpl;
|
||||
import org.eclipse.che.ide.machine.MachineResources;
|
||||
import org.eclipse.che.ide.menu.ContextMenu;
|
||||
import org.eclipse.che.ide.processes.panel.ProcessesPanelPresenter;
|
||||
|
||||
/**
|
||||
* Menu for adding new tab in processes panel.
|
||||
*
|
||||
* @author Vitaliy Guliy
|
||||
*/
|
||||
public class AddTabMenu extends ContextMenu {
|
||||
|
||||
private AppContext appContext;
|
||||
|
||||
private ProcessesPanelPresenter processesPanelPresenter;
|
||||
|
||||
private CoreLocalizationConstant coreLocalizationConstant;
|
||||
private MachineResources machineResources;
|
||||
|
||||
@Inject
|
||||
public AddTabMenu(
|
||||
ActionManager actionManager,
|
||||
KeyBindingAgent keyBindingAgent,
|
||||
Provider<PerspectiveManager> managerProvider,
|
||||
AppContext appContext,
|
||||
ProcessesPanelPresenter processesPanelPresenter,
|
||||
CoreLocalizationConstant coreLocalizationConstant,
|
||||
MachineResources machineResources) {
|
||||
super(actionManager, keyBindingAgent, managerProvider);
|
||||
|
||||
this.appContext = appContext;
|
||||
this.processesPanelPresenter = processesPanelPresenter;
|
||||
this.coreLocalizationConstant = coreLocalizationConstant;
|
||||
this.machineResources = machineResources;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected String getGroupMenu() {
|
||||
return IdeActions.GROUP_CONSOLES_TREE_CONTEXT_MENU;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ActionGroup updateActions() {
|
||||
final DefaultActionGroup actionGroup = new DefaultActionGroup(actionManager);
|
||||
|
||||
Map<String, MachineImpl> machines = appContext.getWorkspace().getRuntime().getMachines();
|
||||
for (MachineImpl machine : machines.values()) {
|
||||
Separator separ = new Separator(machine.getName() + ":");
|
||||
actionGroup.add(separ);
|
||||
|
||||
if (machine.getServerByName(SERVER_TERMINAL_REFERENCE).isPresent()) {
|
||||
NewTerminalMenuAction newTerminalMenuAction =
|
||||
new NewTerminalMenuAction(
|
||||
coreLocalizationConstant, machineResources, machine.getName());
|
||||
actionGroup.add(newTerminalMenuAction);
|
||||
}
|
||||
|
||||
if (machine.getServerByName(SERVER_SSH_REFERENCE).isPresent()) {
|
||||
AddSSHMenuAction addSSHMenuAction = new AddSSHMenuAction(machine.getName());
|
||||
actionGroup.add(addSSHMenuAction);
|
||||
}
|
||||
}
|
||||
|
||||
return actionGroup;
|
||||
}
|
||||
|
||||
/** Action to add new Terminal tab. */
|
||||
public class NewTerminalMenuAction extends Action {
|
||||
|
||||
private String machineName;
|
||||
|
||||
public NewTerminalMenuAction(
|
||||
CoreLocalizationConstant locale, MachineResources machineResources, String machineName) {
|
||||
super(
|
||||
locale.newTerminal(),
|
||||
locale.newTerminalDescription(),
|
||||
null,
|
||||
machineResources.addTerminalIcon());
|
||||
this.machineName = machineName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
processesPanelPresenter.onAddTerminal(machineName, this);
|
||||
}
|
||||
}
|
||||
|
||||
/** Action to add new SSH tab. */
|
||||
public class AddSSHMenuAction extends Action {
|
||||
|
||||
private String machineName;
|
||||
|
||||
public AddSSHMenuAction(String machineName) {
|
||||
super("SSH", "SSH", null, null, FontAwesome.RETWEET);
|
||||
this.machineName = machineName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
processesPanelPresenter.onPreviewSsh(machineName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2017 Red Hat, Inc.
|
||||
* 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:
|
||||
* Red Hat, Inc. - initial API and implementation
|
||||
*/
|
||||
package org.eclipse.che.ide.processes.actions;
|
||||
|
||||
/** Factory to create menu for adding new tab */
|
||||
public interface AddTabMenuFactory {
|
||||
|
||||
/**
|
||||
* Creates new menu for adding new tab in processes panel.
|
||||
*
|
||||
* @return menu
|
||||
*/
|
||||
AddTabMenu newAddTabMenu();
|
||||
}
|
||||
|
|
@ -90,6 +90,7 @@ import org.eclipse.che.ide.console.DefaultOutputConsole;
|
|||
import org.eclipse.che.ide.machine.MachineResources;
|
||||
import org.eclipse.che.ide.processes.ProcessTreeNode;
|
||||
import org.eclipse.che.ide.processes.ProcessTreeNodeSelectedEvent;
|
||||
import org.eclipse.che.ide.processes.actions.AddTabMenuFactory;
|
||||
import org.eclipse.che.ide.processes.actions.ConsoleTreeContextMenu;
|
||||
import org.eclipse.che.ide.processes.actions.ConsoleTreeContextMenuFactory;
|
||||
import org.eclipse.che.ide.terminal.TerminalFactory;
|
||||
|
|
@ -136,6 +137,7 @@ public class ProcessesPanelPresenter extends BasePresenter
|
|||
private final CommandConsoleFactory commandConsoleFactory;
|
||||
private final DialogFactory dialogFactory;
|
||||
private final ConsoleTreeContextMenuFactory consoleTreeContextMenuFactory;
|
||||
private final AddTabMenuFactory addTabMenuFactory;
|
||||
private final CommandTypeRegistry commandTypeRegistry;
|
||||
private final ExecAgentCommandManager execAgentCommandManager;
|
||||
private final Provider<MacroProcessor> macroProcessorProvider;
|
||||
|
|
@ -158,6 +160,7 @@ public class ProcessesPanelPresenter extends BasePresenter
|
|||
CommandConsoleFactory commandConsoleFactory,
|
||||
DialogFactory dialogFactory,
|
||||
ConsoleTreeContextMenuFactory consoleTreeContextMenuFactory,
|
||||
AddTabMenuFactory addTabMenuFactory,
|
||||
CommandManager commandManager,
|
||||
CommandTypeRegistry commandTypeRegistry,
|
||||
SshServiceClient sshServiceClient,
|
||||
|
|
@ -175,6 +178,7 @@ public class ProcessesPanelPresenter extends BasePresenter
|
|||
this.commandConsoleFactory = commandConsoleFactory;
|
||||
this.dialogFactory = dialogFactory;
|
||||
this.consoleTreeContextMenuFactory = consoleTreeContextMenuFactory;
|
||||
this.addTabMenuFactory = addTabMenuFactory;
|
||||
this.eventBus = eventBus;
|
||||
this.commandTypeRegistry = commandTypeRegistry;
|
||||
this.execAgentCommandManager = execAgentCommandManager;
|
||||
|
|
@ -1283,6 +1287,18 @@ public class ProcessesPanelPresenter extends BasePresenter
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddTabButtonClicked(final int mouseX, final int mouseY) {
|
||||
Scheduler.get()
|
||||
.scheduleDeferred(
|
||||
new Scheduler.ScheduledCommand() {
|
||||
@Override
|
||||
public void execute() {
|
||||
addTabMenuFactory.newAddTabMenu().show(mouseX, mouseY);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadWorkspaceOutput(DownloadWorkspaceOutputEvent event) {
|
||||
WorkspaceImpl workspace = appContext.getWorkspace();
|
||||
|
|
@ -1324,15 +1340,15 @@ public class ProcessesPanelPresenter extends BasePresenter
|
|||
* @param text file content
|
||||
*/
|
||||
private native void download(String fileName, String text) /*-{
|
||||
var element = $doc.createElement('a');
|
||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||
element.setAttribute('download', fileName);
|
||||
var element = $doc.createElement('a');
|
||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||
element.setAttribute('download', fileName);
|
||||
|
||||
element.style.display = 'none';
|
||||
$doc.body.appendChild(element);
|
||||
element.style.display = 'none';
|
||||
$doc.body.appendChild(element);
|
||||
|
||||
element.click();
|
||||
element.click();
|
||||
|
||||
$doc.body.removeChild(element);
|
||||
}-*/;
|
||||
$doc.body.removeChild(element);
|
||||
}-*/;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,10 +141,16 @@ public interface ProcessesPanelView extends View<ProcessesPanelView.ActionDelega
|
|||
*/
|
||||
void onCloseCommandOutputClick(ProcessTreeNode node);
|
||||
|
||||
/**
|
||||
* Will be called when user is going to close command tab.
|
||||
*
|
||||
* @param node node of process to stop with closing output
|
||||
* @param removeCallback remove callback
|
||||
*/
|
||||
void onCommandTabClosing(ProcessTreeNode node, SubPanel.RemoveCallback removeCallback);
|
||||
|
||||
/**
|
||||
* Is called when user has clicked right mouse button.
|
||||
* Will be called when click right mouse button.
|
||||
*
|
||||
* @param mouseX mouse x coordinate
|
||||
* @param mouseY mouse y coordinate
|
||||
|
|
@ -152,7 +158,15 @@ public interface ProcessesPanelView extends View<ProcessesPanelView.ActionDelega
|
|||
*/
|
||||
void onContextMenu(int mouseX, int mouseY, ProcessTreeNode node);
|
||||
|
||||
/** Is called when user has double clicked on console tab to maximize/restore the console. */
|
||||
/** Will be called when double click on console tab to maximize/restore the console. */
|
||||
void onToggleMaximizeConsole();
|
||||
|
||||
/**
|
||||
* Will be called when click on Add tab button.
|
||||
*
|
||||
* @param mouseX absolute mouse left position
|
||||
* @param mouseY absolute mouse top position
|
||||
*/
|
||||
void onAddTabButtonClicked(int mouseX, int mouseY);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public class ProcessesPanelViewImpl extends BaseView<ProcessesPanelView.ActionDe
|
|||
implements ProcessesPanelView,
|
||||
SubPanel.FocusListener,
|
||||
SubPanel.DoubleClickListener,
|
||||
SubPanel.AddTabButtonClickListener,
|
||||
RequiresResize {
|
||||
|
||||
@UiField(provided = true)
|
||||
|
|
@ -176,6 +177,7 @@ public class ProcessesPanelViewImpl extends BaseView<ProcessesPanelView.ActionDe
|
|||
final SubPanel subPanel = subPanelFactory.newPanel();
|
||||
subPanel.setFocusListener(this);
|
||||
subPanel.setDoubleClickListener(this);
|
||||
subPanel.setAddTabButtonClickListener(this);
|
||||
splitLayoutPanel.add(subPanel.getView());
|
||||
focusedSubPanel = subPanel;
|
||||
|
||||
|
|
@ -505,6 +507,12 @@ public class ProcessesPanelViewImpl extends BaseView<ProcessesPanelView.ActionDe
|
|||
((RequiresResize) widget).onResize();
|
||||
}
|
||||
}
|
||||
|
||||
for (SubPanel panel : widget2Panels.values()) {
|
||||
if (panel.getView() instanceof RequiresResize) {
|
||||
((RequiresResize) panel.getView()).onResize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -513,6 +521,11 @@ public class ProcessesPanelViewImpl extends BaseView<ProcessesPanelView.ActionDe
|
|||
navigationPanelVisible = visible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddTabButtonClicked(int mouseX, int mouseY) {
|
||||
delegate.onAddTabButtonClicked(mouseX, mouseY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProcessesTreeVisible() {
|
||||
return navigationPanelVisible;
|
||||
|
|
|
|||
|
|
@ -722,6 +722,11 @@ public class DarkTheme implements Theme {
|
|||
return this.getMenuBackgroundColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mainMenuDelimiterBackground() {
|
||||
return "#383f53";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMainMenuSelectedBkgColor() {
|
||||
return "#2e3a45";
|
||||
|
|
|
|||
|
|
@ -694,6 +694,11 @@ public class LightTheme implements Theme {
|
|||
return "#cacacc";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mainMenuDelimiterBackground() {
|
||||
return "#ececec";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMainMenuSelectedBkgColor() {
|
||||
return "#ffffff";
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ public class EditorPartStackPresenterTest {
|
|||
@Mock private CloseAllTabsPaneAction closeAllTabsPaneAction;
|
||||
@Mock private EditorPaneMenuItemFactory editorPaneMenuItemFactory;
|
||||
@Mock private EditorAgent editorAgent;
|
||||
@Mock private AddEditorTabMenuFactory addEditorTabMenuFactory;
|
||||
|
||||
//additional mocks
|
||||
@Mock private SplitHorizontallyAction splitHorizontallyAction;
|
||||
|
|
@ -183,7 +184,8 @@ public class EditorPartStackPresenterTest {
|
|||
actionManager,
|
||||
closePaneAction,
|
||||
closeAllTabsPaneAction,
|
||||
editorAgent);
|
||||
editorAgent,
|
||||
addEditorTabMenuFactory);
|
||||
|
||||
when(tabItemFactory.createEditorPartButton(partPresenter1, presenter)).thenReturn(editorTab1);
|
||||
when(tabItemFactory.createEditorPartButton(partPresenter2, presenter)).thenReturn(editorTab2);
|
||||
|
|
|
|||
|
|
@ -14,22 +14,22 @@
|
|||
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||
<ui:style>
|
||||
.innerPanel {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
margin-top: 3px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.innerPanel:active {
|
||||
opacity: 0.4;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.outerPanel {
|
||||
position: relative;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin: 6px 0 6px 3px;
|
||||
position: relative;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin: 6px 0 6px 3px;
|
||||
}
|
||||
</ui:style>
|
||||
|
||||
|
|
|
|||
|
|
@ -78,28 +78,32 @@ public interface SubPanel {
|
|||
*/
|
||||
void setDoubleClickListener(DoubleClickListener listener);
|
||||
|
||||
interface WidgetRemovingListener {
|
||||
/** Set the listener to be notified when Add Tab button has been clicked. */
|
||||
void setAddTabButtonClickListener(AddTabButtonClickListener listener);
|
||||
|
||||
interface WidgetRemovingListener {
|
||||
/** Invoked when a widget is going to be removed. */
|
||||
void onWidgetRemoving(RemoveCallback removeCallback);
|
||||
}
|
||||
|
||||
/** Callback that may be used for actual removing widget. */
|
||||
interface RemoveCallback {
|
||||
|
||||
/** Tells panel to remove widget. */
|
||||
void remove();
|
||||
}
|
||||
|
||||
interface FocusListener {
|
||||
|
||||
/** Invoked when a {@code widget} on a {@code panel} gains the focus. */
|
||||
void focusGained(SubPanel panel, IsWidget widget);
|
||||
}
|
||||
|
||||
interface DoubleClickListener {
|
||||
|
||||
/** Invoked when a {@code widget} on a {@code panel} has been double clicked. */
|
||||
void onDoubleClicked(SubPanel panel, IsWidget widget);
|
||||
}
|
||||
|
||||
interface AddTabButtonClickListener {
|
||||
/** Invoked when `Add Tab` button has been clicked. */
|
||||
void onAddTabButtonClicked(int mouseX, int mouseY);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public class SubPanelPresenter implements SubPanel, SubPanelView.ActionDelegate
|
|||
|
||||
private FocusListener focusListener;
|
||||
private DoubleClickListener doubleClickListener;
|
||||
private AddTabButtonClickListener addTabButtonClickListener;
|
||||
|
||||
@AssistedInject
|
||||
public SubPanelPresenter(
|
||||
|
|
@ -147,6 +148,11 @@ public class SubPanelPresenter implements SubPanel, SubPanelView.ActionDelegate
|
|||
doubleClickListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAddTabButtonClickListener(AddTabButtonClickListener listener) {
|
||||
addTabButtonClickListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWidgetFocused(IsWidget widget) {
|
||||
focusListener.focusGained(this, widget);
|
||||
|
|
@ -164,4 +170,11 @@ public class SubPanelPresenter implements SubPanel, SubPanelView.ActionDelegate
|
|||
listener.onWidgetRemoving(removeCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddTabButtonClicked(int mouseX, int mouseY) {
|
||||
if (addTabButtonClickListener != null) {
|
||||
addTabButtonClickListener.onAddTabButtonClicked(mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,5 +68,8 @@ public interface SubPanelView extends View<SubPanelView.ActionDelegate> {
|
|||
|
||||
/** Called when the {@code widget} is going to be removed from the panel. */
|
||||
void onWidgetRemoving(IsWidget widget, SubPanel.RemoveCallback removeCallback);
|
||||
|
||||
/** Called when the `Add Tab` button has been clicked. */
|
||||
void onAddTabButtonClicked(int mouseX, int mouseY);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,12 @@ package org.eclipse.che.ide.ui.multisplitpanel.panel;
|
|||
|
||||
import static com.google.gwt.user.client.ui.DockLayoutPanel.Direction.CENTER;
|
||||
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
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.Timer;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.DeckLayoutPanel;
|
||||
import com.google.gwt.user.client.ui.DockLayoutPanel;
|
||||
|
|
@ -30,6 +33,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.eclipse.che.commons.annotation.Nullable;
|
||||
import org.eclipse.che.ide.FontAwesome;
|
||||
import org.eclipse.che.ide.api.action.Action;
|
||||
import org.eclipse.che.ide.ui.multisplitpanel.SubPanel;
|
||||
import org.eclipse.che.ide.ui.multisplitpanel.WidgetToShow;
|
||||
|
|
@ -52,6 +56,10 @@ import org.eclipse.che.ide.ui.multisplitpanel.tab.TabItemFactory;
|
|||
public class SubPanelViewImpl extends Composite
|
||||
implements SubPanelView, Menu.ActionDelegate, Tab.ActionDelegate, RequiresResize {
|
||||
|
||||
interface SubPanelViewImplUiBinder extends UiBinder<Widget, SubPanelViewImpl> {}
|
||||
|
||||
private static final int POPUP_OFFSET = 15;
|
||||
|
||||
private final TabItemFactory tabItemFactory;
|
||||
private final Menu menu;
|
||||
private final Map<Tab, WidgetToShow> tabs2Widgets;
|
||||
|
|
@ -66,6 +74,10 @@ public class SubPanelViewImpl extends Composite
|
|||
|
||||
@UiField FlowPanel tabsPanel;
|
||||
|
||||
@UiField FlowPanel plusPanel;
|
||||
|
||||
@UiField FlowPanel menuPanel;
|
||||
|
||||
@UiField DeckLayoutPanel widgetsPanel;
|
||||
|
||||
private ActionDelegate delegate;
|
||||
|
|
@ -73,6 +85,9 @@ public class SubPanelViewImpl extends Composite
|
|||
private List<SubPanelView> eastSubPanels;
|
||||
private List<SubPanelView> southSubPanels;
|
||||
|
||||
private Tab selectedTab;
|
||||
private int tabsPanelWidth = 0;
|
||||
|
||||
@Inject
|
||||
public SubPanelViewImpl(
|
||||
SubPanelViewImplUiBinder uiBinder,
|
||||
|
|
@ -103,13 +118,45 @@ public class SubPanelViewImpl extends Composite
|
|||
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
|
||||
tabsPanel.add(menu);
|
||||
menuPanel.add(menu);
|
||||
|
||||
plusPanel.getElement().setInnerHTML(FontAwesome.PLUS);
|
||||
plusPanel.addDomHandler(
|
||||
new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent clickEvent) {
|
||||
delegate.onAddTabButtonClicked(
|
||||
getAbsoluteLeft(plusPanel.getElement()) + POPUP_OFFSET,
|
||||
getAbsoluteTop(plusPanel.getElement()) + POPUP_OFFSET);
|
||||
}
|
||||
},
|
||||
ClickEvent.getType());
|
||||
|
||||
widgetsPanel.ensureDebugId("process-output-panel-holder");
|
||||
widgetsPanel.addDomHandler(
|
||||
event -> delegate.onWidgetFocused(widgetsPanel.getVisibleWidget()), ClickEvent.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns absolute left position of the element.
|
||||
*
|
||||
* @param element element
|
||||
* @return element left position
|
||||
*/
|
||||
private native int getAbsoluteLeft(JavaScriptObject element) /*-{
|
||||
return element.getBoundingClientRect().left;
|
||||
}-*/;
|
||||
|
||||
/**
|
||||
* Returns absolute top position of the element.
|
||||
*
|
||||
* @param element element
|
||||
* @return element top position
|
||||
*/
|
||||
private native int getAbsoluteTop(JavaScriptObject element) /*-{
|
||||
return element.getBoundingClientRect().top;
|
||||
}-*/;
|
||||
|
||||
@Override
|
||||
public void setDelegate(ActionDelegate delegate) {
|
||||
this.delegate = delegate;
|
||||
|
|
@ -149,7 +196,7 @@ public class SubPanelViewImpl extends Composite
|
|||
tabs2Widgets.put(tab, widget);
|
||||
widgets2Tabs.put(widget, tab);
|
||||
|
||||
tabsPanel.add(tab);
|
||||
tabsPanel.insert(tab, tabsPanel.getWidgetIndex(plusPanel));
|
||||
widgetsPanel.setWidget(widget.getWidget());
|
||||
|
||||
// add item to drop-down menu
|
||||
|
|
@ -325,6 +372,9 @@ public class SubPanelViewImpl extends Composite
|
|||
}
|
||||
|
||||
tab.select();
|
||||
|
||||
selectedTab = tab;
|
||||
ensureActiveTabVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -339,7 +389,96 @@ public class SubPanelViewImpl extends Composite
|
|||
((RequiresResize) widgetToShow.getWidget()).onResize();
|
||||
}
|
||||
}
|
||||
|
||||
// reset timer and schedule it again
|
||||
ensureActiveTabVisibleTimer.cancel();
|
||||
ensureActiveTabVisibleTimer.schedule(200);
|
||||
}
|
||||
|
||||
interface SubPanelViewImplUiBinder extends UiBinder<Widget, SubPanelViewImpl> {}
|
||||
/**
|
||||
* Timer to prevent updating tabs visibility while resizing. It needs to update tabs once when
|
||||
* resizing has stopped.
|
||||
*/
|
||||
private Timer ensureActiveTabVisibleTimer =
|
||||
new Timer() {
|
||||
@Override
|
||||
public void run() {
|
||||
ensureActiveTabVisible();
|
||||
}
|
||||
};
|
||||
|
||||
/** Ensures active tab and plus button are visible */
|
||||
private void ensureActiveTabVisible() {
|
||||
// do nothing if selected tab is null
|
||||
if (selectedTab == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do nothing if selected tab is visible and plus button is visible
|
||||
if (selectedTab.asWidget().getElement().getAbsoluteTop()
|
||||
== tabsPanel.getElement().getAbsoluteTop()
|
||||
&& plusPanel.getElement().getAbsoluteTop() == tabsPanel.getElement().getAbsoluteTop()
|
||||
&& tabsPanelWidth == tabsPanel.getOffsetWidth()) {
|
||||
return;
|
||||
}
|
||||
|
||||
tabsPanelWidth = tabsPanel.getOffsetWidth();
|
||||
|
||||
// hide all widgets except plus button
|
||||
for (int i = 0; i < tabsPanel.getWidgetCount(); i++) {
|
||||
Widget w = tabsPanel.getWidget(i);
|
||||
if (plusPanel == w) {
|
||||
continue;
|
||||
}
|
||||
|
||||
w.setVisible(false);
|
||||
}
|
||||
|
||||
// determine selected tab index
|
||||
int selectedTabIndex = tabsPanel.getWidgetIndex(selectedTab.asWidget());
|
||||
|
||||
// show all possible tabs before selected tab
|
||||
for (int i = selectedTabIndex; i >= 0; i--) {
|
||||
Widget w = tabsPanel.getWidget(i);
|
||||
|
||||
// skip for plus button
|
||||
if (plusPanel == w) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// set tab visible
|
||||
w.setVisible(true);
|
||||
|
||||
// continue cycle if plus button visible
|
||||
if (plusPanel.getElement().getAbsoluteTop() == tabsPanel.getElement().getAbsoluteTop()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// otherwise hide tab and break
|
||||
w.setVisible(false);
|
||||
break;
|
||||
}
|
||||
|
||||
// show all possible tabs after selected tab
|
||||
for (int i = selectedTabIndex + 1; i < tabsPanel.getWidgetCount(); i++) {
|
||||
Widget w = tabsPanel.getWidget(i);
|
||||
|
||||
// skip for plus button
|
||||
if (plusPanel == w) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// set tab visible
|
||||
w.setVisible(true);
|
||||
|
||||
// continue cycle if plus button visible
|
||||
if (plusPanel.getElement().getAbsoluteTop() == tabsPanel.getElement().getAbsoluteTop()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// otherwise hide tab and break
|
||||
w.setVisible(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,17 +14,54 @@
|
|||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
|
||||
xmlns:g="urn:import:com.google.gwt.user.client.ui">
|
||||
|
||||
<ui:style>
|
||||
@eval editorPanelBackgroundColor org.eclipse.che.ide.api.theme.Style.theme.editorPanelBackgroundColor();
|
||||
@eval editorPanelBorderColor org.eclipse.che.ide.api.theme.Style.theme.editorPanelBorderColor();
|
||||
<ui:style src="org/eclipse/che/ide/api/ui/style.css">
|
||||
|
||||
.tabsPanel {
|
||||
.topPanel {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
background-color: editorPanelBackgroundColor;
|
||||
border-bottom: 1px solid editorPanelBorderColor;
|
||||
overflow: hidden;
|
||||
background-color: editorPanelBackgroundColor;
|
||||
}
|
||||
|
||||
.tabsPanel {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
height: 23px;
|
||||
left: 0px;
|
||||
right: 34px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.plusPanel {
|
||||
float: left;
|
||||
width: 23px;
|
||||
height: 23px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
line-height: 23px;
|
||||
text-align: center;
|
||||
font-size: 10px;
|
||||
opacity: 0.6;
|
||||
color: editorTabIconColor;
|
||||
}
|
||||
|
||||
.plusPanel:HOVER {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.menuPanel {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
height: 23px;
|
||||
right: 0px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.menuPanel > div {
|
||||
position: absolute;
|
||||
|
||||
}
|
||||
|
||||
</ui:style>
|
||||
|
|
@ -33,7 +70,12 @@
|
|||
<g:center>
|
||||
<g:DockLayoutPanel ui:field="mainPanel" width="100%" height="100%">
|
||||
<g:north size="23">
|
||||
<g:FlowPanel ui:field="tabsPanel" addStyleNames="{style.tabsPanel}" debugId="multiSplitPanel-tabsPanel"/>
|
||||
<g:FlowPanel styleName="{style.topPanel}">
|
||||
<g:FlowPanel ui:field="tabsPanel" styleName="{style.tabsPanel}" debugId="multiSplitPanel-tabsPanel">
|
||||
<g:FlowPanel ui:field="plusPanel" styleName="{style.plusPanel}" debugId="plusPanel"></g:FlowPanel>
|
||||
</g:FlowPanel>
|
||||
<g:FlowPanel ui:field="menuPanel" styleName="{style.menuPanel}"></g:FlowPanel>
|
||||
</g:FlowPanel>
|
||||
</g:north>
|
||||
<g:center>
|
||||
<g:DeckLayoutPanel ui:field="widgetsPanel"/>
|
||||
|
|
|
|||
|
|
@ -70,13 +70,14 @@
|
|||
}
|
||||
|
||||
.popupMenuTextDelimiter {
|
||||
background: editorPanelBackgroundColor;
|
||||
background: mainMenuDelimiterBackground;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.popupMenuTextDelimiter > div {
|
||||
display: inline-block;
|
||||
line-height: 20px;
|
||||
margin-left: 14px;
|
||||
margin-left: 5px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,11 +60,17 @@ public class FontAwesome {
|
|||
public static final String MINUS = "<i class=\"fa fa-minus-circle\"></i>";
|
||||
|
||||
/** http://fortawesome.github.io/Font-Awesome/icon/plus-circle/ */
|
||||
public static final String PLUS = "<i class=\"fa fa-plus-circle\"></i>";
|
||||
public static final String PLUS_CIRCLE = "<i class=\"fa fa-plus-circle\"></i>";
|
||||
|
||||
/** http://fortawesome.github.io/Font-Awesome/icon/plus/ */
|
||||
public static final String PLUS = "<i class=\"fa fa-plus\"></i>";
|
||||
|
||||
/** http://fortawesome.github.io/Font-Awesome/icon/refresh/ */
|
||||
public static final String REFRESH = "<i class=\"fa fa-refresh\"></i>";
|
||||
|
||||
/** http://fortawesome.github.io/Font-Awesome/icon/retweet/ */
|
||||
public static final String RETWEET = "<i class=\"fa fa-retweet\" aria-hidden=\"true\"></i>";
|
||||
|
||||
/** http://fortawesome.github.io/Font-Awesome/icon/exchange/ */
|
||||
public static final String EXCHANGE = "<i class=\"fa fa-exchange\"></i>";
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,11 @@ public class AddToIndexAction extends GitAction {
|
|||
ProcessesPanelPresenter consolesPanelPresenter,
|
||||
GitServiceClient service,
|
||||
NotificationManager notificationManager) {
|
||||
super(constant.addToIndexTitle(), constant.addToIndexTitle(), FontAwesome.PLUS, appContext);
|
||||
super(
|
||||
constant.addToIndexTitle(),
|
||||
constant.addToIndexTitle(),
|
||||
FontAwesome.PLUS_CIRCLE,
|
||||
appContext);
|
||||
this.presenter = presenter;
|
||||
this.constant = constant;
|
||||
this.gitOutputConsoleFactory = gitOutputConsoleFactory;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public final class ChainExecutor {
|
|||
public void execute(final WorkflowExecutor workflow, final Context context) {
|
||||
if (chainIt.hasNext()) {
|
||||
currentStep = chainIt.next();
|
||||
Log.info(
|
||||
Log.debug(
|
||||
getClass(),
|
||||
"Executing :: " + context.getProject().getName() + " :: => " + currentStep.getClass());
|
||||
currentStep.execute(workflow, context);
|
||||
|
|
|
|||
Loading…
Reference in New Issue