blob: 301cceee7e19fbe1fbca016f01be18a22c49fc92 [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.ui.layout.impl;
import com.intellij.execution.ui.layout.*;
import com.intellij.execution.ui.layout.actions.CloseViewAction;
import com.intellij.execution.ui.layout.actions.MinimizeViewAction;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.DimensionService;
import com.intellij.openapi.util.MutualMap;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManager;
import com.intellij.ui.switcher.SwitchTarget;
import com.intellij.ui.tabs.JBTabs;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsListener;
import com.intellij.ui.tabs.UiDecorator;
import com.intellij.ui.tabs.impl.JBTabsImpl;
import com.intellij.util.containers.HashSet;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class GridCellImpl implements GridCell {
private final GridImpl myContainer;
private final MutualMap<Content, TabInfo> myContents = new MutualMap<Content, TabInfo>(true);
private final Set<Content> myMinimizedContents = new HashSet<Content>();
private final JBTabs myTabs;
private final GridImpl.Placeholder myPlaceholder;
private final PlaceInGrid myPlaceInGrid;
private final ViewContextEx myContext;
private JBPopup myPopup;
public GridCellImpl(ViewContextEx context, @NotNull GridImpl container, GridImpl.Placeholder placeholder, PlaceInGrid placeInGrid) {
myContext = context;
myContainer = container;
myPlaceInGrid = placeInGrid;
myPlaceholder = placeholder;
myTabs = new JBTabsImpl(myContext.getProject(), myContext.getActionManager(), myContext.getFocusManager(), container) {
@SuppressWarnings("UseJBColor")
@Override
protected Color getFocusedTopFillColor() {
return UIUtil.isUnderDarcula() ? ColorUtil.toAlpha(new Color(0x1E2533), 100) : new Color(202, 211, 227);
}
@Override
public boolean useSmallLabels() {
return true;
}
@Override
protected void paintBorder(Graphics2D g2d, ShapeInfo shape, Color borderColor) {
if (UIUtil.isUnderDarcula()) {
return;
}
super.paintBorder(g2d, shape, borderColor);
}
@SuppressWarnings("UseJBColor")
@Override
protected Color getFocusedBottomFillColor() {
return UIUtil.isUnderDarcula() ? new Color(0x1E2533) : new Color(0xc2cbdb);
}
@SuppressWarnings("UseJBColor")
@Override
public Color getBackground() {
return UIUtil.isUnderDarcula() ? new Color(0x27292A) : super.getBackground();
}
@Override
public void processDropOver(TabInfo over, RelativePoint point) {
((RunnerContentUi)myContext).myTabs.processDropOver(over, point);
}
@Override
public Image startDropOver(TabInfo tabInfo, RelativePoint point) {
return ((RunnerContentUi)myContext).myTabs.startDropOver(tabInfo, point);
}
@Override
public void resetDropOver(TabInfo tabInfo) {
((RunnerContentUi)myContext).myTabs.resetDropOver(tabInfo);
}
}.setDataProvider(new DataProvider() {
@Override
@Nullable
public Object getData(@NonNls final String dataId) {
if (ViewContext.CONTENT_KEY.is(dataId)) {
TabInfo target = myTabs.getTargetInfo();
if (target != null) {
return new Content[]{getContentFor(target)};
}
}
else if (ViewContext.CONTEXT_KEY.is(dataId)) {
return myContext;
}
return null;
}
});
myTabs.getPresentation().setUiDecorator(new UiDecorator() {
@Override
@NotNull
public UiDecoration getDecoration() {
return new UiDecoration(null, new Insets(1, -1, 1, -1));
}
}).setSideComponentVertical(!context.getLayoutSettings().isToolbarHorizontal())
.setStealthTabMode(true).setFocusCycle(false).setPaintFocus(true)
.setProvideSwitchTargets(false).setTabDraggingEnabled(true).setSideComponentOnTabs(false);
myTabs.addTabMouseListener(new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent e) {
if (UIUtil.isCloseClick(e)) {
// see RunnerContentUi tabMouseListener as well
closeOrMinimize(e);
}
}
});
rebuildPopupGroup();
myTabs.addListener(new TabsListener.Adapter() {
@Override
public void beforeSelectionChanged(TabInfo oldSelection, TabInfo newSelection) {
if (oldSelection != null && myContext.isStateBeingRestored()) {
saveUiState();
}
}
@Override
public void selectionChanged(final TabInfo oldSelection, final TabInfo newSelection) {
updateSelection(myTabs.getComponent().isShowing());
if (!myTabs.getComponent().isShowing()) return;
if (newSelection != null) {
newSelection.stopAlerting();
}
}
});
}
public void rebuildPopupGroup() {
myTabs.setPopupGroup(myContext.getCellPopupGroup(ViewContext.CELL_POPUP_PLACE),
ViewContext.CELL_POPUP_PLACE, true);
}
public PlaceInGrid getPlaceInGrid() {
return myPlaceInGrid;
}
void add(final Content content) {
if (myContents.containsKey(content)) return;
myContents.put(content, null);
revalidateCell(new Runnable() {
@Override
public void run() {
myTabs.addTab(createTabInfoFor(content));
}
});
updateSelection(myTabs.getComponent().getRootPane() != null);
}
void remove(Content content) {
if (!myContents.containsKey(content)) return;
final TabInfo info = getTabFor(content);
myContents.remove(content);
revalidateCell(new Runnable() {
@Override
public void run() {
myTabs.removeTab(info);
}
});
updateSelection(myTabs.getComponent().getRootPane() != null);
}
private void revalidateCell(Runnable contentAction) {
if (myContents.size() == 0) {
myPlaceholder.removeAll();
myTabs.removeAllTabs();
if (myPopup != null) {
myPopup.cancel();
myPopup = null;
}
}
else {
if (myPlaceholder.isNull()) {
myPlaceholder.setContent(myTabs.getComponent());
}
contentAction.run();
}
restoreProportions();
myTabs.getComponent().revalidate();
myTabs.getComponent().repaint();
}
void setHideTabs(boolean hide) {
myTabs.getPresentation().setHideTabs(hide);
}
private TabInfo createTabInfoFor(Content content) {
final TabInfo tabInfo = updatePresentation(new TabInfo(new ProviderWrapper(content, myContext)), content)
.setObject(content)
.setPreferredFocusableComponent(content.getPreferredFocusableComponent())
.setActionsContextComponent(content.getActionsContextComponent());
myContents.remove(content);
myContents.put(content, tabInfo);
ActionGroup group = (ActionGroup)myContext.getActionManager().getAction(RunnerContentUi.VIEW_TOOLBAR);
tabInfo.setTabLabelActions(group, ViewContext.CELL_TOOLBAR_PLACE);
tabInfo.setDragOutDelegate(((RunnerContentUi)myContext).myDragOutDelegate);
return tabInfo;
}
@Nullable
private static TabInfo updatePresentation(TabInfo info, Content content) {
if (info == null) {
return null;
}
return info.
setIcon(content.getIcon()).
setText(content.getDisplayName()).
setTooltipText(content.getDescription()).
setActionsContextComponent(content.getActionsContextComponent()).
setActions(content.getActions(), content.getPlace());
}
public ActionCallback select(final Content content, final boolean requestFocus) {
final TabInfo tabInfo = myContents.getValue(content);
return tabInfo != null ? myTabs.select(tabInfo, requestFocus) : new ActionCallback.Done();
}
public void processAlert(final Content content, final boolean activate) {
if (myMinimizedContents.contains(content)) return;
TabInfo tab = getTabFor(content);
if (tab == null) return;
if (myTabs.getSelectedInfo() != tab) {
if (activate) {
tab.fireAlert();
}
else {
tab.stopAlerting();
}
}
}
public void updateTabPresentation(Content content) {
updatePresentation(myTabs.findInfo(content), content);
}
public boolean isMinimized(Content content) {
return myMinimizedContents.contains(content);
}
public List<SwitchTarget> getTargets(boolean onlyVisible) {
if (myTabs.getPresentation().isHideTabs()) return new ArrayList<SwitchTarget>();
return myTabs.getTargets(onlyVisible, false);
}
public SwitchTarget getTargetForSelection() {
return myTabs.getCurrentTarget();
}
public boolean contains(Component c) {
return myTabs.getComponent().isAncestorOf(c);
}
private static class ProviderWrapper extends NonOpaquePanel implements DataProvider {
Content myContent;
ViewContext myContext;
private ProviderWrapper(final Content content, final ViewContext context) {
myContent = content;
myContext = context;
setLayout(new BorderLayout());
add(content.getComponent(), BorderLayout.CENTER);
}
@Override
@Nullable
public Object getData(@NonNls final String dataId) {
if (ViewContext.CONTENT_KEY.is(dataId)) {
return new Content[]{myContent};
}
else if (ViewContext.CONTEXT_KEY.is(dataId)) {
return myContext;
}
return null;
}
}
@Nullable
TabInfo getTabFor(Content content) {
return myContents.getValue(content);
}
@NotNull
private Content getContentFor(TabInfo tab) {
return myContents.getKey(tab);
}
public void setToolbarHorizontal(final boolean horizontal) {
myTabs.getPresentation().setSideComponentVertical(!horizontal);
}
public ActionCallback restoreLastUiState() {
final ActionCallback result = new ActionCallback();
restoreProportions();
Content[] contents = getContents();
int window = 0;
for (Content each : contents) {
final View view = myContainer.getStateFor(each);
if (view.isMinimizedInGrid()) {
minimize(each);
}
window = view.getWindow();
}
final Tab tab = myContainer.getTab();
final boolean detached = (tab != null && tab.isDetached(myPlaceInGrid)) || window != myContext.getWindow();
if (detached && contents.length > 0) {
if (tab != null) {
tab.setDetached(myPlaceInGrid, false);
}
myContext.detachTo(window, this).notifyWhenDone(result);
}
else {
result.setDone();
}
return result;
}
Content[] getContents() {
return myContents.getKeys().toArray(new Content[myContents.size()]);
}
@Override
public int getContentCount() {
return myContents.size();
}
public void saveUiState() {
saveProportions();
for (Content each : myContents.getKeys()) {
saveState(each, false);
}
for (Content each : myMinimizedContents) {
saveState(each, true);
}
final DimensionService service = DimensionService.getInstance();
final Dimension size = myContext.getContentManager().getComponent().getSize();
service.setSize(getDimensionKey(), size, myContext.getProject());
if (myContext.getWindow() != 0) {
final Window frame = SwingUtilities.getWindowAncestor(myPlaceholder);
if (frame != null) {
service.setLocation(getDimensionKey(), frame.getLocationOnScreen());
}
}
}
public void saveProportions() {
myContainer.saveSplitterProportions(myPlaceInGrid);
}
private void saveState(Content content, boolean minimized) {
View state = myContext.getStateFor(content);
state.setMinimizedInGrid(minimized);
state.setPlaceInGrid(myPlaceInGrid);
state.assignTab(myContainer.getTabIndex());
state.setWindow(myContext.getWindow());
}
public void restoreProportions() {
myContainer.restoreLastSplitterProportions(myPlaceInGrid);
}
public void updateSelection(final boolean isShowing) {
ContentManager contentManager = myContext.getContentManager();
if (contentManager.isDisposed()) return;
for (Content each : myContents.getKeys()) {
final TabInfo eachTab = getTabFor(each);
boolean isSelected = eachTab != null && myTabs.getSelectedInfo() == eachTab;
if (isSelected && isShowing) {
contentManager.addSelectedContent(each);
}
else {
contentManager.removeFromSelection(each);
}
}
for (Content each : myMinimizedContents) {
contentManager.removeFromSelection(each);
}
}
public void minimize(Content[] contents) {
myContext.saveUiState();
for (final Content each : contents) {
myMinimizedContents.add(each);
remove(each);
boolean isShowing = myTabs.getComponent().getRootPane() != null;
updateSelection(isShowing);
myContainer.minimize(each, new CellTransform.Restore() {
@Override
public ActionCallback restoreInGrid() {
return restore(each);
}
});
}
}
@Nullable
public Point getLocation() {
return DimensionService.getInstance().getLocation(getDimensionKey(), myContext.getProject());
}
@Nullable
public Dimension getSize() {
return DimensionService.getInstance().getSize(getDimensionKey(), myContext.getProject());
}
private String getDimensionKey() {
return "GridCell.Tab." + myContainer.getTab().getIndex() + "." + myPlaceInGrid.name();
}
public boolean isValidForCalculateProportions() {
return getContentCount() > 0;
}
@Override
public void minimize(Content content) {
minimize(new Content[]{content});
}
public void closeOrMinimize(MouseEvent e) {
TabInfo tabInfo = myTabs.findInfo(e);
if (tabInfo == null) return;
Content content = getContentFor(tabInfo);
if (CloseViewAction.isEnabled(new Content[]{content})) {
CloseViewAction.perform(myContext, content);
}
else if (MinimizeViewAction.isEnabled(myContext, getContents(), ViewContext.CELL_TOOLBAR_PLACE)) {
minimize(content);
}
}
ActionCallback restore(Content content) {
myMinimizedContents.remove(content);
return new ActionCallback.Done();
}
}