package jetbrains.mps.vcs.diff.ui.merge;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import java.beans.PropertyChangeListener;
import com.intellij.openapi.project.Project;
import jetbrains.mps.vcs.diff.merge.MergeSession;
import org.jetbrains.mps.openapi.model.SNodeId;
import jetbrains.mps.vcs.diff.ui.common.ChangeEditorMessage;
import java.util.List;
import jetbrains.mps.vcs.diff.ui.common.DiffEditor;
import com.intellij.diff.tools.util.side.ThreesideContentPanel;
import com.intellij.ide.util.PropertiesComponent;
import jetbrains.mps.vcs.diff.ui.common.ChangeGroupLayout;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import java.util.Map;
import jetbrains.mps.vcs.diff.ui.common.DiffChangeGroupLayout;
import jetbrains.mps.internal.collections.runtime.MapSequence;
import java.util.HashMap;
import jetbrains.mps.vcs.diff.ui.common.DiffEditorsGroup;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import jetbrains.mps.vcs.diff.ui.common.NextPreviousTraverser;
import com.intellij.ui.JBSplitter;
import jetbrains.mps.vcs.changesmanager.CurrentDifferenceRegistry;
import jetbrains.mps.vcs.diff.ui.common.TripleChangeGroupLayout;
import jetbrains.mps.vcs.diff.ui.common.ChangeGroupMessages;
import org.jetbrains.annotations.Nullable;
import com.intellij.diff.DiffEditorTitleCustomizer;
import jetbrains.mps.vcs.diff.changes.ModelChange;
import jetbrains.mps.internal.collections.runtime.Sequence;
import org.jetbrains.mps.openapi.module.ModelAccess;
import jetbrains.mps.ide.project.ProjectHelper;
import org.jetbrains.mps.openapi.model.EditableSModel;
import jetbrains.mps.vcs.changesmanager.CurrentDifference;
import jetbrains.mps.vcs.changesmanager.CurrentDifferenceAdapter;
import org.jetbrains.annotations.NotNull;
import java.beans.PropertyChangeEvent;
import com.intellij.openapi.ui.Splitter;
import java.util.Arrays;
import com.intellij.diff.util.Side;
import javax.swing.JComponent;
import com.intellij.diff.util.DiffUtil;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.project.DumbAware;
import jetbrains.mps.ide.icons.IdeIcons;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.diff.DiffBundle;
import jetbrains.mps.workbench.action.BaseGroup;
import com.intellij.openapi.actionSystem.AnAction;
import jetbrains.mps.vcs.diff.ui.common.DiffSettingsUtil;
import com.intellij.diff.tools.util.DiffSplitter;
import java.awt.Graphics;
import com.intellij.openapi.actionSystem.ActionGroup;
import javax.swing.JPanel;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.repository.CommandListener;
import java.util.concurrent.atomic.AtomicBoolean;

@GeneratedClass(node = "r:351fe3d9-2ce5-4ea0-8afc-9b076259a949(jetbrains.mps.vcs.diff.ui.merge)/2657001694096388534", model = "r:351fe3d9-2ce5-4ea0-8afc-9b076259a949(jetbrains.mps.vcs.diff.ui.merge)")
public class MergeRootsPane implements PropertyChangeListener {
  private static final String PARAM_SHOW_INSPECTOR = MergeRootsPane.class.getName() + "ShowInspector";
  private static final String PARAM_INSPECTOR_SPLITTER_POSITION = MergeRootsPane.class.getName() + "InspectorSplitterPosition";
  private static final String PARAM_ENABLE_EDITORS_SCROLL_SYNC = MergeRootsPane.class.getName() + "_EnableSync";

  private Project myProject;
  private MergeSession myMergeSession;
  private SNodeId myRootId;
  private MergeSession.MergeSessionFullState myStateToRestore;
  private boolean myDisposed = false;

  private ChangeEditorMessage.ConflictChecker myConflictChecker;
  private List<String> myTitles;
  private DiffEditor myResultEditor;
  private DiffEditor myMineEditor;
  private DiffEditor myRepositoryEditor;

  private ThreesideContentPanel myPanel;
  private boolean isInspectorShown = PropertiesComponent.getInstance().getBoolean(PARAM_SHOW_INSPECTOR, true);

  private List<ChangeGroupLayout> myChangeGroupLayouts = ListSequence.fromList(new ArrayList<ChangeGroupLayout>());
  private Map<DiffChangeGroupLayout, Boolean> myDiffLayoutPart = MapSequence.fromMap(new HashMap<DiffChangeGroupLayout, Boolean>());
  private boolean myIsEditorsSyncEnabled = isEditorsScrollingSyncOptionEnabled();
  private DiffEditorsGroup myDiffEditorsGroup = new DiffEditorsGroup(myIsEditorsSyncEnabled);

  private DefaultActionGroup myActionGroup;
  private NextPreviousTraverser myTraverser;
  private List<JBSplitter> mySplitters = ListSequence.fromList(new ArrayList<JBSplitter>());

  private final CurrentDifferenceRegistry myDiffRegistry;
  private MyDifferenceListener myDifferenceListener = new MyDifferenceListener();

  private final InvalidationHandler myInvalidationHandler;
  private TripleChangeGroupLayout myMainLayout;
  private TripleChangeGroupLayout myInspectorLayout;
  private final List<ChangeGroupMessages> myGutterMessagesRebuilders = ListSequence.fromList(new ArrayList<ChangeGroupMessages>());
  @Nullable
  private final List<DiffEditorTitleCustomizer> myTitleCustomizers;
  private final TrackMovedNodesModeUpdater myTrackMovedNodesModeUpdater;


  public MergeRootsPane(Project project, MergeSession mergeSession, SNodeId rootId, String rootName, List<String> titles, @Nullable List<DiffEditorTitleCustomizer> titleCustomizers, TrackMovedNodesModeUpdater trackMovedNodesModeUpdater) {
    myProject = project;
    myMergeSession = mergeSession;
    myRootId = rootId;
    myStateToRestore = myMergeSession.getCurrentFullState();
    myTitles = titles;
    myTitleCustomizers = titleCustomizers;
    myConflictChecker = (ModelChange ch) -> Sequence.fromIterable(myMergeSession.getConflictedWith(ch)).isNotEmpty();
    myTrackMovedNodesModeUpdater = trackMovedNodesModeUpdater;

    myMineEditor = addEditor(0, myMergeSession.getMyModel());
    myResultEditor = addEditor(1, myMergeSession.getResultModel());
    myRepositoryEditor = addEditor(2, myMergeSession.getRepositoryModel());

    myPanel = createThreesideContentPanel();

    ModelAccess modelAccess = ProjectHelper.fromIdeaProject(myProject).getRepository().getModelAccess();
    myInvalidationHandler = new InvalidationHandler(modelAccess);
    myMergeSession.setChangesInvalidateHandler(myInvalidationHandler);

    myTraverser = new NextPreviousTraverser(myChangeGroupLayouts, myResultEditor.getMainEditor());

    createActionGroup();

    highlightAllChanges();
    myTraverser.goToFirstChangeLater();
    myDiffRegistry = CurrentDifferenceRegistry.getInstance(myProject);
    myDiffRegistry.getCommandQueue().runTask(() -> {
      if (myMergeSession.getMyModel() instanceof EditableSModel) {
        final CurrentDifference currentDifference = myDiffRegistry.getCurrentDifference((EditableSModel) myMergeSession.getMyModel());
        currentDifference.addDifferenceListener(myDifferenceListener);
      }
    });
  }

  private class MyDifferenceListener extends CurrentDifferenceAdapter {

    @Override
    public void changeUpdateFinished() {
      rehighlightWithRebuild();
    }
    @Override
    public void changesAdded(@NotNull List<ModelChange> changes) {
      rehighlightWithRebuild();
    }
    @Override
    public void changesRemoved(@NotNull List<ModelChange> changes) {
      rehighlightWithRebuild();
    }

    private void rehighlightWithRebuild() {
      check_lifo0_a0a5pb(ProjectHelper.getModelAccess(myProject), this);
    }
    private void doRehighlight() {
      rehighlight();
    }
  }

  @Override
  public void propertyChange(PropertyChangeEvent event) {
    if (!(Splitter.PROP_PROPORTION.equals(event.getPropertyName()))) {
      return;
    }
    Splitter sourceSplitter = (Splitter) event.getSource();
    for (JBSplitter splitter : ListSequence.fromList(mySplitters)) {
      if (splitter != sourceSplitter) {
        splitter.removePropertyChangeListener(Splitter.PROP_PROPORTION, this);
        splitter.setProportion((float) event.getNewValue());
        splitter.addPropertyChangeListener(Splitter.PROP_PROPORTION, this);
      }
    }
  }

  private ThreesideContentPanel createThreesideContentPanel() {
    ThreesideContentPanel panel = new ThreesideContentPanel(Arrays.asList(myMineEditor.getPanel(), myResultEditor.getPanel(), myRepositoryEditor.getPanel()));
    ListSequence.fromList(mySplitters).addElement((JBSplitter) myMineEditor.getPanel());
    ListSequence.fromList(mySplitters).addElement((JBSplitter) myResultEditor.getPanel());
    ListSequence.fromList(mySplitters).addElement((JBSplitter) myRepositoryEditor.getPanel());
    for (JBSplitter splitter : ListSequence.fromList(mySplitters)) {
      splitter.setSplitterProportionKey(PARAM_INSPECTOR_SPLITTER_POSITION);
      splitter.addPropertyChangeListener(Splitter.PROP_PROPORTION, this);
    }

    panel.setTitles(createTitles());

    linkEditors(panel, true, false);
    linkEditors(panel, false, false);
    myMainLayout = new TripleChangeGroupLayout((DiffChangeGroupLayout) ListSequence.fromList(myChangeGroupLayouts).getElement(0), (DiffChangeGroupLayout) ListSequence.fromList(myChangeGroupLayouts).getElement(1), false);
    linkEditors(panel, true, true);
    linkEditors(panel, false, true);
    myInspectorLayout = new TripleChangeGroupLayout((DiffChangeGroupLayout) ListSequence.fromList(myChangeGroupLayouts).getElement(2), (DiffChangeGroupLayout) ListSequence.fromList(myChangeGroupLayouts).getElement(3), true);
    panel.setPainter(new MyDividerPainter(true), Side.LEFT);
    panel.setPainter(new MyDividerPainter(false), Side.RIGHT);
    return panel;
  }

  protected List<JComponent> createTitles() {
    if (myTitleCustomizers != null) {
      List<JComponent> titles = ListSequence.fromList(new ArrayList<JComponent>());
      for (int i = 0; i < ListSequence.fromList(myTitles).count(); i++) {
        ListSequence.fromList(titles).addElement(DiffUtil.createTitle(ListSequence.fromList(myTitles).getElement(i), ListSequence.fromList(myTitleCustomizers).getElement(i)));
      }
      return titles;
    }
    return Arrays.asList(myMineEditor.getTitleComponent(), myResultEditor.getTitleComponent(), myRepositoryEditor.getTitleComponent());
  }

  private void createActionGroup() {
    myActionGroup = new DefaultActionGroup();
    myActionGroup.add(new ApplyNonConflictsForRoot(this));
    myActionGroup.addSeparator();
    myActionGroup.addAll(myTraverser.previousAction(), myTraverser.nextAction());
    myTraverser.previousAction().registerCustomShortcutSet(NextPreviousTraverser.PREV_CHANGE_SHORTCUT, myPanel);
    myTraverser.nextAction().registerCustomShortcutSet(NextPreviousTraverser.NEXT_CHANGE_SHORTCUT, myPanel);
    myActionGroup.addSeparator();
    myActionGroup.add(new ShowInspectorAction());
    myActionGroup.add(new SyncScrollingAction());
    myActionGroup.add(new SettingsAction());
  }

  private class ShowInspectorAction extends ToggleAction implements DumbAware {
    private ShowInspectorAction() {
      super("Show Inspector", "Show Inspector Windows", IdeIcons.INSPECTOR_ICON);
    }
    @Override
    public boolean isSelected(AnActionEvent e) {
      return isInspectorShown;
    }
    @Override
    public void setSelected(AnActionEvent e, boolean b) {
      showInspector(b);
    }
  }

  private class SyncScrollingAction extends ToggleAction implements DumbAware {
    private SyncScrollingAction() {
      super(() -> DiffBundle.message("synchronize.scrolling", new Object[0]), IdeIcons.SYNC_SCROLLING);
    }
    @Override
    public boolean isSelected(@NotNull AnActionEvent p1) {
      return isEditorsScrollingSyncOptionEnabled();
    }
    @Override
    public void setSelected(@NotNull AnActionEvent e, boolean b) {
      saveEditorsScrollingSyncOption(b);
      enableEditorsScrollingSynchronization(b);
    }
    @Override
    public void update(@NotNull AnActionEvent e) {
      super.update(e);
      enableEditorsScrollingSynchronization(isEditorsScrollingSyncOptionEnabled());
    }
  }

  private class SettingsAction extends BaseGroup {

    private SettingsAction() {
      super("Settings", null, IdeIcons.GEAR_PLAIN_ICON);
      setPopup(true);
    }

    @Override
    public AnAction[] getChildren(@Nullable AnActionEvent event) {
      return new AnAction[]{new UseShortChangeDescriptionsAction(), new TrackMovedNodesAction()};
    }
  }

  private class TrackMovedNodesAction extends ToggleAction implements DumbAware {

    private TrackMovedNodesAction() {
      super("Track Moved Nodes");
    }

    @Override
    public boolean isSelected(@NotNull AnActionEvent p1) {
      return DiffSettingsUtil.getTrackMovedNodesMergeOption();
    }

    @Override
    public void setSelected(@NotNull AnActionEvent p1, boolean p2) {
      check_lifo0_a0a5fc(myTrackMovedNodesModeUpdater);
    }
  }

  private static class UseShortChangeDescriptionsAction extends ToggleAction implements DumbAware {

    private UseShortChangeDescriptionsAction() {
      super("Use Short Change Descriptions");
    }

    @Override
    public boolean isSelected(@NotNull AnActionEvent p1) {
      return DiffSettingsUtil.getUseShortDescriptionsOption();
    }

    @Override
    public void setSelected(@NotNull AnActionEvent p1, boolean p2) {
      DiffSettingsUtil.setUseShortDescriptionsOption(p2);
    }
  }

  public interface TrackMovedNodesModeUpdater {
    void trackMovedNodesModeChanged();
  }

  private class MyDividerPainter implements DiffSplitter.Painter {

    private final boolean mine;

    public MyDividerPainter(boolean mine) {
      this.mine = mine;
    }

    @Override
    public void paint(@NotNull Graphics g, @NotNull JComponent divider) {
      paintDividerPart(g, divider, false);
      if (isInspectorShown) {
        paintDividerPart(g, divider, true);
      }
    }

    private void paintDividerPart(@NotNull Graphics g, @NotNull JComponent divider, boolean inspector) {
      TripleChangeGroupLayout layout = (inspector ? myInspectorLayout : myMainLayout);
      DiffEditor leftEditor = (mine ? myMineEditor : myResultEditor);
      DiffEditor rightEditor = (mine ? myResultEditor : myRepositoryEditor);
      layout.paintPolygons(g, divider, leftEditor, rightEditor);
    }
  }

  public ActionGroup getActions() {
    return myActionGroup;
  }

  public void registerShortcuts(JComponent component) {
    myTraverser.previousAction().registerCustomShortcutSet(NextPreviousTraverser.PREV_CHANGE_SHORTCUT, component);
    myTraverser.nextAction().registerCustomShortcutSet(NextPreviousTraverser.NEXT_CHANGE_SHORTCUT, component);
  }

  public void unregisterShortcuts(JComponent component) {
    myTraverser.previousAction().unregisterCustomShortcutSet(component);
    myTraverser.nextAction().unregisterCustomShortcutSet(component);
  }

  public JPanel getPanel() {
    return myPanel;
  }

  public SNodeId getRootId() {
    return myRootId;
  }

  public void setRootId(SNodeId rootId) {
    myRootId = rootId;
    myStateToRestore = myMergeSession.getCurrentFullState();
    myMineEditor.editRoot(getRootNodeId(myMergeSession.getMyModel()), myMergeSession.getMyModel());
    myResultEditor.editRoot(getRootNodeId(myMergeSession.getResultModel()), myMergeSession.getResultModel());
    myRepositoryEditor.editRoot(getRootNodeId(myMergeSession.getRepositoryModel()), myMergeSession.getRepositoryModel());
    rehighlight();
    myTraverser.goToFirstChangeLater();
  }

  public void setRoodId(SNodeId rootId, final MergeSession mergeSession) {
    myMergeSession = mergeSession;
    MapSequence.fromMap(myDiffLayoutPart).visitAll((it) -> it.key().setChangeSet((it.value() ? mergeSession.getMyChangeSet() : mergeSession.getRepositoryChangeSet())));
    setRootId(rootId);
  }

  private void showInspector(boolean show) {
    if (isInspectorShown == show) {
      return;
    }
    isInspectorShown = show;
    PropertiesComponent.getInstance().setValue(PARAM_SHOW_INSPECTOR, show + "");
    myMineEditor.showInspector(show);
    myResultEditor.showInspector(show);
    myRepositoryEditor.showInspector(show);
  }

  private static boolean isEditorsScrollingSyncOptionEnabled() {
    return PropertiesComponent.getInstance().getBoolean(PARAM_ENABLE_EDITORS_SCROLL_SYNC, true);
  }

  private void saveEditorsScrollingSyncOption(boolean enable) {
    PropertiesComponent.getInstance().setValue(PARAM_ENABLE_EDITORS_SCROLL_SYNC, enable, true);
  }

  private void enableEditorsScrollingSynchronization(boolean isEditorsSyncEnabled) {
    if (myIsEditorsSyncEnabled == isEditorsSyncEnabled) {
      return;
    }
    myIsEditorsSyncEnabled = isEditorsSyncEnabled;
    myDiffEditorsGroup.enableEditorsSynchronization(isEditorsSyncEnabled);
  }

  public void rehighlight() {
    if (myDisposed) {
      return;
    }
    myMineEditor.unhighlightAllChanges();
    myResultEditor.unhighlightAllChanges();
    myRepositoryEditor.unhighlightAllChanges();

    if (myResultEditor.getEditedNode() == null) {
      SModel resultModel = myMergeSession.getResultModel();
      SNodeId nodeId = getRootNodeId(resultModel);
      if (nodeId != null) {
        myResultEditor.editRoot(nodeId, resultModel);
      }
    }

    myResultEditor.getMainEditor().rebuildEditorContent();

    highlightAllChanges();
  }

  private void highlightAllChanges() {
    ListSequence.fromList(myChangeGroupLayouts).visitAll((b) -> b.invalidate());

    List<ModelChange> changesForRoot = ListSequence.fromList(myMergeSession.getChangesForRoot(myRootId)).where((ch) -> !(myMergeSession.isChangeResolved(ch))).toList();
    for (ModelChange change : ListSequence.fromList(changesForRoot)) {
      higlightChange(myResultEditor, myMergeSession.getResultModel(), true, change);
      if (myMergeSession.isMyChange(change)) {
        higlightChange(myMineEditor, myMergeSession.getMyModel(), false, change);
      } else {
        higlightChange(myRepositoryEditor, myMergeSession.getRepositoryModel(), false, change);
      }
    }
    ListSequence.fromList(myChangeGroupLayouts).visitAll((b) -> b.invalidate());
    myMineEditor.repaintAndRebuildEditorMessages();
    myResultEditor.repaintAndRebuildEditorMessages();
    myRepositoryEditor.repaintAndRebuildEditorMessages();
  }

  private void higlightChange(DiffEditor diffEditor, SModel model, boolean isOldEditor, ModelChange change) {
    diffEditor.highlightChange(model, change, isOldEditor, myConflictChecker);
  }

  private void linkEditors(ThreesideContentPanel panel, boolean mine, boolean inspector) {
    DiffChangeGroupLayout layout = new DiffChangeGroupLayout(myConflictChecker, (mine ? myMergeSession.getMyChangeSet() : myMergeSession.getRepositoryChangeSet()), (mine ? myMineEditor : myResultEditor), (mine ? myResultEditor : myRepositoryEditor), getSplitterRepainter(panel, mine), inspector);
    layout.setIsMerge();
    MapSequence.fromMap(myDiffLayoutPart).put(layout, mine);
    ListSequence.fromList(myGutterMessagesRebuilders).addElement(new ChangeGroupMessages(layout, mine));
    ListSequence.fromList(myChangeGroupLayouts).addElement(layout);
    MergeButtonsPainter.addTo(this, (mine ? myMineEditor : myRepositoryEditor), layout, inspector);
  }

  private DiffChangeGroupLayout.SplitterRepainter getSplitterRepainter(final ThreesideContentPanel panel, final boolean mine) {
    return new DiffChangeGroupLayout.SplitterRepainter() {
      @Override
      public void repaintSplitter() {
        panel.repaintDivider((mine ? Side.LEFT : Side.RIGHT));
      }
    };
  }

  private SNodeId getRootNodeId(SModel model) {
    SNode node = model.getNode(myRootId);
    if (node != null && node.getParent() == null) {
      return myRootId;
    }
    if (model == myMergeSession.getResultModel()) {
      SNodeId replacement = myMergeSession.getReplacementId(myRootId);
      if (replacement != null) {
        return replacement;
      }
    }
    return null;
  }

  private DiffEditor addEditor(int index, SModel model) {
    SNodeId rootId = getRootNodeId(model);
    final DiffEditor result = new DiffEditor(ProjectHelper.fromIdeaProject(myProject), model, rootId, ListSequence.fromList(myTitles).getElement(index), index == 0, isInspectorShown);
    myDiffEditorsGroup.add(result);
    return result;
  }

  /*package*/ MergeSession getMergeSession() {
    return myMergeSession;
  }

  /*package*/ void setMergeSession(final MergeSession mergeSession) {
    myMergeSession = mergeSession;
    MapSequence.fromMap(myDiffLayoutPart).visitAll((it) -> it.key().setChangeSet((it.value() ? mergeSession.getMyChangeSet() : mergeSession.getRepositoryChangeSet())));
    myResultEditor.editRoot(getRootNodeId(myMergeSession.getResultModel()), myMergeSession.getResultModel());
    rehighlight();

    myDiffEditorsGroup.synchronizeViewWithOther(myMineEditor, myResultEditor, false);
    myDiffEditorsGroup.synchronizeViewWithOther(myMineEditor, myResultEditor, true);
  }

  public void restoreState() {
    myMergeSession.restoreFullState(myStateToRestore);
  }

  public void dispose() {
    synchronized (this) {
      if (myDisposed) {
        return;
      }
      ListSequence.fromList(myGutterMessagesRebuilders).visitAll((it) -> it.dispose());
      myDiffRegistry.getCommandQueue().runTask(() -> {
        if (myMergeSession.getMyModel() instanceof EditableSModel) {
          myDiffRegistry.getCurrentDifference((EditableSModel) myMergeSession.getMyModel()).removeDifferenceListener(myDifferenceListener);
        }
      });
      if (myActionGroup != null) {
        myActionGroup.removeAll();
      }
      myActionGroup = null;
      myMainLayout.dispose();
      myInspectorLayout.dispose();
      myDiffEditorsGroup.dispose();
      myMineEditor = null;
      myResultEditor = null;
      myRepositoryEditor = null;
      myInvalidationHandler.dispose();
      myMergeSession.setChangesInvalidateHandler(null);
      myDisposed = true;
    }
  }

  private final class InvalidationHandler implements MergeSession.ChangesInvalidateHandler, CommandListener {
    private final AtomicBoolean myHighlighScheduled = new AtomicBoolean(false);
    private final ModelAccess myMA;

    private InvalidationHandler(@NotNull ModelAccess ma) {
      myMA = ma;
      myMA.addCommandListener(this);
    }

    private void doInvalidate() {
      myMA.runReadInEDT(() -> rehighlight());
    }

    public void dispose() {
      myMA.removeCommandListener(this);
    }

    @Override
    public void someChangesInvalidated() {
      myHighlighScheduled.set(true);
    }

    @Override
    public void commandStarted() {
      // nop
    }

    @Override
    public void commandFinished() {
      if (myHighlighScheduled.compareAndSet(true, false)) {
        doInvalidate();
      }
    }
  }
  private static void check_lifo0_a0a5pb(ModelAccess checkedDotOperand, final MyDifferenceListener checkedDotThisExpression) {
    if (null != checkedDotOperand) {
      checkedDotOperand.runReadInEDT(() -> checkedDotThisExpression.doRehighlight());
    }

  }
  private static void check_lifo0_a0a5fc(TrackMovedNodesModeUpdater checkedDotOperand) {
    if (null != checkedDotOperand) {
      checkedDotOperand.trackMovedNodesModeChanged();
    }

  }
}
