All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.vcs.log.graph.linearBek.LinearBekController Maven / Gradle / Ivy

/*
 * 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.vcs.log.graph.linearBek;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.graph.actions.GraphAction;
import com.intellij.vcs.log.graph.api.EdgeFilter;
import com.intellij.vcs.log.graph.api.GraphLayout;
import com.intellij.vcs.log.graph.api.LinearGraph;
import com.intellij.vcs.log.graph.api.elements.GraphEdge;
import com.intellij.vcs.log.graph.api.elements.GraphEdgeType;
import com.intellij.vcs.log.graph.api.elements.GraphElement;
import com.intellij.vcs.log.graph.api.elements.GraphNode;
import com.intellij.vcs.log.graph.api.permanent.PermanentGraphInfo;
import com.intellij.vcs.log.graph.impl.facade.BekBaseController;
import com.intellij.vcs.log.graph.impl.facade.CascadeController;
import com.intellij.vcs.log.graph.impl.facade.GraphChangesUtil;
import com.intellij.vcs.log.graph.impl.facade.bek.BekIntMap;
import com.intellij.vcs.log.graph.utils.LinearGraphUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class LinearBekController extends CascadeController {
  private static final Logger LOG = Logger.getInstance(LinearBekController.class);
  @NotNull private final LinearBekGraph myCompiledGraph;
  private final LinearBekGraphBuilder myLinearBekGraphBuilder;
  private final BekGraphLayout myBekGraphLayout;

  public LinearBekController(@NotNull BekBaseController controller, @NotNull PermanentGraphInfo permanentGraphInfo) {
    super(controller, permanentGraphInfo);
    myCompiledGraph = new LinearBekGraph(getDelegateGraph());
    myBekGraphLayout = new BekGraphLayout(permanentGraphInfo.getPermanentGraphLayout(), controller.getBekIntMap());
    myLinearBekGraphBuilder = new LinearBekGraphBuilder(myCompiledGraph, myBekGraphLayout);

    long start = System.currentTimeMillis();
    myLinearBekGraphBuilder.collapseAll();
    LOG.info("Linear bek took " + (System.currentTimeMillis() - start) / 1000.0 + " sec");
  }

  @NotNull
  @Override
  protected LinearGraphAnswer delegateGraphChanged(@NotNull LinearGraphAnswer delegateAnswer) {
    return delegateAnswer;
  }

  @Nullable
  @Override
  protected LinearGraphAnswer performAction(@NotNull LinearGraphAction action) {
    if (action.getAffectedElement() != null) {
      if (action.getType() == GraphAction.Type.MOUSE_CLICK) {
        GraphElement graphElement = action.getAffectedElement().getGraphElement();
        if (graphElement instanceof GraphNode) {
          LinearGraphAnswer answer = collapseNode((GraphNode)graphElement);
          if (answer != null) return answer;
          for (GraphEdge dottedEdge : getAllAdjacentDottedEdges((GraphNode)graphElement)) {
            LinearGraphAnswer expandedAnswer = expandEdge(dottedEdge);
            if (expandedAnswer != null) return expandedAnswer;
          }
        }
        else if (graphElement instanceof GraphEdge) {
          return expandEdge((GraphEdge)graphElement);
        }
      }
      else if (action.getType() == GraphAction.Type.MOUSE_OVER) {
        GraphElement graphElement = action.getAffectedElement().getGraphElement();
        if (graphElement instanceof GraphNode) {
          LinearGraphAnswer answer = highlightNode((GraphNode)graphElement);
          if (answer != null) return answer;
          for (GraphEdge dottedEdge : getAllAdjacentDottedEdges((GraphNode)graphElement)) {
            LinearGraphAnswer highlightAnswer = highlightEdge(dottedEdge);
            if (highlightAnswer != null) return highlightAnswer;
          }
        }
        else if (graphElement instanceof GraphEdge) {
          return highlightEdge((GraphEdge)graphElement);
        }
      }
    }
    else if (action.getType() == GraphAction.Type.BUTTON_COLLAPSE) {
      return collapseAll();
    }
    else if (action.getType() == GraphAction.Type.BUTTON_EXPAND) {
      return expandAll();
    }
    return null;
  }

  @NotNull
  private List getAllAdjacentDottedEdges(GraphNode graphElement) {
    return ContainerUtil.filter(myCompiledGraph.getAdjacentEdges(graphElement.getNodeIndex(), EdgeFilter.ALL), new Condition() {
      @Override
      public boolean value(GraphEdge graphEdge) {
        return graphEdge.getType() == GraphEdgeType.DOTTED;
      }
    });
  }

  @NotNull
  private LinearGraphAnswer expandAll() {
    return new LinearGraphAnswer(GraphChangesUtil.SOME_CHANGES, null, null, null) {
      @Nullable
      @Override
      public Runnable getGraphUpdater() {
        return new Runnable() {
          @Override
          public void run() {
            myCompiledGraph.myDottedEdges.removeAll();
            myCompiledGraph.myHiddenEdges.removeAll();
          }
        };
      }
    };
  }

  @NotNull
  private LinearGraphAnswer collapseAll() {
    final LinearBekGraph.WorkingLinearBekGraph workingGraph = new LinearBekGraph.WorkingLinearBekGraph(myCompiledGraph);
    new LinearBekGraphBuilder(workingGraph, myBekGraphLayout).collapseAll();
    return new LinearGraphAnswer(
      GraphChangesUtil.edgesReplaced(workingGraph.getRemovedEdges(), workingGraph.getAddedEdges(), getDelegateGraph()), null, null, null) {
      @Nullable
      @Override
      public Runnable getGraphUpdater() {
        return new Runnable() {
          @Override
          public void run() {
            workingGraph.applyChanges();
          }
        };
      }
    };
  }

  @Nullable
  private LinearGraphAnswer highlightNode(GraphNode node) {
    Set toCollapse = collectFragmentsToCollapse(node);
    if (toCollapse.isEmpty()) return null;

    Set toHighlight = ContainerUtil.newHashSet();
    for (LinearBekGraphBuilder.MergeFragment fragment : toCollapse) {
      toHighlight.addAll(fragment.getAllNodes());
    }

    return LinearGraphUtils.createSelectedAnswer(myCompiledGraph, toHighlight);
  }

  @Nullable
  private LinearGraphAnswer highlightEdge(GraphEdge edge) {
    if (edge.getType() == GraphEdgeType.DOTTED) {
      return LinearGraphUtils.createSelectedAnswer(myCompiledGraph, ContainerUtil.set(edge.getUpNodeIndex(), edge.getDownNodeIndex()));
    }
    return null;
  }

  @Nullable
  private LinearGraphAnswer collapseNode(GraphNode node) {
    SortedSet toCollapse = collectNodesToCollapse(node);

    if (toCollapse.isEmpty()) return null;

    for (Integer i : toCollapse) {
      myLinearBekGraphBuilder.collapseFragment(i);
    }
    return new LinearGraphAnswer(GraphChangesUtil.SOME_CHANGES, null, null, null);
  }

  private SortedSet collectNodesToCollapse(GraphNode node) {
    SortedSet toCollapse = new TreeSet(new Comparator() {
      @Override
      public int compare(Integer o1, Integer o2) {
        return o2.compareTo(o1);
      }
    });
    for (LinearBekGraphBuilder.MergeFragment f : collectFragmentsToCollapse(node)) {
      toCollapse.add(f.getParent());
      toCollapse.addAll(f.getTailsAndBody());
    }
    return toCollapse;
  }

  @NotNull
  private Set collectFragmentsToCollapse(GraphNode node) {
    Set result = ContainerUtil.newHashSet();

    int mergesCount = 0;

    LinkedHashSet toProcess = ContainerUtil.newLinkedHashSet();
    toProcess.add(node.getNodeIndex());
    while (!toProcess.isEmpty()) {
      Integer i = ContainerUtil.getFirstItem(toProcess);
      toProcess.remove(i);

      LinearBekGraphBuilder.MergeFragment fragment = myLinearBekGraphBuilder.getFragment(i);
      if (fragment == null) continue;

      result.add(fragment);
      toProcess.addAll(fragment.getTailsAndBody());

      mergesCount++;
      if (mergesCount > 10) break;
    }
    return result;
  }

  @Nullable
  private LinearGraphAnswer expandEdge(GraphEdge edge) {
    if (edge.getType() == GraphEdgeType.DOTTED) {
      return new LinearGraphAnswer(
        GraphChangesUtil.edgesReplaced(Collections.singleton(edge), myCompiledGraph.expandEdge(edge), getDelegateGraph()), null, null,
        null);
    }
    return null;
  }

  @NotNull
  private LinearGraph getDelegateGraph() {
    return getDelegateController().getCompiledGraph();
  }

  @NotNull
  @Override
  public LinearGraph getCompiledGraph() {
    return myCompiledGraph;
  }

  private static class BekGraphLayout implements GraphLayout {
    private final GraphLayout myGraphLayout;
    private final BekIntMap myBekIntMap;

    public BekGraphLayout(GraphLayout graphLayout, BekIntMap bekIntMap) {
      myGraphLayout = graphLayout;
      myBekIntMap = bekIntMap;
    }

    @Override
    public int getLayoutIndex(int nodeIndex) {
      return myGraphLayout.getLayoutIndex(myBekIntMap.getUsualIndex(nodeIndex));
    }

    @Override
    public int getOneOfHeadNodeIndex(int nodeIndex) {
      int usualIndex = myGraphLayout.getOneOfHeadNodeIndex(myBekIntMap.getUsualIndex(nodeIndex));
      return myBekIntMap.getBekIndex(usualIndex);
    }

    @NotNull
    @Override
    public List getHeadNodeIndex() {
      List bekIndexes = new ArrayList();
      for (int head : myGraphLayout.getHeadNodeIndex()) {
        bekIndexes.add(myBekIntMap.getBekIndex(head));
      }
      return bekIndexes;
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy