blob: 2230f9c4ff5948d3fc461c5a40733b9e519cc9f3 [file] [log] [blame]
/*
* 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.openapi.vcs.ex;
import com.intellij.codeInsight.hint.EditorFragmentComponent;
import com.intellij.codeInsight.hint.HintManagerImpl;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.diff.DiffColors;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
import com.intellij.openapi.editor.markup.ActiveGutterRenderer;
import com.intellij.openapi.editor.markup.EffectType;
import com.intellij.openapi.editor.markup.LineMarkerRenderer;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.vcs.actions.ShowNextChangeMarkerAction;
import com.intellij.openapi.vcs.actions.ShowPrevChangeMarkerAction;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.ColoredSideBorder;
import com.intellij.ui.HintHint;
import com.intellij.ui.HintListener;
import com.intellij.ui.LightweightHint;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import java.util.List;
/**
* @author irengrig
*/
public class LineStatusTrackerDrawing {
private LineStatusTrackerDrawing() {
}
static TextAttributes getAttributesFor(final Range range) {
final Color stripeColor = getDiffColor(range, false);
final TextAttributes textAttributes = new TextAttributes(null, stripeColor, null, EffectType.BOXED, Font.PLAIN);
textAttributes.setErrorStripeColor(stripeColor);
return textAttributes;
}
private static void paintGutterFragment(final Editor editor, final Graphics g, final Rectangle r, final Color stripeColor) {
final EditorGutterComponentEx gutter = ((EditorEx)editor).getGutterComponentEx();
g.setColor(stripeColor);
final int endX = gutter.getWhitespaceSeparatorOffset();
final int x = r.x + r.width - 5;
final int width = endX - x;
if (r.height > 0) {
g.fillRect(x, r.y, width, r.height);
g.setColor(gutter.getOutlineColor(false));
UIUtil.drawLine(g, x, r.y, x + width, r.y);
UIUtil.drawLine(g, x, r.y, x, r.y + r.height - 1);
UIUtil.drawLine(g, x, r.y + r.height - 1, x + width, r.y + r.height - 1);
}
else {
final int[] xPoints = new int[]{x,
x,
x + width - 1};
final int[] yPoints = new int[]{r.y - 4,
r.y + 4,
r.y};
g.fillPolygon(xPoints, yPoints, 3);
g.setColor(gutter.getOutlineColor(false));
g.drawPolygon(xPoints, yPoints, 3);
}
}
@Nullable
private static Color brighter(final Color color) {
if (color == null) {
return null;
}
final float[] hsbStripeColor = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
if (hsbStripeColor[1] < 0.02f) {
// color is grey
hsbStripeColor[2] = Math.min(1.0f, hsbStripeColor[2] * 1.3f);
} else {
// let's decrease color saturation
hsbStripeColor[1] *= 0.3;
// max brightness
hsbStripeColor[2] = 1.0f;
}
return Color.getHSBColor(hsbStripeColor[0], hsbStripeColor[1], hsbStripeColor[2]);
}
public static LineMarkerRenderer createRenderer(final Range range, final LineStatusTracker tracker) {
return new ActiveGutterRenderer() {
public void paint(final Editor editor, final Graphics g, final Rectangle r) {
paintGutterFragment(editor, g, r, getDiffColor(range, true));
}
public void doAction(final Editor editor, final MouseEvent e) {
e.consume();
final JComponent comp = (JComponent)e.getComponent(); // shall be EditorGutterComponent, cast is safe.
final JLayeredPane layeredPane = comp.getRootPane().getLayeredPane();
final Point point = SwingUtilities.convertPoint(comp, ((EditorEx)editor).getGutterComponentEx().getWidth(), e.getY(), layeredPane);
showActiveHint(range, editor, point, tracker);
}
public boolean canDoAction(final MouseEvent e) {
final EditorGutterComponentEx gutter = (EditorGutterComponentEx)e.getComponent();
return e.getX() > gutter.getLineMarkerAreaOffset() + gutter.getIconsAreaWidth();
}
};
}
public static void showActiveHint(final Range range, final Editor editor, final Point point, final LineStatusTracker tracker) {
final DefaultActionGroup group = new DefaultActionGroup();
final AnAction globalShowNextAction = ActionManager.getInstance().getAction("VcsShowNextChangeMarker");
final AnAction globalShowPrevAction = ActionManager.getInstance().getAction("VcsShowPrevChangeMarker");
final ShowPrevChangeMarkerAction localShowPrevAction = new ShowPrevChangeMarkerAction(tracker.getPrevRange(range), tracker, editor);
final ShowNextChangeMarkerAction localShowNextAction = new ShowNextChangeMarkerAction(tracker.getNextRange(range), tracker, editor);
final JComponent editorComponent = editor.getComponent();
localShowNextAction.registerCustomShortcutSet(localShowNextAction.getShortcutSet(), editorComponent);
localShowPrevAction.registerCustomShortcutSet(localShowPrevAction.getShortcutSet(), editorComponent);
group.add(localShowPrevAction);
group.add(localShowNextAction);
localShowNextAction.copyFrom(globalShowNextAction);
localShowPrevAction.copyFrom(globalShowPrevAction);
final RollbackLineStatusRangeAction rollback = new RollbackLineStatusRangeAction(tracker, range, editor);
final ShowLineStatusRangeDiffAction showDiff = new ShowLineStatusRangeDiffAction(tracker, range, editor);
final CopyLineStatusRangeAction copyRange = new CopyLineStatusRangeAction(tracker, range);
group.add(rollback);
group.add(showDiff);
group.add(copyRange);
EmptyAction.setupAction(rollback, IdeActions.SELECTED_CHANGES_ROLLBACK, editorComponent);
EmptyAction.setupAction(showDiff, "ChangesView.Diff", editorComponent);
EmptyAction.setupAction(copyRange, IdeActions.ACTION_COPY, editorComponent);
final JComponent toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.FILEHISTORY_VIEW_TOOLBAR, group, true).getComponent();
final Color background = ((EditorEx)editor).getBackgroundColor();
final Color foreground = editor.getColorsScheme().getColor(EditorColors.CARET_COLOR);
toolbar.setBackground(background);
toolbar.setBorder(new ColoredSideBorder(foreground, foreground, (range.getType() != Range.INSERTED) ? null : foreground, foreground, 1));
final JPanel component = new JPanel(new BorderLayout());
component.setOpaque(false);
final JPanel toolbarPanel = new JPanel(new BorderLayout());
toolbarPanel.setOpaque(false);
toolbarPanel.add(toolbar, BorderLayout.WEST);
JPanel emptyPanel = new JPanel();
emptyPanel.setOpaque(false);
toolbarPanel.add(emptyPanel, BorderLayout.CENTER);
MouseAdapter listener = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
editor.getContentComponent().dispatchEvent(SwingUtilities.convertMouseEvent(e.getComponent(), e, editor.getContentComponent()));
}
@Override
public void mouseClicked(MouseEvent e) {
editor.getContentComponent().dispatchEvent(SwingUtilities.convertMouseEvent(e.getComponent(), e, editor.getContentComponent()));
}
public void mouseReleased(final MouseEvent e) {
editor.getContentComponent().dispatchEvent(SwingUtilities.convertMouseEvent(e.getComponent(), e, editor.getContentComponent()));
}
};
emptyPanel.addMouseListener(listener);
component.add(toolbarPanel, BorderLayout.NORTH);
if (range.getType() != Range.INSERTED) {
final DocumentEx doc = (DocumentEx) tracker.getVcsDocument();
final EditorEx uEditor = (EditorEx)EditorFactory.getInstance().createViewer(doc, tracker.getProject());
final EditorHighlighter highlighter = EditorHighlighterFactory.getInstance().createEditorHighlighter(tracker.getProject(), getFileName(tracker.getDocument()));
uEditor.setHighlighter(highlighter);
final EditorFragmentComponent editorFragmentComponent =
EditorFragmentComponent.createEditorFragmentComponent(uEditor, range.getVcsLine1(), range.getVcsLine2(), false, false);
component.add(editorFragmentComponent, BorderLayout.CENTER);
EditorFactory.getInstance().releaseEditor(uEditor);
}
final List<AnAction> actionList = ActionUtil.getActions(editorComponent);
final LightweightHint lightweightHint = new LightweightHint(component);
HintListener closeListener = new HintListener() {
public void hintHidden(final EventObject event) {
actionList.remove(rollback);
actionList.remove(showDiff);
actionList.remove(copyRange);
actionList.remove(localShowPrevAction);
actionList.remove(localShowNextAction);
}
};
lightweightHint.addHintListener(closeListener);
HintManagerImpl.getInstanceImpl().showEditorHint(lightweightHint, editor, point, HintManagerImpl.HIDE_BY_ANY_KEY | HintManagerImpl.HIDE_BY_TEXT_CHANGE |
HintManagerImpl.HIDE_BY_SCROLLING,
-1, false, new HintHint(editor, point));
if (!lightweightHint.isVisible()) {
closeListener.hintHidden(null);
}
}
private static String getFileName(final Document document) {
final VirtualFile file = FileDocumentManager.getInstance().getFile(document);
if (file == null) return "";
return file.getName();
}
public static void moveToRange(final Range range, final Editor editor, final LineStatusTracker tracker) {
final Document document = tracker.getDocument();
final int lastOffset = document.getLineStartOffset(Math.min(range.getLine2(), document.getLineCount() - 1));
editor.getCaretModel().moveToOffset(lastOffset);
editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
editor.getScrollingModel().runActionOnScrollingFinished(new Runnable() {
public void run() {
Point p = editor.visualPositionToXY(editor.offsetToVisualPosition(lastOffset));
final JComponent editorComponent = editor.getContentComponent();
final JLayeredPane layeredPane = editorComponent.getRootPane().getLayeredPane();
p = SwingUtilities.convertPoint(editorComponent, 0, p.y, layeredPane);
showActiveHint(range, editor, p, tracker);
}
});
}
private static Color getDiffColor(Range range, boolean gutter) {
final EditorColorsScheme globalScheme = EditorColorsManager.getInstance().getGlobalScheme();
switch (range.getType()) {
case Range.INSERTED:
return gutter ? globalScheme.getColor(EditorColors.ADDED_LINES_COLOR)
: globalScheme.getAttributes(DiffColors.DIFF_INSERTED).getErrorStripeColor();
case Range.DELETED:
return globalScheme.getAttributes(DiffColors.DIFF_DELETED).getErrorStripeColor();
case Range.MODIFIED:
return gutter ? globalScheme.getColor(EditorColors.MODIFIED_LINES_COLOR)
: globalScheme.getAttributes(DiffColors.DIFF_MODIFIED).getErrorStripeColor();
default:
assert false;
return null;
}
}
}