Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ekaterina Tuzova
2014-10-13 17:43:12 +04:00
24 changed files with 393 additions and 278 deletions
@@ -187,23 +187,11 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
}
if (rearrangeEntries && file != null && editor != null) {
final ArrangementEngine engine = ServiceManager.getService(project, ArrangementEngine.class);
try {
final PsiFile finalFile = file;
SelectionModel selectionModel = editor.getSelectionModel();
final TextRange rangeToUse = selectionModel.hasSelection()
? TextRange.create(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd())
: TextRange.create(0, editor.getDocument().getTextLength());
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
@Override
public void run() {
engine.arrange(editor, finalFile, Collections.singleton(rangeToUse));
}
}, getTemplatePresentation().getText(), null);
}
finally {
PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument());
}
SelectionModel selectionModel = editor.getSelectionModel();
final TextRange rangeToUse = selectionModel.hasSelection()
? TextRange.create(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd())
: TextRange.create(0, editor.getDocument().getTextLength());
new RearrangeCodeProcessor(project, file, Collections.singleton(rangeToUse)).run();
}
}
@@ -24,7 +24,6 @@ import com.intellij.ui.ColorUtil;
import com.intellij.ui.Gray;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsUtil;
import com.intellij.ui.tabs.UiDecorator;
import com.intellij.ui.tabs.impl.JBTabsImpl;
import com.intellij.ui.tabs.impl.TabLabel;
@@ -75,7 +74,7 @@ public class
int _y = effectiveBounds.y + insets.top + 3;
int _width = effectiveBounds.width - insets.left - insets.right;
int _height = effectiveBounds.height - insets.top - insets.bottom - 3;
_height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
_height -= getActiveTabUnderlineHeight();
if (dark) {
g2d.setPaint(UIUtil.getGradientPaint(_x, _y, ColorUtil.shift(UIUtil.getListBackground(), 1.3), _x, _y + effectiveBounds.height, UIUtil.getPanelBackground()));
g2d.fillRect(_x, _y, _width, _height);
@@ -122,7 +121,7 @@ public class
Rectangle rectangle;
int y = r2.y + insets.top;
int height = maxLength - insets.top - insets.bottom;
height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
height -= getActiveTabUnderlineHeight();
rectangle = new Rectangle(maxOffset, y, r2.width - maxOffset - insets.left - insets.right, height);
@@ -194,7 +193,7 @@ public class
shape.insets = shape.path.transformInsets(getLayoutInsets());
shape.labelPath = shape.path.createTransform(r);
shape.labelBottomY = shape.labelPath.getMaxY() - shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1);
shape.labelBottomY = shape.labelPath.getMaxY() - shape.labelPath.deltaY(getActiveTabUnderlineHeight() - 1);
shape.labelTopY = shape.labelPath.getY() + shape.labelPath.deltaY(1);
shape.labelLeftX = shape.labelPath.getX();
shape.labelRightX = shape.labelPath.getMaxX() - shape.labelPath.deltaX(1);
@@ -210,8 +209,8 @@ public class
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(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
shape.path.lineTo(leftX, shape.labelBottomY + shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
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();
@@ -298,7 +297,7 @@ public class
@Override
public Dimension getPreferredSize() {
Dimension result = super.getPreferredSize();
result.height += TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
result.height += myTabs.getActiveTabUnderlineHeight();
return result;
}
}
@@ -47,6 +47,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.util.containers.WeakList;
import com.intellij.util.ui.ButtonlessScrollBarUI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -825,7 +826,7 @@ public class EditorWindowImpl extends UserDataHolderBase implements EditorWindow
}
@Override
public void registerScrollBarRepaintCallback(@Nullable RepaintCallback callback) {
public void registerScrollBarRepaintCallback(@Nullable ButtonlessScrollBarUI.ScrollbarRepaintCallback callback) {
myDelegate.registerScrollBarRepaintCallback(callback);
}
@@ -71,7 +71,6 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Convertor;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import com.intellij.xml.util.XmlStringUtil;
import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -733,6 +732,22 @@ public class SingleInspectionProfilePanel extends JPanel {
TreeUtil.sort(myRoot, new InspectionsConfigTreeComparator());
}
private boolean readHTML(String text) {
try {
myBrowser.read(new StringReader(text), null);
return true;
}
catch (IOException ignored) {
return false;
}
}
private String toHTML(String text) {
final HintHint hintHint = new HintHint(myBrowser, new Point(0, 0));
hintHint.setFont(UIUtil.getLabelFont());
return HintUtil.prepareHintText(text, hintHint);
}
private void updateOptionsAndDescriptionPanel(final TreePath... paths) {
if (mySelectedProfile == null || paths == null || paths.length == 0) {
return;
@@ -748,18 +763,8 @@ public class SingleInspectionProfilePanel extends JPanel {
final Descriptor defaultDescriptor = singleNode.getDefaultDescriptor();
final String description = defaultDescriptor.loadDescription();
try {
final HintHint hintHint = new HintHint(myBrowser, new Point(0, 0));
hintHint.setFont(myBrowser.getFont());
myBrowser
.read(new StringReader(SearchUtil.markup(HintUtil.prepareHintText(description, hintHint), myProfileFilter.getFilter())), null);
}
catch (IOException e2) {
try {
//noinspection HardCodedStringLiteral
myBrowser.read(new StringReader(XmlStringUtil.wrapInHtml("<b>" + UNDER_CONSTRUCTION + "</b>")), null);
}
catch (IOException e1) {
//Can't be
if (!readHTML(SearchUtil.markup(toHTML(description), myProfileFilter.getFilter()))) {
readHTML(toHTML("<b>" + UNDER_CONSTRUCTION + "</b>"));
}
}
catch (Throwable t) {
@@ -771,12 +776,7 @@ public class SingleInspectionProfilePanel extends JPanel {
}
else {
try {
myBrowser.read(new StringReader("<html><body>Multiple inspections are selected. You can edit them as a single inspection.</body></html>"), null);
}
catch (IOException e1) {
//Can't be
}
readHTML(toHTML("Multiple inspections are selected. You can edit them as a single inspection."));
}
myOptionsPanel.removeAll();
@@ -952,12 +952,7 @@ public class SingleInspectionProfilePanel extends JPanel {
private void initOptionsAndDescriptionPanel() {
myOptionsPanel.removeAll();
try {
myBrowser.read(new StringReader(EMPTY_HTML), null);
}
catch (IOException e1) {
//Can't be
}
readHTML(EMPTY_HTML);
myOptionsPanel.validate();
myOptionsPanel.repaint();
}
@@ -96,16 +96,30 @@ public class TableScrollingUtil {
}
private static int getLeadingRow(JTable table,Rectangle visibleRect) {
Point leadingPoint;
return table.rowAtPoint(getLeadingPoint(table, visibleRect));
}
private static Point getLeadingPoint(JTable table, Rectangle visibleRect) {
if (table.getComponentOrientation().isLeftToRight()) {
return new Point(visibleRect.x, visibleRect.y);
}
else {
return new Point(visibleRect.x + visibleRect.width,
visibleRect.y);
}
}
public static int getReadableRow(JTable table, int maximumHiddenPart) {
Rectangle visibleRect = table.getVisibleRect();
Point leadingPoint = getLeadingPoint(table, visibleRect);
int row = table.rowAtPoint(leadingPoint);
int column = table.columnAtPoint(leadingPoint);
if (leadingPoint.y - table.getCellRect(row, column, true).getY() <= maximumHiddenPart) {
return row;
} else {
return Math.min(row + 1, table.getRowCount() - 1); // just in case
}
if (table.getComponentOrientation().isLeftToRight()) {
leadingPoint = new Point(visibleRect.x, visibleRect.y);
}
else {
leadingPoint = new Point(visibleRect.x + visibleRect.width,
visibleRect.y);
}
return table.rowAtPoint(leadingPoint);
}
private static int getTrailingRow(JTable table,Rectangle visibleRect) {
@@ -26,7 +26,6 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.tabs.JBTabsPosition;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsUtil;
import com.intellij.ui.tabs.impl.singleRow.ScrollableSingleRowLayout;
import com.intellij.ui.tabs.impl.singleRow.SingleRowLayout;
import com.intellij.ui.tabs.impl.table.TableLayout;
@@ -98,9 +97,11 @@ public class JBEditorTabs extends JBTabsImpl {
@Override
public boolean hasUnderline() {
return true;
return isSingleRow();
}
protected void doPaintInactive(Graphics2D g2d,
boolean leftGhostExists,
TabLabel label,
@@ -116,14 +117,14 @@ public class JBEditorTabs extends JBTabsImpl {
if ((!isSingleRow() /* for multiline */) || (isSingleRow() && isHorizontalTabs())) {
if (isSingleRow() && getPosition() == JBTabsPosition.bottom) {
_y += TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
_y += getActiveTabUnderlineHeight();
} else {
if (isSingleRow()) {
_height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
_height -= getActiveTabUnderlineHeight();
} else {
TabInfo info = label.getInfo();
if (((TableLayout)getEffectiveLayout()).isLastRow(info)) {
_height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
_height -= getActiveTabUnderlineHeight();
}
}
}
@@ -131,7 +132,19 @@ public class JBEditorTabs extends JBTabsImpl {
final boolean vertical = getTabsPosition() == JBTabsPosition.left || getTabsPosition() == JBTabsPosition.right;
final Color tabColor = label.getInfo().getTabColor();
final Composite oldComposite = g2d.getComposite();
//if (label != getSelectedLabel()) {
// g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.9f));
//}
getPainter().doPaintInactive(g2d, effectiveBounds, _x, _y, _width, _height, tabColor, row, column, vertical);
//g2d.setComposite(oldComposite);
}
@Override
public int getActiveTabUnderlineHeight() {
return hasUnderline() ? super.getActiveTabUnderlineHeight() : 1;
}
JBEditorTabsPainter getPainter() {
@@ -186,9 +199,9 @@ public class JBEditorTabs extends JBTabsImpl {
int y = r2.y + insets.top;
int height = maxLength - insets.top - insets.bottom;
if (getTabsPosition() == JBTabsPosition.bottom) {
y = r2.height - height - insets.top + TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
y = r2.height - height - insets.top + getActiveTabUnderlineHeight();
} else {
height -= TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
height -= getActiveTabUnderlineHeight();
}
rectangle = new Rectangle(maxOffset, y, r2.width - maxOffset - insets.left - insets.right, height);
@@ -229,7 +242,7 @@ public class JBEditorTabs extends JBTabsImpl {
shape.insets = shape.path.transformInsets(getLayoutInsets());
shape.labelPath = shape.path.createTransform(getSelectedLabel().getBounds());
shape.labelBottomY = shape.labelPath.getMaxY() - shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1);
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(
@@ -247,8 +260,8 @@ public class JBEditorTabs extends JBTabsImpl {
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(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
shape.path.lineTo(leftX, shape.labelBottomY + shape.labelPath.deltaY(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1));
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();
@@ -345,6 +345,10 @@ public class JBTabsImpl extends JComponent
return this;
}
public int getActiveTabUnderlineHeight() {
return TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT;
}
public boolean isEditorTabs() {
return false;
}
@@ -53,7 +53,7 @@ public class TabLabel extends JPanel {
private boolean myCentered;
private final Wrapper myLabelPlaceholder = new Wrapper(false);
private final JBTabsImpl myTabs;
protected final JBTabsImpl myTabs;
private BufferedImage myInactiveStateImage;
private Rectangle myLastPaintedInactiveImageBounds;
@@ -241,7 +241,12 @@ public class TabLabel extends JPanel {
}
});
final Composite oldComposite = ((Graphics2D)g).getComposite();
if (myTabs instanceof JBEditorTabs && !myTabs.isSingleRow() && myTabs.getSelectedInfo() != myInfo) {
((Graphics2D)g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f));
}
super.paint(g);
((Graphics2D)g).setComposite(oldComposite);
doTranslate(new PairConsumer<Integer, Integer>() {
@Override
@@ -253,7 +258,7 @@ public class TabLabel extends JPanel {
protected int getNonSelectedOffset() {
if (myTabs.isEditorTabs() && (myTabs.isSingleRow() || ((TableLayout)myTabs.getEffectiveLayout()).isLastRow(getInfo()))) {
return -TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT / 2 + 1;
return -myTabs.getActiveTabUnderlineHeight() / 2 + 1;
}
return 1;
}
@@ -275,7 +280,7 @@ public class TabLabel extends JPanel {
switch (pos) {
case top:
case bottom:
if (myTabs.hasUnderline()) size.height += TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT - 1;
if (myTabs.hasUnderline()) size.height += myTabs.getActiveTabUnderlineHeight() - 1;
break;
case left:
case right:
@@ -18,7 +18,6 @@ package com.intellij.ui.tabs.impl.singleRow;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.tabs.JBTabsPosition;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsUtil;
import com.intellij.ui.tabs.impl.*;
import org.jetbrains.annotations.Nullable;
@@ -50,8 +49,8 @@ public class SingleRowLayout extends TabLayout {
protected int getIconY(Rectangle iconRec) {
final int shift;
switch (myTabs.getTabsPosition()) {
case bottom: shift = TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT; break;
case top: shift = -(TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT / 2); break;
case bottom: shift = myTabs.getActiveTabUnderlineHeight(); break;
case top: shift = -(myTabs.getActiveTabUnderlineHeight() / 2); break;
default: shift = 0;
}
return super.getIconY(iconRec) + shift;
@@ -16,7 +16,6 @@
package com.intellij.ui.tabs.impl.table;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.TabsUtil;
import com.intellij.ui.tabs.impl.JBTabsImpl;
import com.intellij.ui.tabs.impl.LayoutPassInfo;
import com.intellij.ui.tabs.impl.TabLabel;
@@ -103,10 +102,10 @@ public class TableLayout extends TabLayout {
toMove.add(data.table.get(i));
}
for (TableRow eachMove : toMove) {
data.table.remove(eachMove);
data.table.add(0, eachMove);
}
//for (TableRow eachMove : toMove) {
// data.table.remove(eachMove);
// data.table.add(0, eachMove);
//}
return data;
@@ -131,7 +130,7 @@ public class TableLayout extends TabLayout {
int eachY = insets.top;
int eachX;
int row = 0;
final int tabUnderlineFix = myTabs.isEditorTabs() ? TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT : 0;
final int tabUnderlineFix = myTabs.isEditorTabs() ? myTabs.getActiveTabUnderlineHeight() : 0;
for (TableRow eachRow : data.table) {
eachX = insets.left;
@@ -91,7 +91,8 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
private Animator myMacScrollbarFadeAnimator;
private double myMacScrollbarFadeLevel = 0;
private boolean myMacScrollbarHidden;
private ScrollbarRepaintCallback myRepaintCallback;
protected ButtonlessScrollBarUI() {
myAdjustmentListener = new AdjustmentListener() {
@@ -264,6 +265,43 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
}
}
/**
* This is overridden only to increase the invalid area.
* This ensures that whole track will be repainted in case of installed callback
*/
@Override
protected void setThumbBounds(int x, int y, int width, int height) {
if (myRepaintCallback == null) {
super.setThumbBounds(x, y, width, height);
}
else {
/* If the thumbs bounds haven't changed, we're done.
*/
if ((thumbRect.x == x) &&
(thumbRect.y == y) &&
(thumbRect.width == width) &&
(thumbRect.height == height)) {
return;
}
/* Update thumbRect, and repaint the union of x,y,w,h and
* the old thumbRect.
*/
int minX = Math.min(x, trackRect.x);
int minY = Math.min(y, trackRect.y);
int maxX = Math.max(x + width, trackRect.x + trackRect.width);
int maxY = Math.max(y + height, trackRect.y + trackRect.height);
thumbRect.setBounds(x, y, width, height);
scrollbar.repaint(minX, minY, maxX - minX, maxY - minY);
// Once there is API to determine the mouse location this will need
// to be changed.
setThumbRollover(false);
}
}
@Override
protected ModelListener createModelListener() {
return new ModelListener() {
@@ -615,6 +653,10 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
else {
g.drawLine(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y);
}
if (myRepaintCallback != null) {
myRepaintCallback.call(g);
}
}
@Override
@@ -774,6 +816,10 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
return myMacScrollbarHidden && Registry.is("editor.distraction.free.mode");
}
public void registerRepaintCallback(ScrollbarRepaintCallback callback) {
myRepaintCallback = callback;
}
private static class EmptyButton extends JButton {
private EmptyButton() {
setFocusable(false);
@@ -795,4 +841,8 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI {
return getMaximumSize();
}
}
public interface ScrollbarRepaintCallback {
void call(Graphics g);
}
}
@@ -32,15 +32,14 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.plaf.ScrollBarUI;
import java.awt.*;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
/**
* The container for an {@link Editor}, which is added then to {@link com.intellij.openapi.diff.impl.util.ThreePanels}.
*/
public class EditorPlace extends JComponent implements Disposable, EditorEx.RepaintCallback {
public class EditorPlace extends JComponent implements Disposable, ButtonlessScrollBarUI.ScrollbarRepaintCallback {
private static final Logger LOG = Logger.getInstance(EditorPlace.class);
@NotNull private final MergePanel2.DiffEditorState myState;
@@ -58,121 +57,57 @@ public class EditorPlace extends JComponent implements Disposable, EditorEx.Repa
}
@Override
public void paint(Graphics g) {
super.paint(g);
public void call(Graphics g) {
paintThis(g);
}
public void call(Graphics g) {
repaintScrollbar();
}
private void repaintScrollbar() {
if (myEditor == null || myColumn != MergePanelColumn.BASE) {
return; // we draw above the scrollbar only in the central column
}
Component editorComponent = myEditor.getComponent();
JScrollBar scrollBar = myEditor.getScrollPane().getVerticalScrollBar();
repaint(editorComponent.getWidth() - scrollBar.getWidth(), 0, scrollBar.getWidth(), scrollBar.getHeight());
}
private void paintThis(Graphics g) {
if (myEditor != null) {
ArrayList<DividerPolygon> polygons = DividerPolygon.createVisiblePolygons(myMergePanel.getSecondEditingSide(), FragmentSide.SIDE1,
DiffDivider.MERGE_DIVIDER_POLYGONS_OFFSET);
for (DividerPolygon polygon : polygons) {
int startY = polygon.getTopLeftY();
int endY = polygon.getBottomLeftY();
int height = endY - startY;
if (myEditor == null) return;
// painting only above the central scrollbar, because painting on edge scrollbars is not needed, and there are error stripes
if (myColumn != MergePanelColumn.BASE) return;
if (height == 0) { // draw at least a one-pixel line (e.g. for insertion or deletion), as it is done in highlighters
height = 1;
}
int offset = DiffDivider.MERGE_SCROLL_DIVIDER_POLYGONS_OFFSET;
ArrayList<DividerPolygon> polygons =
DividerPolygon.createVisiblePolygons(myMergePanel.getSecondEditingSide(true), FragmentSide.SIDE1, offset);
for (DividerPolygon polygon : polygons) {
int startY = polygon.getTopLeftY();
int endY = polygon.getBottomLeftY();
int height = endY - startY;
drawPolygonAboveScrollBar((Graphics2D)g, startY, height, polygon.getColor(), polygon.isApplied());
if (height == 0) { // draw at least a one-pixel line (e.g. for insertion or deletion), as it is done in highlighters
height = 1;
}
drawPolygon((Graphics2D)g, startY, height, polygon.getColor(), polygon.isApplied());
}
}
private void drawPolygonAboveScrollBar(@NotNull Graphics2D g, int startY, int height, @NotNull Color color, boolean applied) {
// painting only above the central scrollbar, because painting on edge scrollbars is not needed, and there are error stripes
if (myColumn != MergePanelColumn.BASE) {
return;
}
g.setColor(color);
JScrollBar scrollBar = myEditor.getScrollPane().getVerticalScrollBar();
int startX = scrollBar.getX();
int endX = startX + scrollBar.getWidth() - 1;
Rectangle thumb = calcThumbBounds(scrollBar);
private void drawPolygon(@NotNull Graphics2D g, int startY, int height, @NotNull Color color, boolean applied) {
int scrollbarWidth = myEditor.getScrollPane().getVerticalScrollBar().getWidth();
int startX = 0;
int endX = startX + scrollbarWidth - 1;
int endY = startY + height;
g.setColor(color);
if (!applied) {
if (height > 2) {
fillRectAboveScrollBar(g, startX, startY, scrollBar.getWidth(), height, thumb);
g.fillRect(startX, startY, scrollbarWidth, height);
Color framingColor = DiffUtil.getFramingColor(color);
if (outsideBounds(startY, thumb)) {
UIUtil.drawLine(g, startX, startY, endX, startY, null, framingColor);
}
if (outsideBounds(endY, thumb)) {
UIUtil.drawLine(g, startX, endY, endX, endY, null, framingColor);
}
UIUtil.drawLine(g, startX, startY, endX, startY, null, framingColor);
UIUtil.drawLine(g, startX, endY, endX, endY, null, framingColor);
}
else {
if (outsideBounds(startY, thumb)) {
DiffUtil.drawDoubleShadowedLine(g, startX, endX, startY, color);
}
DiffUtil.drawDoubleShadowedLine(g, startX, endX, startY, color);
}
}
else {
if (outsideBounds(startY, thumb)) {
UIUtil.drawBoldDottedLine(g, startX, endX, startY, null, color, false);
}
if (outsideBounds(endY, thumb)) {
UIUtil.drawBoldDottedLine(g, startX, endX, endY, null, color, false);
}
UIUtil.drawBoldDottedLine(g, startX, endX, startY, null, color, false);
UIUtil.drawBoldDottedLine(g, startX, endX, endY, null, color, false);
}
}
private static void fillRectAboveScrollBar(Graphics2D g, int startX, int startY, int width, int height, Rectangle thumb) {
int endY = startY + height;
int thumbEndY = thumb == null ? 0 : thumb.y + thumb.height; // it's for further readability (could have a 2-level ifs for the variable)
if (thumb == null) {
g.fillRect(startX, startY, width, height);
}
else if (outsideBounds(startY, thumb) && !outsideBounds(endY, thumb)) {
g.fillRect(startX, startY, width, thumb.y - startY);
}
else if (!outsideBounds(startY, thumb) && outsideBounds(endY, thumb)) {
g.fillRect(startX, thumbEndY, width, endY - thumbEndY);
}
else if (startY < thumb.y && endY > thumbEndY) { // surrounding the thumb
g.fillRect(startX, startY, width, thumb.y - startY);
g.fillRect(startX, thumbEndY, width, endY - thumbEndY);
}
else if (outsideBounds(startY, thumb) && outsideBounds(endY, thumb)) { // outside without intersection
g.fillRect(startX, startY, width, height);
}
}
private static boolean outsideBounds(int y, @Nullable Rectangle rectangle) {
if (rectangle == null) {
return true;
}
return y < rectangle.y || y > rectangle.y + rectangle.height;
}
@Nullable
private static Rectangle calcThumbBounds(JScrollBar scrollBar) {
ScrollBarUI scrollBarUI = scrollBar.getUI();
if (scrollBarUI instanceof ButtonlessScrollBarUI) {
return ((ButtonlessScrollBarUI)scrollBarUI).getThumbBounds();
}
return null;
}
public void addNotify() {
if (myEditor != null) {
super.addNotify();
@@ -249,6 +184,7 @@ public class EditorPlace extends JComponent implements Disposable, EditorEx.Repa
public interface EditorListener {
void onEditorCreated(EditorPlace place);
void onEditorReleased(Editor releasedEditor);
}
@@ -29,6 +29,7 @@ import java.awt.*;
public class DiffDivider extends JComponent {
public static final int MERGE_DIVIDER_POLYGONS_OFFSET = 1;
public static final int MERGE_SCROLL_DIVIDER_POLYGONS_OFFSET = 2;
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.util.DiffDivider");
private final Editor[] myEditors = new Editor[2];
private final FragmentSide myLeftSide;
@@ -32,6 +32,7 @@ import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.ButtonlessScrollBarUI;
import org.intellij.lang.annotations.MagicConstant;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -262,10 +263,5 @@ public interface EditorEx extends Editor {
* @param callback callback which will be called from the {@link javax.swing.JComponent#paint(java.awt.Graphics)} method of
* the editor vertical scrollbar.
*/
void registerScrollBarRepaintCallback(@Nullable RepaintCallback callback);
interface RepaintCallback {
void call(Graphics g);
}
void registerScrollBarRepaintCallback(@Nullable ButtonlessScrollBarUI.ScrollbarRepaintCallback callback);
}
@@ -597,7 +597,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
@Override
public void registerScrollBarRepaintCallback(@Nullable RepaintCallback callback) {
public void registerScrollBarRepaintCallback(@Nullable ButtonlessScrollBarUI.ScrollbarRepaintCallback callback) {
myVerticalScrollBar.registerRepaintCallback(callback);
}
@@ -2724,12 +2724,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
int visibleLine = clip.y / lineHeight;
// The main idea is that there is a possible case that we need to perform painting starting from soft-wrapped logical line.
// We may want to skip necessary number of visual lines then. Hence, we remember logical position that corresponds to the starting
// visual line in order to use it for further processing. As soon as necessary number of visual lines is skipped, logical
// position is expected to be set to null as an indication that no soft wrap-introduced visual lines should be skipped on
// current painting iteration.
Ref<LogicalPosition> logicalPosition = new Ref<LogicalPosition>(clipStartPosition);
int startLine = clipStartPosition.line;
int start = clipStartOffset;
@@ -2737,7 +2731,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
if (startLine == 0 && myPrefixText != null) {
position.x = drawStringWithSoftWraps(g, new CharArrayCharSequence(myPrefixText), 0, myPrefixText.length, position, clip,
myPrefixAttributes.getEffectColor(), myPrefixAttributes.getEffectType(),
myPrefixAttributes.getFontType(), myPrefixAttributes.getForegroundColor(), logicalPosition,
myPrefixAttributes.getFontType(), myPrefixAttributes.getForegroundColor(), -1,
PAINT_NO_WHITESPACE);
}
if (startLine >= myDocument.getLineCount() || startLine < 0) {
@@ -2773,7 +2767,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
FoldRegion collapsedFolderAt = myFoldingModel.getCollapsedRegionAtOffset(start);
if (collapsedFolderAt == null) {
drawStringWithSoftWraps(g, chars, start, lEnd - lIterator.getSeparatorLength(), position, clip, effectColor,
effectType, fontType, currentColor, logicalPosition, context);
effectType, fontType, currentColor, clipStartOffset, context);
final VirtualFile file = getVirtualFile();
if (myProject != null && file != null && !isOneLineMode()) {
int offset = position.x;
@@ -2789,7 +2783,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
info.getEffectType() == null ? effectType : info.getEffectType(),
info.getFontType(),
info.getColor() == null ? currentColor : info.getColor(),
logicalPosition, context);
clipStartOffset, context);
}
}
}
@@ -2820,7 +2814,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
if (softWrap != null) {
position.x = drawStringWithSoftWraps(
g, chars, collapsedFolderAt.getStartOffset(), collapsedFolderAt.getStartOffset(), position, clip, effectColor, effectType,
fontType, currentColor, logicalPosition, context
fontType, currentColor, clipStartOffset, context
);
}
int foldingXStart = position.x;
@@ -2833,7 +2827,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
else {
position.x = drawStringWithSoftWraps(g, chars, start, Math.min(hEnd, lEnd - lIterator.getSeparatorLength()), position, clip,
effectColor, effectType, fontType, currentColor, logicalPosition, context);
effectColor, effectType, fontType, currentColor, clipStartOffset, context);
}
iterationState.advance();
@@ -2856,7 +2850,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
if (collapsedFolderAt != null) {
int foldingXStart = position.x;
int foldingXEnd = drawStringWithSoftWraps(
g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType, fontType, currentColor, logicalPosition,
g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType, fontType, currentColor, clipStartOffset,
PAINT_NO_WHITESPACE);
BorderEffect.paintFoldedEffect(g, foldingXStart, position.y, foldingXEnd, getLineHeight(), effectColor, effectType);
// myBorderEffect.collapsedFolderReached(g, this);
@@ -3084,15 +3078,15 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
EffectType effectType,
@JdkConstants.FontStyle int fontType,
Color fontColor,
@NotNull Ref<LogicalPosition> startDrawingLogicalPosition,
int startDrawingOffset,
WhitespacePaintingStrategy context) {
return drawStringWithSoftWraps(g, text, 0, text.length(), position, clip, effectColor, effectType,
fontType, fontColor, startDrawingLogicalPosition, context);
fontType, fontColor, startDrawingOffset, context);
}
private int drawStringWithSoftWraps(@NotNull Graphics g,
final CharSequence text,
final int start,
int start,
final int end,
@NotNull Point position,
@NotNull Rectangle clip,
@@ -3100,49 +3094,26 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
EffectType effectType,
@JdkConstants.FontStyle int fontType,
Color fontColor,
@NotNull Ref<LogicalPosition> startDrawingLogicalPosition,
int startDrawingOffset,
WhitespacePaintingStrategy context) {
int startToUse = start;
// There is a possible case that starting logical line is split by soft-wraps and it's part after the split should be drawn.
// We need to skip necessary number of visual lines then.
int softWrapLinesToSkip = 0;
if (startDrawingLogicalPosition.get() != null) {
softWrapLinesToSkip = startDrawingLogicalPosition.get().softWrapLinesOnCurrentLogicalLine;
}
SoftWrap lastSkippedSoftWrap = null;
if (softWrapLinesToSkip > 0) {
List<? extends SoftWrap> softWraps = getSoftWrapModel().getSoftWrapsForLine(startDrawingLogicalPosition.get().line);
for (SoftWrap softWrap : softWraps) {
softWrapLinesToSkip--; // Assuming that soft wrap has a single line feed all the time
if (softWrapLinesToSkip <= 0) {
lastSkippedSoftWrap = softWrap;
startToUse = softWrap.getStart();
break;
}
}
}
startToUse = Math.max(startToUse, start);
if (startToUse >= end && getSoftWrapModel().getSoftWrap(startToUse) == null) {
if (start >= end && getSoftWrapModel().getSoftWrap(start) == null) {
return position.x;
}
startDrawingLogicalPosition.set(null);
// Given 'end' offset is exclusive though SoftWrapModel.getSoftWrapsForRange() uses inclusive end offset.
// Hence, we decrement it if necessary. Please note that we don't do that if start is equal to end. That is the case,
// for example, for soft-wrapped collapsed fold region - we need to draw soft wrap before it.
int softWrapRetrievalEndOffset = end;
if (startToUse < end) {
if (start < end) {
softWrapRetrievalEndOffset--;
}
outer:
for (SoftWrap softWrap : getSoftWrapModel().getSoftWrapsForRange(startToUse, softWrapRetrievalEndOffset)) {
for (SoftWrap softWrap : getSoftWrapModel().getSoftWrapsForRange(start, softWrapRetrievalEndOffset)) {
char[] softWrapChars = softWrap.getChars();
CharArrayCharSequence softWrapSeq = new CharArrayCharSequence(softWrapChars);
if (softWrap.equals(lastSkippedSoftWrap)) {
if (softWrap.getStart() == startDrawingOffset) {
// If we are here that means that we are located on soft wrap-introduced visual line just after soft wrap. Hence, we need
// to draw soft wrap indent if any and 'after soft wrap' sign.
int i = CharArrayUtil.lastIndexOf(softWrapChars, '\n', 0, softWrapChars.length);
@@ -3157,13 +3128,13 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
// Draw token text before the wrap.
if (softWrap.getStart() > startToUse) {
if (softWrap.getStart() > start) {
position.x = drawString(
g, text, startToUse, softWrap.getStart(), position, clip, null, null, fontType, fontColor, context
g, text, start, softWrap.getStart(), position, clip, null, null, fontType, fontColor, context
);
}
startToUse = softWrap.getStart();
start = softWrap.getStart();
// We don't draw every soft wrap symbol one-by-one but whole visual line. Current variable holds index that points
// to the first soft wrap symbol that is not drawn yet.
@@ -3201,7 +3172,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
position.x += mySoftWrapModel.paint(g, SoftWrapDrawingType.AFTER_SOFT_WRAP, position.x, position.y, getLineHeight());
}
return position.x = drawString(g, text, startToUse, end, position, clip, effectColor, effectType, fontType, fontColor, context);
return position.x = drawString(g, text, start, end, position, clip, effectColor, effectType, fontType, fontColor, context);
}
private int drawString(@NotNull Graphics g,
@@ -4808,7 +4779,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
class MyScrollBar extends JBScrollBar implements IdeGlassPane.TopComponent {
@NonNls private static final String APPLE_LAF_AQUA_SCROLL_BAR_UI_CLASS = "apple.laf.AquaScrollBarUI";
private ScrollBarUI myPersistentUI;
@Nullable private RepaintCallback myRepaintCallback;
private MyScrollBar(@JdkConstants.AdjustableOrientation int orientation) {
super(orientation);
@@ -4833,9 +4803,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
@Override
public void paint(@NotNull Graphics g) {
super.paint(g);
if (myRepaintCallback != null) {
myRepaintCallback.call(g);
}
}
/**
@@ -4906,8 +4873,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
return myEditorComponent.getScrollableBlockIncrement(vr, SwingConstants.VERTICAL, direction);
}
public void registerRepaintCallback(@Nullable RepaintCallback callback) {
myRepaintCallback = callback;
public void registerRepaintCallback(@Nullable ButtonlessScrollBarUI.ScrollbarRepaintCallback callback) {
if (myPersistentUI instanceof ButtonlessScrollBarUI) {
((ButtonlessScrollBarUI)myPersistentUI).registerRepaintCallback(callback);
}
}
}
@@ -117,7 +117,7 @@ public class ModifierKeyDoubleClickHandler {
resetState();
return false;
}
if (ourOtherKeyWasPressed.get() && Clock.getTime() - ourLastTimePressed.get() < 500) {
if (myActionKeyCode == -1 && ourOtherKeyWasPressed.get() && Clock.getTime() - ourLastTimePressed.get() < 500) {
resetState();
return false;
}
@@ -612,7 +612,12 @@ public final class WindowManagerImpl extends WindowManagerEx implements NamedCom
}
frame.addWindowListener(myActivationListener);
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentMoved(@NotNull ComponentEvent e) {
updateFrameBounds(frame);
}
});
myEventDispatcher.getMulticaster().frameCreated(frame);
return frame;
@@ -778,7 +783,21 @@ public final class WindowManagerImpl extends WindowManagerEx implements NamedCom
return null;
}
int extendedState = updateFrameBounds(frame);
Rectangle rectangle = myFrameBounds;
final Element frameElement = new Element(FRAME_ELEMENT);
frameElement.setAttribute(X_ATTR, Integer.toString(rectangle.x));
frameElement.setAttribute(Y_ATTR, Integer.toString(rectangle.y));
frameElement.setAttribute(WIDTH_ATTR, Integer.toString(rectangle.width));
frameElement.setAttribute(HEIGHT_ATTR, Integer.toString(rectangle.height));
if (!(frame.isInFullScreen() && SystemInfo.isAppleJvm)) {
frameElement.setAttribute(EXTENDED_STATE_ATTR, Integer.toString(extendedState));
}
return frameElement;
}
private int updateFrameBounds(IdeFrameImpl frame) {
int extendedState = frame.getExtendedState();
if (SystemInfo.isMacOSLion) {
@SuppressWarnings("deprecation") ComponentPeer peer = frame.getPeer();
@@ -792,16 +811,10 @@ public final class WindowManagerImpl extends WindowManagerEx implements NamedCom
boolean usePreviousBounds = isMaximized &&
myFrameBounds != null &&
frame.getBounds().contains(new Point((int)myFrameBounds.getCenterX(), (int)myFrameBounds.getCenterY()));
Rectangle rectangle = usePreviousBounds ? myFrameBounds : frame.getBounds();
frameElement.setAttribute(X_ATTR, Integer.toString(rectangle.x));
frameElement.setAttribute(Y_ATTR, Integer.toString(rectangle.y));
frameElement.setAttribute(WIDTH_ATTR, Integer.toString(rectangle.width));
frameElement.setAttribute(HEIGHT_ATTR, Integer.toString(rectangle.height));
if (!(frame.isInFullScreen() && SystemInfo.isAppleJvm)) {
frameElement.setAttribute(EXTENDED_STATE_ATTR, Integer.toString(extendedState));
if (!usePreviousBounds) {
myFrameBounds = frame.getBounds();
}
return frameElement;
return extendedState;
}
@Override
@@ -65,11 +65,11 @@ public class JBTabsPaneImpl implements TabbedPane, SwingConstants {
maxOffset++;
g2d.setPaint(UIUtil.getPanelBackground());
if (getFirstTabOffset() > 0) {
g2d.fillRect(clip.x, clip.y, clip.x + getFirstTabOffset() - 1, clip.y + maxLength - TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT);
g2d.fillRect(clip.x, clip.y, clip.x + getFirstTabOffset() - 1, clip.y + maxLength - getActiveTabUnderlineHeight());
}
g2d.fillRect(clip.x + maxOffset, clip.y, clip.width - maxOffset, clip.y + maxLength - TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT);
g2d.fillRect(clip.x + maxOffset, clip.y, clip.width - maxOffset, clip.y + maxLength - getActiveTabUnderlineHeight());
g2d.setPaint(new JBColor(Gray._181, UIUtil.getPanelBackground()));
g2d.drawLine(clip.x + maxOffset, clip.y + maxLength - TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT, clip.x + clip.width, clip.y + maxLength - TabsUtil.ACTIVE_TAB_UNDERLINE_HEIGHT);
g2d.drawLine(clip.x + maxOffset, clip.y + maxLength - getActiveTabUnderlineHeight(), clip.x + clip.width, clip.y + maxLength - getActiveTabUnderlineHeight());
g2d.setPaint(UIUtil.getPanelBackground());
g2d.drawLine(clip.x, clip.y + maxLength, clip.width, clip.y + maxLength);
}
@@ -43,6 +43,7 @@ public class VcsLogUiProperties implements PersistentStateComponent<VcsLogUiProp
public boolean SHOW_DETAILS = true;
public boolean LONG_EDGES_VISIBLE = false;
public boolean BEK_SORT = false;
public boolean SHOW_ROOT_NAMES = false;
public Deque<UserGroup> RECENTLY_FILTERED_USER_GROUPS = new ArrayDeque<UserGroup>();
public Deque<UserGroup> RECENTLY_FILTERED_BRANCH_GROUPS = new ArrayDeque<UserGroup>();
}
@@ -126,6 +127,14 @@ public class VcsLogUiProperties implements PersistentStateComponent<VcsLogUiProp
myState.BEK_SORT = isBek;
}
public boolean isShowRootNames() {
return myState.SHOW_ROOT_NAMES;
}
public void setShowRootNames(boolean isShowRootNames) {
myState.SHOW_ROOT_NAMES = isShowRootNames;
}
public static class UserGroup {
public List<String> users = new ArrayList<String>();
@@ -185,6 +185,14 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable {
return myUiProperties.isBek();
}
public void setShowRootNames(boolean isShowRootNames) {
myUiProperties.setShowRootNames(isShowRootNames);
}
public boolean isShowRootNames() {
return myUiProperties.isShowRootNames();
}
public void jumpToCommit(@NotNull Hash commitHash) {
jumpTo(commitHash, new PairFunction<GraphTableModel, Hash, Integer>() {
@Override
@@ -91,7 +91,7 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider {
myToolbar = createActionsToolbar();
myDetailsSplitter = new Splitter(true, 0.7f);
myDetailsSplitter.setFirstComponent(ScrollPaneFactory.createScrollPane(myGraphTable));
myDetailsSplitter.setFirstComponent(setupScrolledGraph());
setupDetailsSplitter(myUiProperties.isShowDetails());
JComponent toolbars = new JPanel(new BorderLayout());
@@ -156,6 +156,12 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider {
myDetailsSplitter.setSecondComponent(state ? myDetailsPanel : null);
}
private JScrollPane setupScrolledGraph() {
JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myGraphTable);
myGraphTable.viewportSet(scrollPane.getViewport());
return scrollPane;
}
private static void setDefaultEmptyText(ChangesBrowser changesBrowser) {
changesBrowser.getViewer().setEmptyText("");
}
@@ -18,14 +18,17 @@ package com.intellij.vcs.log.ui.frame;
import com.intellij.ide.CopyProvider;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.ide.CopyPasteManager;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.committed.CommittedChangesTreeBrowser;
import com.intellij.openapi.vcs.changes.issueLinks.TableLinkMouseListener;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.ColoredTableCellRenderer;
import com.intellij.ui.JBColor;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.TableScrollingUtil;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.table.JBTable;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.DateFormatUtil;
@@ -49,6 +52,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
@@ -67,6 +74,7 @@ import static com.intellij.vcs.log.printer.idea.PrintParameters.HEIGHT_CELL;
public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, CopyProvider {
private static final int ROOT_INDICATOR_WIDTH = 5;
private static final int ROOT_NAME_MAX_WIDTH = 200;
private static final int MAX_DEFAULT_AUTHOR_COLUMN_WIDTH = 200;
private static final int MAX_ROWS_TO_CALC_WIDTH = 1000;
private static final int MAX_ROWS_TO_CALC_OFFSET = 100;
@@ -97,7 +105,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C
myGraphCommitCellRender = new GraphCommitCellRender(myUI.getColorManager(), logDataHolder, myGraphCellPainter,
myDataPack.getVisibleGraph(), this);
setDefaultRenderer(VirtualFile.class, new RootCellRenderer(myUI, myLogDataHolder.isMultiRoot()));
setDefaultRenderer(VirtualFile.class, new RootCellRenderer(myUI));
setDefaultRenderer(GraphCommitCell.class, myGraphCommitCellRender);
setDefaultRenderer(String.class, new StringCellRenderer());
@@ -127,12 +135,8 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C
private void setColumnPreferredSize() {
for (int i = 0; i < getColumnCount(); i++) {
TableColumn column = getColumnModel().getColumn(i);
if (i == GraphTableModel.ROOT_COLUMN) { // thin stripe or nothing
int rootWidth = myUI.getColorManager().isMultipleRoots() ? ROOT_INDICATOR_WIDTH : 0;
// NB: all further instructions and their order are important, otherwise the minimum size which is less than 15 won't be applied
column.setMinWidth(rootWidth);
column.setMaxWidth(rootWidth);
column.setPreferredWidth(rootWidth);
if (i == GraphTableModel.ROOT_COLUMN) { // thin stripe, or root name, or nothing
setRootColumnSize(column);
}
else if (i == GraphTableModel.COMMIT_COLUMN) { // let commit message occupy as much as possible
column.setPreferredWidth(Short.MAX_VALUE);
@@ -155,6 +159,33 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C
}
}
private void setRootColumnSize(TableColumn column) {
int rootWidth;
if (!myUI.getColorManager().isMultipleRoots()) {
rootWidth = 0;
}
else if (!myUI.isShowRootNames()) {
rootWidth = ROOT_INDICATOR_WIDTH;
}
else {
rootWidth = Math.min(calculateMaxRootWidth(), ROOT_NAME_MAX_WIDTH);
}
// NB: all further instructions and their order are important, otherwise the minimum size which is less than 15 won't be applied
column.setMinWidth(rootWidth);
column.setMaxWidth(rootWidth);
column.setPreferredWidth(rootWidth);
}
private int calculateMaxRootWidth() {
int width = 0;
for (VirtualFile file : myLogDataHolder.getRoots()) {
Font tableFont = UIManager.getFont("Table.font");
width = Math.max(getFontMetrics(tableFont).stringWidth(file.getName() + " "), width);
}
return width;
}
private int calcMaxContentColumnWidth(int columnIndex, int maxRowsToCheck) {
int maxWidth = 0;
for (int row = 0; row < maxRowsToCheck; row++) {
@@ -175,7 +206,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C
if (column == GraphTableModel.ROOT_COLUMN) {
Object at = getValueAt(row, column);
if (at instanceof VirtualFile) {
return ((VirtualFile)at).getPresentableUrl();
return "<html><b>" + ((VirtualFile)at).getPresentableUrl() + "</b><br/>Click to " + (myUI.isShowRootNames() ? "collapse" : "expand") + "</html>";
}
}
return null;
@@ -292,6 +323,19 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C
}
}
public void viewportSet(JViewport viewport) {
viewport.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
TableModel model = getModel();
if (model instanceof AbstractTableModel) {
Couple<Integer> visibleRows = TableScrollingUtil.getVisibleRows(VcsLogGraphTable.this);
((AbstractTableModel)model).fireTableChanged(new TableModelEvent(model, visibleRows.first - 1, visibleRows.second, GraphTableModel.ROOT_COLUMN));
}
}
});
}
private class MyMouseAdapter extends MouseAdapter {
private final TableLinkMouseListener myLinkListener;
@@ -306,6 +350,8 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C
}
if (e.getClickCount() == 1) {
if (expandOrCollapseRoots(e)) return;
performAction(e, MyGraphMouseAction.Type.CLICK);
}
}
@@ -320,6 +366,17 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C
}
}
private boolean expandOrCollapseRoots(MouseEvent e) {
int column = convertColumnIndexToModel(columnAtPoint(e.getPoint()));
if (column == GraphTableModel.ROOT_COLUMN && myLogDataHolder.isMultiRoot()) {
myUI.setShowRootNames(!myUI.isShowRootNames());
setColumnPreferredSize();
setRootColumnSize(getColumnModel().getColumn(column));
return true;
}
return false;
}
private void performAction(@NotNull MouseEvent e, @NotNull final MyGraphMouseAction.Type actionType) {
int row = PositionUtil.getRowIndex(e.getPoint());
if (row > getRowCount() - 1) {
@@ -381,34 +438,78 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C
return myLogDataHolder.isMultiRoot() ? rootColumn.getWidth() : 0;
}
private static class RootCellRenderer extends JPanel implements TableCellRenderer {
private static class RootCellRenderer extends JBLabel implements TableCellRenderer {
@NotNull private final VcsLogUiImpl myUi;
@NotNull private Color myColor = UIUtil.getTableBackground();
private boolean myHasBorder;
RootCellRenderer(@NotNull VcsLogUiImpl ui, boolean multiRoot) {
RootCellRenderer(@NotNull VcsLogUiImpl ui) {
super("", CENTER);
myUi = ui;
int rootWidth = multiRoot ? ROOT_INDICATOR_WIDTH : 0;
setPreferredSize(new Dimension(rootWidth, -1));
}
@Override
protected void paintComponent(Graphics g) {
g.setColor(myColor);
g.fillRect(0, 0, ROOT_INDICATOR_WIDTH - 1, HEIGHT_CELL);
UIUtil.drawLine((Graphics2D)g, ROOT_INDICATOR_WIDTH - 1, 0, ROOT_INDICATOR_WIDTH - 1, HEIGHT_CELL, null,
myUi.getColorManager().getRootIndicatorBorder());
int width = getWidth();
if (myHasBorder) {
g.fillRect(0, 0, width - 1, HEIGHT_CELL);
UIUtil.drawLine((Graphics2D)g, width - 1, 0, width - 1, HEIGHT_CELL, null, myUi.getColorManager().getRootIndicatorBorder());
}
else {
g.fillRect(0, 0, width, HEIGHT_CELL);
}
super.paintComponent(g);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
String text;
Color color;
if (value instanceof VirtualFile) {
myColor = myUi.getColorManager().getRootColor((VirtualFile)value);
VirtualFile root = (VirtualFile)value;
int readableRow = TableScrollingUtil.getReadableRow(table, Math.round(HEIGHT_CELL * 0.5f));
if (row < readableRow) {
text = "";
} else if (row == 0 || !value.equals(table.getModel().getValueAt(row - 1, column)) || readableRow == row) {
text = root.getName();
} else {
text = "";
}
color = myUi.getColorManager().getRootColor(root);
}
else {
myColor = UIUtil.getTableBackground(isSelected);
text = null;
color = UIUtil.getTableBackground(isSelected);
}
if (myUi.isShowRootNames()) {
// pale colors, honors selection, does not have border
if (isSelected) {
myColor = UIUtil.getTableBackground(isSelected);
}
else {
//we create JBColor later
//noinspection UseJBColor
Color transparentColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), 50);
myColor = new JBColor(transparentColor, transparentColor);
}
setForeground(UIUtil.getTableForeground(isSelected));
setText(text);
myHasBorder = false;
}
else {
// bright colors, does not know about the selection, has border
setForeground(UIUtil.getTableForeground(false));
myColor = color;
setText("");
myHasBorder = true;
}
return this;
}
}
@@ -42,6 +42,7 @@ import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.ToolWindowId;
@@ -381,13 +382,21 @@ public class XDebugSessionImpl implements XDebugSession {
private <B extends XBreakpoint<?>> void handleBreakpoint(final XBreakpointHandler<B> handler, final B b, final boolean register,
final boolean temporary) {
if (register && isBreakpointActive(b)) {
synchronized (myRegisteredBreakpoints) {
myRegisteredBreakpoints.put(b, new CustomizedBreakpointPresentation());
if (register) {
boolean active = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return isBreakpointActive(b);
}
});
if (active) {
synchronized (myRegisteredBreakpoints) {
myRegisteredBreakpoints.put(b, new CustomizedBreakpointPresentation());
}
handler.registerBreakpoint(b);
}
handler.registerBreakpoint(b);
}
if (!register) {
else {
boolean removed;
synchronized (myRegisteredBreakpoints) {
removed = myRegisteredBreakpoints.remove(b) != null;
@@ -61,7 +61,7 @@ import static org.jetbrains.plugins.github.util.GithubUtil.setVisibleEnabled;
*/
public class GithubRebaseAction extends DumbAwareAction {
private static final Logger LOG = GithubUtil.LOG;
private static final String CANNOT_PERFORM_GITHUB_REBASE = "Can't perform github rebase";
private static final String CANNOT_PERFORM_GITHUB_REBASE = "Can't perform GitHub rebase";
public GithubRebaseAction() {
super("Rebase my GitHub fork", "Rebase your GitHub forked repository relative to the origin", GithubIcons.Github_icon);
@@ -165,7 +165,7 @@ public class GithubRebaseAction extends DumbAwareAction {
if (!repositoryInfo.isFork() || repositoryInfo.getParent() == null) {
GithubNotifications.showWarningURL(project, CANNOT_PERFORM_GITHUB_REBASE, "GitHub repository ", "'" + repositoryInfo.getName() + "'",
" is not a forked one", repositoryInfo.getHtmlUrl());
" is not a fork", repositoryInfo.getHtmlUrl());
return null;
}
@@ -188,7 +188,7 @@ public class GithubRebaseAction extends DumbAwareAction {
@NotNull ProgressIndicator indicator) {
final String remoteUrl = GithubUtil.findGithubRemoteUrl(gitRepository);
if (remoteUrl == null) {
GithubNotifications.showError(project, CANNOT_PERFORM_GITHUB_REBASE, "Can't find github remote");
GithubNotifications.showError(project, CANNOT_PERFORM_GITHUB_REBASE, "Can't find GitHub remote");
return null;
}
final GithubFullPath userAndRepo = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl);