diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java index 258115b3a101..e1d055d7af62 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java @@ -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); + } } } diff --git a/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java b/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java index 46341c274783..4963797eb5f9 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/EditorWindow.java @@ -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); diff --git a/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java b/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java index d7ee52134f17..5a4544f2c0ca 100644 --- a/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java +++ b/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewPanel.java @@ -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 { diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ToggleAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ToggleAction.java index 9a1235e3ec6d..f09383c7bcea 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ToggleAction.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ToggleAction.java @@ -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); } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java index db78e75c285a..918b3f1a6609 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java @@ -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()); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java index 10f92e976815..407c50ecd4d3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffUtil.java @@ -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); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeHighlighterHolder.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeHighlighterHolder.java index b9da081a35e4..f9c4bdd93412 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeHighlighterHolder.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeHighlighterHolder.java @@ -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); + } + } + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeType.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeType.java index 49f2423b8dc6..89aa052bcb30 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeType.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ChangeType.java @@ -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); + } + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/EditorPlace.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/EditorPlace.java index 7624bc5fd8e8..aaa5c98e9702 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/EditorPlace.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/EditorPlace.java @@ -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 myListeners = new ArrayList(); - 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 myListeners = new ArrayList(); + @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 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 void updateValue(Editor editor, ViewProperty 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 { - 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(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java index b2daffd4989a..219c3f9e0e7a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java @@ -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 EDITOR_SCHEME = new EditorPlace.ViewProperty(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 LINE_NUMBERS = new EditorPlace.ViewProperty(Boolean.TRUE) { - public void doUpdateEditor(EditorEx editorEx, Boolean aBoolean, EditorPlace.ComponentState state) { - editorEx.getSettings().setLineNumbersShown(aBoolean.booleanValue()); - } - }; - public static final EditorPlace.ViewProperty LINE_MARKERS_AREA = new EditorPlace.ViewProperty(Boolean.TRUE) { - public void doUpdateEditor(EditorEx editorEx, Boolean aBoolean, EditorPlace.ComponentState state) { - editorEx.getSettings().setLineMarkerAreaShown(aBoolean.booleanValue()); - } - }; - public static final EditorPlace.ViewProperty ADDITIONAL_LINES = new EditorPlace.ViewProperty(null) { - public void doUpdateEditor(EditorEx editorEx, Integer integer, EditorPlace.ComponentState state) { - if (integer != null) editorEx.getSettings().setAdditionalLinesCount(integer.intValue()); - } - }; - public static final EditorPlace.ViewProperty ADDITIONAL_COLUMNS = new EditorPlace.ViewProperty(null) { - public void doUpdateEditor(EditorEx editorEx, Integer integer, EditorPlace.ComponentState state) { - if (integer != null) editorEx.getSettings().setAdditionalColumnsCount(integer.intValue()); - } - }; - public static final EditorPlace.ViewProperty HIGHLIGHTER_SETTINGS = - new EditorPlace.ViewProperty(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 ALL_PROPERTIES = Arrays.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 getEditors() { + Collection editors = new ArrayList(3); + for (EditorPlace place : getEditorPlaces()) { + editors.add(place.getEditor()); } - }; + return editors; + } + + @NotNull + private Collection getEditorPlaces() { + Collection editorPlaces = new ArrayList(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 myProperties = new HashMap(); + 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 notProcessedDefaults = new HashSet(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 void updateValue(Editor editor, EditorPlace.ViewProperty 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 void setEditorProperty(EditorPlace.ViewProperty 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); } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanelColumn.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanelColumn.java new file mode 100644 index 000000000000..88d7a9f260f0 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanelColumn.java @@ -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 +} diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergeToolEditorSetting.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergeToolEditorSetting.java new file mode 100644 index 000000000000..2c81e18db057 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergeToolEditorSetting.java @@ -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; + +/** + *

+ * Properties of the editors used in the merge tool. Most of them are customizable by the user. + *

+ * + * @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; + } + +} diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergeToolSettings.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergeToolSettings.java new file mode 100644 index 000000000000..69d30c78112b --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergeToolSettings.java @@ -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 { + + 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; + } + +} diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergeToolSettingsAction.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergeToolSettingsAction.java new file mode 100644 index 000000000000..3fff9cd07cae --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergeToolSettingsAction.java @@ -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 myEditors; + private final ActionGroup myActionGroup; + + MergeToolSettingsAction(@NotNull Collection 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 myEditors; + + private MergeToolToggleAction(String actionId, MergeToolEditorSetting setting, Collection 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; + } + } + +} diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java index 6798ec93fbca..9e889122d631 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/mergeTool/MergeRequestImpl.java @@ -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()); diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DiffDividerPaint.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DiffDividerPaint.java index bf1e435f7b93..dd9b4b470ea1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DiffDividerPaint.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DiffDividerPaint.java @@ -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(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java index 023ec4e9aaf2..bf809557a2c3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/splitter/DividerPolygon.java @@ -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 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 createVisiblePolygons(EditingSides sides, FragmentSide left) { + public static ArrayList 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) { diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/DiffDivider.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/DiffDivider.java index 15ade80ec853..e9c3168e401c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/DiffDivider.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/DiffDivider.java @@ -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) { diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/TextDiffType.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/TextDiffType.java index 1d24fc30a1e7..f1d5bcaae932 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/TextDiffType.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/util/TextDiffType.java @@ -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; } + } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorEx.java index 899134dc93ba..b5e04cbabe43 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorEx.java @@ -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); + } + } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java index 1d936db0345e..43090c6dfe42 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorGutterComponentEx.java @@ -56,4 +56,6 @@ public abstract class EditorGutterComponentEx extends JComponent implements Edit public abstract Point getPoint(GutterIconRenderer renderer); public abstract void setLineNumberConvertor(final Convertor lineNumberConvertor); + + public abstract void setShowDefaultGutterPopup(boolean show); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorMarkupModel.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorMarkupModel.java index 0cdae1ae1a7a..0f70bf4010cd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorMarkupModel.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorMarkupModel.java @@ -40,4 +40,6 @@ public interface EditorMarkupModel extends MarkupModel { ErrorStripTooltipRendererProvider getErrorStripTooltipRendererProvider(); void setMinMarkHeight(int minMarkHeight); + + boolean isErrorStripeVisible(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 1d82cdc4fda8..fa55c3e41e28 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -93,6 +93,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse private String myLastGutterToolTip = null; private int myLastPreferredHeight = -1; private Convertor 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(); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 30e85060ba4a..c62fe597f758 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -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; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java index dbd917cb1c98..5201b146675c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorMarkupModelImpl.java @@ -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 highlighters) { diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml index 733ca23c4ee6..43bb478254cf 100644 --- a/platform/platform-resources/src/META-INF/VcsExtensions.xml +++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml @@ -10,6 +10,8 @@ serviceImplementation="com.intellij.openapi.diff.impl.dir.DirDiffManagerImpl"/> + + diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 081f67008d6a..8c92cdf0a8a3 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -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 lines = new ArrayList();