/*
* Copyright 2000-2012 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.ui.tabs.impl;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.ui.laf.JBEditorTabsPainter;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.tabs.JBTabsPosition;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.impl.singleRow.CompressibleSingleRowLayout;
import com.intellij.ui.tabs.impl.singleRow.ScrollableSingleRowLayout;
import com.intellij.ui.tabs.impl.singleRow.SingleRowLayout;
import com.intellij.ui.tabs.impl.table.TableLayout;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.List;
/**
* @author pegov
*/
public class JBEditorTabs extends JBTabsImpl {
private static class PainterUtil {
@NotNull
private static JBEditorTabsPainter createPainter() {
JBEditorTabsPainter painter = PainterUtil.createPainterFromLaf();
if(painter == null) {
painter = PainterUtil.createDefaultPainter();
}
return painter;
}
private static JBEditorTabsPainter createPainterFromLaf() {
String className = UIManager.getString("jbeditor.tabs.painter");
if(className == null) {
return null;
}
return createPainter(className);
}
private static JBEditorTabsPainter createDefaultPainter() {
return createPainter("com.intellij.ide.ui.laf.intellij.DefaultEditorTabsPainter");
}
private static JBEditorTabsPainter createPainter(String clazz) {
try {
Class<?> c = Class.forName(clazz);
return (JBEditorTabsPainter)ReflectionUtil.createInstance(c.getConstructors()[0]);
}
catch (ClassNotFoundException e) {
return null;
}
}
}
public static final String TABS_ALPHABETICAL_KEY = "tabs.alphabetical";
private JBEditorTabsPainter myTabPainter;
public JBEditorTabs(@Nullable Project project, ActionManager actionManager, IdeFocusManager focusManager, @NotNull Disposable parent) {
super(project, actionManager, focusManager, parent);
}
@Override
protected SingleRowLayout createSingleRowLayout() {
if (!UISettings.getInstance().HIDE_TABS_IF_NEED && supportsCompression()) {
return new CompressibleSingleRowLayout(this);
}
else if (ApplicationManager.getApplication().isInternal() || Registry.is("editor.use.scrollable.tabs")) {
return new ScrollableSingleRowLayout(this);
}
return super.createSingleRowLayout();
}
@Override
public void updateUI() {
myTabPainter = null;
super.updateUI();
}
@Override
public boolean supportsCompression() {
return true;
}
@Nullable
public Rectangle getSelectedBounds() {
TabLabel label = getSelectedLabel();
return label != null ? label.getBounds() : null;
}
@Override
public boolean isEditorTabs() {
return true;
}
@Override
protected void paintFirstGhost(Graphics2D g2d) {
}
@Override
protected void paintLastGhost(Graphics2D g2d) {
}
@Override
public boolean isGhostsAlwaysVisible() {
return false;
}
@Override
public boolean useSmallLabels() {
return UISettings.getInstance().USE_SMALL_LABELS_ON_TABS;
}
@Override
public boolean useBoldLabels() {
return SystemInfo.isMac && Registry.is("ide.mac.boldEditorTabs");
}
@Override
public boolean hasUnderline() {
return true;
}
@Override
protected void doPaintInactive(Graphics2D g2d,
boolean leftGhostExists,
TabLabel label,
Rectangle effectiveBounds,
boolean rightGhostExists, int row, int column) {
Insets insets = getTabsBorder().getEffectiveBorder();
int _x = effectiveBounds.x + insets.left;
int _y = effectiveBounds.y + insets.top;
int _width = effectiveBounds.width - insets.left - insets.right + (getTabsPosition() == JBTabsPosition.right ? 1 : 0);
int _height = effectiveBounds.height - insets.top - insets.bottom;
if ((!isSingleRow() /* for multiline */) || (isSingleRow() && isHorizontalTabs())) {
if (isSingleRow() && getPosition() == JBTabsPosition.bottom) {
_y += getActiveTabUnderlineHeight();
} else {
if (isSingleRow()) {
_height -= getActiveTabUnderlineHeight();
} else {
TabInfo info = label.getInfo();
if (((TableLayout)getEffectiveLayout()).isLastRow(info)) {
_height -= getActiveTabUnderlineHeight();
}
}
}
}
final boolean vertical = getTabsPosition() == JBTabsPosition.left || getTabsPosition() == JBTabsPosition.right;
final Color tabColor = label.getInfo().getTabColor();
getPainter().doPaintInactive(g2d, effectiveBounds, _x, _y, _width, _height, tabColor, row, column, vertical);
}
@NotNull
private JBEditorTabsPainter getPainter() {
if(myTabPainter == null) {
myTabPainter = createPainter();
}
return myTabPainter;
}
protected JBEditorTabsPainter createPainter() {
return PainterUtil.createPainter();
}
@Override
public int getActiveTabUnderlineHeight() {
return hasUnderline() ? super.getActiveTabUnderlineHeight() : 1;
}
@Override
public boolean isAlphabeticalMode() {
return Registry.is(TABS_ALPHABETICAL_KEY);
}
public static void setAlphabeticalMode(boolean on) {
Registry.get(TABS_ALPHABETICAL_KEY).setValue(on);
}
@Override
protected void doPaintBackground(Graphics2D g2d, Rectangle clip) {
List<TabInfo> visibleInfos = getVisibleInfos();
final boolean vertical = getTabsPosition() == JBTabsPosition.left || getTabsPosition() == JBTabsPosition.right;
Insets insets = getTabsBorder().getEffectiveBorder();
int maxOffset = 0;
int maxLength = 0;
for (int i = visibleInfos.size() - 1; i >= 0; i--) {
TabInfo visibleInfo = visibleInfos.get(i);
TabLabel tabLabel = myInfo2Label.get(visibleInfo);
Rectangle r = tabLabel.getBounds();
if (r.width == 0 || r.height == 0) continue;
maxOffset = vertical ? r.y + r.height : r.x + r.width;
maxLength = vertical ? r.width : r.height;
break;
}
maxOffset++;
Rectangle r2 = getBounds();
Rectangle rectangle;
if (vertical) {
rectangle = new Rectangle(insets.left, maxOffset, getWidth(),
r2.height - maxOffset - insets.top - insets.bottom);
}
else {
int y = r2.y + insets.top;
int height = maxLength - insets.top - insets.bottom;
if (getTabsPosition() == JBTabsPosition.bottom) {
y = r2.height - height - insets.top + getActiveTabUnderlineHeight();
}
else {
height -= getActiveTabUnderlineHeight();
}
rectangle = new Rectangle(maxOffset, y, r2.width - maxOffset - insets.left - insets.right, height);
}
getPainter().doPaintBackground(g2d, clip, vertical, rectangle);
}
@Override
protected void paintSelectionAndBorder(Graphics2D g2d) {
if (getSelectedInfo() == null || isHideTabs()) return;
TabLabel label = getSelectedLabel();
Rectangle r = label.getBounds();
ShapeInfo selectedShape = _computeSelectedLabelShape();
Insets insets = getTabsBorder().getEffectiveBorder();
Color tabColor = label.getInfo().getTabColor();
final boolean isHorizontalTabs = isHorizontalTabs();
getPainter().paintSelectionAndBorder(g2d, r, selectedShape, insets, tabColor, isHorizontalTabs);
}
@Override
public Color getBackground() {
return getPainter().getBackgroundColor();
}
@Override
public Color getForeground() {
return UIUtil.getLabelForeground();
}
protected ShapeInfo _computeSelectedLabelShape() {
final ShapeInfo shape = new ShapeInfo();
shape.path = getEffectiveLayout().createShapeTransform(getSize());
shape.insets = shape.path.transformInsets(getLayoutInsets());
shape.labelPath = shape.path.createTransform(getSelectedLabel().getBounds());
shape.labelBottomY = shape.labelPath.getMaxY() - shape.labelPath.deltaY(getActiveTabUnderlineHeight() - 1);
shape.labelTopY =
shape.labelPath.getY() + (getPosition() == JBTabsPosition.top || getPosition() == JBTabsPosition.bottom ? shape.labelPath.deltaY(1) : 0) ;
shape.labelLeftX = shape.labelPath.getX() + (getPosition() == JBTabsPosition.top || getPosition() == JBTabsPosition.bottom ? 0 : shape.labelPath.deltaX(
1));
shape.labelRightX = shape.labelPath.getMaxX() - shape.labelPath.deltaX(1);
int leftX = shape.insets.left + (getPosition() == JBTabsPosition.top || getPosition() == JBTabsPosition.bottom ? 0 : shape.labelPath.deltaX(1));
shape.path.moveTo(leftX, shape.labelBottomY);
shape.path.lineTo(shape.labelLeftX, shape.labelBottomY);
shape.path.lineTo(shape.labelLeftX, shape.labelTopY);
shape.path.lineTo(shape.labelRightX, shape.labelTopY);
shape.path.lineTo(shape.labelRightX, shape.labelBottomY);
int lastX = shape.path.getWidth() - shape.path.deltaX(shape.insets.right);
shape.path.lineTo(lastX, shape.labelBottomY);
shape.path.lineTo(lastX, shape.labelBottomY + shape.labelPath.deltaY(getActiveTabUnderlineHeight() - 1));
shape.path.lineTo(leftX, shape.labelBottomY + shape.labelPath.deltaY(getActiveTabUnderlineHeight() - 1));
shape.path.closePath();
shape.fillPath = shape.path.copy();
return shape;
}
}