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