Merge branch 'merge_tool_dividers'

This commit is contained in:
Kirill Likhodedov
2012-07-17 15:30:42 +04:00
27 changed files with 879 additions and 195 deletions
@@ -117,15 +117,17 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable {
public static void setOrRefreshErrorStripeRenderer(@NotNull EditorMarkupModel editorMarkupModel, @NotNull Project project, Document document, PsiFile file) {
ApplicationManager.getApplication().assertIsDispatchThread();
ErrorStripeRenderer renderer = editorMarkupModel.getErrorStripeRenderer();
if (renderer instanceof TrafficLightRenderer) {
((TrafficLightRenderer)renderer).refresh();
((EditorMarkupModelImpl)editorMarkupModel).repaintVerticalScrollBar();
}
else {
renderer = new TrafficLightRenderer(project, document, file);
Disposer.register(((EditorImpl)editorMarkupModel.getEditor()).getDisposable(), (Disposable)renderer);
editorMarkupModel.setErrorStripeRenderer(renderer);
if (editorMarkupModel.isErrorStripeVisible()) {
ErrorStripeRenderer renderer = editorMarkupModel.getErrorStripeRenderer();
if (renderer instanceof TrafficLightRenderer) {
((TrafficLightRenderer)renderer).refresh();
((EditorMarkupModelImpl)editorMarkupModel).repaintVerticalScrollBar();
}
else {
renderer = new TrafficLightRenderer(project, document, file);
Disposer.register(((EditorImpl)editorMarkupModel.getEditor()).getDisposable(), (Disposable)renderer);
editorMarkupModel.setErrorStripeRenderer(renderer);
}
}
}
@@ -697,6 +697,11 @@ public class EditorWindow extends UserDataHolderBase implements EditorEx {
myDelegate.setVerticalScrollbarOrientation(type);
}
@Override
public int getVerticalScrollbarOrientation() {
return myDelegate.getVerticalScrollbarOrientation();
}
@Override
public void setVerticalScrollbarVisible(final boolean b) {
myDelegate.setVerticalScrollbarVisible(b);
@@ -784,6 +789,11 @@ public class EditorWindow extends UserDataHolderBase implements EditorEx {
myDelegate.setPurePaintingMode(enabled);
}
@Override
public void registerScrollBarRepaintCallback(@Nullable RepaintCallback callback) {
myDelegate.registerScrollBarRepaintCallback(callback);
}
@Override
public void setPrefixTextAndAttributes(@Nullable String prefixText, @Nullable TextAttributes attributes) {
myDelegate.setPrefixTextAndAttributes(prefixText, attributes);
@@ -40,6 +40,9 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
/**
* The panel from the Settings, that allows to see changes to diff/merge coloring scheme right away.
*/
public class DiffPreviewPanel implements PreviewPanel {
private final MergePanel2.AsComponent myMergePanelComponent;
private final JPanel myPanel = new JPanel(new BorderLayout());
@@ -51,10 +54,8 @@ public class DiffPreviewPanel implements PreviewPanel {
myPanel.add(myMergePanelComponent, BorderLayout.CENTER);
myMergePanelComponent.setToolbarEnabled(false);
MergePanel2 mergePanel = getMergePanel();
mergePanel.setEditorProperty(MergePanel2.LINE_NUMBERS, Boolean.FALSE);
mergePanel.setEditorProperty(MergePanel2.LINE_MARKERS_AREA, Boolean.FALSE);
mergePanel.setEditorProperty(MergePanel2.ADDITIONAL_LINES, 1);
mergePanel.setEditorProperty(MergePanel2.ADDITIONAL_COLUMNS, 1);
mergePanel.setShowLineNumbers(false);
mergePanel.setAdditionalLinesAndColumns(1, 1);
mergePanel.setScrollToFirstDiff(false);
for (int i = 0; i < MergePanel2.EDITORS_COUNT; i++) {
@@ -102,7 +103,7 @@ public class DiffPreviewPanel implements PreviewPanel {
public void setColorScheme(final EditorColorsScheme highlighterSettings) {
getMergePanel().setColorScheme(highlighterSettings);
getMergePanel().setEditorProperty(MergePanel2.HIGHLIGHTER_SETTINGS, highlighterSettings);
getMergePanel().setHighlighterSettings(highlighterSettings);
}
private class EditorMouseListener extends EditorMouseMotionAdapter {
@@ -15,6 +15,8 @@
*/
package com.intellij.openapi.actionSystem;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
/**
@@ -26,11 +28,11 @@ public abstract class ToggleAction extends AnAction implements Toggleable {
public ToggleAction(){
}
public ToggleAction(final String text){
public ToggleAction(@Nullable final String text){
super(text);
}
public ToggleAction(final String text, final String description, final Icon icon){
public ToggleAction(@Nullable final String text, @Nullable final String description, @Nullable final Icon icon){
super(text, description, icon);
}
@@ -17,7 +17,10 @@ package com.intellij.openapi.diff.impl;
import com.intellij.ide.actions.EditSourceAction;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.CommonShortcuts;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
@@ -68,13 +71,13 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseListener;
import java.security.InvalidParameterException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSidesContainer {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.DiffPanelImpl");
public static final int DIFF_DIVIDER_POLYGONS_OFFSET = 3;
private final DiffSplitterI mySplitter;
private final DiffPanelOuterComponent myPanel;
@@ -127,7 +130,7 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid
if (horizontal) {
mySplitter = new DiffSplitter(myLeftSide.getComponent(), myRightSide.getComponent(),
new DiffDividerPaint(this, FragmentSide.SIDE1), myData);
new DiffDividerPaint(this, FragmentSide.SIDE1, DIFF_DIVIDER_POLYGONS_OFFSET), myData);
}
else {
mySplitter = new HorizontalDiffSplitter(myLeftSide.getComponent(), myRightSide.getComponent());
@@ -32,10 +32,12 @@ import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.FrameWrapper;
import com.intellij.util.ImageLoader;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
public class DiffUtil {
private DiffUtil() {
@@ -94,4 +96,9 @@ public class DiffUtil {
editor.getGutterComponentEx().revalidateMarkup();
return editor;
}
public static void drawBoldDottedFramingLines(Graphics2D g, int startX, int endX, int startY, int bottomY, Color color) {
UIUtil.drawBoldDottedLine(g, startX, endX, startY, null, color, false);
UIUtil.drawBoldDottedLine(g, startX, endX, bottomY, null, color, false);
}
}
@@ -17,13 +17,16 @@ package com.intellij.openapi.diff.impl.incrementalMerge;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.impl.DiffUtil;
import com.intellij.openapi.diff.impl.splitter.DividerPolygon;
import com.intellij.openapi.diff.impl.util.GutterActionRenderer;
import com.intellij.openapi.diff.impl.util.TextDiffType;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.markup.HighlighterTargetArea;
import com.intellij.openapi.editor.markup.MarkupModel;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
import com.intellij.openapi.editor.markup.*;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -78,6 +81,7 @@ class ChangeHighlighterHolder {
RangeHighlighter highlighter = getMarkupModel().addLineHighlighter(line, layer, null);
highlighter.setLineSeparatorColor(diffType.getTextBackground(myEditor));
highlighterCreated(highlighter, diffType.getTextAttributes(myEditor), applied);
highlighter.setLineMarkerRenderer(new ChangesColoringLineMarkerRenderer(diffType));
return highlighter;
}
@@ -88,6 +92,7 @@ class ChangeHighlighterHolder {
TextAttributes attributes = type.getTextAttributes(myEditor);
RangeHighlighter highlighter = getMarkupModel().addRangeHighlighter(start, end, layer, attributes, targetArea);
highlighterCreated(highlighter, attributes, applied);
highlighter.setLineMarkerRenderer(new ChangesColoringLineMarkerRenderer(type));
return highlighter;
}
@@ -131,7 +136,7 @@ class ChangeHighlighterHolder {
if (myMainHighlighter != null && myActions != null && myActions.length > 0) {
myActionHighlighters = new RangeHighlighter[myActions.length];
for (int i = 0; i < myActionHighlighters.length; i++) {
RangeHighlighter highlighter = cloneMainHighlighter(myMainHighlighter);
RangeHighlighterEx highlighter = (RangeHighlighterEx)cloneMainHighlighter(myMainHighlighter);
highlighter.setGutterIconRenderer(new GutterActionRenderer(myActions[i]));
myActionHighlighters[i] = highlighter;
}
@@ -148,4 +153,45 @@ class ChangeHighlighterHolder {
removeHighlighters();
setHighlighter(changeSide, type);
}
/**
* Expands the change highlighters to the editor's gutter.
*/
private class ChangesColoringLineMarkerRenderer implements LineMarkerRenderer {
private final TextDiffType myDiffType;
public ChangesColoringLineMarkerRenderer(@NotNull TextDiffType diffType) {
myDiffType = diffType;
}
@Override
public void paint(Editor editor, Graphics g, Rectangle range) {
Color color = myDiffType.getPolygonColor(myEditor);
if (color == null) {
return;
}
EditorGutterComponentEx gutter = ((EditorEx)editor).getGutterComponentEx();
Graphics2D g2 = (Graphics2D)g;
int x = 0;
int y = range.y;
int width = gutter.getWidth();
int height = range.height;
if (!myDiffType.isApplied()) {
if (height > 2) {
g.setColor(color);
g.fillRect(x, y, width, height);
UIUtil.drawFramingLines(g2, x, x + width, y - 1, y + height - 1, DividerPolygon.FRAMING_LINE_COLOR);
}
else {
// insertion or deletion, when a range is null, and the text highlighter is a 2 pixel line
UIUtil.drawFramingLines(g2, x, x + width, y - 1, y + height, color);
}
}
else {
DiffUtil.drawBoldDottedFramingLines(g2, x, x + width, y - 1, y + height - 1, color);
}
}
}
}
@@ -16,7 +16,6 @@
package com.intellij.openapi.diff.impl.incrementalMerge;
import com.intellij.openapi.diff.ex.DiffFragment;
import com.intellij.openapi.diff.impl.highlighting.LineRenderer;
import com.intellij.openapi.diff.impl.util.TextDiffType;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.markup.*;
@@ -38,6 +37,8 @@ public class ChangeType {
private final TextDiffType myDiffType;
private final boolean myApplied;
private static final EmptyRangeLineSeparatorRenderer EMPTY_RANGE_LINE_SEPARATOR_RENDERER = new EmptyRangeLineSeparatorRenderer();
private ChangeType(TextDiffType diffType, boolean applied) {
myApplied = applied;
if (applied) {
@@ -79,32 +80,32 @@ public class ChangeType {
}
@Nullable
private RangeHighlighter addBlock(String text, ChangeSide changeSide, ChangeHighlighterHolder markup, TextDiffType diffType) {
private RangeHighlighter addBlock(String text, ChangeSide changeSide, final ChangeHighlighterHolder markup, TextDiffType diffType) {
EditorColorsScheme colorScheme = markup.getEditor().getColorsScheme();
Color separatorColor = getSeparatorColor(diffType.getLegendColor(colorScheme));
LineSeparatorRenderer separatorRenderer = new LineSeparatorRenderer() {
@Override
public void drawLine(Graphics g, int x1, int x2, int y) {
Graphics2D g2 = (Graphics2D) g;
if (myApplied) {
UIUtil.drawBoldDottedLine(g2, x1, x2, y, g2.getBackground(), g2.getColor(), false);
}
else {
UIUtil.drawDottedLine(g2, x1, y, x2, y, g2.getBackground(), g2.getColor());
}
}
};
int length = text.length();
int start = changeSide.getStart();
int end = start + length;
RangeHighlighter highlighter = markup.addRangeHighlighter(start, end, LAYER, diffType, HighlighterTargetArea.EXACT_RANGE, myApplied);
LineSeparatorRenderer lineSeparatorRenderer = new LineSeparatorRenderer() {
@Override
public void drawLine(Graphics g, int x1, int x2, int y) {
Graphics2D g2 = (Graphics2D)g;
if (myApplied) {
UIUtil.drawBoldDottedLine(g2, x1, x2, y, null, myDiffType.getPolygonColor(markup.getEditor()), false);
}
else {
UIUtil.drawDottedLine(g2, x1, y, x2, y, null, g2.getColor());
}
}
};
if (highlighter != null) {
highlighter.setLineSeparatorPlacement(SeparatorPlacement.TOP);
highlighter.setLineSeparatorColor(separatorColor);
highlighter.setLineSeparatorRenderer(separatorRenderer);
highlighter.setLineMarkerRenderer(LineRenderer.top());
highlighter.setLineSeparatorRenderer(lineSeparatorRenderer);
}
if (text.charAt(length - 1) == '\n') {
@@ -115,8 +116,7 @@ public class ChangeType {
if (highlighter != null) {
highlighter.setLineSeparatorPlacement(SeparatorPlacement.BOTTOM);
highlighter.setLineSeparatorColor(separatorColor);
highlighter.setLineSeparatorRenderer(separatorRenderer);
highlighter.setLineMarkerRenderer(LineRenderer.bottom());
highlighter.setLineSeparatorRenderer(lineSeparatorRenderer);
}
return highlighter;
}
@@ -128,6 +128,7 @@ public class ChangeType {
return null;
}
highlighter.setLineSeparatorPlacement(placement);
highlighter.setLineSeparatorRenderer(EMPTY_RANGE_LINE_SEPARATOR_RENDERER);
return highlighter;
}
@@ -156,4 +157,15 @@ public class ChangeType {
}
/**
* Insertion or deletion change have an empty range on one of the sides (inserting to, deleting from).
* A solid line is used to indicate this change in the target/original editor.
*/
private static class EmptyRangeLineSeparatorRenderer implements LineSeparatorRenderer {
@Override
public void drawLine(Graphics g, int x1, int x2, int y) {
g.drawLine(x1, y, x2, y);
g.drawLine(x1, y + 1, x2, y + 1);
}
}
}
@@ -17,26 +17,103 @@ package com.intellij.openapi.diff.impl.incrementalMerge.ui;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.impl.DiffUtil;
import com.intellij.openapi.diff.impl.highlighting.FragmentSide;
import com.intellij.openapi.diff.impl.splitter.DividerPolygon;
import com.intellij.openapi.diff.impl.util.DiffDivider;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.ex.EditorEx;
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.ArrayList;
public class EditorPlace extends JComponent implements Disposable {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.incrementalMerge.ui.EditorPlace");
private final ComponentState myState;
private final ArrayList<EditorListener> myListeners = new ArrayList<EditorListener>();
private Editor myEditor = null;
/**
* 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 {
private static final Logger LOG = Logger.getInstance(EditorPlace.class);
public EditorPlace(ComponentState state) {
@NotNull private final MergePanel2.DiffEditorState myState;
@NotNull private final MergePanelColumn myColumn;
@NotNull private final MergePanel2 myMergePanel;
@NotNull private final ArrayList<EditorListener> myListeners = new ArrayList<EditorListener>();
@Nullable private EditorEx myEditor;
public EditorPlace(@NotNull MergePanel2.DiffEditorState state, @NotNull MergePanelColumn column, @NotNull MergePanel2 mergePanel) {
myState = state;
myColumn = column;
myMergePanel = mergePanel;
setLayout(new BorderLayout());
}
@Override
public void paint(Graphics g) {
super.paint(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 (height == 0) { // draw at least a one-pixel line (e.g. for insertion or deletion), as it is done in highlighters
height = 1;
}
drawPolygonAboveScrollBar((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;
if (!applied) {
if (height > 2) {
g.fillRect(startX, startY, scrollBar.getWidth(), height);
UIUtil.drawFramingLines(g, startX, endX, startY, startY + height, DividerPolygon.FRAMING_LINE_COLOR);
}
else {
UIUtil.drawFramingLines(g, startX, endX, startY, startY + height, color);
}
}
else {
DiffUtil.drawBoldDottedFramingLines(g, startX, endX, startY, startY + height, color);
}
}
public void addNotify() {
if (myEditor != null) {
super.addNotify();
@@ -52,6 +129,9 @@ public class EditorPlace extends JComponent implements Disposable {
myEditor = myState.createEditor();
if (myEditor == null) return;
add(myEditor.getComponent(), BorderLayout.CENTER);
myEditor.registerScrollBarRepaintCallback(this);
repaint();
fireEditorCreated();
}
@@ -86,6 +166,7 @@ public class EditorPlace extends JComponent implements Disposable {
private void removeEditor() {
if (myEditor != null) {
myEditor.registerScrollBarRepaintCallback(null);
Editor releasedEditor = myEditor;
remove(myEditor.getComponent());
getEditorFactory().releaseEditor(myEditor);
@@ -94,6 +175,7 @@ public class EditorPlace extends JComponent implements Disposable {
}
}
@Nullable
public Editor getEditor() {
return myEditor;
}
@@ -109,25 +191,11 @@ public class EditorPlace extends JComponent implements Disposable {
return myState.getDocument();
}
public ComponentState getState() {
@NotNull
public MergePanel2.DiffEditorState getState() {
return myState;
}
public abstract static class ComponentState {
private Document myDocument;
public abstract Editor createEditor();
public void setDocument(Document document) {
myDocument = document;
}
public Document getDocument() {
return myDocument;
}
public abstract <T> void updateValue(Editor editor, ViewProperty<T> property, T value);
}
public interface EditorListener {
void onEditorCreated(EditorPlace place);
void onEditorReleased(Editor releasedEditor);
@@ -137,27 +205,11 @@ public class EditorPlace extends JComponent implements Disposable {
return EditorFactory.getInstance();
}
@Nullable
public JComponent getContentComponent() {
return myEditor == null ? null : myEditor.getContentComponent();
}
public abstract static class ViewProperty<T> {
private final T myDefault;
protected ViewProperty(T aDefault) {
myDefault = aDefault;
}
public void updateEditor(Editor editor, T value, ComponentState state) {
if (editor == null) return;
if (value == null) value = myDefault;
EditorEx editorEx = (EditorEx)editor;
doUpdateEditor(editorEx, value, state);
}
protected abstract void doUpdateEditor(EditorEx editorEx, T value, ComponentState state);
}
public void dispose() {
removeEditor();
}
@@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.*;
import com.intellij.openapi.diff.actions.NextDiffAction;
@@ -51,11 +52,10 @@ import com.intellij.openapi.ui.LabeledComponent;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.EditorNotificationPanel;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
import com.intellij.util.diff.FilesTooBigForDiffException;
import gnu.trove.TIntHashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -101,7 +101,7 @@ public class MergePanel2 implements DiffViewer {
}
};
for (int i = 0; i < EDITORS_COUNT; i++) {
EditorPlace editorPlace = new EditorPlace(new DiffEditorState(i));
EditorPlace editorPlace = new EditorPlace(new DiffEditorState(i), indexToColumn(i), this);
Disposer.register(parent, editorPlace);
editorPlaces.add(editorPlace);
editorPlace.addListener(placeListener);
@@ -110,70 +110,74 @@ public class MergePanel2 implements DiffViewer {
myEditorsPanels[i].setComponent(editorPlace);
}
FontSizeSynchronizer.attachTo(editorPlaces);
myPanel = new DiffPanelOuterComponent(TextDiffType.MERGE_TYPES, TOOLBAR);
myPanel = new DiffPanelOuterComponent(TextDiffType.MERGE_TYPES, createToolbar());
myPanel.insertDiffComponent(new ThreePanels(myEditorsPanels, myDividers), new MyScrollingPanel());
myProvider = new MyDataProvider();
myPanel.setDataProvider(myProvider);
myBuilder = builder;
}
private static final EditorPlace.ViewProperty<EditorColorsScheme> EDITOR_SCHEME = new EditorPlace.ViewProperty<EditorColorsScheme>(null) {
public void doUpdateEditor(EditorEx editorEx, EditorColorsScheme scheme, EditorPlace.ComponentState state) {
if (scheme != null) editorEx.setColorsScheme(scheme);
/**
* Convert legacy-style editor (or panel) number to the {@link MergePanelColumn}.
* @param i 0, 1 or 2
* @return Left, base or right, respectively.
*/
private static MergePanelColumn indexToColumn(int i) {
switch (i) {
case 0: return MergePanelColumn.LEFT;
case 1: return MergePanelColumn.BASE;
case 2: return MergePanelColumn.RIGHT;
default: throw new IllegalStateException("Incorrect value for a merge column: " + i);
}
};
public static final EditorPlace.ViewProperty<Boolean> LINE_NUMBERS = new EditorPlace.ViewProperty<Boolean>(Boolean.TRUE) {
public void doUpdateEditor(EditorEx editorEx, Boolean aBoolean, EditorPlace.ComponentState state) {
editorEx.getSettings().setLineNumbersShown(aBoolean.booleanValue());
}
};
public static final EditorPlace.ViewProperty<Boolean> LINE_MARKERS_AREA = new EditorPlace.ViewProperty<Boolean>(Boolean.TRUE) {
public void doUpdateEditor(EditorEx editorEx, Boolean aBoolean, EditorPlace.ComponentState state) {
editorEx.getSettings().setLineMarkerAreaShown(aBoolean.booleanValue());
}
};
public static final EditorPlace.ViewProperty<Integer> ADDITIONAL_LINES = new EditorPlace.ViewProperty<Integer>(null) {
public void doUpdateEditor(EditorEx editorEx, Integer integer, EditorPlace.ComponentState state) {
if (integer != null) editorEx.getSettings().setAdditionalLinesCount(integer.intValue());
}
};
public static final EditorPlace.ViewProperty<Integer> ADDITIONAL_COLUMNS = new EditorPlace.ViewProperty<Integer>(null) {
public void doUpdateEditor(EditorEx editorEx, Integer integer, EditorPlace.ComponentState state) {
if (integer != null) editorEx.getSettings().setAdditionalColumnsCount(integer.intValue());
}
};
public static final EditorPlace.ViewProperty<EditorColorsScheme> HIGHLIGHTER_SETTINGS =
new EditorPlace.ViewProperty<EditorColorsScheme>(null) {
public void doUpdateEditor(EditorEx editorEx, EditorColorsScheme settings, EditorPlace.ComponentState state) {
if (settings == null) settings = EditorColorsManager.getInstance().getGlobalScheme();
DiffEditorState editorState = (DiffEditorState)state;
editorEx.setHighlighter(
EditorHighlighterFactory.getInstance().createEditorHighlighter(editorState.getFileType(), settings, editorState.getProject()));
}
@NotNull
private DiffRequest.ToolbarAddons createToolbar() {
return new DiffRequest.ToolbarAddons() {
public void customize(DiffToolbar toolbar) {
ActionManager actionManager = ActionManager.getInstance();
toolbar.addAction(actionManager.getAction(IdeActions.ACTION_COPY));
toolbar.addAction(actionManager.getAction(IdeActions.ACTION_FIND));
toolbar.addAction(PreviousDiffAction.find());
toolbar.addAction(NextDiffAction.find());
toolbar.addSeparator();
toolbar.addAction(new OpenPartialDiffAction(1, 0, AllIcons.Diff.LeftDiff));
toolbar.addAction(new OpenPartialDiffAction(1, 2, AllIcons.Diff.RightDiff));
toolbar.addAction(new OpenPartialDiffAction(0, 2, AllIcons.Diff.BranchDiff));
toolbar.addSeparator();
toolbar.addAction(new ApplyNonConflicts());
toolbar.addSeparator();
toolbar.addAction(new MergeToolSettingsAction(getEditors()));
}
};
private static final Collection<EditorPlace.ViewProperty> ALL_PROPERTIES = Arrays.<EditorPlace.ViewProperty>asList
(ADDITIONAL_COLUMNS, ADDITIONAL_LINES, EDITOR_SCHEME, HIGHLIGHTER_SETTINGS, LINE_MARKERS_AREA, LINE_NUMBERS);
}
private static final DiffRequest.ToolbarAddons TOOLBAR = new DiffRequest.ToolbarAddons() {
public void customize(DiffToolbar toolbar) {
ActionManager actionManager = ActionManager.getInstance();
toolbar.addAction(actionManager.getAction(IdeActions.ACTION_COPY));
toolbar.addAction(actionManager.getAction(IdeActions.ACTION_FIND));
toolbar.addAction(PreviousDiffAction.find());
toolbar.addAction(NextDiffAction.find());
toolbar.addSeparator();
toolbar.addAction(new OpenPartialDiffAction(1, 0, AllIcons.Diff.LeftDiff));
toolbar.addAction(new OpenPartialDiffAction(1, 2, AllIcons.Diff.RightDiff));
toolbar.addAction(new OpenPartialDiffAction(0, 2, AllIcons.Diff.BranchDiff));
toolbar.addSeparator();
toolbar.addAction(new ApplyNonConflicts());
@NotNull
private Collection<Editor> getEditors() {
Collection<Editor> editors = new ArrayList<Editor>(3);
for (EditorPlace place : getEditorPlaces()) {
editors.add(place.getEditor());
}
};
return editors;
}
@NotNull
private Collection<EditorPlace> getEditorPlaces() {
Collection<EditorPlace> editorPlaces = new ArrayList<EditorPlace>(3);
for (LabeledComponent editorsPanel : myEditorsPanels) {
editorPlaces.add((EditorPlace) editorsPanel.getComponent());
}
return editorPlaces;
}
public void setScrollToFirstDiff(final boolean scrollToFirstDiff) {
myScrollToFirstDiff = scrollToFirstDiff;
}
/**
* @deprecated Because it references by index.
*/
@Deprecated
public Editor getEditor(int index) {
return getEditorPlace(index).getEditor();
}
@@ -182,10 +186,18 @@ public class MergePanel2 implements DiffViewer {
return myData == null ? FileTypes.PLAIN_TEXT : getContentType(myData);
}
/**
* @deprecated Because it references by index.
*/
@Deprecated
public String getVersionTitle(int index) {
return myEditorsPanels[index].getRawText();
}
/**
* @deprecated Because it references by index.
*/
@Deprecated
public EditorPlace getEditorPlace(int index) {
return (EditorPlace)myEditorsPanels[index].getComponent();
}
@@ -194,7 +206,9 @@ public class MergePanel2 implements DiffViewer {
if (myData == null) return;
DiffContent[] contents = myData.getContents();
for (int i = 0; i < EDITORS_COUNT; i++) {
getEditorPlace(i).setDocument(contents[i].getDocument());
EditorPlace editorPlace = getEditorPlace(i);
editorPlace.setDocument(contents[i].getDocument());
setHighlighterSettings(null, editorPlace);
}
tryInitView();
}
@@ -209,8 +223,9 @@ public class MergePanel2 implements DiffViewer {
Editor left = getEditor(0);
Editor base = getEditor(1);
Editor right = getEditor(2);
myMergeList.setMarkups(left, base, right);
EditingSides[] sides = {new MyEditingSides(FragmentSide.SIDE1), new MyEditingSides(FragmentSide.SIDE2)};
EditingSides[] sides = {getFirstEditingSide(), getSecondEditingSide()};
myScrollSupport.install(sides);
for (int i = 0; i < myDividers.length; i++) {
myDividers[i].listenEditors(sides[i]);
@@ -228,6 +243,54 @@ public class MergePanel2 implements DiffViewer {
}
}
@NotNull
EditingSides getFirstEditingSide() {
return new MyEditingSides(FragmentSide.SIDE1);
}
@NotNull
EditingSides getSecondEditingSide() {
return new MyEditingSides(FragmentSide.SIDE2);
}
public void setHighlighterSettings(@Nullable EditorColorsScheme settings) {
for (EditorPlace place : getEditorPlaces()) {
setHighlighterSettings(settings, place);
}
}
private void setHighlighterSettings(@Nullable EditorColorsScheme settings, @NotNull EditorPlace place) {
if (settings == null) {
settings = EditorColorsManager.getInstance().getGlobalScheme();
}
Editor editor = place.getEditor();
DiffEditorState editorState = place.getState();
((EditorEx)editor).setHighlighter(EditorHighlighterFactory.getInstance().
createEditorHighlighter(editorState.getFileType(), settings, editorState.getProject()));
}
public void setAdditionalLinesAndColumns(int lines, int columns) {
for (Editor editor : getEditors()) {
editor.getSettings().setAdditionalLinesCount(lines);
editor.getSettings().setAdditionalColumnsCount(columns);
}
}
public void setShowLineNumbers(boolean show) {
for (Editor editor : getEditors()) {
MergeToolEditorSetting.LINE_NUMBERS.apply(editor, show);
}
}
private static void initEditorSettings(@NotNull Editor editor) {
Project project = editor.getProject();
MergeToolSettings settings = project == null ? null : ServiceManager.getService(project, MergeToolSettings.class);
for (MergeToolEditorSetting property : MergeToolEditorSetting.values()) {
property.apply(editor, settings == null ? property.getDefault() : settings.getPreference(property));
}
editor.getSettings().setLineMarkerAreaShown(true);
}
private void disposeMergeList() {
if (myMergeList == null) return;
if (myStatusUpdater != null) {
@@ -361,15 +424,24 @@ public class MergePanel2 implements DiffViewer {
}
}
private class DiffEditorState extends EditorPlace.ComponentState {
private final HashMap<EditorPlace.ViewProperty, Object> myProperties = new HashMap<EditorPlace.ViewProperty, Object>();
class DiffEditorState {
private final int myIndex;
private Document myDocument;
private DiffEditorState(int index) {
myIndex = index;
}
public Editor createEditor() {
public void setDocument(Document document) {
myDocument = document;
}
public Document getDocument() {
return myDocument;
}
@Nullable
public EditorEx createEditor() {
Document document = getDocument();
if (document == null) return null;
Project project = myData.getProject();
@@ -382,20 +454,12 @@ public class MergePanel2 implements DiffViewer {
if (myIndex != 1) ((EditorMarkupModel)editor.getMarkupModel()).setErrorStripeVisible(true);
editor.getSettings().setFoldingOutlineShown(false);
editor.getFoldingModel().setFoldingEnabled(false);
HashSet<EditorPlace.ViewProperty> notProcessedDefaults = new HashSet<EditorPlace.ViewProperty>(ALL_PROPERTIES);
for (EditorPlace.ViewProperty viewProperty : myProperties.keySet()) {
notProcessedDefaults.remove(viewProperty);
viewProperty.updateEditor(editor, myProperties.get(viewProperty), this);
}
for (EditorPlace.ViewProperty viewProperty : notProcessedDefaults) {
viewProperty.updateEditor(editor, null, this);
}
return editor;
}
editor.getSettings().setLineMarkerAreaShown(false);
editor.getSettings().setFoldingOutlineShown(false);
editor.getGutterComponentEx().setShowDefaultGutterPopup(false);
initEditorSettings(editor);
public <T> void updateValue(Editor editor, EditorPlace.ViewProperty<T> property, T value) {
myProperties.put(property, value);
property.updateEditor(editor, value, this);
return editor;
}
public FileType getFileType() {
@@ -485,15 +549,10 @@ public class MergePanel2 implements DiffViewer {
return myMergeList;
}
public <T> void setEditorProperty(EditorPlace.ViewProperty<T> property, T value) {
for (int i = 0; i < EDITORS_COUNT; i++) {
EditorPlace editorPlace = getEditorPlace(i);
editorPlace.getState().updateValue(editorPlace.getEditor(), property, value);
}
}
public void setColorScheme(EditorColorsScheme scheme) {
setEditorProperty(EDITOR_SCHEME, scheme);
for (Editor editor : getEditors()) {
((EditorEx)editor).setColorsScheme(scheme);
}
myPanel.setColorScheme(scheme);
}
@@ -0,0 +1,31 @@
/*
* 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.diff.impl.incrementalMerge.ui;
import com.intellij.openapi.diff.impl.highlighting.FragmentSide;
/**
* Represents one of three columns in the 3-way merge.
* To be used when specific column code is needed.
*
* Little by little, this should substitute all legacy code, that references merge columns by digital indexes from 1 to 3 or from 0 to 2,
* as well as by {@link FragmentSide FragmentSides}.
*
* @author Kirill Likhodedov
*/
public enum MergePanelColumn {
LEFT, BASE, RIGHT
}
@@ -0,0 +1,73 @@
/*
* 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.diff.impl.incrementalMerge.ui;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ex.EditorEx;
/**
* <p>
* Properties of the editors used in the merge tool. Most of them are customizable by the user.
* </p>
*
* @author Kirill Likhodedov
* @see MergeToolSettings
*/
enum MergeToolEditorSetting {
WHITESPACES(false) {
@Override
protected void apply(Editor editor, boolean state) {
editor.getSettings().setWhitespacesShown(state);
editor.getComponent().repaint();
}
},
LINE_NUMBERS(false) {
@Override
protected void apply(Editor editor, boolean state) {
editor.getSettings().setLineNumbersShown(state);
editor.getComponent().repaint();
}
},
INDENT_LINES(false) {
@Override
protected void apply(Editor editor, boolean state) {
editor.getSettings().setIndentGuidesShown(state);
editor.getComponent().repaint();
}
},
SOFT_WRAPS(false) {
@Override
protected void apply(Editor editor, boolean state) {
editor.getSettings().setUseSoftWraps(state);
if (editor instanceof EditorEx) {
((EditorEx)editor).reinitSettings();
}
}
};
private final boolean myDefault;
MergeToolEditorSetting(boolean aDefault) {
myDefault = aDefault;
}
protected abstract void apply(Editor editor, boolean state);
boolean getDefault() {
return myDefault;
}
}
@@ -0,0 +1,114 @@
/*
* 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.diff.impl.incrementalMerge.ui;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
import org.jetbrains.annotations.NotNull;
/**
* Workspace-wide settings for merge tool UI customization.
*
* @author Kirill Likhodedov
*/
@State(name = "MergeToolSettings", storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)})
public class MergeToolSettings implements PersistentStateComponent<MergeToolSettings.State> {
private State myState = new State();
public static class State {
public boolean WHITESPACES = false;
public boolean LINE_NUMBERS = true;
public boolean INDENT_LINES = false;
public boolean SOFT_WRAPS = false;
}
@Override
public State getState() {
return myState;
}
@Override
public void loadState(State state) {
myState = state;
}
public void setPreference(@NotNull MergeToolEditorSetting setting, boolean state) {
switch (setting) {
case WHITESPACES:
setShowWhiteSpaces(state);
break;
case LINE_NUMBERS:
setShowLineNumbers(state);
break;
case INDENT_LINES:
setShowIndentLines(state);
break;
case SOFT_WRAPS:
setUseSoftWraps(state);
break;
}
}
public boolean getPreference(@NotNull MergeToolEditorSetting setting) {
switch (setting) {
case WHITESPACES:
return isShowWhitespaces();
case LINE_NUMBERS:
return isShowLineNumbers();
case INDENT_LINES:
return isShowIndentLines();
case SOFT_WRAPS:
return isUseSoftWraps();
}
return false;
}
public void setShowLineNumbers(boolean state) {
myState.LINE_NUMBERS = state;
}
public boolean isShowLineNumbers() {
return myState.LINE_NUMBERS;
}
public void setShowWhiteSpaces(boolean state) {
myState.WHITESPACES = state;
}
public boolean isShowWhitespaces() {
return myState.WHITESPACES;
}
public void setShowIndentLines(boolean state) {
myState.INDENT_LINES = state;
}
public boolean isShowIndentLines() {
return myState.INDENT_LINES;
}
public void setUseSoftWraps(boolean state) {
myState.SOFT_WRAPS = state;
}
public boolean isUseSoftWraps() {
return myState.SOFT_WRAPS;
}
}
@@ -0,0 +1,126 @@
/*
* 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.diff.impl.incrementalMerge.ui;
import com.intellij.icons.AllIcons;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.impl.content.ToolWindowContentUi;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.util.Collection;
/**
* The "gear" action allowing to configure merge tool visual preferences, such as displaying whitespaces, line numbers and soft wraps.
*
* @author Kirill Likhodedov
* @see MergeToolSettings
*/
class MergeToolSettingsAction extends AnAction {
private final Collection<Editor> myEditors;
private final ActionGroup myActionGroup;
MergeToolSettingsAction(@NotNull Collection<Editor> editors) {
super(AllIcons.General.Gear);
myEditors = editors;
myActionGroup = new MergeToolActionGroup();
}
@Override
public void actionPerformed(AnActionEvent e) {
InputEvent inputEvent = e.getInputEvent();
ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(ToolWindowContentUi.POPUP_PLACE, myActionGroup);
int x = 0;
int y = 0;
if (inputEvent instanceof MouseEvent) {
x = ((MouseEvent)inputEvent).getX();
y = ((MouseEvent)inputEvent).getY();
}
popupMenu.getComponent().show(inputEvent.getComponent(), x, y);
}
private class MergeToolActionGroup extends ActionGroup {
@NotNull
@Override
public AnAction[] getChildren(@Nullable AnActionEvent e) {
return new AnAction[] {
new MergeToolToggleAction("EditorToggleShowWhitespaces", MergeToolEditorSetting.WHITESPACES, myEditors),
new MergeToolToggleAction("EditorToggleShowLineNumbers", MergeToolEditorSetting.LINE_NUMBERS, myEditors),
new MergeToolToggleAction("EditorToggleShowIndentLines", MergeToolEditorSetting.INDENT_LINES, myEditors),
new MergeToolToggleAction("EditorToggleUseSoftWraps", MergeToolEditorSetting.SOFT_WRAPS, myEditors)
};
}
}
/**
* Common class for all actions toggling merge tool editor settings.
*/
private static class MergeToolToggleAction extends ToggleAction {
private final MergeToolEditorSetting mySetting;
private final Collection<Editor> myEditors;
private MergeToolToggleAction(String actionId, MergeToolEditorSetting setting, Collection<Editor> editors) {
super(ActionsBundle.actionText(actionId), ActionsBundle.actionDescription(actionId), null);
mySetting = setting;
myEditors = editors;
}
@Override
public boolean isSelected(AnActionEvent e) {
return getPreference(e, mySetting);
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
setPreference(e, mySetting, state);
for (Editor editor : myEditors) {
mySetting.apply(editor, state);
}
}
private static void setPreference(AnActionEvent event, MergeToolEditorSetting preference, boolean state) {
MergeToolSettings settings = getSettings(event.getProject());
if (settings != null) {
settings.setPreference(preference, state);
}
}
private static boolean getPreference(AnActionEvent event, MergeToolEditorSetting preference) {
MergeToolSettings settings = getSettings(event.getProject());
if (settings != null) {
return settings.getPreference(preference);
}
return false;
}
@Nullable
private static MergeToolSettings getSettings(@Nullable Project project) {
if (project != null) {
return ServiceManager.getService(project, MergeToolSettings.class);
}
return null;
}
}
}
@@ -236,7 +236,7 @@ public class MergeRequestImpl extends MergeRequest {
}
}
private class AllResolvedListener implements ChangeCounter.Listener, Runnable {
private static class AllResolvedListener implements ChangeCounter.Listener, Runnable {
private final MergePanel2 myMergePanel;
private final DialogWrapper myDialogWrapper;
private boolean myWasInvoked = false;
@@ -255,7 +255,7 @@ public class MergeRequestImpl extends MergeRequest {
myWasInvoked = true;
ChangeCounter.getOrCreate(myMergePanel.getMergeList()).removeListener(this);
int doApply = Messages
.showOkCancelDialog(getProject(), DiffBundle.message("merge.all.changes.have.processed.save.and.finish.confirmation.text"),
.showOkCancelDialog(getWholePanel(), DiffBundle.message("merge.all.changes.have.processed.save.and.finish.confirmation.text"),
DiffBundle.message("all.changes.processed.dialog.title"),
DiffBundle.message("merge.save.and.finish.button"), DiffBundle.message("merge.continue.button"),
Messages.getQuestionIcon());
@@ -24,10 +24,12 @@ import java.awt.*;
public class DiffDividerPaint {
private final EditingSides mySides;
private final FragmentSide myLeftSide;
private final int myDiffDividerPolygonsOffset;
public DiffDividerPaint(EditingSides sides, FragmentSide leftSide) {
public DiffDividerPaint(EditingSides sides, FragmentSide leftSide, int diffDividerPolygonsOffset) {
mySides = sides;
myLeftSide = leftSide;
myDiffDividerPolygonsOffset = diffDividerPolygonsOffset;
}
public void paint(Graphics g, JComponent component) {
@@ -36,7 +38,7 @@ public class DiffDividerPaint {
int height = component.getHeight();
int editorHeight = mySides.getEditor(myLeftSide).getComponent().getHeight();
Graphics2D gg = (Graphics2D)g.create(0, height - editorHeight, width, editorHeight);
DividerPolygon.paintPolygons(DividerPolygon.createVisiblePolygons(mySides, myLeftSide), gg, width);
DividerPolygon.paintPolygons(DividerPolygon.createVisiblePolygons(mySides, myLeftSide, myDiffDividerPolygonsOffset), gg, width);
gg.dispose();
}
@@ -26,15 +26,22 @@ import com.intellij.util.ui.UIUtil;
import java.awt.*;
import java.util.ArrayList;
/**
* A polygon, which is drawn between editors in merge or diff dialogs, and which indicates the change flow from one editor to another.
*/
public class DividerPolygon {
public static final int OFFSET = 3;
public static final int TRANSPARENCY = 150;
public static final Color FRAMING_LINE_COLOR = Color.LIGHT_GRAY;
private final Color myColor;
private final int myStart1;
private final int myStart2;
private final int myEnd1;
private final int myEnd2;
private final boolean myApplied;
public DividerPolygon(int start1, int start2, int end1, int end2, Color color) {
public DividerPolygon(int start1, int start2, int end1, int end2, Color color, boolean applied) {
myApplied = applied;
myStart1 = advance(start1);
myStart2 = advance(start2);
myEnd1 = advance(end1);
@@ -47,11 +54,20 @@ public class DividerPolygon {
}
private void paint(Graphics2D g, int width) {
g.setColor(myColor);
g.fill(new Polygon(new int[]{0, 0, width, width}, new int[]{myStart1, myEnd1, myEnd2, myStart2}, 4));
g.setColor(Color.GRAY);
UIUtil.drawLine(g, 0, myStart1, width, myStart2);
UIUtil.drawLine(g, 0, myEnd1, width, myEnd2);
if (!myApplied) {
g.setColor(myColor);
g.fill(new Polygon(new int[]{0, 0, width, width}, new int[]{myStart1, myEnd1, myEnd2, myStart2}, 4));
g.setColor(FRAMING_LINE_COLOR);
UIUtil.drawLine(g, 0, myStart1, width, myStart2);
UIUtil.drawLine(g, 0, myEnd1, width, myEnd2);
}
else {
g.setColor(myColor);
UIUtil.drawLine(g, 0, myStart1 + 1, width, myStart2 + 1);
UIUtil.drawLine(g, 0, myStart1 + 2, width, myStart2 + 2);
UIUtil.drawLine(g, 0, myEnd1 + 1, width, myEnd2 + 1);
UIUtil.drawLine(g, 0, myEnd1, width, myEnd2);
}
}
public int hashCode() {
@@ -71,10 +87,30 @@ public class DividerPolygon {
return "<" + myStart1 + ", " + myEnd1 + " : " + myStart2 + ", " + myEnd2 + "> " + myColor;
}
Color getColor() {
public Color getColor() {
return myColor;
}
public int getTopLeftY() {
return myStart1;
}
public int getTopRightY() {
return myStart2;
}
public int getBottomLeftY() {
return myEnd1;
}
public int getBottomRightY() {
return myEnd2;
}
public boolean isApplied() {
return myApplied;
}
public static void paintPolygons(ArrayList<DividerPolygon> polygons, Graphics2D g, int width) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
@@ -86,7 +122,7 @@ public class DividerPolygon {
//g.setComposite(composite);
}
public static ArrayList<DividerPolygon> createVisiblePolygons(EditingSides sides, FragmentSide left) {
public static ArrayList<DividerPolygon> createVisiblePolygons(EditingSides sides, FragmentSide left, int diffDividerPolygonsOffset) {
Editor editor1 = sides.getEditor(left);
Editor editor2 = sides.getEditor(left.otherSide());
LineBlocks lineBlocks = sides.getLineBlocks();
@@ -100,7 +136,7 @@ public class DividerPolygon {
Trapezium trapezium = lineBlocks.getTrapezium(i);
final TextDiffType type = lineBlocks.getType(i);
Color color = type.getPolygonColor(editor1);
polygons.add(createPolygon(transformations, trapezium, color, left));
polygons.add(createPolygon(transformations, trapezium, color, left, diffDividerPolygonsOffset, type.isApplied()));
}
return polygons;
}
@@ -110,7 +146,8 @@ public class DividerPolygon {
return new FoldingTransformation(editor);
}
private static DividerPolygon createPolygon(Transformation[] transformations, Trapezium trapezium, Color color, FragmentSide left) {
private static DividerPolygon createPolygon(Transformation[] transformations, Trapezium trapezium, Color color, FragmentSide left,
int diffDividerPolygonsOffset, boolean applied) {
Interval base1 = trapezium.getBase(left);
Interval base2 = trapezium.getBase(left.otherSide());
Transformation leftTransform = transformations[left.getIndex()];
@@ -119,7 +156,9 @@ public class DividerPolygon {
int end1 = leftTransform.transform(base1.getEnd());
int start2 = rightTransform.transform(base2.getStart());
int end2 = rightTransform.transform(base2.getEnd());
return new DividerPolygon(start1 - OFFSET, start2 - OFFSET, end1 - OFFSET, end2 - OFFSET, color);
return new DividerPolygon(start1 - diffDividerPolygonsOffset, start2 - diffDividerPolygonsOffset,
end1 - diffDividerPolygonsOffset, end2 - diffDividerPolygonsOffset,
color, applied);
}
static Interval getVisibleInterval(Editor editor) {
@@ -28,6 +28,7 @@ import javax.swing.*;
import java.awt.*;
public class DiffDivider extends JComponent {
public static final int MERGE_DIVIDER_POLYGONS_OFFSET = 1;
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;
@@ -72,7 +73,7 @@ public class DiffDivider extends JComponent {
public void listenEditors(@NotNull EditingSides sides) {
stopListenEditors();
myPaint = new DiffDividerPaint(sides, myLeftSide);
myPaint = new DiffDividerPaint(sides, myLeftSide, MERGE_DIVIDER_POLYGONS_OFFSET);
myEditors[0] = sides.getEditor(FragmentSide.SIDE1);
myEditors[1] = sides.getEditor(FragmentSide.SIDE2);
if (myEditors[0] == null || myEditors[1] == null) {
@@ -52,6 +52,10 @@ public class TextDiffType implements DiffStatusBar.LegendTypeDescriptor {
private final String myDisplayName;
private final boolean myApplied;
public boolean isApplied() {
return myApplied;
}
public static TextDiffType create(@Nullable final TextDiffTypeEnum type) {
if (TextDiffTypeEnum.INSERT.equals(type)) {
return INSERT;
@@ -101,25 +105,33 @@ public class TextDiffType implements DiffStatusBar.LegendTypeDescriptor {
return myAttributesKey;
}
@Nullable
public TextAttributes getTextAttributes(EditorColorsScheme scheme) {
TextAttributes originalAttrs = scheme.getAttributes(myAttributesKey);
if (!myApplied) {
return originalAttrs;
if (originalAttrs == null) {
return null;
}
else {
TextAttributes overridingAttributes = new TextAttributes();
TextAttributes overridingAttributes = new TextAttributes();
if (myApplied) {
overridingAttributes.setBackgroundColor(scheme.getDefaultBackground());
return TextAttributes.merge(originalAttrs, overridingAttributes);
}
return TextAttributes.merge(originalAttrs, overridingAttributes);
}
@Nullable
public Color getPolygonColor(Editor editor) {
return getLegendColor(editor.getColorsScheme());
if (isApplied()) {
return getLegendColor(editor.getColorsScheme());
}
else {
TextAttributes attributes = getTextAttributes(editor.getColorsScheme());
return attributes == null ? null : attributes.getBackgroundColor();
}
}
public TextAttributes getTextAttributes(Editor editor1) {
return getTextAttributes(editor1.getColorsScheme());
@Nullable
public TextAttributes getTextAttributes(Editor editor) {
return getTextAttributes(editor.getColorsScheme());
}
@Nullable
@@ -135,4 +147,5 @@ public class TextDiffType implements DiffStatusBar.LegendTypeDescriptor {
public TextDiffTypeEnum getType() {
return myType;
}
}
@@ -73,6 +73,9 @@ public interface EditorEx extends Editor {
void setVerticalScrollbarOrientation(@MagicConstant(intValues = {VERTICAL_SCROLLBAR_LEFT, VERTICAL_SCROLLBAR_RIGHT}) int type);
@MagicConstant(intValues = {VERTICAL_SCROLLBAR_LEFT, VERTICAL_SCROLLBAR_RIGHT})
int getVerticalScrollbarOrientation();
void setVerticalScrollbarVisible(boolean b);
void setHorizontalScrollbarVisible(boolean b);
@@ -234,4 +237,19 @@ public interface EditorEx extends Editor {
* @param enabled 'pure painting mode' status to use
*/
void setPurePaintingMode(boolean enabled);
/**
* Allows to register a callback that will be called one each repaint of the editor vertical scrollbar.
* This is needed to allow a parent component draw above the scrollbar components (e.g. in the merge tool),
* otherwise the drawings are cleared once the scrollbar gets repainted (which may happen suddenly, because the scrollbar UI uses the
* {@link com.intellij.util.ui.Animator} to draw itself.
* @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);
}
}
@@ -56,4 +56,6 @@ public abstract class EditorGutterComponentEx extends JComponent implements Edit
public abstract Point getPoint(GutterIconRenderer renderer);
public abstract void setLineNumberConvertor(final Convertor<Integer, Integer> lineNumberConvertor);
public abstract void setShowDefaultGutterPopup(boolean show);
}
@@ -40,4 +40,6 @@ public interface EditorMarkupModel extends MarkupModel {
ErrorStripTooltipRendererProvider getErrorStripTooltipRendererProvider();
void setMinMarkHeight(int minMarkHeight);
boolean isErrorStripeVisible();
}
@@ -93,6 +93,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
private String myLastGutterToolTip = null;
private int myLastPreferredHeight = -1;
private Convertor<Integer, Integer> myLineNumberConvertor;
private boolean myShowDefaultGutterPopup = true;
@SuppressWarnings("unchecked")
public EditorGutterComponentImpl(EditorImpl editor) {
@@ -186,7 +187,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
UISettings.setupAntialiasing(g);
paintLineNumbers(g, clip);
paintLineNumbersBackground(g, clip);
paintAnnotations(g, clip);
Object hint = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
@@ -198,6 +199,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
paintFoldingBackground(g, clip, firstVisibleOffset, lastVisibleOffset);
paintLineMarkers(g, clip, firstVisibleOffset, lastVisibleOffset);
paintFoldingTree(g, clip, firstVisibleOffset, lastVisibleOffset);
paintLineNumbers(g, clip);
}
finally {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, hint);
@@ -293,7 +295,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
doPaintFoldingTree((Graphics2D)g, clip, firstVisibleOffset, lastVisibleOffset);
}
else {
UIUtil.drawVDottedLine((Graphics2D)g, clip.x + clip.width -1, clip.y, clip.y + clip.height, null, getOutlineColor(false));
UIUtil.drawVDottedLine((Graphics2D)g, clip.x + clip.width - 1, clip.y, clip.y + clip.height, null, getOutlineColor(false));
}
}
@@ -323,13 +325,18 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
private void paintLineNumbers(Graphics g, Rectangle clip) {
if (isLineNumbersShown()) {
paintBackground(g, clip, getLineNumberAreaOffset(), getLineNumberAreaWidth());
int x = getLineNumberAreaOffset() + getLineNumberAreaWidth() - 2;
UIUtil.drawVDottedLine((Graphics2D)g, x, clip.y, clip.y + clip.height, null, getOutlineColor(false));
doPaintLineNumbers(g, clip);
}
}
private void paintLineNumbersBackground(Graphics g, Rectangle clip) {
if (isLineNumbersShown()) {
paintBackground(g, clip, getLineNumberAreaOffset(), getLineNumberAreaWidth());
}
}
@Override
public Color getBackground() {
if (myBackgroundColor == null) {
@@ -554,7 +561,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
});
myLineMarkerAreaWidth = myIconsAreaWidth + FREE_PAINTERS_AREA_WIDTH +
(isFoldingOutlineShown() ? 0 : getFoldingAnchorWidth() / 2);
(isFoldingOutlineShown() ? getFoldingAnchorWidth() / 2 : 0);
}
private void paintGutterRenderers(final Graphics g, int firstVisibleOffset, int lastVisibleOffset) {
@@ -1345,6 +1352,11 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
myLineNumberConvertor = lineNumberConvertor;
}
@Override
public void setShowDefaultGutterPopup(boolean show) {
myShowDefaultGutterPopup = show;
}
private void invokePopup(MouseEvent e) {
final ActionManager actionManager = ActionManager.getInstance();
if (myEditor.getMouseEventArea(e) == EditorMouseEventArea.ANNOTATIONS_AREA) {
@@ -1383,9 +1395,11 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
}
}
else {
ActionGroup group = (ActionGroup)CustomActionsSchema.getInstance().getCorrectedAction(IdeActions.GROUP_EDITOR_GUTTER);
ActionPopupMenu popupMenu = actionManager.createActionPopupMenu(ActionPlaces.UNKNOWN, group);
popupMenu.getComponent().show(this, e.getX(), e.getY());
if (myShowDefaultGutterPopup) {
ActionGroup group = (ActionGroup)CustomActionsSchema.getInstance().getCorrectedAction(IdeActions.GROUP_EDITOR_GUTTER);
ActionPopupMenu popupMenu = actionManager.createActionPopupMenu(ActionPlaces.UNKNOWN, group);
popupMenu.getComponent().show(this, e.getX(), e.getY());
}
e.consume();
}
}
@@ -74,10 +74,7 @@ import com.intellij.ui.LightweightHint;
import com.intellij.ui.SideBorder;
import com.intellij.ui.components.JBScrollBar;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.Alarm;
import com.intellij.util.IJSwingUtilities;
import com.intellij.util.Processor;
import com.intellij.util.Producer;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.HashMap;
@@ -527,6 +524,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
myPurePaintingMode = enabled;
}
@Override
public void registerScrollBarRepaintCallback(@Nullable RepaintCallback callback) {
myVerticalScrollBar.registerRepaintCallback(callback);
}
@Override
public boolean isViewer() {
return myIsViewer || myIsRendererMode;
@@ -4440,6 +4442,7 @@ 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);
@@ -4461,6 +4464,14 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
super.setUI(myPersistentUI);
}
@Override
public void paint(Graphics g) {
super.paint(g);
if (myRepaintCallback != null) {
myRepaintCallback.call(g);
}
}
/**
* This is helper method. It returns height of the top (decrease) scroll bar
* button. Please note, that it's possible to return real height only if scroll bar
@@ -4531,6 +4542,10 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
Rectangle vr = vp.getViewRect();
return myEditorComponent.getScrollableBlockIncrement(vr, SwingConstants.VERTICAL, direction);
}
public void registerRepaintCallback(@Nullable RepaintCallback callback) {
myRepaintCallback = callback;
}
}
private MyEditable getViewer() {
@@ -4681,7 +4696,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
}
int getVerticalScrollbarOrientation() {
public int getVerticalScrollbarOrientation() {
return myScrollBarOrientation;
}
@@ -777,6 +777,11 @@ public class EditorMarkupModelImpl extends MarkupModelImpl implements EditorMark
myMinMarkHeight = minMarkHeight;
}
@Override
public boolean isErrorStripeVisible() {
return getErrorPanel() != null;
}
private static class BasicTooltipRendererProvider implements ErrorStripTooltipRendererProvider {
@Override
public TooltipRenderer calcTooltipRenderer(@NotNull final Collection<RangeHighlighter> highlighters) {
@@ -10,6 +10,8 @@
serviceImplementation="com.intellij.openapi.diff.impl.dir.DirDiffManagerImpl"/>
<projectService serviceImplementation="com.intellij.openapi.vcs.VcsConfiguration"/>
<projectService serviceImplementation="com.intellij.openapi.vcs.contentAnnotation.VcsContentAnnotationSettings"/>
<projectService serviceImplementation="com.intellij.openapi.diff.impl.incrementalMerge.ui.MergeToolSettings"/>
<selectInTarget implementation="com.intellij.openapi.vcs.changes.SelectInChangesViewTarget"/>
@@ -111,6 +111,21 @@ public class UIUtil {
MacUIUtil.getInvertedTextCursor(): Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR);
}
/**
* Draws two horizontal lines, the first at {@code topY}, the second at {@code bottomY}.
* The purpose of this method (and the ground of the name) is to draw two lines framing a horizontal filled rectangle.
* @param g Graphics context to draw with.
* @param startX x-start point.
* @param endX x-end point.
* @param topY y-coordinate of the first line.
* @param bottomY y-coordinate of the second line.
* @param color color of the lines.
*/
public static void drawFramingLines(@NotNull Graphics2D g, int startX, int endX, int topY, int bottomY, @NotNull Color color) {
drawLine(g, startX, topY, endX, topY, null, color);
drawLine(g, startX, bottomY, endX, bottomY, null, color);
}
public enum FontSize {NORMAL, SMALL, MINI}
public enum ComponentStyle {REGULAR, SMALL, MINI}
public enum FontColor {NORMAL, BRIGHTER}
@@ -289,6 +304,24 @@ public class UIUtil {
g.drawLine(x1, y1, x2, y2);
}
public static void drawLine(Graphics2D g, int x1, int y1, int x2, int y2, @Nullable Color bgColor, @Nullable Color fgColor) {
Color oldFg = g.getColor();
Color oldBg = g.getBackground();
if (fgColor != null) {
g.setColor(fgColor);
}
if (bgColor != null) {
g.setBackground(bgColor);
}
drawLine(g, x1, y1, x2, y2);
if (fgColor != null) {
g.setColor(oldFg);
}
if (bgColor != null) {
g.setBackground(oldBg);
}
}
@NotNull
public static String[] splitText(String text, FontMetrics fontMetrics, int widthLimit, char separator) {
ArrayList<String> lines = new ArrayList<String>();