| /* |
| * 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; |
| } |
| } |
| } |