package jetbrains.mps.vcs.diff.ui.common; /*Generated by MPS */ import org.apache.log4j.Logger; import org.apache.log4j.LogManager; import javax.swing.Icon; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.ShortcutSet; import com.intellij.openapi.actionSystem.CustomShortcutSet; import java.util.List; import jetbrains.mps.openapi.editor.EditorComponent; import com.intellij.openapi.actionSystem.ActionToolbar; import org.jetbrains.annotations.NotNull; import jetbrains.mps.openapi.editor.selection.SelectionListener; import jetbrains.mps.openapi.editor.selection.Selection; import jetbrains.mps.internal.collections.runtime.ListSequence; import jetbrains.mps.internal.collections.runtime.IVisitor; import jetbrains.mps.internal.collections.runtime.SetSequence; import java.util.HashSet; import jetbrains.mps.internal.collections.runtime.ITranslator2; import java.util.Arrays; import com.intellij.openapi.application.ApplicationManager; import org.jetbrains.annotations.Nullable; import jetbrains.mps.internal.collections.runtime.IWhereFilter; import org.apache.log4j.Level; import jetbrains.mps.openapi.editor.cells.EditorCell; import jetbrains.mps.baseLanguage.tuples.runtime.Tuples; import jetbrains.mps.baseLanguage.tuples.runtime.MultiTuple; import jetbrains.mps.workbench.action.BaseAction; import jetbrains.mps.smodel.ModelAccess; import jetbrains.mps.util.Computable; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.actionSystem.AnActionEvent; import java.util.Map; import org.jetbrains.mps.openapi.language.SConcept; import org.jetbrains.mps.openapi.model.SNode; public class NextPreviousTraverser { private static final Logger LOG = LogManager.getLogger(NextPreviousTraverser.class); private static final Icon PREVIOUS_ICON = AllIcons.Actions.PreviousOccurence; private static final Icon NEXT_ICON = AllIcons.Actions.NextOccurence; public static final ShortcutSet PREV_CHANGE_SHORTCUT = CustomShortcutSet.fromString("shift F7"); public static final ShortcutSet NEXT_CHANGE_SHORTCUT = CustomShortcutSet.fromString("F7"); private List<ChangeGroupLayout> myChangeGroupLayouts; private EditorComponent myLastEditor; private NextPreviousTraverser.TheAction myPreviousAction = new NextPreviousTraverser.TheAction(true); private NextPreviousTraverser.TheAction myNextAction = new NextPreviousTraverser.TheAction(false); private ActionToolbar myActionToolbar = null; public NextPreviousTraverser(@NotNull List<ChangeGroupLayout> changeGroupLayouts, @NotNull EditorComponent firstEditor) { myChangeGroupLayouts = changeGroupLayouts; myLastEditor = firstEditor; final SelectionListener selectionListener = new SelectionListener() { public void selectionChanged(EditorComponent editorComponent, Selection oldSelection, Selection newSelection) { if (oldSelection == newSelection) { return; } setLastEditor(editorComponent); updateToolbar(); } }; ListSequence.fromList(myChangeGroupLayouts).visitAll(new IVisitor<ChangeGroupLayout>() { public void visit(ChangeGroupLayout cgb) { cgb.addInvalidateListener(new ChangeGroupInvalidateListener() { public void changeGroupsInvalidated() { updateToolbar(); } }); } }); SetSequence.fromSet(SetSequence.fromSetWithValues(new HashSet<EditorComponent>(), ListSequence.fromList(myChangeGroupLayouts).translate(new ITranslator2<ChangeGroupLayout, EditorComponent>() { public Iterable<EditorComponent> translate(ChangeGroupLayout b) { return Arrays.<EditorComponent>asList(b.getLeftComponent(), b.getRightComponent()); } }))).visitAll(new IVisitor<EditorComponent>() { public void visit(EditorComponent ec) { ec.getSelectionManager().addSelectionListener(selectionListener); } }); } public void setActionToolbar(ActionToolbar actionToolbar) { myActionToolbar = actionToolbar; } private void updateToolbar() { if (myActionToolbar != null) { ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { myActionToolbar.updateActionsImmediately(); } }); } } @Nullable private ChangeGroupLayout getLayoutAsLeft() { return ListSequence.fromList(myChangeGroupLayouts).findFirst(new IWhereFilter<ChangeGroupLayout>() { public boolean accept(ChangeGroupLayout b) { return b.getLeftComponent() == myLastEditor; } }); } @Nullable private ChangeGroupLayout getLayoutAsRight() { return ListSequence.fromList(myChangeGroupLayouts).findFirst(new IWhereFilter<ChangeGroupLayout>() { public boolean accept(ChangeGroupLayout b) { return b.getRightComponent() == myLastEditor; } }); } private synchronized void setLastEditor(EditorComponent editor) { myLastEditor = editor; if (!(ListSequence.fromList(myChangeGroupLayouts).any(new IWhereFilter<ChangeGroupLayout>() { public boolean accept(ChangeGroupLayout b) { return b.getLeftComponent() == myLastEditor || b.getRightComponent() == myLastEditor; } }))) { if (LOG.isEnabledFor(Level.ERROR)) { LOG.error("last editor is uknown: " + myLastEditor, new AssertionError()); } } } private Bounds findNeighbourGroupAsLeftOrRight(final int currentY, boolean previous, final boolean left) { ChangeGroupLayout layout = (left ? getLayoutAsLeft() : getLayoutAsRight()); if (layout == null) { return null; } List<ChangeGroup> changeGroups = layout.getChangeGroups(); ChangeGroup changeGroup; if (previous) { changeGroup = ListSequence.fromList(changeGroups).findLast(new IWhereFilter<ChangeGroup>() { public boolean accept(ChangeGroup cg) { return (int) cg.getBounds(left).end() < currentY; } }); } else { changeGroup = ListSequence.fromList(changeGroups).findFirst(new IWhereFilter<ChangeGroup>() { public boolean accept(ChangeGroup cg) { return (int) cg.getBounds(left).start() > currentY; } }); } return check_mf966z_a5a51(changeGroup, left); } private synchronized Bounds getNeighbourGroupBounds(boolean previous) { // -1 means that group is not available int currentY = ((jetbrains.mps.nodeEditor.EditorComponent) myLastEditor).getViewport().getViewPosition().y; EditorCell selectedCell = ((jetbrains.mps.nodeEditor.EditorComponent) myLastEditor).getSelectedCell(); if (selectedCell != null) { currentY = selectedCell.getY(); } Bounds asLeft = findNeighbourGroupAsLeftOrRight(currentY, previous, true); Bounds asRight = findNeighbourGroupAsLeftOrRight(currentY, previous, false); Bounds max; Bounds min; if (asLeft == null) { { Tuples._2<Bounds, Bounds> _tmp_mf966z_a0j0q = MultiTuple.<Bounds,Bounds>from(null, asRight); min = _tmp_mf966z_a0j0q._0(); max = _tmp_mf966z_a0j0q._1(); } } else if (asRight == null) { { Tuples._2<Bounds, Bounds> _tmp_mf966z_a0a9a61 = MultiTuple.<Bounds,Bounds>from(null, asLeft); min = _tmp_mf966z_a0a9a61._0(); max = _tmp_mf966z_a0a9a61._1(); } } else { if ((int) asLeft.start() < (int) asRight.start()) { { Tuples._2<Bounds, Bounds> _tmp_mf966z_a0a0a9a61 = MultiTuple.<Bounds,Bounds>from(asLeft, asRight); min = _tmp_mf966z_a0a0a9a61._0(); max = _tmp_mf966z_a0a0a9a61._1(); } } else { { Tuples._2<Bounds, Bounds> _tmp_mf966z_a0a0a0j0q = MultiTuple.<Bounds,Bounds>from(asRight, asLeft); min = _tmp_mf966z_a0a0a0j0q._0(); max = _tmp_mf966z_a0a0a0j0q._1(); } } } if (asLeft != null && asRight != null) { return (previous ? max : min); } else { return max; } } public BaseAction previousAction() { return myPreviousAction; } public BaseAction nextAction() { return myNextAction; } public void goToFirstChangeLater() { Bounds firstGroup = getNeighbourGroupBounds(false); EditorCell rc = myLastEditor.getRootCell(); final int minY = (firstGroup == null ? rc.getY() + 1 : (int) firstGroup.start()); final int maxY = rc.getY() + rc.getHeight() - 2; ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { goToBounds(new Bounds(minY, maxY)); } }); } public void goToBounds(Bounds bounds) { if (!(myLastEditor.isDisposed())) { goToY((int) bounds.end()); goToY((int) bounds.start()); } } private synchronized void goToY(int y) { EditorCell editorCell = ((jetbrains.mps.nodeEditor.EditorComponent) myLastEditor).findCellWeak(1, y + 1); if (editorCell != null) { myLastEditor.changeSelection(editorCell); } else { if (LOG.isEnabledFor(Level.WARN)) { LOG.warn(String.format("Could not find cell for coordinates (1, %d), editor for concept %s", y, ModelAccess.instance().<String>runReadAction(new Computable<String>() { public String compute() { return check_mf966z_a0a0a2a0a0b0v(check_mf966z_a0a0a0c0a0a1a12(myLastEditor.getEditedNode())); } }))); } } } private class TheAction extends BaseAction implements DumbAware { private boolean myPrevious; private TheAction(boolean previous) { super("Go to " + ((previous ? "Previous" : "Next")) + " Change", null, (previous ? NextPreviousTraverser.PREVIOUS_ICON : NextPreviousTraverser.NEXT_ICON)); setDisableOnNoProject(false); setExecuteOutsideCommand(true); myPrevious = previous; } @Override protected void doExecute(AnActionEvent event, Map<String, Object> map) { assert getNeighbourGroupBounds(myPrevious) != null; goToBounds(getNeighbourGroupBounds(myPrevious)); } @Override protected void doUpdate(AnActionEvent event, Map<String, Object> map) { event.getPresentation().setEnabled(getNeighbourGroupBounds(myPrevious) != null); } } private static Bounds check_mf966z_a5a51(ChangeGroup checkedDotOperand, Boolean left) { if (null != checkedDotOperand) { return checkedDotOperand.getBounds(left); } return null; } private static String check_mf966z_a0a0a2a0a0b0v(SConcept checkedDotOperand) { if (null != checkedDotOperand) { return checkedDotOperand.getQualifiedName(); } return null; } private static SConcept check_mf966z_a0a0a0c0a0a1a12(SNode checkedDotOperand) { if (null != checkedDotOperand) { return checkedDotOperand.getConcept(); } return null; } }