blob: 6afbc181b98c8133fe59a807a4c000b6e6033856 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.vcs.changes;
import com.intellij.codeStyle.CodeStyleFacade;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diff.DiffPanel;
import com.intellij.openapi.diff.ex.DiffPanelEx;
import com.intellij.openapi.diff.ex.DiffPanelOptions;
import com.intellij.openapi.diff.impl.DiffPanelImpl;
import com.intellij.openapi.diff.impl.DiffSideView;
import com.intellij.openapi.diff.impl.IgnoreSpaceEnum;
import com.intellij.openapi.diff.impl.fragments.Fragment;
import com.intellij.openapi.diff.impl.fragments.FragmentList;
import com.intellij.openapi.diff.impl.highlighting.DiffPanelState;
import com.intellij.openapi.diff.impl.highlighting.FragmentSide;
import com.intellij.openapi.diff.impl.highlighting.FragmentedDiffPanelState;
import com.intellij.openapi.diff.impl.util.TextDiffTypeEnum;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.highlighter.FragmentedEditorHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.DialogWrapperDialog;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.*;
import com.intellij.openapi.vcs.VcsConfiguration;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.BeforeAfter;
import com.intellij.util.PlatformIcons;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.util.Hashtable;
import java.util.List;
/**
* @author irengrig
* Date: 6/15/11
* Time: 4:00 PM
*/
public class ChangesFragmentedDiffPanel implements Disposable {
private static final int SHORT_DIFF_DIVIDER_POLYGONS_OFFSET = 2;
private final JPanel myPanel;
private final Project myProject;
private final JComponent myParent;
private PreparedFragmentedContent myFragmentedContent;
private final String myFilePath;
private final VcsConfiguration myConfiguration;
private DiffPanel myHorizontal;
private DiffPanel myVertical;
private boolean myCurrentHorizontal;
private JPanel myTopPanel;
private List<Integer> myLeftLines;
private final MyNextDiffAction myNextDiff;
private final MyPreviousDiffAction myPreviousDiff;
private final JLabel myTitleLabel;
private ChangesFragmentedDiffPanel.PresentationState myPresentationState;
private DumbAwareAction myNavigateAction;
public ChangesFragmentedDiffPanel(final Project project, String filePath, JComponent parent) {
myProject = project;
myParent = parent;
myConfiguration = VcsConfiguration.getInstance(myProject);
myFilePath = filePath;
myPanel = new JPanel(new BorderLayout());
myNextDiff = new MyNextDiffAction();
myPreviousDiff = new MyPreviousDiffAction();
myTitleLabel = new JLabel(myFilePath);
}
@Override
public void dispose() {
// to remove links to editor that is in scrolling helper
myPanel.removeAll();
myHorizontal = null;
myVertical = null;
myPreviousDiff.unregisterCustomShortcutSet(myParent);
myNextDiff.unregisterCustomShortcutSet(myParent);
}
public void buildUi() {
myTopPanel = new JPanel(new BorderLayout());
final JPanel wrapper = new JPanel();
//final BoxLayout boxLayout = new BoxLayout(wrapper, BoxLayout.X_AXIS);
wrapper.setLayout(new BorderLayout());
myTitleLabel.setBorder(BorderFactory.createEmptyBorder(1, 2, 0, 0));
wrapper.add(myTitleLabel, BorderLayout.WEST);
DefaultActionGroup dag = new DefaultActionGroup();
myPreviousDiff.copyShortcutFrom(ActionManager.getInstance().getAction("PreviousDiff"));
myNextDiff.copyShortcutFrom(ActionManager.getInstance().getAction("NextDiff"));
dag.add(new MyChangeContextAction());
dag.add(myPreviousDiff);
dag.add(myNextDiff);
createNavigateAction();
dag.add(myNavigateAction);
myPreviousDiff.registerCustomShortcutSet(myPreviousDiff.getShortcutSet(), myPanel);
myNextDiff.registerCustomShortcutSet(myNextDiff.getShortcutSet(), myPanel);
dag.add(new PopupAction());
ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, dag, true);
wrapper.add(toolbar.getComponent(), BorderLayout.EAST);
myTopPanel.add(wrapper, BorderLayout.CENTER);
final JPanel wrapperDiffs = new JPanel(new GridBagLayout());
final JPanel oneMore = new JPanel(new BorderLayout());
oneMore.add(wrapperDiffs, BorderLayout.NORTH);
myCurrentHorizontal = myConfiguration.SHORT_DIFF_HORIZONTALLY;
myHorizontal = createPanel(true);
myVertical = createPanel(false);
myPanel.add(myTopPanel, BorderLayout.NORTH);
myPanel.add(getCurrentPanel().getComponent(), BorderLayout.CENTER);
myPreviousDiff.registerCustomShortcutSet(myPreviousDiff.getShortcutSet(), myParent);
myNextDiff.registerCustomShortcutSet(myNextDiff.getShortcutSet(), myParent);
}
private void createNavigateAction() {
myNavigateAction = new DumbAwareAction("Edit Source", "Edit Source", AllIcons.Actions.EditSource) {
@Nullable
private OpenFileDescriptor createDescriptor() {
if (myFragmentedContent == null || myFragmentedContent.getFile() == null) return null;
final DiffPanel panel = myCurrentHorizontal ? myHorizontal : myVertical;
final DiffSideView side = ((DiffPanelImpl)panel).getCurrentSide();
if (side == null || side.getEditor() == null) return null;
final boolean isAfter = FragmentSide.SIDE2.equals(side.getSide());
if (isAfter) {
final LogicalPosition position = side.getEditor().getCaretModel().getLogicalPosition();
final int line = position.line;
final int converted = myFragmentedContent.getNewConvertor().execute(line);
return new OpenFileDescriptor(myProject, myFragmentedContent.getFile(), converted, position.column);
}
if (((DiffPanelImpl)panel).getEditor1().getDocument().getTextLength() == 0) {
return new OpenFileDescriptor(myProject, myFragmentedContent.getFile(), 0);
}
final CaretModel model = side.getEditor().getCaretModel();
final FragmentList fragments = ((DiffPanelImpl)panel).getFragments();
final int line = model.getLogicalPosition().line;
//final int offset = side.getEditor().getDocument().getLineStartOffset(line);
final int offset = model.getOffset();
BeforeAfter<Integer> current = null;
final List<BeforeAfter<Integer>> ranges = myFragmentedContent.getLineRanges();
for (BeforeAfter<Integer> range : ranges) {
if (range.getBefore() > line) break;
current = range;
}
if (current == null) return null;
final Fragment at = fragments.getFragmentAt(offset, FragmentSide.SIDE1, Conditions.<Fragment>alwaysTrue());
if (at == null) return null;
final TextRange opposite = at.getRange(FragmentSide.SIDE2);
final int lineInNew = ((DiffPanelImpl)panel).getEditor2().getDocument().getLineNumber(opposite.getStartOffset());
int correctLine;
int column;
if (at.getType() == null || TextDiffTypeEnum.NONE.equals(at.getType())) {
column = model.getLogicalPosition().column;
final int startIn1 =
((DiffPanelImpl)panel).getEditor1().getDocument().getLineNumber(at.getRange(FragmentSide.SIDE1).getStartOffset());
correctLine = lineInNew + line - startIn1;
}
else {
column = 0;
correctLine = Math.max(lineInNew, current.getAfter());
}
int converted = myFragmentedContent.getNewConvertor().execute(correctLine);
return new OpenFileDescriptor(myProject, myFragmentedContent.getFile(), converted, column);
}
@Override
public void actionPerformed(AnActionEvent e) {
if (!getEnabled()) return;
final OpenFileDescriptor descriptor = createDescriptor();
if (descriptor == null) return;
final Runnable runnable = new Runnable() {
@Override
public void run() {
FileEditorManager.getInstance(myProject).openTextEditor(descriptor, true);
}
};
if (ModalityState.NON_MODAL.equals(ModalityState.current())) {
runnable.run();
}
else {
final Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow();
if (window instanceof DialogWrapperDialog) {
final DialogWrapper wrapper = ((DialogWrapperDialog)window).getDialogWrapper();
if (wrapper != null) {
wrapper.doCancelAction();
ApplicationManager.getApplication().invokeLater(runnable, ModalityState.NON_MODAL, myProject.getDisposed());
}
}
}
}
@Override
public void update(AnActionEvent e) {
super.update(e);
final boolean enabled = getEnabled();
e.getPresentation().setEnabled(enabled);
}
private boolean getEnabled() {
final DiffPanel panel = myCurrentHorizontal ? myHorizontal : myVertical;
if (panel == null) return false;
final DiffSideView side = ((DiffPanelImpl)panel).getCurrentSide();
return side != null && side.getEditor() != null;
}
};
}
public void setTitle(String filePath) {
myTitleLabel.setText(filePath);
}
public void refreshData(final PreparedFragmentedContent fragmentedContent) {
myPresentationState = new PresentationState(myConfiguration, myCurrentHorizontal);
myFragmentedContent = fragmentedContent;
boolean navigationEnabled = !myFragmentedContent.isOneSide();
myNextDiff.setEnabled(navigationEnabled);
myPreviousDiff.setEnabled(navigationEnabled);
adjustPanelData((DiffPanelImpl)myHorizontal);
adjustPanelData((DiffPanelImpl)myVertical);
if (((DiffPanelImpl) myHorizontal).getEditor1() != null) {
myNavigateAction.registerCustomShortcutSet(CommonShortcuts.getEditSource(), ((DiffPanelImpl) myHorizontal).getEditor1().getComponent());
myNavigateAction.registerCustomShortcutSet(CommonShortcuts.getEditSource(), ((DiffPanelImpl) myVertical).getEditor1().getComponent());
}
if (((DiffPanelImpl) myHorizontal).getEditor2() != null) {
myNavigateAction.registerCustomShortcutSet(CommonShortcuts.getEditSource(), ((DiffPanelImpl) myHorizontal).getEditor2().getComponent());
myNavigateAction.registerCustomShortcutSet(CommonShortcuts.getEditSource(), ((DiffPanelImpl) myVertical).getEditor2().getComponent());
}
DiffPanel currentPanel = getCurrentPanel();
FragmentedDiffPanelState state = (FragmentedDiffPanelState)((DiffPanelImpl)currentPanel).getDiffPanelState();
myTitleLabel.setText(titleText((DiffPanelImpl)currentPanel));
myLeftLines = state.getLeftLines();
EditorEx hEditor1 = (EditorEx)((DiffPanelImpl)myHorizontal).getEditor1();
EditorEx vEditor1 = (EditorEx)((DiffPanelImpl)myVertical).getEditor1();
EditorEx hEditor2 = (EditorEx)((DiffPanelImpl)myHorizontal).getEditor2();
EditorEx vEditor2 = (EditorEx)((DiffPanelImpl)myVertical).getEditor2();
assert hEditor1 != null;
assert vEditor1 != null;
assert hEditor2 != null;
assert vEditor2 != null;
FragmentedEditorHighlighter bh = fragmentedContent.getBeforeHighlighter();
if (bh != null) {
hEditor1.setHighlighter(bh);
vEditor1.setHighlighter(bh);
}
FragmentedEditorHighlighter ah = fragmentedContent.getAfterHighlighter();
if (ah != null) {
hEditor2.setHighlighter(ah);
vEditor2.setHighlighter(ah);
}
if (((DiffPanelImpl) currentPanel).getEditor1() != null) {
highlightTodo(true, fragmentedContent.getBeforeTodoRanges());
}
if (((DiffPanelImpl) currentPanel).getEditor2() != null) {
highlightTodo(false, fragmentedContent.getAfterTodoRanges());
}
if (fragmentedContent.getFileType() != null && myProject != null && !myProject.isDisposed()) {
CodeStyleFacade codeStyleFacade = CodeStyleFacade.getInstance(myProject);
int tabSize = codeStyleFacade.getTabSize(fragmentedContent.getFileType());
boolean useTabCharacter = codeStyleFacade.useTabCharacter(fragmentedContent.getFileType());
hEditor1.getSettings().setTabSize(tabSize);
vEditor1.getSettings().setTabSize(tabSize);
hEditor2.getSettings().setTabSize(tabSize);
vEditor2.getSettings().setTabSize(tabSize);
hEditor1.getSettings().setUseTabCharacter(useTabCharacter);
vEditor1.getSettings().setUseTabCharacter(useTabCharacter);
hEditor2.getSettings().setUseTabCharacter(useTabCharacter);
vEditor2.getSettings().setUseTabCharacter(useTabCharacter);
}
ensurePresentation();
softWraps(myConfiguration.SOFT_WRAPS_IN_SHORT_DIFF);
}
private void softWraps(final boolean value) {
DiffPanel currentPanel = getCurrentPanel();
if (((DiffPanelImpl) currentPanel).getEditor1() != null) {
((DiffPanelImpl) myHorizontal).getEditor1().getSettings().setUseSoftWraps(value);
((DiffPanelImpl) myVertical).getEditor1().getSettings().setUseSoftWraps(value);
}
if (((DiffPanelImpl) currentPanel).getEditor2() != null) {
((DiffPanelImpl) myHorizontal).getEditor2().getSettings().setUseSoftWraps(value);
((DiffPanelImpl) myVertical).getEditor2().getSettings().setUseSoftWraps(value);
}
}
private void highlightTodo(boolean left, List<Pair<TextRange, TextAttributes>> todoRanges) {
FragmentedDiffPanelState panelState = (FragmentedDiffPanelState)((DiffPanelImpl)myHorizontal).getDiffPanelState();
FragmentedDiffPanelState panelState2 = (FragmentedDiffPanelState)((DiffPanelImpl)myVertical).getDiffPanelState();
for (Pair<TextRange, TextAttributes> range : todoRanges) {
TextAttributes second = range.getSecond().clone();
panelState.addRangeHighlighter(left, range.getFirst().getStartOffset(), range.getFirst().getEndOffset(), second);
panelState2.addRangeHighlighter(left, range.getFirst().getStartOffset(), range.getFirst().getEndOffset(), second);
}
}
private String titleText(DiffPanelImpl diffPanel) {
return myFilePath + " " + diffPanel.getNumDifferencesText();
}
private void adjustPanelData(final DiffPanelImpl diffPanel) {
final FragmentedDiffPanelState diffPanelState = (FragmentedDiffPanelState)diffPanel.getDiffPanelState();
diffPanelState.setRanges(myFragmentedContent.getLineRanges());
diffPanel.setContents(myFragmentedContent.createBeforeContent(), myFragmentedContent.createAfterContent());
diffPanel.setLineNumberConvertors(myFragmentedContent.getOldConvertor(), myFragmentedContent.getNewConvertor());
diffPanel.prefferedSizeByContents(-1);
}
private DiffPanel createPanel(final boolean horizontal) {
final DiffPanel diffPanel = new DiffPanelImpl(null, myProject, false, horizontal, SHORT_DIFF_DIVIDER_POLYGONS_OFFSET, null) {
@Override
protected DiffPanelState createDiffPanelState(@NotNull Disposable parentDisposable) {
return new FragmentedDiffPanelState(this, myProject, getDiffDividerPolygonsOffset(), ! horizontal, parentDisposable);
}
};
diffPanel.enableToolbar(false);
diffPanel.removeStatusBar();
DiffPanelOptions o = ((DiffPanelEx)diffPanel).getOptions();
o.setRequestFocusOnNewContent(false);
Disposer.register(this, diffPanel);
return diffPanel;
}
public void away() {
myPreviousDiff.unregisterCustomShortcutSet(myParent);
myNextDiff.unregisterCustomShortcutSet(myParent);
}
private static class PresentationState {
private final IgnoreSpaceEnum myIgnoreSpace;
private final boolean myHorizontal;
private final int myContextLines;
private final boolean mySoftWraps;
private PresentationState(@NotNull VcsConfiguration configuration, boolean currentHorizontal) {
myIgnoreSpace = configuration.SHORT_DIFF_IGNORE_SPACE;
myHorizontal = currentHorizontal;
myContextLines = configuration.SHORT_DIFF_EXTRA_LINES;
mySoftWraps = configuration.SOFT_WRAPS_IN_SHORT_DIFF;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PresentationState that = (PresentationState)o;
if (myContextLines != that.myContextLines) return false;
if (myHorizontal != that.myHorizontal) return false;
if (mySoftWraps != that.mySoftWraps) return false;
if (myIgnoreSpace != that.myIgnoreSpace) return false;
return true;
}
@Override
public int hashCode() {
int result = myIgnoreSpace != null ? myIgnoreSpace.hashCode() : 0;
result = 31 * result + (myHorizontal ? 1 : 0);
result = 31 * result + myContextLines;
result = 31 * result + (mySoftWraps ? 1 : 0);
return result;
}
}
public void refreshPresentation() {
// 1. vertical 2. number of lines 3. soft wraps (4. ignore spaces)
PresentationState current = new PresentationState(myConfiguration, myCurrentHorizontal);
if (myFragmentedContent != null && ! Comparing.equal(myPresentationState, current)) {
recalculatePresentation();
}
else {
ensurePresentation();
}
myPreviousDiff.registerCustomShortcutSet(myPreviousDiff.getShortcutSet(), myParent);
myNextDiff.registerCustomShortcutSet(myNextDiff.getShortcutSet(), myParent);
}
private static final Icon ourIcon = PlatformIcons.CHECK_ICON;
private class PopupAction extends DumbAwareAction {
private final AnAction myUsual;
private final AnAction myNumbered;
private final ChangesFragmentedDiffPanel.MyUseSoftWrapsAction mySoftWrapsAction;
private PopupAction() {
super("Settings", "Settings", AllIcons.General.SecondaryGroup);
myUsual = new AnAction("Top | Bottom", "", AllIcons.General.Mdot_empty) {
@Override
public void actionPerformed(AnActionEvent e) {
myConfiguration.SHORT_DIFF_HORIZONTALLY = false;
ensurePresentation();
}
@Override
public void update(AnActionEvent e) {
super.update(e);
e.getPresentation().setIcon(myConfiguration.SHORT_DIFF_HORIZONTALLY ? AllIcons.General.Mdot_empty : AllIcons.General.Mdot);
}
};
myNumbered = new AnAction("Left | Right", "", AllIcons.General.Mdot_empty) {
@Override
public void actionPerformed(AnActionEvent e) {
myConfiguration.SHORT_DIFF_HORIZONTALLY = true;
ensurePresentation();
}
@Override
public void update(AnActionEvent e) {
super.update(e);
e.getPresentation().setIcon(myConfiguration.SHORT_DIFF_HORIZONTALLY ? AllIcons.General.Mdot : AllIcons.General.Mdot_empty);
}
};
mySoftWrapsAction = new MyUseSoftWrapsAction();
}
@Override
public void actionPerformed(AnActionEvent e) {
final DefaultActionGroup dag = new DefaultActionGroup();
dag.add(myUsual);
dag.add(myNumbered);
dag.add(new Separator());
dag.add(mySoftWrapsAction);
final ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(null, dag, e.getDataContext(),
JBPopupFactory.ActionSelectionAid.SPEEDSEARCH,
false);
if (e.getInputEvent() instanceof MouseEvent) {
popup.show(new RelativePoint((MouseEvent)e.getInputEvent()));
} else {
// todo correct
/*final Dimension dimension = popup.getContent().getPreferredSize();
final Point at = new Point(-dimension.width / 2, 0);
popup.show(new RelativePoint(myParent, at));*/
popup.showInBestPositionFor(e.getDataContext());
}
}
}
/*private class MyShowSettingsButton extends ActionButton implements DumbAware {
MyShowSettingsButton() {
this(new PopupAction(), new Presentation(), ActionPlaces.CHANGES_LOCAL_DIFF_SETTINGS, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE);
}
MyShowSettingsButton(AnAction action, Presentation presentation, String place, @NotNull Dimension minimumSize) {
super(action, presentation, place, minimumSize);
((PopupAction) getAction()).setParent(this);
myPresentation.setIcon(IconLoader.getIcon("/general/secondaryGroup.png"));
}
}*/
private void ensurePresentation() {
if (myCurrentHorizontal != myConfiguration.SHORT_DIFF_HORIZONTALLY) {
final DiffPanel panel = getCurrentPanel();
myPanel.removeAll();
myPanel.add(myTopPanel, BorderLayout.NORTH);
myPanel.add(panel.getComponent(), BorderLayout.CENTER);
myPanel.revalidate();
myPanel.repaint();
myCurrentHorizontal = myConfiguration.SHORT_DIFF_HORIZONTALLY;
}
}
private DiffPanel getCurrentPanel() {
DiffPanel panel;
if (myConfiguration.SHORT_DIFF_HORIZONTALLY) {
panel = myHorizontal;
} else {
panel = myVertical;
}
return panel;
}
private int getCurrentLogicalLineIdx(final boolean forward) {
assert ! myLeftLines.isEmpty();
BeforeAfter<Integer> editorLines = getEditorLines();
if (forward) {
Integer line = editorLines.getAfter();
if (line >= myLeftLines.get(myLeftLines.size() - 1)) {
return myLeftLines.size() - 1;
}
for (int i = myLeftLines.size() - 1; i >= 0; i--) {
Integer integer = myLeftLines.get(i);
if (integer <= line) return i;
}
return 0;
} else {
Integer line = editorLines.getBefore();
if (line <= myLeftLines.get(0)) return 0;
for (int i = 0; i < myLeftLines.size(); i++) {
Integer integer = myLeftLines.get(i);
if (integer >= line) {
return i;
}
}
return myLeftLines.size() - 1;
}
}
private BeforeAfter<Integer> getEditorLines() {
final Editor editor = ((DiffPanelImpl) getCurrentPanel()).getEditor1();
Rectangle visibleArea = editor.getScrollingModel().getVisibleArea();
final int offset = editor.getScrollingModel().getVerticalScrollOffset();
int leftPixels = offset % editor.getLineHeight();
final Point start = visibleArea.getLocation();
final LogicalPosition startLp = editor.xyToLogicalPosition(start);
final Point location = new Point(start.x + visibleArea.width, start.y + visibleArea.height);
final LogicalPosition lp = editor.xyToLogicalPosition(location);
int curStartLine = startLp.line == editor.getDocument().getLineCount() - 1 ? startLp.line : startLp.line + 1;
int cutEndLine = lp.line == 0 ? 0 : lp.line - 1;
boolean commonPartOk = leftPixels == 0 || startLp.line == lp.line;
return new BeforeAfter<Integer>(commonPartOk && startLp.softWrapLinesOnCurrentLogicalLine == 0 ? startLp.line : curStartLine,
commonPartOk && lp.softWrapLinesOnCurrentLogicalLine == 0 ? lp.line : cutEndLine);
}
private static final int[] ourMarks = {1,2,4,8,-1};
public static final Hashtable<Integer, JComponent> LABELS = new Hashtable<Integer, JComponent>();
public static final int ALL_VALUE = 5;
static {
LABELS.put(1, markLabel("1"));
LABELS.put(2, markLabel("2"));
LABELS.put(3, markLabel("4"));
LABELS.put(4, markLabel("8"));
LABELS.put(ALL_VALUE, markLabel("All"));
}
private static JLabel markLabel(final String text) {
JLabel label = new JLabel(text);
label.setFont(UIUtil.getLabelFont());
return label;
}
private class MyUseSoftWrapsAction extends ToggleAction implements DumbAware {
private final Icon myIcon;
private MyUseSoftWrapsAction() {
super("Use soft wraps", "", ourIcon);
myIcon = ourIcon;
}
@Override
public boolean isSelected(AnActionEvent e) {
return myConfiguration.SOFT_WRAPS_IN_SHORT_DIFF;
}
@Override
public void setSelected(AnActionEvent e, boolean state) {
myConfiguration.SOFT_WRAPS_IN_SHORT_DIFF = state;
softWraps(myConfiguration.SOFT_WRAPS_IN_SHORT_DIFF);
}
@Override
public void update(AnActionEvent e) {
super.update(e);
e.getPresentation().setIcon(myConfiguration.SOFT_WRAPS_IN_SHORT_DIFF ? myIcon : null);
}
}
private class MyChangeContextAction extends DumbAwareAction {
private MyChangeContextAction() {
super("More/Less Lines...", "More/Less Lines...", AllIcons.Actions.Expandall);
}
@Override
public void actionPerformed(AnActionEvent e) {
JPanel result = new JPanel(new BorderLayout());
JLabel label = new JLabel("Lines around:");
label.setBorder(BorderFactory.createEmptyBorder(4, 4, 0, 0));
JPanel wrapper = new JPanel(new BorderLayout());
wrapper.add(label, BorderLayout.NORTH);
result.add(wrapper, BorderLayout.WEST);
final JSlider slider = new JSlider(SwingConstants.HORIZONTAL, 1, 5, 1);
slider.setMinorTickSpacing(1);
slider.setPaintTicks(true);
slider.setPaintTrack(true);
slider.setSnapToTicks(true);
UIUtil.setSliderIsFilled(slider, true);
slider.setPaintLabels(true);
slider.setLabelTable(LABELS);
result.add(slider, BorderLayout.CENTER);
final VcsConfiguration configuration = VcsConfiguration.getInstance(myProject);
for (int i = 0; i < ourMarks.length; i++) {
int mark = ourMarks[i];
if (mark == configuration.SHORT_DIFF_EXTRA_LINES) {
slider.setValue(i + 1);
}
}
JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(result, slider).createPopup();
popup.setFinalRunnable(new Runnable() {
@Override
public void run() {
int value = slider.getModel().getValue();
if (configuration.SHORT_DIFF_EXTRA_LINES != ourMarks[value - 1]) {
configuration.SHORT_DIFF_EXTRA_LINES = ourMarks[value - 1];
try {
recalculatePresentation();
} catch (ChangeOutdatedException e) {
//
}
}
}
});
InputEvent inputEvent = e.getInputEvent();
if (inputEvent instanceof MouseEvent) {
int width = result.getPreferredSize().width;
MouseEvent inputEvent1 = (MouseEvent)inputEvent;
Point point1 = new Point(inputEvent1.getX() - width / 2, inputEvent1.getY());
RelativePoint point = new RelativePoint(inputEvent1.getComponent(), point1);
popup.show(point);
} else {
popup.showInBestPositionFor(e.getDataContext());
}
}
}
private void recalculatePresentation() {
myFragmentedContent.recalculate();
refreshData(myFragmentedContent);
}
private class MyPreviousDiffAction extends DumbAwareAction {
private boolean myEnabled;
private MyPreviousDiffAction() {
super("Previous Change", "Previous Change", AllIcons.Actions.PreviousOccurence);
}
@Override
public void actionPerformed(AnActionEvent e) {
int currentLogicalLineIdx = getCurrentLogicalLineIdx(false);
int nextLineIdx = currentLogicalLineIdx == 0 ? 0 : currentLogicalLineIdx - 1;
DiffPanelImpl panel = (DiffPanelImpl) getCurrentPanel();
panel.getSideView(FragmentSide.SIDE1).scrollToFirstDiff(myLeftLines.get(nextLineIdx));
}
public void setEnabled(boolean enabled) {
myEnabled = enabled;
}
@Override
public void update(AnActionEvent e) {
super.update(e);
e.getPresentation().setEnabled(myEnabled);
}
}
private class MyNextDiffAction extends DumbAwareAction {
private boolean myEnabled;
private MyNextDiffAction() {
super("Next Change", "Next Change", AllIcons.Actions.NextOccurence);
}
@Override
public void actionPerformed(AnActionEvent e) {
int currentLogicalLineIdx = getCurrentLogicalLineIdx(true);
int nextLineIdx = currentLogicalLineIdx == myLeftLines.size() - 1 ? currentLogicalLineIdx : currentLogicalLineIdx + 1;
DiffPanelImpl panel = (DiffPanelImpl) getCurrentPanel();
panel.getSideView(FragmentSide.SIDE1).scrollToFirstDiff(myLeftLines.get(nextLineIdx));
}
public void setEnabled(boolean enabled) {
myEnabled = enabled;
}
@Override
public void update(AnActionEvent e) {
super.update(e);
e.getPresentation().setEnabled(myEnabled);
}
}
public JPanel getPanel() {
return myPanel;
}
}