diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 35612c80f3d0..d61dc2424be3 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -2101,6 +2101,30 @@ public class ContainerUtil extends ContainerUtilRt { return -1; } + @Contract(pure=true) + public static int lastIndexOf(@NotNull List list, @NotNull Condition condition) { + for (int i = list.size() - 1; i >= 0; i--) { + T t = list.get(i); + if (condition.value(t)) { + return i; + } + } + return -1; + } + + @Nullable + @Contract(pure = true) + public static U findLastInstance(@NotNull List list, @NotNull final Class clazz) { + int i = lastIndexOf(list, new Condition() { + @Override + public boolean value(T t) { + return clazz.isInstance(t); + } + }); + //noinspection unchecked + return i < 0 ? null : (U)list.get(i); + } + @Contract(pure=true) public static int indexOf(@NotNull List list, @NotNull final T object) { return indexOf(list, new Condition() { @@ -2243,6 +2267,20 @@ public class ContainerUtil extends ContainerUtilRt { return ContainerUtilRt.map2Set(collection, mapper); } + @NotNull + @Contract(pure=true) + public static Set map2SetNotNull(@NotNull Collection collection, @NotNull Function mapper) { + if (collection.isEmpty()) return Collections.emptySet(); + Set set = new HashSet(collection.size()); + for (T t : collection) { + V value = mapper.fun(t); + if (value != null) { + set.add(value); + } + } + return set.isEmpty() ? Collections.emptySet() : set; + } + @NotNull @Contract(pure=true) public static T[] toArray(@NotNull List collection, @NotNull T[] array) { diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ChangeCursorActionRequest.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ChangeCursorActionRequest.java deleted file mode 100644 index ec7908295875..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ChangeCursorActionRequest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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; - -import org.jetbrains.annotations.NotNull; - -import java.awt.*; - -public class ChangeCursorActionRequest implements GraphActionRequest { - @NotNull private final Cursor myCursor; - - public ChangeCursorActionRequest(@NotNull Cursor cursor) { - myCursor = cursor; - } - - @NotNull - public Cursor getCursor() { - return myCursor; - } -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ClickGraphAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ClickGraphAction.java deleted file mode 100644 index fc037f701855..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/ClickGraphAction.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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; - -import org.jetbrains.annotations.Nullable; - -import java.awt.*; - -public class ClickGraphAction implements GraphAction { - - private final int myVisibleRow; - @Nullable private final Point myRelativePoint; - - public ClickGraphAction(int visibleRow, @Nullable Point relativePoint) { - myVisibleRow = visibleRow; - myRelativePoint = relativePoint; - } - - public int getRow() { - return myVisibleRow; - } - - @Nullable - public Point getRelativePoint() { - return myRelativePoint; - } - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAction.java deleted file mode 100644 index a08aaaf928c7..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAction.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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; - -public interface GraphAction { -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphActionRequest.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphActionRequest.java deleted file mode 100644 index a963da2a5ae5..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphActionRequest.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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; - -/** - * Action which should be executed by the code which called {@link GraphFacade#performAction(com.intellij.vcs.log.graph.GraphAction)}. - * E.g. when user clicks to the arrow to go to the parent/child commit, the table should jump to concrete row. - */ -public interface GraphActionRequest { - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAnswer.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAnswer.java deleted file mode 100644 index 57c985155e89..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphAnswer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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; - -import org.jetbrains.annotations.Nullable; - -/** - * The graph returns an instance of the GraphAnswer as a reaction to {@link #performAction(com.intellij.vcs.log.graph.GraphAction)}. - */ -public interface GraphAnswer { - - /** - * Tells how graph was changed after performing action
- * {@code null} means that graph didn't change (e.g. when user clicks on the arrow to go to the parent/child commit). - */ - @Nullable - GraphChange getGraphChange(); - - /** - * Tells which action should be execute by the client code.
- * {@code null} means that the graph doesn't expect the client code to execute anything special - * (although of course it can react somehow on the returned {@link #getGraphChange() GraphChange}. - */ - @Nullable - GraphActionRequest getActionRequest(); - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphChange.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphChange.java deleted file mode 100644 index 41cdaa1f14a6..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphChange.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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; - -/** - * Describes how graph was changed after {@link GraphFacade#performAction(GraphAction) executing some action on it} - * (e.g. a linear branch was collapsed). - */ -public interface GraphChange { - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphFacade.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphFacade.java deleted file mode 100644 index b48e70266f50..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphFacade.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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; - -import com.intellij.openapi.util.Condition; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collection; -import java.util.List; - -/** - * The only point of interaction with the Graph. - *

- * Any access to the methods of this class must be performed from the EDT. - */ -public interface GraphFacade { - - /** - * Paints the given row. - */ - @NotNull - PaintInfo paint(int visibleRow); - - /** - * Performs some user action on the graph, which can be a click, hover, drag, changing view parameters, etc.
- * Changes are applied to the graph immediately, and the method returns the result of such action.
- * In some cases the action might take significant time (say, 1 second) - clients of this method take care of it themselves: by showing - * some modal progress or else. - */ - @Nullable - GraphAnswer performAction(@NotNull GraphAction action); - - /** - * Returns all commits in the graph without considering commits visibility. - * To get visible commits use {@link #getVisibleCommitCount} & {@link #getCommitAtRow}. - */ - @NotNull - List> getAllCommits(); - - /** - * A shorthand to getVisibleCommits().get(visibleRow), but may be faster. - */ - int getCommitAtRow(int visibleRow); - - /** - * A shorthand to {@code getVisibleCommits().size()}, but is faster. - */ - int getVisibleCommitCount(); - - /** - * Set branches which should be visible in the log, all others will be hidden. - * Pass {@code null} to show all branches, i.e. reset this branch filter. - * - * @param heads branches represented by commit indices of commits they point to; or {@code null} if all branches should be shown. - * @see #setFilter(Condition) - */ - void setVisibleBranches(@Nullable Collection heads); - - /** - * Set filter to the commits displayed by the log. - * - * @param visibilityPredicate check if the given commit should be shown or not. null means no filter. - * @see #setVisibleBranches(Collection) - */ - void setFilter(@Nullable Condition visibilityPredicate); - - /** - * Returns the provider of some information about the graph. - */ - @NotNull - GraphInfoProvider getInfoProvider(); - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphInfoProvider.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphInfoProvider.java deleted file mode 100644 index 308a4c6ec0c8..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/GraphInfoProvider.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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; - -import org.jetbrains.annotations.NotNull; - -import java.util.Set; - -/** - * Use this provider to get information from the Graph.
- * An instance of GraphInfoProvider is obtained via {@link GraphFacade#getInfoProvider()}. - */ -public interface GraphInfoProvider { - - @NotNull - Set getContainingBranches(int visibleRow); // this requires graph iteration => can take some time - - @NotNull - RowInfo getRowInfo(int visibleRow); - - boolean areLongEdgesHidden(); - - /** - * Some information about row highlighting etc. TBD - */ - interface RowInfo { - int getOneOfHeads(); - } - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToNotLoadCommitActionRequest.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToNotLoadCommitActionRequest.java deleted file mode 100644 index c4348f3e6b1c..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToNotLoadCommitActionRequest.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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; - -public class JumpToNotLoadCommitActionRequest implements GraphActionRequest { - private final int commitHashIndex; - - public JumpToNotLoadCommitActionRequest(int commitHashIndex) { - this.commitHashIndex = commitHashIndex; - } - - public int getCommitHashIndex() { - return commitHashIndex; - } -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToRowActionRequest.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToRowActionRequest.java deleted file mode 100644 index 5b2518b26f8a..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/JumpToRowActionRequest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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; - -public class JumpToRowActionRequest implements GraphActionRequest { - - private final int myRow; - - public JumpToRowActionRequest(int row) { - myRow = row; - } - - public int getRow() { - return myRow; - } - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LinearBranchesExpansionAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LinearBranchesExpansionAction.java deleted file mode 100644 index dbfd046cf0b6..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LinearBranchesExpansionAction.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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; - -public class LinearBranchesExpansionAction implements GraphAction { - - public static LinearBranchesExpansionAction EXPAND = new LinearBranchesExpansionAction(true); - public static LinearBranchesExpansionAction COLLAPSE = new LinearBranchesExpansionAction(false); - - private final boolean myExpand; - - private LinearBranchesExpansionAction(boolean expand) { - myExpand = expand; - } - - public boolean shouldExpand() { - return myExpand; - } -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LongEdgesAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LongEdgesAction.java deleted file mode 100644 index 4824f0b13c65..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/LongEdgesAction.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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; - -public class LongEdgesAction implements GraphAction { - - private static LongEdgesAction SHOW = new LongEdgesAction(true); - private static LongEdgesAction HIDE = new LongEdgesAction(false); - - private final boolean myShowLongEdges; - - public static LongEdgesAction valueOf(boolean showLongEdges) { - return showLongEdges ? SHOW : HIDE; - } - - private LongEdgesAction(boolean show) { - myShowLongEdges = show; - } - - public boolean shouldShowLongEdges() { - return myShowLongEdges; - } - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/MouseOverAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/MouseOverAction.java deleted file mode 100644 index ca619c6e55f3..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/MouseOverAction.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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; - -import org.jetbrains.annotations.NotNull; - -import java.awt.*; - -public class MouseOverAction implements GraphAction { - - private final int myVisibleRow; - @NotNull private final Point myRelativePoint; - - public MouseOverAction(int visibleRow, @NotNull Point relativePoint) { - myVisibleRow = visibleRow; - myRelativePoint = relativePoint; - } - - public int getRow() { - return myVisibleRow; - } - - @NotNull - public Point getRelativePoint() { - return myRelativePoint; - } - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/PaintInfo.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/PaintInfo.java deleted file mode 100644 index 42e56042756e..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/PaintInfo.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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; - -import org.jetbrains.annotations.NotNull; - -import java.awt.*; - -public interface PaintInfo { - - /** - * Returns the image to actually paint. - */ - @NotNull - Image getImage(); - - /** - * Returns the "interesting" width of the painted image, i.e. the width which the text in the table should be offset by.
- * It can be smaller than the width of {@link #getImage() the image}, because we allow the text to cover part of the graph - * (some diagonal edges, etc.) - */ - int getWidth(); - -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/SelectAllRelativeCommitsAction.java b/platform/vcs-log/api/src/com/intellij/vcs/log/graph/SelectAllRelativeCommitsAction.java deleted file mode 100644 index f35d226692c4..000000000000 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/SelectAllRelativeCommitsAction.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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; - -public class SelectAllRelativeCommitsAction implements GraphAction { - public static final SelectAllRelativeCommitsAction DESELECT_ALL = new SelectAllRelativeCommitsAction(-1); - - private final int visibleRowIndex; - - public SelectAllRelativeCommitsAction(int visibleRowIndex) { - this.visibleRowIndex = visibleRowIndex; - } - - public int getVisibleRowIndex() { - return visibleRowIndex; - } -} diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/DelegateGraphFacade.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/DelegateGraphFacade.java deleted file mode 100644 index 7e723580afaf..000000000000 --- a/platform/vcs-log/graph/src/com/intellij/vcs/log/DelegateGraphFacade.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * 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; - -import com.intellij.openapi.util.Condition; -import com.intellij.util.ui.UIUtil; -import com.intellij.vcs.log.graph.*; -import com.intellij.vcs.log.graph.actions.ActionController; -import com.intellij.vcs.log.graph.actions.GraphMouseAction; -import com.intellij.vcs.log.printer.idea.ColorGenerator; -import com.intellij.vcs.log.printer.idea.GraphCellPainter; -import com.intellij.vcs.log.printer.idea.PrintParameters; -import com.intellij.vcs.log.printer.idea.SimpleGraphCellPainter; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class DelegateGraphFacade implements GraphFacade { - @NotNull - public static final GraphAnswer JUMP_TO_0_GRAPH_ANSWER = new GraphAnswer() { - @Nullable - @Override - public GraphChange getGraphChange() { - return new GraphChange() { - }; - } - - @Nullable - @Override - public GraphActionRequest getActionRequest() { - return new JumpToRowActionRequest(0); - } - }; - - @NotNull - private final PermanentGraph myPermanentGraph; - private final GraphCellPainter myGraphCellPainter; - - @NotNull - private PermanentGraph.SortType mySortType = PermanentGraph.SortType.Normal; - - @NotNull - private VisibleGraph myVisibleGraph; - - @Nullable - private Set myHeads = null; - - @Nullable - private Condition myVisibilityPredicate = null; - - public DelegateGraphFacade(@NotNull PermanentGraph permanentGraph, @NotNull ColorGenerator colorGenerator) { - myPermanentGraph = permanentGraph; - myGraphCellPainter = new SimpleGraphCellPainter(colorGenerator); - updateVisibleGraph(); - } - - private void updateVisibleGraph() { - myVisibleGraph = myPermanentGraph.createVisibleGraph(mySortType, myHeads, myVisibilityPredicate); - } - - @NotNull - @Override - public PaintInfo paint(int visibleRow) { - Collection printElements = myVisibleGraph.getRowInfo(visibleRow).getPrintElements(); - int maxIndex = 0; - for (PrintElement printElement : printElements) { - maxIndex = Math.max(maxIndex, printElement.getPositionInCurrentRow()); - } - maxIndex++; - final BufferedImage image = - UIUtil.createImage(PrintParameters.WIDTH_NODE * (maxIndex + 4), PrintParameters.HEIGHT_CELL, BufferedImage.TYPE_INT_ARGB); - Graphics2D g2 = image.createGraphics(); - myGraphCellPainter.draw(g2, printElements); - - final int width = maxIndex * PrintParameters.WIDTH_NODE; - return new PaintInfo() { - @NotNull - @Override - public Image getImage() { - return image; - } - - @Override - public int getWidth() { - return width; - } - }; - } - - @Nullable - @Override - public GraphAnswer performAction(@NotNull GraphAction action) { - ActionController actionController = myVisibleGraph.getActionController(); - if (action instanceof ClickGraphAction) { - ClickGraphAction clickGraphAction = (ClickGraphAction)action; - Point relativePoint = clickGraphAction.getRelativePoint(); - PrintElement printElement = null; - if (relativePoint != null) { - Collection printElements = myVisibleGraph.getRowInfo(clickGraphAction.getRow()).getPrintElements(); - printElement = myGraphCellPainter.mouseOver(printElements, relativePoint.x, relativePoint.y); - } - return convert(actionController.performMouseAction(new GraphMouseActionImpl(printElement, GraphMouseAction.Type.CLICK))); - } - - if (action instanceof MouseOverAction) { - MouseOverAction mouseOverAction = (MouseOverAction)action; - Point relativePoint = mouseOverAction.getRelativePoint(); - Collection printElements = myVisibleGraph.getRowInfo(mouseOverAction.getRow()).getPrintElements(); - PrintElement printElement = myGraphCellPainter.mouseOver(printElements, relativePoint.x, relativePoint.y); - - return convert(actionController.performMouseAction(new GraphMouseActionImpl(printElement, GraphMouseAction.Type.OVER))); - } - - if (action instanceof LongEdgesAction) { - boolean shouldShowLongEdges = ((LongEdgesAction)action).shouldShowLongEdges(); - actionController.setLongEdgesHidden(!shouldShowLongEdges); - } - - if (action instanceof LinearBranchesExpansionAction) { - boolean shouldExpand = ((LinearBranchesExpansionAction)action).shouldExpand(); - actionController.setLinearBranchesExpansion(!shouldExpand); - return JUMP_TO_0_GRAPH_ANSWER; - } - - if (action instanceof BekGraphAction) { - mySortType = ((BekGraphAction)action).getSortType(); - updateVisibleGraph(); - return JUMP_TO_0_GRAPH_ANSWER; - } - - return null; - } - - @NotNull - private GraphAnswer convert(@NotNull com.intellij.vcs.log.graph.actions.GraphAnswer graphAnswer) { - final Integer commitToJump = graphAnswer.getCommitToJump(); - final Cursor cursorToSet = graphAnswer.getCursorToSet(); - return new GraphAnswer() { - @Nullable - @Override - public GraphChange getGraphChange() { - if (commitToJump != null) { - return new GraphChange() {}; - } - return null; - } - - @Nullable - @Override - public GraphActionRequest getActionRequest() { - if (cursorToSet != null) - return new ChangeCursorActionRequest(cursorToSet); - if (commitToJump != null) { - int visibleRowIndex = myVisibleGraph.getVisibleRowIndex(commitToJump); - if (visibleRowIndex == -1) - return new JumpToNotLoadCommitActionRequest(commitToJump); - return new JumpToRowActionRequest(visibleRowIndex); - } - return null; - } - }; - } - - @NotNull - @Override - public List> getAllCommits() { - return myPermanentGraph.getAllCommits(); - } - - @Override - public int getCommitAtRow(int visibleRow) { - return myVisibleGraph.getRowInfo(visibleRow).getCommit(); - } - - @Override - public int getVisibleCommitCount() { - return myVisibleGraph.getVisibleCommitCount(); - } - - @Override - public void setVisibleBranches(@Nullable Collection heads) { - boolean needUpdate; - if (heads == null) { - needUpdate = myHeads != null; - myHeads = null; - } else { - needUpdate = true; - myHeads = new HashSet(heads); - } - if (needUpdate) - updateVisibleGraph(); - } - - @Override - public void setFilter(@Nullable Condition visibilityPredicate) { - boolean needUpdate = !(visibilityPredicate == myVisibilityPredicate); - - myVisibilityPredicate = visibilityPredicate; - if (needUpdate) - updateVisibleGraph(); - } - - @NotNull - @Override - public GraphInfoProvider getInfoProvider() { - return new GraphInfoProvider() { - @NotNull - @Override - public Set getContainingBranches(int visibleRow) { - return myPermanentGraph.getContainingBranches(getCommitAtRow(visibleRow)); - } - - @NotNull - @Override - public RowInfo getRowInfo(int visibleRow) { - final Integer oneOfHeads = myVisibleGraph.getRowInfo(visibleRow).getOneOfHeads(); - return new RowInfo() { - @Override - public int getOneOfHeads() { - return oneOfHeads; - } - }; - } - - @Override - public boolean areLongEdgesHidden() { - return myVisibleGraph.getActionController().areLongEdgesHidden(); - } - }; - } - - private static class GraphMouseActionImpl implements GraphMouseAction { - @Nullable - private final PrintElement myAffectedElement; - @NotNull - private final Type myType; - - private GraphMouseActionImpl(@Nullable PrintElement affectedElement, @NotNull Type type) { - myAffectedElement = affectedElement; - myType = type; - } - - @Nullable - @Override - public PrintElement getAffectedElement() { - return myAffectedElement; - } - - @NotNull - @Override - public Type getType() { - return myType; - } - } -} diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/BekGraphAction.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/CommitCountStage.java similarity index 62% rename from platform/vcs-log/api/src/com/intellij/vcs/log/graph/BekGraphAction.java rename to platform/vcs-log/impl/src/com/intellij/vcs/log/data/CommitCountStage.java index 1deb51f6632b..574a098a1e90 100644 --- a/platform/vcs-log/api/src/com/intellij/vcs/log/graph/BekGraphAction.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/CommitCountStage.java @@ -13,21 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.vcs.log.graph; +package com.intellij.vcs.log.data; import org.jetbrains.annotations.NotNull; -public class BekGraphAction implements GraphAction { +enum CommitCountStage { - @NotNull - private final PermanentGraph.SortType mySortType; + INITIAL(5), + FIRST_STEP(2000), + ALL(Integer.MAX_VALUE); - public BekGraphAction(@NotNull PermanentGraph.SortType sortType) { - mySortType = sortType; + private final int myCount; + + CommitCountStage(int count) { + myCount = count; } @NotNull - public PermanentGraph.SortType getSortType() { - return mySortType; + CommitCountStage next() { + CommitCountStage[] values = values(); + return ordinal() == values.length - 1 ? this : values[ordinal() + 1]; + } + + public int getCount() { + return myCount; } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataGetter.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataGetter.java index c31db3894f53..532073437f28 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataGetter.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataGetter.java @@ -12,7 +12,7 @@ import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsLogProvider; import com.intellij.vcs.log.VcsShortCommitDetails; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; +import com.intellij.vcs.log.ui.tables.GraphTableModel; import com.intellij.vcs.log.util.SequentialLimitedLifoExecutor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -81,7 +81,7 @@ public abstract class DataGetter implements Dis } @Nullable - public T getCommitData(int row, @NotNull AbstractVcsLogTableModel tableModel) { + public T getCommitData(int row, @NotNull GraphTableModel tableModel) { assert EventQueue.isDispatchThread(); Hash hash = tableModel.getHashAtRow(row); if (hash == null) { @@ -122,7 +122,7 @@ public abstract class DataGetter implements Dis @Nullable protected abstract T getFromAdditionalCache(@NotNull Hash hash); - private void runLoadAroundCommitData(int row, @NotNull AbstractVcsLogTableModel tableModel) { + private void runLoadAroundCommitData(int row, @NotNull GraphTableModel tableModel) { long taskNumber = myCurrentTaskIndex++; MultiMap commits = getCommitsAround(row, tableModel, UP_PRELOAD_COUNT, DOWN_PRELOAD_COUNT); for (Map.Entry> hashesByRoots : commits.entrySet()) { @@ -143,7 +143,7 @@ public abstract class DataGetter implements Dis } @NotNull - private static MultiMap getCommitsAround(int selectedRow, @NotNull AbstractVcsLogTableModel model, + private static MultiMap getCommitsAround(int selectedRow, @NotNull GraphTableModel model, int above, int below) { MultiMap commits = MultiMap.create(); for (int row = Math.max(0, selectedRow - above); row < selectedRow + below && row < model.getRowCount(); row++) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java index 975808611ed4..c884649c0820 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java @@ -6,22 +6,18 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; import com.intellij.vcs.log.graph.GraphColorManagerImpl; import com.intellij.vcs.log.graph.GraphCommit; -import com.intellij.vcs.log.graph.GraphFacade; import com.intellij.vcs.log.graph.PermanentGraph; import com.intellij.vcs.log.graph.impl.facade.PermanentGraphImpl; -import com.intellij.vcs.log.printer.idea.ColorGenerator; import com.intellij.vcs.log.util.StopWatch; import org.jetbrains.annotations.NotNull; -import java.awt.*; import java.util.*; import java.util.List; -public class DataPack implements VcsLogDataPack { +public class DataPack { @NotNull private final RefsModel myRefsModel; @NotNull private final PermanentGraph myPermanentGraph; - @NotNull private final GraphFacade myGraphFacade; @NotNull private final Map myLogProviders; private boolean myFull; @@ -33,25 +29,7 @@ public class DataPack implements VcsLogDataPack { boolean full) { RefsModel refsModel = new RefsModel(refs, hashMap.asIndexGetter()); PermanentGraph graph = buildPermanentGraph(commits, refsModel, hashMap.asIndexGetter(), hashMap.asHashGetter(), providers); - return new DataPack(refsModel, graph, createGraphFacade(graph), providers, full); - } - - @NotNull - private static GraphFacade createGraphFacade(@NotNull PermanentGraph permanentGraph) { - GraphFacade facade; - if (!permanentGraph.getAllCommits().isEmpty()) { - ColorGenerator colorGenerator = new ColorGenerator() { - @Override - public Color getColor(int colorId) { - return com.intellij.vcs.log.graph.ColorGenerator.getColor(colorId); - } - }; - facade = new DelegateGraphFacade(permanentGraph, colorGenerator); - } - else { - facade = new EmptyGraphFacade(); - } - return facade; + return new DataPack(refsModel, graph, providers, full); } @NotNull @@ -91,22 +69,17 @@ public class DataPack implements VcsLogDataPack { return map; } - DataPack(@NotNull RefsModel refsModel, @NotNull PermanentGraph permanentGraph, @NotNull GraphFacade graphFacade, - @NotNull Map providers, boolean full) { + DataPack(@NotNull RefsModel refsModel, + @NotNull PermanentGraph permanentGraph, + @NotNull Map providers, + boolean full) { myRefsModel = refsModel; myPermanentGraph = permanentGraph; - myGraphFacade = graphFacade; myLogProviders = providers; myFull = full; } @NotNull - public GraphFacade getGraphFacade() { - return myGraphFacade; - } - - @NotNull - @Override public VcsLogRefs getRefs() { return myRefsModel; } @@ -117,7 +90,6 @@ public class DataPack implements VcsLogDataPack { } @NotNull - @Override public Map getLogProviders() { return myLogProviders; } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java index 54140afb3940..66a9cadd6745 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java @@ -30,7 +30,7 @@ public class EmptyDataPack { @NotNull public static DataPack getInstance() { RefsModel emptyModel = new RefsModel(Collections.>emptyMap(), new ConstantFunction(0)); - return new DataPack(emptyModel, EmptyPermanentGraph.getInstance(), new EmptyGraphFacade(), Collections.emptyMap(), false); + return new DataPack(emptyModel, EmptyPermanentGraph.getInstance(), Collections.emptyMap(), false); } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyGraphFacade.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyGraphFacade.java deleted file mode 100644 index cf52495938bf..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyGraphFacade.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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.data; - -import com.intellij.openapi.util.Condition; -import com.intellij.util.ui.UIUtil; -import com.intellij.vcs.log.graph.*; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -class EmptyGraphFacade implements GraphFacade { - - public static final BufferedImage EMPTY_IMAGE = UIUtil.createImage(1, 1, Transparency.TRANSLUCENT); - - @NotNull - @Override - public PaintInfo paint(int visibleRow) { - return new PaintInfo() { - @NotNull - @Override - public Image getImage() { - return EMPTY_IMAGE; - } - - @Override - public int getWidth() { - return 0; - } - }; - } - - @Nullable - @Override - public GraphAnswer performAction(@NotNull GraphAction action) { - return null; - } - - @NotNull - @Override - public List> getAllCommits() { - return Collections.emptyList(); - } - - @Override - public int getCommitAtRow(int visibleRow) { - return -1; - } - - @Override - public int getVisibleCommitCount() { - return 0; - } - - @Override - public void setVisibleBranches(@Nullable Collection heads) { - } - - @Override - public void setFilter(@Nullable Condition visibilityPredicate) { - } - - @NotNull - @Override - public GraphInfoProvider getInfoProvider() { - return new GraphInfoProvider() { - @NotNull - @Override - public Set getContainingBranches(int visibleRow) { - return Collections.emptySet(); - } - - @NotNull - @Override - public RowInfo getRowInfo(int visibleRow) { - return new RowInfo() { - @Override - public int getOneOfHeads() { - return -1; - } - }; - } - - @Override - public boolean areLongEdgesHidden() { - return false; - } - }; - } -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/LoadMoreStage.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/LoadMoreStage.java deleted file mode 100644 index 1ca383ccbe1c..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/LoadMoreStage.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2000-2013 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.data; - -public enum LoadMoreStage { - /** - * Initial table view; "load more" was not requested yet. - */ - INITIAL, - - /** - * "Load more" was once requested with a limited number of commits. - */ - LOADED_MORE, - - /** - * All commits matching the given filters were requested from the VCS, requesting more won't cause any effect. - */ - ALL_REQUESTED -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java index 24b2d2e2f3a8..7d535982cfd0 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/SingleTaskController.java @@ -18,6 +18,7 @@ package com.intellij.vcs.log.data; import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -82,10 +83,13 @@ public abstract class SingleTaskController { /** * The underlying currently active task should use this method to inform that it has completed the execution.
- * The result is immediately passed to the result handler specified in the constructor. + * If the result is not null, it is immediately passed to the result handler specified in the constructor. + * Otherwise result handler is not called, the task just completes. */ - protected final void taskCompleted(@NotNull Result result) { - myResultHandler.consume(result); + protected final void taskCompleted(@Nullable Result result) { + if (result != null) { + myResultHandler.consume(result); + } synchronized (LOCK) { if (myAwaitingRequests.isEmpty()) { myActive = false; diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java index 91385926cd93..80d351204cba 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogDataHolder.java @@ -22,7 +22,6 @@ import com.intellij.openapi.progress.BackgroundTaskQueue; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; @@ -30,8 +29,8 @@ import com.intellij.util.Consumer; import com.intellij.util.ThrowableConsumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.Topic; -import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.*; +import com.intellij.vcs.log.graph.PermanentGraph; import com.intellij.vcs.log.util.StopWatch; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -61,13 +60,6 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { private final Map myCurrentUser = ContainerUtil.newHashMap(); private final Consumer myDataPackUpdateHandler; - /** - * Indicates if user wants the whole log graph to be shown. - * Initially we show only the top of the log (even after we've loaded the whole log structure) for performance reasons. - * However, if user once navigates to some old commit, we build the whole graph and show it until the next full refresh or project reload. - */ - private volatile boolean myFullLogShowing; - /** * Cached details of the latest commits. * We store them separately from the cache of {@link DataGetter}, to make sure that they are always available, @@ -82,11 +74,14 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { private final ContainingBranchesGetter myContainingBranchesGetter; @NotNull private final VcsLogRefresher myRefresher; + private final VcsLogFiltererImpl myFilterer; public VcsLogDataHolder(@NotNull Project project, @NotNull Disposable parentDisposable, @NotNull Map logProviders, - @NotNull VcsLogSettings settings, Consumer dataPackUpdateHandler) { + @NotNull VcsLogSettings settings, + @NotNull VcsLogUiProperties uiProperties, + @NotNull Consumer visiblePackConsumer) { Disposer.register(parentDisposable, this); myProject = project; myLogProviders = logProviders; @@ -94,7 +89,6 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { myMiniDetailsGetter = new MiniDetailsGetter(this, logProviders); myDetailsGetter = new CommitDetailsGetter(this, logProviders); mySettings = settings; - myDataPackUpdateHandler = dataPackUpdateHandler; myUserRegistry = (VcsUserRegistryImpl)ServiceManager.getService(project, VcsUserRegistry.class); try { @@ -105,8 +99,20 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { } myContainingBranchesGetter = new ContainingBranchesGetter(project, this, this); + myFilterer = new VcsLogFiltererImpl(myProject, myLogProviders, myHashMap, myTopCommitsDetailsCache, myDetailsGetter, + uiProperties.isBek() ? PermanentGraph.SortType.Bek : PermanentGraph.SortType.Normal, + visiblePackConsumer); + + myDataPackUpdateHandler = new Consumer() { + @Override + public void consume(DataPack dataPack) { + myFilterer.onRefresh(dataPack); + myProject.getMessageBus().syncPublisher(REFRESH_COMPLETED).refresh(dataPack); + } + }; + myRefresher = new VcsLogRefresherImpl(myProject, myHashMap, myLogProviders, myUserRegistry, myTopCommitsDetailsCache, - dataPackUpdateHandler, new Consumer() { + myDataPackUpdateHandler, new Consumer() { @Override public void consume(Exception e) { LOG.error(e); @@ -114,6 +120,11 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { }, mySettings.getRecentCommitsCount()); } + @NotNull + public VcsLogFilterer getFilterer() { + return myFilterer; + } + @Override @NotNull public Hash getHash(int commitIndex) { @@ -167,54 +178,9 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { } private void resetState() { - myFullLogShowing = false; myTopCommitsDetailsCache.clear(); } - /** - * Show the full log tree to the user. - * Initially only the top part of the log is shown to avoid memory and performance problems. - * However, if user wants to navigate to something in the past, we rebuild the log and show it. - *

- * Method returns immediately, log building is executed in the background. - *

- * TODO: in most cases, users don't need to go to such deep past even if they need to go deeper than to 1000 most recent commits. - * Therefore optimize: Add a hash parameter, and build only the necessary part of the log + some commits below. - * - * @param onSuccess Invoked in the EDT after the log DataPack is built. - */ - public void showFullLog(@NotNull final Runnable onSuccess) { - if (myFullLogShowing) { - return; - } - - runInBackground(new ThrowableConsumer() { - @Override - public void consume(ProgressIndicator indicator) throws VcsException { - if (myFullLogShowing) { - return; - } - - // TODO - - myFullLogShowing = true; - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - if (!Disposer.isDisposed(VcsLogDataHolder.this)) { - onSuccess.run(); - } - } - }); - } - }, "Building full log..."); - } - - - public boolean isFullLogShowing() { - return myFullLogShowing; - } - @NotNull public Set getAllUsers() { return myUserRegistry.getUsers(); @@ -253,23 +219,6 @@ public class VcsLogDataHolder implements Disposable, VcsLogDataProvider { return myContainingBranchesGetter; } - @Nullable - public Hash findHashByString(@NotNull String string) { - final String pHash = string.toLowerCase(); - try { - return myHashMap.findHash(new Condition() { - @Override - public boolean value(@NotNull Hash hash) { - return hash.toString().toLowerCase().startsWith(pHash); - } - }); - } - catch (IOException e) { - LOG.error(e); - return null; - } - } - void runInBackground(final ThrowableConsumer task, final String title) { myDataLoaderQueue.run(new Task.Backgroundable(myProject, title) { @Override diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFilterer.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFilterer.java index f0bf75c08dcf..e1e5f9411bbe 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFilterer.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFilterer.java @@ -1,269 +1,34 @@ +/* + * 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.data; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.EmptyRunnable; -import com.intellij.openapi.util.Ref; -import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; -import com.intellij.util.Function; -import com.intellij.util.ThrowableConsumer; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.HashSet; -import com.intellij.util.ui.UIUtil; -import com.intellij.vcs.log.*; -import com.intellij.vcs.log.graph.GraphFacade; -import com.intellij.vcs.log.impl.VcsLogUtil; -import com.intellij.vcs.log.ui.VcsLogUiImpl; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; -import com.intellij.vcs.log.ui.tables.EmptyTableModel; -import com.intellij.vcs.log.ui.tables.GraphTableModel; -import gnu.trove.TIntHashSet; +import com.intellij.vcs.log.VcsLogFilterCollection; +import com.intellij.vcs.log.graph.PermanentGraph; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; +/** + */ +public interface VcsLogFilterer { -public class VcsLogFilterer { + void onRefresh(@NotNull DataPack dataPack); - private static final Logger LOG = Logger.getInstance(VcsLogFilterer.class); + void onFiltersChange(@NotNull VcsLogFilterCollection filters); - private static final int LOAD_MORE_COMMITS_FIRST_STEP_LIMIT = 2000; + void onSortTypeChange(@NotNull PermanentGraph.SortType sortType); - @NotNull private final VcsLogDataHolder myLogDataHolder; - @NotNull private final VcsLogUiImpl myUI; - - public VcsLogFilterer(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUiImpl ui) { - myLogDataHolder = logDataHolder; - myUI = ui; - } - - @NotNull - public AbstractVcsLogTableModel applyFiltersAndUpdateUi(@NotNull DataPack dataPack, @NotNull VcsLogFilterCollection filters) { - resetFilters(dataPack); - VcsLogHashFilter hashFilter = filters.getHashFilter(); - if (hashFilter != null && !hashFilter.getHashes().isEmpty()) { // hashes should be shown, no matter if they match other filters or not - return applyHashFilter(dataPack, hashFilter.getHashes()); - } - List detailsFilters = filters.getDetailsFilters(); - applyGraphFilters(dataPack, filters.getBranchFilter()); - return applyDetailsFilter(dataPack, detailsFilters); - } - - private GraphTableModel applyHashFilter(@NotNull DataPack dataPack, @NotNull Collection hashes) { - final List indices = ContainerUtil.mapNotNull(hashes, new Function() { - @Override - public Integer fun(String partOfHash) { - Hash hash = myLogDataHolder.findHashByString(partOfHash); - return hash != null ? myLogDataHolder.getCommitIndex(hash) : null; - } - }); - dataPack.getGraphFacade().setVisibleBranches(null); - dataPack.getGraphFacade().setFilter(new Condition() { - @Override - public boolean value(Integer integer) { - return indices.contains(integer); - } - }); - return new GraphTableModel(dataPack, myLogDataHolder, myUI, LoadMoreStage.ALL_REQUESTED); - } - - private static void resetFilters(@NotNull DataPack dataPack) { - GraphFacade facade = dataPack.getGraphFacade(); - facade.setVisibleBranches(null); - facade.setFilter(null); - } - - private AbstractVcsLogTableModel applyDetailsFilter(DataPack dataPack, List detailsFilters) { - if (!detailsFilters.isEmpty()) { - List filteredCommits = filterInMemory(dataPack, detailsFilters); - if (filteredCommits.isEmpty()) { - return new EmptyTableModel(dataPack, myLogDataHolder, myUI, LoadMoreStage.INITIAL); - } - else{ - Condition filter = getFilterFromCommits(filteredCommits); - dataPack.getGraphFacade().setFilter(filter); - } - } - else { - dataPack.getGraphFacade().setFilter(null); - } - return new GraphTableModel(dataPack, myLogDataHolder, myUI, LoadMoreStage.INITIAL); - } - - private Condition getFilterFromCommits(List filteredCommits) { - final Set commitSet = ContainerUtil.map2Set(filteredCommits, new Function() { - @Override - public Integer fun(Hash hash) { - return myLogDataHolder.getCommitIndex(hash); - } - }); - return new Condition() { - @Override - public boolean value(Integer integer) { - return commitSet.contains(integer); - } - }; - } - - public void requestVcs(@NotNull final DataPack dataPack, @NotNull VcsLogFilterCollection filters, - @NotNull final LoadMoreStage loadMoreStage, @NotNull final Runnable onSuccess) { - ApplicationManager.getApplication().assertIsDispatchThread(); - int maxCount = loadMoreStage == LoadMoreStage.INITIAL ? LOAD_MORE_COMMITS_FIRST_STEP_LIMIT : -1; - getFilteredDetailsFromTheVcs(dataPack.getLogProviders(), filters, new Consumer>() { - @Override - public void consume(List hashes) { - LoadMoreStage newLoadMoreStage = advanceLoadMoreStage(loadMoreStage); - TIntHashSet previouslySelected = myUI.getSelectedCommits(); - AbstractVcsLogTableModel model; - if (hashes.isEmpty()) { - model = new EmptyTableModel(dataPack, myLogDataHolder, myUI, newLoadMoreStage); - } - else { - dataPack.getGraphFacade().setFilter(getFilterFromCommits(hashes)); - model = new GraphTableModel(dataPack, myLogDataHolder, myUI, newLoadMoreStage); - } - myUI.setModel(model, dataPack, previouslySelected); - myUI.repaintUI(); - onSuccess.run(); - } - }, maxCount); - } - - @NotNull - private static LoadMoreStage advanceLoadMoreStage(@NotNull LoadMoreStage loadMoreStage) { - LoadMoreStage newLoadMoreStage; - if (loadMoreStage == LoadMoreStage.INITIAL) { - newLoadMoreStage = LoadMoreStage.LOADED_MORE; - } - else if (loadMoreStage == LoadMoreStage.LOADED_MORE) { - newLoadMoreStage = LoadMoreStage.ALL_REQUESTED; - } - else { - LOG.warn("Incorrect previous load more stage: " + loadMoreStage); - newLoadMoreStage = LoadMoreStage.ALL_REQUESTED; - } - return newLoadMoreStage; - } - - private void applyGraphFilters(@NotNull final DataPack dataPack, @Nullable final VcsLogBranchFilter branchFilter) { - try { - dataPack.getGraphFacade().setVisibleBranches(branchFilter != null ? getMatchingHeads(dataPack, branchFilter) : null); - } - catch (InvalidRequestException e) { - if (!myLogDataHolder.isFullLogShowing()) { - myLogDataHolder.showFullLog(EmptyRunnable.getInstance()); - throw new ProcessCanceledException(); - } - else { - throw e; - } - } - } - - @NotNull - private Collection getMatchingHeads(@NotNull DataPack dataPack, @NotNull VcsLogBranchFilter branchFilter) { - final Collection branchNames = new HashSet(branchFilter.getBranchNames()); - return ContainerUtil.mapNotNull(dataPack.getRefsModel().getAllRefs(), new Function() { - @Override - public Integer fun(VcsRef ref) { - if (branchNames.contains(ref.getName())) { - return myLogDataHolder.getCommitIndex(ref.getCommitHash()); - } - return null; - } - }); - } - - @NotNull - private List filterInMemory(@NotNull DataPack dataPack, @NotNull List detailsFilters) { - List result = ContainerUtil.newArrayList(); - for (int visibleCommit : VcsLogUtil.getVisibleCommits(dataPack.getGraphFacade())) { - VcsCommitMetadata data = getDetailsFromCache(visibleCommit); - if (data == null) { - // no more continuous details in the cache - break; - } - if (matchesAllFilters(data, detailsFilters)) { - result.add(data.getId()); - } - } - return result; - } - - private static boolean matchesAllFilters(@NotNull final VcsCommitMetadata commit, @NotNull List detailsFilters) { - return !ContainerUtil.exists(detailsFilters, new Condition() { - @Override - public boolean value(VcsLogDetailsFilter filter) { - return !filter.matches(commit); - } - }); - } - - @Nullable - private VcsCommitMetadata getDetailsFromCache(final int commitIndex) { - final Hash hash = myLogDataHolder.getHash(commitIndex); - VcsCommitMetadata details = myLogDataHolder.getTopCommitDetails(hash); - if (details != null) { - return details; - } - final Ref ref = Ref.create(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - ref.set(myLogDataHolder.getCommitDetailsGetter().getCommitDataIfAvailable(hash)); - } - }); - return ref.get(); - } - - public void getFilteredDetailsFromTheVcs(@NotNull final Map providers, - @NotNull final VcsLogFilterCollection filterCollection, - @NotNull final Consumer> success, - final int maxCount) { - myLogDataHolder.runInBackground(new ThrowableConsumer() { - @Override - public void consume(ProgressIndicator indicator) throws VcsException { - Collection> logs = ContainerUtil.newArrayList(); - for (Map.Entry entry : providers.entrySet()) { - final VirtualFile root = entry.getKey(); - - if (filterCollection.getStructureFilter() != null && filterCollection.getStructureFilter().getFiles(root).isEmpty() - || filterCollection.getUserFilter() != null && filterCollection.getUserFilter().getUserNames(root).isEmpty()) { - // there is a structure or user filter, but it doesn't match this root - continue; - } - - List matchingCommits = entry.getValue().getCommitsMatchingFilter(root, filterCollection, maxCount); - logs.add(matchingCommits); - } - - final List compoundLog = new VcsLogMultiRepoJoiner().join(logs); - - final List list = ContainerUtil.map(compoundLog, new Function() { - @Override - public Hash fun(TimedVcsCommit commit) { - return commit.getId(); - } - }); - - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - if (!myLogDataHolder.getProject().isDisposed()) { - success.consume(list); - } - } - }); - } - }, "Looking for more results..."); - } + void moreCommitsNeeded(@NotNull Runnable onLoaded); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFiltererImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFiltererImpl.java new file mode 100644 index 000000000000..3b03333064f4 --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogFiltererImpl.java @@ -0,0 +1,169 @@ +/* + * 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.data; + +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.progress.impl.ProgressManagerImpl; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Consumer; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcs.log.Hash; +import com.intellij.vcs.log.VcsCommitMetadata; +import com.intellij.vcs.log.VcsLogFilterCollection; +import com.intellij.vcs.log.VcsLogProvider; +import com.intellij.vcs.log.graph.PermanentGraph; +import com.intellij.vcs.log.impl.VcsLogFilterCollectionImpl; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public class VcsLogFiltererImpl implements VcsLogFilterer { + + @NotNull private final SingleTaskController myTaskController; + @NotNull private final VisiblePackBuilder myVisiblePackBuilder; + + @NotNull private VcsLogFilterCollection myFilters; + @NotNull private PermanentGraph.SortType mySortType; + @NotNull private CommitCountStage myCommitCount = CommitCountStage.INITIAL; + @Nullable private DataPack myDataPack; + + VcsLogFiltererImpl(@NotNull final Project project, + @NotNull Map providers, + @NotNull VcsLogHashMap hashMap, + @NotNull Map topCommitsDetailsCache, + @NotNull CommitDetailsGetter detailsGetter, + @NotNull final PermanentGraph.SortType initialSortType, + @NotNull final Consumer visiblePackConsumer) { + myVisiblePackBuilder = new VisiblePackBuilder(providers, hashMap, topCommitsDetailsCache, detailsGetter); + myFilters = new VcsLogFilterCollectionImpl(null, null, null, null, null, null); + mySortType = initialSortType; + + myTaskController = new SingleTaskController(visiblePackConsumer) { + @Override + protected void startNewBackgroundTask() { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + ProgressManagerImpl.runProcessWithProgressAsynchronously(new MyTask(project, "Applying filters...")); + } + }); + } + }; + } + + @Override + public void onRefresh(@NotNull DataPack dataPack) { + myTaskController.request(new RefreshRequest(dataPack)); + } + + @Override + public void onFiltersChange(@NotNull VcsLogFilterCollection newFilters) { + myTaskController.request(new FilterRequest(newFilters)); + } + + @Override + public void onSortTypeChange(@NotNull PermanentGraph.SortType sortType) { + myTaskController.request(new SortTypeRequest(sortType)); + } + + @Override + public void moreCommitsNeeded(@NotNull Runnable onLoaded) { + myTaskController.request(new MoreCommitsRequest(onLoaded)); + } + + private class MyTask extends Task.Backgroundable { + + public MyTask(@Nullable Project project, @NotNull String title) { + super(project, title); + } + + @Override + public void run(@NotNull ProgressIndicator indicator) { + VisiblePack visiblePack = null; + List requests; + while (!(requests = myTaskController.popRequests()).isEmpty()) { + RefreshRequest refreshRequest = ContainerUtil.findLastInstance(requests, RefreshRequest.class); + FilterRequest filterRequest = ContainerUtil.findLastInstance(requests, FilterRequest.class); + SortTypeRequest sortTypeRequest = ContainerUtil.findLastInstance(requests, SortTypeRequest.class); + + if (refreshRequest != null) { + myDataPack = refreshRequest.dataPack; + } + if (filterRequest != null) { + myFilters = filterRequest.filters; + } + if (sortTypeRequest != null) { + mySortType = sortTypeRequest.sortType; + } + + if (myDataPack == null) { // when filter is set during initialization, just remember filters + continue; + } + + if (filterRequest != null) { // "more commits needed" has no effect if filter changes; it also can't come after filter change request + myCommitCount = CommitCountStage.INITIAL; + } + else if (ContainerUtil.findInstance(requests, MoreCommitsRequest.class) != null) { + myCommitCount = myCommitCount.next(); + } + + Pair pair = myVisiblePackBuilder.build(myDataPack, mySortType, myFilters, myCommitCount); + visiblePack = pair.first; + myCommitCount = pair.second; + } + + // visible pack can be null (e.g. when filter is set during initialization) => we just remember filters set by user + myTaskController.taskCompleted(visiblePack); + } + } + + private interface Request { + } + + private static final class RefreshRequest implements Request { + private final DataPack dataPack; + RefreshRequest(DataPack dataPack) { + this.dataPack = dataPack; + } + } + + private static final class FilterRequest implements Request { + private final VcsLogFilterCollection filters; + FilterRequest(VcsLogFilterCollection filters) { + this.filters = filters; + } + } + + private static final class SortTypeRequest implements Request { + private final PermanentGraph.SortType sortType; + SortTypeRequest(PermanentGraph.SortType sortType) { + this.sortType = sortType; + } + } + + private static final class MoreCommitsRequest implements Request { + private final Runnable onLoaded; + MoreCommitsRequest(Runnable onLoaded) { + this.onLoaded = onLoaded; + } + } +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java index e67f8f91e22a..638337a64f36 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java @@ -92,6 +92,23 @@ public class VcsLogHashMap implements Disposable { } } + @Nullable + public Hash findHashByString(@NotNull String string) { + final String pHash = string.toLowerCase(); + try { + return findHash(new Condition() { + @Override + public boolean value(@NotNull Hash hash) { + return hash.toString().toLowerCase().startsWith(pHash); + } + }); + } + catch (IOException e) { + LOG.error(e); + return null; + } + } + @NotNull public NotNullFunction asIndexGetter() { return new NotNullFunction() { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePack.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePack.java new file mode 100644 index 000000000000..99945460e41d --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePack.java @@ -0,0 +1,67 @@ +/* + * 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.data; + +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.vcs.log.VcsLogDataPack; +import com.intellij.vcs.log.VcsLogProvider; +import com.intellij.vcs.log.VcsLogRefs; +import com.intellij.vcs.log.graph.VisibleGraph; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public class VisiblePack implements VcsLogDataPack { + + public static final VisiblePack EMPTY = new VisiblePack(EmptyDataPack.getInstance(), EmptyVisibleGraph.getInstance(), false); + + @NotNull private final DataPack myDataPack; + @NotNull private final VisibleGraph myVisibleGraph; + private final boolean myCanRequestMore; + + VisiblePack(@NotNull DataPack dataPack, @NotNull VisibleGraph graph, boolean canRequestMore) { + myDataPack = dataPack; + myVisibleGraph = graph; + myCanRequestMore = canRequestMore; + } + + @NotNull + public VisibleGraph getVisibleGraph() { + return myVisibleGraph; + } + + public boolean canRequestMore() { + return myCanRequestMore; + } + + @NotNull + @Override + public Map getLogProviders() { + return myDataPack.getLogProviders(); + } + + @NotNull + @Override + public VcsLogRefs getRefs() { + return myDataPack.getRefs(); + } + + @NotNull + public RefsModel getRefsModel() { + return myDataPack.getRefsModel(); + } + +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java new file mode 100644 index 000000000000..54be3ea5ae33 --- /dev/null +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VisiblePackBuilder.java @@ -0,0 +1,228 @@ +/* + * 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.data; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashSet; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcs.log.*; +import com.intellij.vcs.log.graph.GraphCommit; +import com.intellij.vcs.log.graph.PermanentGraph; +import com.intellij.vcs.log.graph.VisibleGraph; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +class VisiblePackBuilder { + + private static final Logger LOG = Logger.getInstance(VisiblePackBuilder.class); + + @NotNull private final VcsLogHashMap myHashMap; + @NotNull private final Map myTopCommitsDetailsCache; + @NotNull private final CommitDetailsGetter myCommitDetailsGetter; + @NotNull private final Map myLogProviders; + + VisiblePackBuilder(@NotNull Map providers, + @NotNull VcsLogHashMap hashMap, + @NotNull Map topCommitsDetailsCache, + @NotNull CommitDetailsGetter detailsGetter) { + myHashMap = hashMap; + myTopCommitsDetailsCache = topCommitsDetailsCache; + myCommitDetailsGetter = detailsGetter; + myLogProviders = providers; + } + + @NotNull + Pair build(@NotNull DataPack dataPack, + @NotNull PermanentGraph.SortType sortType, + @NotNull VcsLogFilterCollection filters, + @NotNull CommitCountStage commitCount) { + VcsLogHashFilter hashFilter = filters.getHashFilter(); + if (hashFilter != null && !hashFilter.getHashes().isEmpty()) { // hashes should be shown, no matter if they match other filters or not + return Pair.create(applyHashFilter(dataPack, hashFilter.getHashes(), sortType), commitCount); + } + + List detailsFilters = filters.getDetailsFilters(); + Condition filter; + boolean canRequestMore; + if (!detailsFilters.isEmpty()) { + List matchingCommits = null; + if (commitCount == CommitCountStage.INITIAL) { + matchingCommits = filterInMemory(dataPack.getPermanentGraph(), detailsFilters); + if (matchingCommits.size() < commitCount.getCount()) { + commitCount = commitCount.next(); + matchingCommits = null; + } + } + + if (matchingCommits == null) { + try { + matchingCommits = getFilteredDetailsFromTheVcs(myLogProviders, filters, commitCount.getCount()); + } + catch (VcsException e) { + // TODO show an error balloon or something else for non-ea guys. + matchingCommits = Collections.emptyList(); + LOG.error(e); + } + } + + filter = getFilterFromCommits(matchingCommits); + canRequestMore = matchingCommits.size() >= commitCount.getCount(); // from VCS: only "==", but from memory can be ">" + } + else { + filter = null; + canRequestMore = false; + } + + Set heads = getMatchingHeads(dataPack.getRefs(), filters); + VisibleGraph visibleGraph = dataPack.getPermanentGraph().createVisibleGraph(sortType, heads, filter); + return Pair.create(new VisiblePack(dataPack, visibleGraph, canRequestMore), commitCount); + } + + private VisiblePack applyHashFilter(@NotNull DataPack dataPack, + @NotNull Collection hashes, + @NotNull PermanentGraph.SortType sortType) { + final Set indices = ContainerUtil.map2SetNotNull(hashes, new Function() { + @Override + public Integer fun(String partOfHash) { + Hash hash = myHashMap.findHashByString(partOfHash); + return hash != null ? myHashMap.getCommitIndex(hash) : null; + } + }); + VisibleGraph visibleGraph = dataPack.getPermanentGraph().createVisibleGraph(sortType, null, new Condition() { + @Override + public boolean value(Integer integer) { + return indices.contains(integer); + } + }); + return new VisiblePack(dataPack, visibleGraph, false); + } + + @Nullable + private Set getMatchingHeads(@NotNull VcsLogRefs refs, @NotNull VcsLogFilterCollection filters) { + VcsLogBranchFilter branchFilter = filters.getBranchFilter(); + if (branchFilter == null) { + return null; + } + + final Collection branchNames = new HashSet(branchFilter.getBranchNames()); + return new HashSet(ContainerUtil.mapNotNull(refs.getBranches(), new Function() { + @Override + public Integer fun(VcsRef ref) { + if (branchNames.contains(ref.getName())) { + return myHashMap.getCommitIndex(ref.getCommitHash()); + } + return null; + } + })); + } + + @NotNull + private List filterInMemory(@NotNull PermanentGraph permanentGraph, @NotNull List detailsFilters) { + List result = ContainerUtil.newArrayList(); + for (GraphCommit commit : permanentGraph.getAllCommits()) { + VcsCommitMetadata data = getDetailsFromCache(commit.getId()); + if (data == null) { + // no more continuous details in the cache + break; + } + if (matchesAllFilters(data, detailsFilters)) { + result.add(data.getId()); + } + } + return result; + } + + private static boolean matchesAllFilters(@NotNull final VcsCommitMetadata commit, @NotNull List detailsFilters) { + return ContainerUtil.and(detailsFilters, new Condition() { + @Override + public boolean value(VcsLogDetailsFilter filter) { + return filter.matches(commit); + } + }); + } + + @Nullable + private VcsCommitMetadata getDetailsFromCache(final int commitIndex) { + final Hash hash = myHashMap.getHash(commitIndex); + VcsCommitMetadata details = myTopCommitsDetailsCache.get(hash); + if (details != null) { + return details; + } + return UIUtil.invokeAndWaitIfNeeded(new Computable() { + @Override + public VcsCommitMetadata compute() { + return myCommitDetailsGetter.getCommitDataIfAvailable(hash); + } + }); + } + + @NotNull + private static List getFilteredDetailsFromTheVcs(@NotNull Map providers, + @NotNull VcsLogFilterCollection filterCollection, + int maxCount) throws VcsException { + Collection> logs = ContainerUtil.newArrayList(); + for (Map.Entry entry : providers.entrySet()) { + VirtualFile root = entry.getKey(); + + if (filterCollection.getStructureFilter() != null && filterCollection.getStructureFilter().getFiles(root).isEmpty() + || filterCollection.getUserFilter() != null && filterCollection.getUserFilter().getUserNames(root).isEmpty()) { + // there is a structure or user filter, but it doesn't match this root + continue; + } + + List matchingCommits = entry.getValue().getCommitsMatchingFilter(root, filterCollection, maxCount); + logs.add(matchingCommits); + } + + List compoundLog = new VcsLogMultiRepoJoiner().join(logs); + return ContainerUtil.map(compoundLog, new Function() { + @Override + public Hash fun(TimedVcsCommit commit) { + return commit.getId(); + } + }); + } + + @Nullable + private Condition getFilterFromCommits(@Nullable List filteredCommits) { + if (filteredCommits == null) { + return null; + } + + final Set commitSet = ContainerUtil.map2Set(filteredCommits, new Function() { + @Override + public Integer fun(Hash hash) { + return myHashMap.getCommitIndex(hash); + } + }); + return new Condition() { + @Override + public boolean value(Integer integer) { + return commitSet.contains(integer); + } + }; + } + +} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java index 6abda6ae2c54..7219749676b2 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogImpl.java @@ -21,7 +21,7 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.ui.VcsLogUiImpl; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; +import com.intellij.vcs.log.ui.tables.GraphTableModel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,7 +48,7 @@ public class VcsLogImpl implements VcsLog { List hashes = ContainerUtil.newArrayList(); JBTable table = myUi.getTable(); for (int row : table.getSelectedRows()) { - Hash hash = ((AbstractVcsLogTableModel)table.getModel()).getHashAtRow(row); + Hash hash = ((GraphTableModel)table.getModel()).getHashAtRow(row); if (hash != null) { hashes.add(hash); } @@ -62,7 +62,7 @@ public class VcsLogImpl implements VcsLog { List details = ContainerUtil.newArrayList(); JBTable table = myUi.getTable(); for (int row : table.getSelectedRows()) { - AbstractVcsLogTableModel model = (AbstractVcsLogTableModel)table.getModel(); + GraphTableModel model = (GraphTableModel)table.getModel(); VcsFullCommitDetails commitDetails = model.getFullCommitDetails(row); if (commitDetails == null) { return ContainerUtil.emptyList(); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java index 77401fdb32f5..8a6ad1dd1d9b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogManager.java @@ -64,23 +64,22 @@ public class VcsLogManager implements Disposable { public JComponent initContent() { final Map logProviders = findLogProviders(); - Consumer dataPackUpdateHandler = new Consumer() { + Consumer visiblePackConsumer = new Consumer() { @Override - public void consume(final DataPack dataPack) { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - if (!Disposer.isDisposed(myUi)) { - myUi.setDataPack(dataPack); - myProject.getMessageBus().syncPublisher(VcsLogDataHolder.REFRESH_COMPLETED).refresh(dataPack); + public void consume(final VisiblePack pack) { + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + if (!Disposer.isDisposed(myUi)) { + myUi.setVisiblePack(pack); + } } - } - }); + }); } }; - VcsLogDataHolder logDataHolder = new VcsLogDataHolder(myProject, this, logProviders, mySettings, dataPackUpdateHandler); + VcsLogDataHolder logDataHolder = new VcsLogDataHolder(myProject, this, logProviders, mySettings, myUiProperties, visiblePackConsumer); myUi = new VcsLogUiImpl(logDataHolder, myProject, mySettings, - new VcsLogColorManagerImpl(logProviders.keySet()), myUiProperties, EmptyDataPack.getInstance()); + new VcsLogColorManagerImpl(logProviders.keySet()), myUiProperties, logDataHolder.getFilterer()); myLogRefresher = new PostponeableLogRefresher(myProject, logDataHolder); refreshLogOnVcsEvents(logProviders); logDataHolder.initialize(); diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUtil.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUtil.java index ad610c45c01a..17c3d2bc6eec 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUtil.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/VcsLogUtil.java @@ -18,7 +18,7 @@ package com.intellij.vcs.log.impl; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.MultiMap; import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.graph.GraphFacade; +import com.intellij.vcs.log.graph.VisibleGraph; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -45,16 +45,16 @@ public class VcsLogUtil { } @NotNull - public static List getVisibleCommits(@NotNull final GraphFacade facade) { + public static List getVisibleCommits(@NotNull final VisibleGraph visibleGraph) { return new AbstractList() { @Override public Integer get(int index) { - return facade.getCommitAtRow(index); + return visibleGraph.getRowInfo(index).getCommit(); } @Override public int size() { - return facade.getVisibleCommitCount(); + return visibleGraph.getVisibleCommitCount(); } }; } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java index b96611dd0f25..8f7b10b33363 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsLogUiImpl.java @@ -7,20 +7,19 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.util.PairFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.*; import com.intellij.vcs.log.data.*; -import com.intellij.vcs.log.graph.ChangeCursorActionRequest; -import com.intellij.vcs.log.graph.ClickGraphAction; -import com.intellij.vcs.log.graph.*; +import com.intellij.vcs.log.graph.PermanentGraph; +import com.intellij.vcs.log.graph.VisibleGraph; +import com.intellij.vcs.log.graph.actions.GraphAnswer; import com.intellij.vcs.log.impl.VcsLogImpl; import com.intellij.vcs.log.ui.frame.MainFrame; import com.intellij.vcs.log.ui.frame.VcsLogGraphTable; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; +import com.intellij.vcs.log.ui.tables.GraphTableModel; import gnu.trove.TIntHashSet; import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; @@ -40,27 +39,44 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { private static final Logger LOG = Logger.getInstance(VcsLogUiImpl.class); @NotNull private final MainFrame myMainFrame; + @NotNull private final VcsLogDataHolder myLogDataHolder; @NotNull private final Project myProject; @NotNull private final VcsLogColorManager myColorManager; - @NotNull private final VcsLogFilterer myFilterer; @NotNull private final VcsLog myLog; @NotNull private final VcsLogUiProperties myUiProperties; + @NotNull private final VcsLogFilterer myFilterer; @NotNull private final Collection myFilterChangeListeners = ContainerUtil.newArrayList(); - @NotNull private DataPack myDataPack; + @NotNull private VisiblePack myVisiblePack; public VcsLogUiImpl(@NotNull VcsLogDataHolder logDataHolder, @NotNull Project project, @NotNull VcsLogSettings settings, - @NotNull VcsLogColorManager manager, @NotNull VcsLogUiProperties uiProperties, @NotNull DataPack initialDataPack) { + @NotNull VcsLogColorManager manager, @NotNull VcsLogUiProperties uiProperties, @NotNull VcsLogFilterer filterer) { + myLogDataHolder = logDataHolder; myProject = project; myColorManager = manager; myUiProperties = uiProperties; - myDataPack = initialDataPack; Disposer.register(logDataHolder, this); - myFilterer = new VcsLogFilterer(logDataHolder, this); + myFilterer = filterer; myLog = new VcsLogImpl(logDataHolder, this); - myMainFrame = new MainFrame(logDataHolder, this, project, settings, uiProperties, myLog, initialDataPack); + myVisiblePack = VisiblePack.EMPTY; + myMainFrame = new MainFrame(logDataHolder, this, project, settings, uiProperties, myLog, myVisiblePack); + } + + public void setVisiblePack(@NotNull VisiblePack pack) { + ApplicationManager.getApplication().assertIsDispatchThread(); + + TIntHashSet previouslySelected = getSelectedCommits(); + + myVisiblePack = pack; + + GraphTableModel newModel = new GraphTableModel(myVisiblePack, myLogDataHolder, this); + setModel(newModel, myVisiblePack.getVisibleGraph(), previouslySelected); + myMainFrame.updateDataPack(myVisiblePack); + setLongEdgeVisibility(myUiProperties.areLongEdgesVisible()); + fireFilterChangeEvent(); + repaintUI(); } @NotNull @@ -77,19 +93,20 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { }); } - public void setModel(@NotNull AbstractVcsLogTableModel newModel, @NotNull DataPack newDataPack, - @NotNull TIntHashSet previouslySelectedCommits) { + private void setModel(@NotNull GraphTableModel newModel, + @NotNull VisibleGraph newVisibleGraph, + @NotNull TIntHashSet previouslySelectedCommits) { final VcsLogGraphTable table = getTable(); table.setModel(newModel); - restoreSelection(newModel, newDataPack, previouslySelectedCommits, table); + restoreSelection(newModel, newVisibleGraph, previouslySelectedCommits, table); table.setPaintBusy(false); } - private static void restoreSelection(@NotNull AbstractVcsLogTableModel newModel, - @NotNull DataPack newDataPack, + private static void restoreSelection(@NotNull GraphTableModel newModel, + @NotNull VisibleGraph newVisibleGraph, @NotNull TIntHashSet previouslySelectedCommits, @NotNull final VcsLogGraphTable table) { - TIntHashSet rowsToSelect = findNewRowsToSelect(newModel, newDataPack, previouslySelectedCommits); + TIntHashSet rowsToSelect = findNewRowsToSelect(newModel, newVisibleGraph, previouslySelectedCommits); rowsToSelect.forEach(new TIntProcedure() { @Override public boolean execute(int row) { @@ -100,8 +117,8 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { } @NotNull - private static TIntHashSet findNewRowsToSelect(@NotNull AbstractVcsLogTableModel newModel, - @NotNull DataPack dataPack, + private static TIntHashSet findNewRowsToSelect(@NotNull GraphTableModel newModel, + @NotNull VisibleGraph visibleGraph, @NotNull TIntHashSet selectedHashes) { TIntHashSet rowsToSelect = new TIntHashSet(); if (newModel.getRowCount() == 0) { @@ -110,10 +127,9 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { // => it has previous values set. return rowsToSelect; } - GraphFacade facade = dataPack.getGraphFacade(); - for (int row = 0; row < facade.getVisibleCommitCount() + for (int row = 0; row < visibleGraph.getVisibleCommitCount() && rowsToSelect.size() < selectedHashes.size(); row++) { //stop iterating if found all hashes - int commit = facade.getCommitAtRow(row); + int commit = visibleGraph.getRowInfo(row).getCommit(); if (selectedHashes.contains(commit)) { rowsToSelect.add(row); } @@ -129,11 +145,11 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { runUnderModalProgress("Expanding linear branches...", new Runnable() { @Override public void run() { - final GraphAnswer answer = myDataPack.getGraphFacade().performAction(LinearBranchesExpansionAction.EXPAND); + myVisiblePack.getVisibleGraph().getActionController().setLinearBranchesExpansion(false); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { - handleAnswer(answer); + handleAnswer(null, true); } }); } @@ -144,11 +160,11 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { runUnderModalProgress("Collapsing linear branches...", new Runnable() { @Override public void run() { - final GraphAnswer answer = myDataPack.getGraphFacade().performAction(LinearBranchesExpansionAction.COLLAPSE); + myVisiblePack.getVisibleGraph().getActionController().setLinearBranchesExpansion(true); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { - handleAnswer(answer); + handleAnswer(null, true); } }); } @@ -156,80 +172,64 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { } public void setLongEdgeVisibility(boolean visibility) { - handleAnswer(myDataPack.getGraphFacade().performAction(LongEdgesAction.valueOf(visibility))); + myVisiblePack.getVisibleGraph().getActionController().setLongEdgesHidden(!visibility); myUiProperties.setLongEdgesVisibility(visibility); } - public boolean areLongEdgesHidden() { - return myDataPack.getGraphFacade().getInfoProvider().areLongEdgesHidden(); - } - public void setBek(boolean bek) { myUiProperties.setBek(bek); - final BekGraphAction bekGraphAction = new BekGraphAction(bek ? PermanentGraph.SortType.Bek : PermanentGraph.SortType.Normal); - runUnderModalProgress("Apply sort type...", new Runnable() { - @Override - public void run() { - final GraphAnswer answer = myDataPack.getGraphFacade().performAction(bekGraphAction); - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - handleAnswer(answer); - } - }); - } - }); + myFilterer.onSortTypeChange(bek ? PermanentGraph.SortType.Bek : PermanentGraph.SortType.Normal); } public boolean isBek() { return myUiProperties.isBek(); } - public void click(int rowIndex) { - handleAnswer(myDataPack.getGraphFacade().performAction(new ClickGraphAction(rowIndex, null))); - } - public void jumpToCommit(@NotNull Hash commitHash) { - jumpTo(commitHash, new PairFunction() { + jumpTo(commitHash, new PairFunction() { @Override - public Integer fun(AbstractVcsLogTableModel model, Hash hash) { + public Integer fun(GraphTableModel model, Hash hash) { return model.getRowOfCommit(hash); } }); } public void jumpToCommitByPartOfHash(@NotNull String commitHash) { - jumpTo(commitHash, new PairFunction() { + jumpTo(commitHash, new PairFunction() { @Override - public Integer fun(AbstractVcsLogTableModel model, String hash) { + public Integer fun(GraphTableModel model, String hash) { return model.getRowOfCommitByPartOfHash(hash); } }); } - public void handleAnswer(@Nullable GraphAnswer answer) { + public void handleAnswer(@Nullable GraphAnswer answer, boolean dataCouldChange) { + if (dataCouldChange) { + ((AbstractTableModel)(getTable().getModel())).fireTableDataChanged(); + } + repaintUI(); if (answer == null) { return; } - GraphChange graphChange = answer.getGraphChange(); - if (graphChange != null) { - ((AbstractTableModel)(getTable().getModel())).fireTableStructureChanged(); - } - GraphActionRequest actionRequest = answer.getActionRequest(); - if (actionRequest instanceof JumpToRowActionRequest) { - int row = ((JumpToRowActionRequest)actionRequest).getRow(); - jumpToRow(row); + if (answer.getCursorToSet() != null) { + myMainFrame.getGraphTable().setCursor(answer.getCursorToSet()); } - else if (actionRequest instanceof ChangeCursorActionRequest) { - myMainFrame.getGraphTable().setCursor(((ChangeCursorActionRequest)actionRequest).getCursor()); + if (answer.getCommitToJump() != null) { + int row = myVisiblePack.getVisibleGraph().getVisibleRowIndex(answer.getCommitToJump()); + if (row >= 0) { + jumpToRow(row); + } + else { + // TODO wait for the full log and then jump + } } } - private void jumpTo(@NotNull final T commitId, @NotNull final PairFunction rowGetter) { - AbstractVcsLogTableModel model = getModel(); + private void jumpTo(@NotNull final T commitId, @NotNull final PairFunction rowGetter) { + GraphTableModel model = getModel(); if (model == null) { return; } @@ -252,10 +252,10 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { } @Nullable - private AbstractVcsLogTableModel getModel() { + private GraphTableModel getModel() { TableModel model = getTable().getModel(); - if (model instanceof AbstractVcsLogTableModel) { - return (AbstractVcsLogTableModel)model; + if (model instanceof GraphTableModel) { + return (GraphTableModel)model; } showMessage(MessageType.WARNING, "The log is not ready to search yet"); return null; @@ -281,61 +281,29 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { } @NotNull - public VcsLogFilterer getFilterer() { - return myFilterer; - } - - @NotNull public TIntHashSet getSelectedCommits() { int[] selectedRows = getTable().getSelectedRows(); - return getCommitsAtRows(myDataPack.getGraphFacade(), selectedRows); + return getCommitsAtRows(myVisiblePack.getVisibleGraph(), selectedRows); } @NotNull - private static TIntHashSet getCommitsAtRows(@NotNull GraphFacade facade, int[] rows) { + private static TIntHashSet getCommitsAtRows(@NotNull VisibleGraph graph, int[] rows) { TIntHashSet commits = new TIntHashSet(); for (int row : rows) { - int commit = facade.getCommitAtRow(row); - if (commit > 0) { - commits.add(commit); + if (row < graph.getVisibleCommitCount()) { + commits.add(graph.getRowInfo(row).getCommit()); } } return commits; } - public void setDataPack(@NotNull DataPack dataPack) { - applyFiltersAndUpdateUi(dataPack); - } - - private void applyFiltersAndUpdateUi(@NotNull final DataPack dataPack) { - runUnderModalProgress("Applying filters...", new Runnable() { - public void run() { - final TIntHashSet previouslySelected = getSelectedCommits(); - final AbstractVcsLogTableModel newModel = myFilterer.applyFiltersAndUpdateUi(dataPack, getFilters()); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - myDataPack = dataPack; - setModel(newModel, myDataPack, previouslySelected); - myMainFrame.updateDataPack(myDataPack); - setLongEdgeVisibility(myUiProperties.areLongEdgesVisible()); - myDataPack.getGraphFacade().performAction(new BekGraphAction(myUiProperties.isBek() ? - PermanentGraph.SortType.Bek : PermanentGraph.SortType.Normal)); - fireFilterChangeEvent(); - repaintUI(); - - if (newModel.getRowCount() == 0) { // getValueAt won't be called for empty model => need to explicitly request to load more - newModel.requestToLoadMore(EmptyRunnable.INSTANCE); - } - } - }); - } - }); - } - public void applyFiltersAndUpdateUi() { - ApplicationManager.getApplication().assertIsDispatchThread(); - applyFiltersAndUpdateUi(myDataPack); + myFilterer.onFiltersChange(getFilters()); + } + + @NotNull + public VcsLogFilterer getFilterer() { + return myFilterer; } @NotNull @@ -358,7 +326,6 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { ProgressManager.getInstance().runProcessWithProgressSynchronously(runnable, task, false, null, getMainFrame().getMainComponent()); } }); - repaintUI(); } public void setBranchesPanelVisible(boolean visible) { @@ -382,9 +349,9 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable { @Override @NotNull - public DataPack getDataPack() { + public VisiblePack getDataPack() { ApplicationManager.getApplication().assertIsDispatchThread(); - return myDataPack; + return myVisiblePack; } @Override diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/BranchFilterPopupComponent.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/BranchFilterPopupComponent.java index d358e86c2a40..c70595bf7d1b 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/BranchFilterPopupComponent.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/BranchFilterPopupComponent.java @@ -22,7 +22,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.*; -import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.VcsLogBranchFilterImpl; import com.intellij.vcs.log.data.VcsLogUiProperties; import com.intellij.vcs.log.impl.VcsLogUtil; @@ -44,7 +43,7 @@ public class BranchFilterPopupComponent extends MultipleValueFilterPopupComponen myUiProperties = uiProperties; } - void updateDataPack(@NotNull DataPack dataPack) { + void updateDataPack(@NotNull VcsLogDataPack dataPack) { myDataPack = dataPack; } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/VcsLogClassicFilterUi.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/VcsLogClassicFilterUi.java index 9a44f320f040..8bc71682ad70 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/VcsLogClassicFilterUi.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/VcsLogClassicFilterUi.java @@ -29,7 +29,6 @@ import com.intellij.ui.SearchTextFieldWithStoredHistory; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.*; -import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.data.VcsLogUiProperties; import com.intellij.vcs.log.impl.VcsLogFilterCollectionImpl; @@ -61,7 +60,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi { @NotNull private final StructureFilterPopupComponent myStructureFilterComponent; public VcsLogClassicFilterUi(@NotNull VcsLogUiImpl ui, @NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUiProperties uiProperties, - @NotNull DataPack initialDataPack) { + @NotNull VcsLogDataPack initialDataPack) { myUi = ui; myTextFilter = new SearchTextFieldWithStoredHistory("Vcs.Log.Text.Filter.History") { @@ -91,7 +90,7 @@ public class VcsLogClassicFilterUi implements VcsLogFilterUi { myActionGroup.add(new FilterActionComponent(myStructureFilterComponent)); } - public void updateDataPack(@NotNull DataPack dataPack) { + public void updateDataPack(@NotNull VcsLogDataPack dataPack) { myBranchFilterComponent.updateDataPack(dataPack); } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index 2328c9fe3b20..8a978929a165 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -33,13 +33,13 @@ import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.LoadingDetails; import com.intellij.vcs.log.data.VcsLogDataHolder; +import com.intellij.vcs.log.data.VisiblePack; import com.intellij.vcs.log.printer.idea.PrintParameters; import com.intellij.vcs.log.ui.VcsLogColorManager; import com.intellij.vcs.log.ui.render.RefPainter; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; +import com.intellij.vcs.log.ui.tables.GraphTableModel; import net.miginfocom.swing.MigLayout; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -71,10 +71,10 @@ class DetailsPanel extends JPanel implements ListSelectionListener { @NotNull private final MessagePanel myMessagePanel; @NotNull private final JBLoadingPanel myLoadingPanel; - @NotNull private DataPack myDataPack; + @NotNull private VisiblePack myDataPack; DetailsPanel(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogGraphTable graphTable, @NotNull VcsLogColorManager colorManager, - @NotNull DataPack initialDataPack) { + @NotNull VisiblePack initialDataPack) { super(new CardLayout()); myLogDataHolder = logDataHolder; myGraphTable = graphTable; @@ -111,7 +111,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { showMessage("No commits selected"); } - void updateDataPack(@NotNull DataPack dataPack) { + void updateDataPack(@NotNull VisiblePack dataPack) { myDataPack = dataPack; } @@ -127,7 +127,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { else { ((CardLayout)getLayout()).show(this, STANDARD_LAYER); int row = rows[0]; - AbstractVcsLogTableModel tableModel = (AbstractVcsLogTableModel)myGraphTable.getModel(); + GraphTableModel tableModel = (GraphTableModel)myGraphTable.getModel(); Hash hash = tableModel.getHashAtRow(row); VcsFullCommitDetails commitData = myLogDataHolder.getCommitDetailsGetter().getCommitData(row, tableModel); if (commitData == null || hash == null) { diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java index 6765c7c394c7..780b720f696f 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/MainFrame.java @@ -22,9 +22,9 @@ import com.intellij.vcs.log.VcsLog; import com.intellij.vcs.log.VcsLogDataKeys; import com.intellij.vcs.log.VcsLogFilterUi; import com.intellij.vcs.log.VcsLogSettings; -import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.VcsLogDataHolder; import com.intellij.vcs.log.data.VcsLogUiProperties; +import com.intellij.vcs.log.data.VisiblePack; import com.intellij.vcs.log.graph.impl.facade.bek.BekSorter; import com.intellij.vcs.log.ui.VcsLogUiImpl; import com.intellij.vcs.log.ui.filter.VcsLogClassicFilterUi; @@ -60,7 +60,7 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider { public MainFrame(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUiImpl vcsLogUI, @NotNull Project project, @NotNull VcsLogSettings settings, @NotNull VcsLogUiProperties uiProperties, @NotNull VcsLog log, - @NotNull DataPack initialDataPack) { + @NotNull VisiblePack initialDataPack) { // collect info myLogDataHolder = logDataHolder; myUI = vcsLogUI; @@ -124,7 +124,7 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider { * Components may want to update their fields and/or rebuild. * @param dataPack new data pack. */ - public void updateDataPack(@NotNull DataPack dataPack) { + public void updateDataPack(@NotNull VisiblePack dataPack) { myFilterUi.updateDataPack(dataPack); myDetailsPanel.updateDataPack(dataPack); myGraphTable.updateDataPack(dataPack); @@ -336,7 +336,7 @@ public class MainFrame extends JPanel implements TypeSafeDataProvider { @Override public boolean isSelected(AnActionEvent e) { - return !myUI.areLongEdgesHidden(); + return !myUI.getDataPack().getVisibleGraph().getActionController().areLongEdgesHidden(); } @Override diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java index f033f752e1ec..f1d1eba2bc35 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/VcsLogGraphTable.java @@ -27,26 +27,28 @@ import com.intellij.ui.ColoredTableCellRenderer; import com.intellij.ui.PopupHandler; import com.intellij.ui.TableScrollingUtil; import com.intellij.ui.table.JBTable; -import com.intellij.util.PairFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; import com.intellij.vcs.log.Hash; import com.intellij.vcs.log.VcsLogHighlighter; -import com.intellij.vcs.log.data.DataPack; import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.graph.*; +import com.intellij.vcs.log.data.VisiblePack; +import com.intellij.vcs.log.graph.ColorGenerator; +import com.intellij.vcs.log.graph.PrintElement; +import com.intellij.vcs.log.graph.actions.GraphAnswer; +import com.intellij.vcs.log.graph.actions.GraphMouseAction; +import com.intellij.vcs.log.printer.idea.GraphCellPainter; import com.intellij.vcs.log.printer.idea.PositionUtil; +import com.intellij.vcs.log.printer.idea.SimpleGraphCellPainter; import com.intellij.vcs.log.ui.VcsLogUiImpl; import com.intellij.vcs.log.ui.render.GraphCommitCell; import com.intellij.vcs.log.ui.render.GraphCommitCellRender; -import com.intellij.vcs.log.ui.tables.AbstractVcsLogTableModel; +import com.intellij.vcs.log.ui.tables.GraphTableModel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableModel; @@ -78,14 +80,22 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C @NotNull private final Collection myHighlighters = ContainerUtil.newArrayList(); - @NotNull private DataPack myDataPack; + private final GraphCellPainter myGraphCellPainter = new SimpleGraphCellPainter(new com.intellij.vcs.log.printer.idea.ColorGenerator() { + @Override + public Color getColor(int colorId) { + return ColorGenerator.getColor(colorId); + } + }); - public VcsLogGraphTable(@NotNull VcsLogUiImpl UI, @NotNull final VcsLogDataHolder logDataHolder, @NotNull DataPack initialDataPack) { + @NotNull private VisiblePack myDataPack; + + public VcsLogGraphTable(@NotNull VcsLogUiImpl UI, @NotNull final VcsLogDataHolder logDataHolder, @NotNull VisiblePack initialDataPack) { super(); myUI = UI; myLogDataHolder = logDataHolder; myDataPack = initialDataPack; - myGraphCommitCellRender = new GraphCommitCellRender(myUI.getColorManager(), logDataHolder, myDataPack.getGraphFacade(), this); + myGraphCommitCellRender = new GraphCommitCellRender(myUI.getColorManager(), logDataHolder, myGraphCellPainter, + myDataPack.getVisibleGraph(), this); setDefaultRenderer(VirtualFile.class, new RootCellRenderer(myUI, myLogDataHolder.isMultiRoot())); setDefaultRenderer(GraphCommitCell.class, myGraphCommitCellRender); @@ -95,16 +105,6 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C setShowHorizontalLines(false); setIntercellSpacing(new Dimension(0, 0)); - getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override - public void valueChanged(ListSelectionEvent e) { - int selectedRow = getSelectedRow(); - if (selectedRow >= 0) { - myUI.click(selectedRow); - } - } - }); - MouseAdapter mouseAdapter = new MyMouseAdapter(); addMouseMotionListener(mouseAdapter); addMouseListener(mouseAdapter); @@ -127,17 +127,17 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C private void setColumnPreferredSize() { for (int i = 0; i < getColumnCount(); i++) { TableColumn column = getColumnModel().getColumn(i); - if (i == AbstractVcsLogTableModel.ROOT_COLUMN) { // thin stripe or nothing + if (i == GraphTableModel.ROOT_COLUMN) { // thin stripe or nothing int rootWidth = myUI.getColorManager().isMultipleRoots() ? ROOT_INDICATOR_WIDTH : 0; // NB: all further instructions and their order are important, otherwise the minimum size which is less than 15 won't be applied column.setMinWidth(rootWidth); column.setMaxWidth(rootWidth); column.setPreferredWidth(rootWidth); } - else if (i == AbstractVcsLogTableModel.COMMIT_COLUMN) { // let commit message occupy as much as possible + else if (i == GraphTableModel.COMMIT_COLUMN) { // let commit message occupy as much as possible column.setPreferredWidth(Short.MAX_VALUE); } - else if (i == AbstractVcsLogTableModel.AUTHOR_COLUMN) { // detect author with the longest name + else if (i == GraphTableModel.AUTHOR_COLUMN) { // detect author with the longest name // to avoid querying the last row (it would lead to full graph loading) int maxRowsToCheck = Math.min(MAX_ROWS_TO_CALC_WIDTH, getRowCount() - MAX_ROWS_TO_CALC_OFFSET); if (maxRowsToCheck < 0) { // but if the log is small, check all of them @@ -147,7 +147,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C column.setMinWidth(Math.min(contentWidth, MAX_DEFAULT_AUTHOR_COLUMN_WIDTH)); column.setWidth(column.getMinWidth()); } - else if (i == AbstractVcsLogTableModel.DATE_COLUMN) { // all dates have nearly equal sizes + else if (i == GraphTableModel.DATE_COLUMN) { // all dates have nearly equal sizes Font tableFont = UIManager.getFont("Table.font"); column.setMinWidth(getFontMetrics(tableFont).stringWidth("mm" + DateFormatUtil.formatDateTime(new Date()))); column.setWidth(column.getMinWidth()); @@ -172,7 +172,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C if (column < 0 || row < 0) { return null; } - if (column == AbstractVcsLogTableModel.ROOT_COLUMN) { + if (column == GraphTableModel.ROOT_COLUMN) { Object at = getValueAt(row, column); if (at instanceof VirtualFile) { return ((VirtualFile)at).getPresentableUrl(); @@ -213,10 +213,10 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C @Nullable public List getSelectedChanges() { TableModel model = getModel(); - if (!(model instanceof AbstractVcsLogTableModel)) { + if (!(model instanceof GraphTableModel)) { return null; } - List changes = ((AbstractVcsLogTableModel)model).getSelectedChanges(sortSelectedRows()); + List changes = ((GraphTableModel)model).getSelectedChanges(sortSelectedRows()); return changes == null ? null : CommittedChangesTreeBrowser.zipChanges(changes); } @@ -241,7 +241,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C public void performCopy(@NotNull DataContext dataContext) { List hashes = ContainerUtil.newArrayList(); for (int row : getSelectedRows()) { - Hash hash = ((AbstractVcsLogTableModel)getModel()).getHashAtRow(row); + Hash hash = ((GraphTableModel)getModel()).getHashAtRow(row); if (hash != null) { hashes.add(hash.asString()); } @@ -261,9 +261,9 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C return true; } - public void updateDataPack(@NotNull DataPack dataPack) { + public void updateDataPack(@NotNull VisiblePack dataPack) { myDataPack = dataPack; - myGraphCommitCellRender.updateGraphFacade(dataPack.getGraphFacade()); + myGraphCommitCellRender.updateVisibleGraph(dataPack.getVisibleGraph()); } public void addHighlighter(@NotNull VcsLogHighlighter highlighter) { @@ -281,7 +281,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C public void applyHighlighters(@NotNull Component rendererComponent, int row, boolean selected) { boolean fgUpdated = false; for (VcsLogHighlighter highlighter : myHighlighters) { - Color color = highlighter.getForeground(myDataPack.getGraphFacade().getCommitAtRow(row), selected); + Color color = highlighter.getForeground(myDataPack.getVisibleGraph().getRowInfo(row).getCommit(), selected); if (color != null) { rendererComponent.setForeground(color); fgUpdated = true; @@ -306,12 +306,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C } if (e.getClickCount() == 1) { - performAction(e, new PairFunction() { - @Override - public GraphAction fun(Integer row, Point point) { - return new ClickGraphAction(row, point); - } - }); + performAction(e, MyGraphMouseAction.Type.CLICK); } } @@ -321,24 +316,22 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } else { - performAction(e, new PairFunction() { - @Override - public GraphAction fun(Integer row, Point point) { - return new MouseOverAction(row, point); - } - }); + performAction(e, MyGraphMouseAction.Type.OVER); } } - private void performAction(@NotNull MouseEvent e, @NotNull PairFunction actionConstructor) { + private void performAction(@NotNull MouseEvent e, @NotNull final MyGraphMouseAction.Type actionType) { int row = PositionUtil.getRowIndex(e.getPoint()); if (row > getRowCount() - 1) { return; } Point point = calcPoint4Graph(e.getPoint()); - GraphFacade graphFacade = myDataPack.getGraphFacade(); - GraphAnswer answer = graphFacade.performAction(actionConstructor.fun(row, point)); - myUI.handleAnswer(answer); + Collection printElements = myDataPack.getVisibleGraph().getRowInfo(row).getPrintElements(); + PrintElement printElement = myGraphCellPainter.mouseOver(printElements, point.x, point.y); + + GraphAnswer answer = myDataPack.getVisibleGraph().getActionController().performMouseAction( + new MyGraphMouseAction(printElement, actionType)); + myUI.handleAnswer(answer, actionType == MyGraphMouseAction.Type.CLICK && printElement != null); } private boolean isAboveLink(MouseEvent e) { @@ -354,6 +347,28 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C public void mouseExited(MouseEvent e) { // Do nothing } + + private class MyGraphMouseAction implements GraphMouseAction { + private final PrintElement myPrintElement; + private final Type myActionType; + + public MyGraphMouseAction(PrintElement printElement, Type actionType) { + myPrintElement = printElement; + myActionType = actionType; + } + + @Nullable + @Override + public PrintElement getAffectedElement() { + return myPrintElement; + } + + @NotNull + @Override + public Type getType() { + return myActionType; + } + } } @NotNull @@ -362,7 +377,7 @@ public class VcsLogGraphTable extends JBTable implements TypeSafeDataProvider, C } private int getXOffset() { - TableColumn rootColumn = getColumnModel().getColumn(AbstractVcsLogTableModel.ROOT_COLUMN); + TableColumn rootColumn = getColumnModel().getColumn(GraphTableModel.ROOT_COLUMN); return myLogDataHolder.isMultiRoot() ? rootColumn.getWidth() : 0; } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/AbstractPaddingCellRender.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/AbstractPaddingCellRender.java deleted file mode 100644 index 23c736b4420b..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/AbstractPaddingCellRender.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.intellij.vcs.log.ui.render; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkRenderer; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.ColoredTableCellRenderer; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.ui.UIUtil; -import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.graph.PaintInfo; -import com.intellij.vcs.log.ui.VcsLogColorManager; -import com.intellij.vcs.log.ui.frame.VcsLogGraphTable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.*; -import java.awt.*; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -public abstract class AbstractPaddingCellRender extends ColoredTableCellRenderer { - - private static final Logger LOG = Logger.getInstance(AbstractPaddingCellRender.class); - - @NotNull private final VcsLogDataHolder myDataHolder; - @NotNull private final VcsLogGraphTable myGraphTable; - - @NotNull private final RefPainter myRefPainter; - @NotNull private final IssueLinkRenderer myIssueLinkRenderer; - - @Nullable private PaintInfo myGraphImage; - @Nullable private Collection myRefs; - - protected AbstractPaddingCellRender(@NotNull VcsLogColorManager colorManager, @NotNull VcsLogDataHolder dataHolder, - @NotNull VcsLogGraphTable table) { - myDataHolder = dataHolder; - myGraphTable = table; - myRefPainter = new RefPainter(colorManager, false); - myIssueLinkRenderer = new IssueLinkRenderer(dataHolder.getProject(), this); - } - - @Nullable - protected abstract PaintInfo getGraphImage(int row); - - @Override - protected void customizeCellRenderer(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - if (value == null) { - return; - } - - GraphCommitCell cell = getAssertCommitCell(value); - myGraphImage = getGraphImage(row); - myRefs = cell.getRefsToThisCommit(); - - int graphPadding; - if (myGraphImage != null) { - graphPadding = myGraphImage.getWidth(); - if (graphPadding < 2) { // TODO temporary diagnostics: why does graph sometimes disappear - LOG.error("Too small image width: " + graphPadding); - } - } - else { - graphPadding = 0; - } - int textPadding = graphPadding + calcRefsPadding(myRefs); - - setBorder(null); - append(""); - appendFixedTextFragmentWidth(textPadding); - myGraphTable.applyHighlighters(this, row, isSelected); - myIssueLinkRenderer.appendTextWithLinks(cell.getText()); - } - - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - - if (myRefs != null) { - int graphPadding = myGraphImage != null ? myGraphImage.getWidth() : 0; - drawRefs((Graphics2D)g, myRefs, graphPadding); - } - - if (myGraphImage != null) { - UIUtil.drawImage(g, myGraphImage.getImage(), 0, 0, null); - } - else { // TODO temporary diagnostics: why does graph sometimes disappear - LOG.error("Image is null"); - } - } - - private static GraphCommitCell getAssertCommitCell(Object value) { - assert value instanceof GraphCommitCell : "Value of incorrect class was supplied: " + value; - return (GraphCommitCell)value; - } - - protected void drawRefs(@NotNull Graphics2D g2, @NotNull Collection refs, int padding) { - myRefPainter.drawLabels(g2, collectLabelsForRefs(refs), padding); - } - - @NotNull - private Map collectLabelsForRefs(@NotNull Collection refs) { - if (refs.isEmpty()) { - return Collections.emptyMap(); - } - VirtualFile root = refs.iterator().next().getRoot(); // all refs are from the same commit => they have the same root - refs = ContainerUtil.sorted(refs, myDataHolder.getLogProvider(root).getReferenceManager().getComparator()); - List branches = getBranches(refs); - Collection tags = ContainerUtil.subtract(refs, branches); - return getLabelsForRefs(branches, tags); - } - - protected int calcRefsPadding(@NotNull Collection refs) { - return myRefPainter.padding(collectLabelsForRefs(refs).keySet(), this.getFontMetrics(RefPainter.DEFAULT_FONT)); - } - - @NotNull - private static Map getLabelsForRefs(@NotNull List branches, @NotNull Collection tags) { - Map labels = ContainerUtil.newLinkedHashMap(); - for (VcsRef branch : branches) { - labels.put(branch.getName(), branch.getType().getBackgroundColor()); - } - if (!tags.isEmpty()) { - VcsRef firstTag = tags.iterator().next(); - Color color = firstTag.getType().getBackgroundColor(); - if (tags.size() > 1) { - labels.put(firstTag.getName() + " +", color); - } - else { - labels.put(firstTag.getName(), color); - } - } - return labels; - } - - private static List getBranches(Collection refs) { - return ContainerUtil.filter(refs, new Condition() { - @Override - public boolean value(VcsRef ref) { - return ref.getType().isBranch(); - } - }); - } -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java index d2698e87a4fd..07e0ee412b4e 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/render/GraphCommitCellRender.java @@ -1,46 +1,199 @@ -/* - * Copyright 2000-2013 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.ui.render; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkRenderer; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.ColoredTableCellRenderer; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcs.log.VcsRef; import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.graph.GraphFacade; -import com.intellij.vcs.log.graph.PaintInfo; +import com.intellij.vcs.log.graph.PrintElement; +import com.intellij.vcs.log.graph.VisibleGraph; +import com.intellij.vcs.log.printer.idea.GraphCellPainter; +import com.intellij.vcs.log.printer.idea.PrintParameters; import com.intellij.vcs.log.ui.VcsLogColorManager; import com.intellij.vcs.log.ui.frame.VcsLogGraphTable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class GraphCommitCellRender extends AbstractPaddingCellRender { +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; - @NotNull private GraphFacade myGraphFacade; +public class GraphCommitCellRender extends ColoredTableCellRenderer { - public GraphCommitCellRender(@NotNull VcsLogColorManager colorManager, @NotNull VcsLogDataHolder dataHolder, - @NotNull GraphFacade graphFacade, @NotNull VcsLogGraphTable table) { - super(colorManager, dataHolder, table); - myGraphFacade = graphFacade; + private static final Logger LOG = Logger.getInstance(GraphCommitCellRender.class); + + @NotNull private final VcsLogDataHolder myDataHolder; + @NotNull private final GraphCellPainter myPainter; + @NotNull private final VcsLogGraphTable myGraphTable; + @NotNull private final RefPainter myRefPainter; + @NotNull private final IssueLinkRenderer myIssueLinkRenderer; + + @NotNull private VisibleGraph myVisibleGraph; + @Nullable private PaintInfo myGraphImage; + @Nullable private Collection myRefs; + + public GraphCommitCellRender(@NotNull VcsLogColorManager colorManager, + @NotNull VcsLogDataHolder dataHolder, + @NotNull GraphCellPainter painter, + @NotNull VisibleGraph graph, + @NotNull VcsLogGraphTable table) { + myDataHolder = dataHolder; + myPainter = painter; + myVisibleGraph = graph; + myGraphTable = table; + myRefPainter = new RefPainter(colorManager, false); + myIssueLinkRenderer = new IssueLinkRenderer(dataHolder.getProject(), this); + } + + public void updateVisibleGraph(@NotNull VisibleGraph visibleGraph) { + myVisibleGraph = visibleGraph; + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + + if (myRefs != null) { + int graphPadding = myGraphImage != null ? myGraphImage.getWidth() : 0; + drawRefs((Graphics2D)g, myRefs, graphPadding); + } + + if (myGraphImage != null) { + UIUtil.drawImage(g, myGraphImage.getImage(), 0, 0, null); + } + else { // TODO temporary diagnostics: why does graph sometimes disappear + LOG.error("Image is null"); + } + } + + @Override + protected void customizeCellRenderer(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if (value == null) { + return; + } + + GraphCommitCell cell = getAssertCommitCell(value); + myGraphImage = getGraphImage(row); + myRefs = cell.getRefsToThisCommit(); + + int graphPadding; + if (myGraphImage != null) { + graphPadding = myGraphImage.getWidth(); + if (graphPadding < 2) { // TODO temporary diagnostics: why does graph sometimes disappear + LOG.error("Too small image width: " + graphPadding); + } + } + else { + graphPadding = 0; + } + int textPadding = graphPadding + calcRefsPadding(myRefs); + + setBorder(null); + append(""); + appendFixedTextFragmentWidth(textPadding); + myGraphTable.applyHighlighters(this, row, isSelected); + myIssueLinkRenderer.appendTextWithLinks(cell.getText()); } @Nullable - @Override - protected PaintInfo getGraphImage(int row) { - return myGraphFacade.paint(row); + private PaintInfo getGraphImage(int row) { + Collection printElements = myVisibleGraph.getRowInfo(row).getPrintElements(); + int maxIndex = 0; + for (PrintElement printElement : printElements) { + maxIndex = Math.max(maxIndex, printElement.getPositionInCurrentRow()); + } + maxIndex++; + final BufferedImage image = + UIUtil.createImage(PrintParameters.WIDTH_NODE * (maxIndex + 4), PrintParameters.HEIGHT_CELL, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = image.createGraphics(); + myPainter.draw(g2, printElements); + + final int width = maxIndex * PrintParameters.WIDTH_NODE; + return new PaintInfo(image, width); } - public void updateGraphFacade(@NotNull GraphFacade graphFacade) { - myGraphFacade = graphFacade; + private static GraphCommitCell getAssertCommitCell(Object value) { + assert value instanceof GraphCommitCell : "Value of incorrect class was supplied: " + value; + return (GraphCommitCell)value; } + private void drawRefs(@NotNull Graphics2D g2, @NotNull Collection refs, int padding) { + myRefPainter.drawLabels(g2, collectLabelsForRefs(refs), padding); + } + + @NotNull + private Map collectLabelsForRefs(@NotNull Collection refs) { + if (refs.isEmpty()) { + return Collections.emptyMap(); + } + VirtualFile root = refs.iterator().next().getRoot(); // all refs are from the same commit => they have the same root + refs = ContainerUtil.sorted(refs, myDataHolder.getLogProvider(root).getReferenceManager().getComparator()); + List branches = getBranches(refs); + Collection tags = ContainerUtil.subtract(refs, branches); + return getLabelsForRefs(branches, tags); + } + + private int calcRefsPadding(@NotNull Collection refs) { + return myRefPainter.padding(collectLabelsForRefs(refs).keySet(), this.getFontMetrics(RefPainter.DEFAULT_FONT)); + } + + @NotNull + private static Map getLabelsForRefs(@NotNull List branches, @NotNull Collection tags) { + Map labels = ContainerUtil.newLinkedHashMap(); + for (VcsRef branch : branches) { + labels.put(branch.getName(), branch.getType().getBackgroundColor()); + } + if (!tags.isEmpty()) { + VcsRef firstTag = tags.iterator().next(); + Color color = firstTag.getType().getBackgroundColor(); + if (tags.size() > 1) { + labels.put(firstTag.getName() + " +", color); + } + else { + labels.put(firstTag.getName(), color); + } + } + return labels; + } + + private static List getBranches(Collection refs) { + return ContainerUtil.filter(refs, new Condition() { + @Override + public boolean value(VcsRef ref) { + return ref.getType().isBranch(); + } + }); + } + + private static class PaintInfo { + private int myWidth; + @NotNull private Image myImage; + + PaintInfo(@NotNull Image image, int width) { + myImage = image; + myWidth = width; + } + + @NotNull + Image getImage() { + return myImage; + } + + /** + * Returns the "interesting" width of the painted image, i.e. the width which the text in the table should be offset by.
+ * It can be smaller than the width of {@link #getImage() the image}, because we allow the text to cover part of the graph + * (some diagonal edges, etc.) + */ + int getWidth() { + return myWidth; + } + } } diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java deleted file mode 100644 index e5f93eeb0235..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/AbstractVcsLogTableModel.java +++ /dev/null @@ -1,185 +0,0 @@ -package com.intellij.vcs.log.ui.tables; - -import com.intellij.openapi.util.EmptyRunnable; -import com.intellij.openapi.vcs.changes.Change; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.newvfs.impl.NullVirtualFile; -import com.intellij.util.text.DateFormatUtil; -import com.intellij.vcs.log.Hash; -import com.intellij.vcs.log.VcsFullCommitDetails; -import com.intellij.vcs.log.VcsShortCommitDetails; -import com.intellij.vcs.log.data.DataPack; -import com.intellij.vcs.log.data.LoadMoreStage; -import com.intellij.vcs.log.data.LoadingDetails; -import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.ui.VcsLogUiImpl; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import javax.swing.table.AbstractTableModel; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -public abstract class AbstractVcsLogTableModel extends AbstractTableModel { - - public static final int ROOT_COLUMN = 0; - public static final int COMMIT_COLUMN = 1; - public static final int AUTHOR_COLUMN = 2; - public static final int DATE_COLUMN = 3; - private static final int COLUMN_COUNT = DATE_COLUMN + 1; - - private static final String[] COLUMN_NAMES = {"", "Subject", "Author", "Date"}; - - @NotNull private final VcsLogDataHolder myLogDataHolder; - @NotNull protected final VcsLogUiImpl myUi; - @NotNull protected final DataPack myDataPack; - @NotNull private final LoadMoreStage myLoadMoreStage; - - @NotNull private final AtomicBoolean myLoadMoreWasRequested = new AtomicBoolean(); - - - protected AbstractVcsLogTableModel(@NotNull VcsLogDataHolder logDataHolder, @NotNull VcsLogUiImpl ui, @NotNull DataPack dataPack, - @NotNull LoadMoreStage loadMoreStage) { - myLogDataHolder = logDataHolder; - myUi = ui; - myDataPack = dataPack; - myLoadMoreStage = loadMoreStage; - } - - @Override - public final int getColumnCount() { - return COLUMN_COUNT; - } - - @Nullable - protected VcsShortCommitDetails getShortDetails(int rowIndex) { - return myLogDataHolder.getMiniDetailsGetter().getCommitData(rowIndex, this); - } - - @Nullable - public VcsFullCommitDetails getFullCommitDetails(int rowIndex) { - return myLogDataHolder.getCommitDetailsGetter().getCommitData(rowIndex, this); - } - - /** - * Requests the proper data provider to load more data from the log & recreate the model. - * @param onLoaded will be called upon task completion on the EDT. - */ - public void requestToLoadMore(@NotNull Runnable onLoaded) { - if (myLoadMoreWasRequested.compareAndSet(false, true) // Don't send the request to VCS twice - && myLoadMoreStage != LoadMoreStage.ALL_REQUESTED) { // or when everything possible is loaded - myUi.getTable().setPaintBusy(true); - myUi.getFilterer().requestVcs(myDataPack, myUi.getFilters(), myLoadMoreStage, onLoaded); - } - } - - @NotNull - @Override - public final Object getValueAt(int rowIndex, int columnIndex) { - if (rowIndex >= getRowCount() - 1) { - requestToLoadMore(EmptyRunnable.INSTANCE); - } - - VcsShortCommitDetails data = getShortDetails(rowIndex); - switch (columnIndex) { - case ROOT_COLUMN: - return getRoot(rowIndex); - case COMMIT_COLUMN: - return getCommitColumnCell(rowIndex, data); - case AUTHOR_COLUMN: - if (data == null) { - return ""; - } - else { - return data.getAuthor().getName(); - } - case DATE_COLUMN: - if (data == null || data.getTimestamp() < 0) { - return ""; - } - else { - return DateFormatUtil.formatDateTime(data.getTimestamp()); - } - default: - throw new IllegalArgumentException("columnIndex is " + columnIndex + " > " + (COLUMN_COUNT - 1)); - } - } - - /** - * Returns true if not all data has been loaded, i.e. there is sense to {@link #requestToLoadMore(Runnable) request more data}. - */ - public boolean canRequestMore() { - return !myUi.getFilters().isEmpty() && myLoadMoreStage != LoadMoreStage.ALL_REQUESTED; - } - - /** - * Returns Changes for commits at selected rows.
- * Rows are given in the order as they appear in the table, i. e. in reverse chronological order.
- * Changes can be returned as-is, i.e. with duplicate changes for a single file. - * @return Changes selected in all rows, or null if this data is not ready yet. - */ - @Nullable - public List getSelectedChanges(@NotNull List selectedRows) { - List changes = new ArrayList(); - for (int row : selectedRows) { - VcsFullCommitDetails commitData = getFullCommitDetails(row); - if (commitData == null || commitData instanceof LoadingDetails) { - return null; - } - changes.addAll(commitData.getChanges()); - } - return changes; - } - - @NotNull - public abstract VirtualFile getRoot(int rowIndex); - - @NotNull - protected abstract CommitColumnClass getCommitColumnCell(int index, @Nullable VcsShortCommitDetails details); - - @NotNull - protected abstract Class getCommitColumnClass(); - - /** - * Returns the Hash of the commit displayed in the given row. - * May be null if there is no commit in the row - * (such situations may appear, for example, if graph is filtered by branch, as described in IDEA-115442). - */ - @Nullable - public abstract Hash getHashAtRow(int row); - - /** - * Returns the row number containing the given commit, - * or -1 if the requested commit is not contained in this table model (possibly because not all data has been loaded). - */ - public abstract int getRowOfCommit(@NotNull Hash hash); - - /** - * Returns the number of the first row which contains a commit which hash starts with the given value, - * or -1 if no such commit was found (possibly because not all data has been loaded). - */ - public abstract int getRowOfCommitByPartOfHash(@NotNull String hash); - - @Override - public Class getColumnClass(int column) { - switch (column) { - case ROOT_COLUMN: - return VirtualFile.class; - case COMMIT_COLUMN: - return getCommitColumnClass(); - case AUTHOR_COLUMN: - return String.class; - case DATE_COLUMN: - return String.class; - default: - throw new IllegalArgumentException("columnIndex is " + column + " > " + (COLUMN_COUNT - 1)); - } - } - - @Override - public String getColumnName(int column) { - return COLUMN_NAMES[column]; - } - -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/EmptyTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/EmptyTableModel.java deleted file mode 100644 index 575be9e5e183..000000000000 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/EmptyTableModel.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.ui.tables; - -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.vcs.log.Hash; -import com.intellij.vcs.log.VcsRef; -import com.intellij.vcs.log.VcsShortCommitDetails; -import com.intellij.vcs.log.data.DataPack; -import com.intellij.vcs.log.data.LoadMoreStage; -import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.ui.VcsLogUiImpl; -import com.intellij.vcs.log.ui.render.GraphCommitCell; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; - -public class EmptyTableModel extends AbstractVcsLogTableModel { - - public EmptyTableModel(@NotNull DataPack dataPack, @NotNull VcsLogDataHolder logDataHolder, - @NotNull VcsLogUiImpl ui, @NotNull LoadMoreStage loadMoreStage) { - super(logDataHolder, ui, dataPack, loadMoreStage); - } - - @Override - public int getRowCount() { - return 0; - } - - @NotNull - @Override - public VirtualFile getRoot(int rowIndex) { - throw new AssertionError("Root shouldn't be requested for empty table model. row: " + rowIndex); - } - - @NotNull - @Override - protected GraphCommitCell getCommitColumnCell(int index, @Nullable VcsShortCommitDetails details) { - return new GraphCommitCell("", Collections.emptyList()); - } - - @NotNull - @Override - protected Class getCommitColumnClass() { - return GraphCommitCell.class; - } - - @Nullable - @Override - public Hash getHashAtRow(int row) { - return null; - } - - @Override - public int getRowOfCommit(@NotNull Hash hash) { - return -1; - } - - @Override - public int getRowOfCommitByPartOfHash(@NotNull String hash) { - return -1; - } - -} diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java index 80ed236cb330..5d9e06b91a22 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/tables/GraphTableModel.java @@ -2,62 +2,63 @@ package com.intellij.vcs.log.ui.tables; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.EmptyRunnable; +import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.text.DateFormatUtil; import com.intellij.vcs.log.Hash; +import com.intellij.vcs.log.VcsFullCommitDetails; import com.intellij.vcs.log.VcsRef; import com.intellij.vcs.log.VcsShortCommitDetails; -import com.intellij.vcs.log.data.DataPack; -import com.intellij.vcs.log.data.LoadMoreStage; +import com.intellij.vcs.log.data.LoadingDetails; import com.intellij.vcs.log.data.VcsLogDataHolder; -import com.intellij.vcs.log.ui.render.GraphCommitCell; +import com.intellij.vcs.log.data.VisiblePack; import com.intellij.vcs.log.impl.VcsLogUtil; import com.intellij.vcs.log.ui.VcsLogUiImpl; +import com.intellij.vcs.log.ui.render.GraphCommitCell; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.table.AbstractTableModel; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -public class GraphTableModel extends AbstractVcsLogTableModel { +public class GraphTableModel extends AbstractTableModel { private static final Logger LOG = Logger.getInstance(GraphTableModel.class); - @NotNull private final DataPack myDataPack; - @NotNull private final VcsLogDataHolder myDataHolder; + public static final int ROOT_COLUMN = 0; + public static final int COMMIT_COLUMN = 1; + public static final int AUTHOR_COLUMN = 2; + public static final int DATE_COLUMN = 3; + private static final int COLUMN_COUNT = DATE_COLUMN + 1; + private static final String[] COLUMN_NAMES = {"", "Subject", "Author", "Date"}; - public GraphTableModel(@NotNull DataPack dataPack, @NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl UI, - @NotNull LoadMoreStage loadMoreStage) { - super(dataHolder, UI, dataPack, loadMoreStage); + @NotNull protected final VcsLogUiImpl myUi; + @NotNull protected final VisiblePack myDataPack; + @NotNull private final VcsLogDataHolder myDataHolder; + @NotNull private final VcsLogDataHolder myLogDataHolder; + + private boolean myMoreRequested; + + public GraphTableModel(@NotNull VisiblePack dataPack, @NotNull VcsLogDataHolder dataHolder, @NotNull VcsLogUiImpl UI) { + myLogDataHolder = dataHolder; + myUi = UI; myDataPack = dataPack; myDataHolder = dataHolder; } @Override public int getRowCount() { - return myDataPack.getGraphFacade().getVisibleCommitCount(); - } - - @Override - public void requestToLoadMore(@NotNull Runnable onLoaded) { - if (!myDataHolder.isFullLogShowing()) { - myDataHolder.showFullLog(onLoaded); - } - else if (!myUi.getFilters().isEmpty()) { - super.requestToLoadMore(onLoaded); - } - } - - @Override - public boolean canRequestMore() { - return !myDataHolder.isFullLogShowing() || super.canRequestMore(); + return myDataPack.getVisibleGraph().getVisibleCommitCount(); } @NotNull - @Override public VirtualFile getRoot(int rowIndex) { - int head = myDataPack.getGraphFacade().getInfoProvider().getRowInfo(rowIndex).getOneOfHeads(); + int head = myDataPack.getVisibleGraph().getRowInfo(rowIndex).getOneOfHeads(); Collection refs = myDataPack.getRefsModel().refsToCommit(head); if (refs.isEmpty()) { LOG.error("No references pointing to head " + head + " identified for commit at row " + rowIndex); @@ -68,7 +69,6 @@ public class GraphTableModel extends AbstractVcsLogTableModel { } @NotNull - @Override protected GraphCommitCell getCommitColumnCell(int rowIndex, @Nullable VcsShortCommitDetails details) { String message = ""; List refs = Collections.emptyList(); @@ -79,22 +79,14 @@ public class GraphTableModel extends AbstractVcsLogTableModel { return new GraphCommitCell(message, refs); } - @NotNull - @Override - protected Class getCommitColumnClass() { - return GraphCommitCell.class; - } - @Nullable - @Override public Hash getHashAtRow(int row) { - return myDataHolder.getHash(myDataPack.getGraphFacade().getCommitAtRow(row)); + return myDataHolder.getHash(myDataPack.getVisibleGraph().getRowInfo(row).getCommit()); } - @Override public int getRowOfCommit(@NotNull final Hash hash) { final int commitIndex = myDataHolder.getCommitIndex(hash); - return ContainerUtil.indexOf(VcsLogUtil.getVisibleCommits(myDataPack.getGraphFacade()), new Condition() { + return ContainerUtil.indexOf(VcsLogUtil.getVisibleCommits(myDataPack.getVisibleGraph()), new Condition() { @Override public boolean value(Integer integer) { return integer == commitIndex; @@ -102,10 +94,112 @@ public class GraphTableModel extends AbstractVcsLogTableModel { }); } - @Override public int getRowOfCommitByPartOfHash(@NotNull String partialHash) { - Hash hash = myDataHolder.findHashByString(partialHash); + Hash hash = myDataHolder.getHashMap().findHashByString(partialHash); return hash != null ? getRowOfCommit(hash) : -1; } + @Override + public final int getColumnCount() { + return COLUMN_COUNT; + } + + @Nullable + private VcsShortCommitDetails getShortDetails(int rowIndex) { + return myLogDataHolder.getMiniDetailsGetter().getCommitData(rowIndex, this); + } + + @Nullable + public VcsFullCommitDetails getFullCommitDetails(int rowIndex) { + return myLogDataHolder.getCommitDetailsGetter().getCommitData(rowIndex, this); + } + + /** + * Requests the proper data provider to load more data from the log & recreate the model. + * @param onLoaded will be called upon task completion on the EDT. + */ + public void requestToLoadMore(@NotNull Runnable onLoaded) { + myMoreRequested = true; + myUi.getFilterer().moreCommitsNeeded(onLoaded); + myUi.getTable().setPaintBusy(true); + } + + @NotNull + @Override + public final Object getValueAt(int rowIndex, int columnIndex) { + if (rowIndex >= getRowCount() - 1 && canRequestMore()) { + requestToLoadMore(EmptyRunnable.INSTANCE); + } + + VcsShortCommitDetails data = getShortDetails(rowIndex); + switch (columnIndex) { + case ROOT_COLUMN: + return getRoot(rowIndex); + case COMMIT_COLUMN: + return getCommitColumnCell(rowIndex, data); + case AUTHOR_COLUMN: + if (data == null) { + return ""; + } + else { + return data.getAuthor().getName(); + } + case DATE_COLUMN: + if (data == null || data.getTimestamp() < 0) { + return ""; + } + else { + return DateFormatUtil.formatDateTime(data.getTimestamp()); + } + default: + throw new IllegalArgumentException("columnIndex is " + columnIndex + " > " + (COLUMN_COUNT - 1)); + } + } + + /** + * Returns true if not all data has been loaded, i.e. there is sense to {@link #requestToLoadMore(Runnable) request more data}. + */ + public boolean canRequestMore() { + return !myMoreRequested && myDataPack.canRequestMore(); + } + + /** + * Returns Changes for commits at selected rows.
+ * Rows are given in the order as they appear in the table, i. e. in reverse chronological order.
+ * Changes can be returned as-is, i.e. with duplicate changes for a single file. + * @return Changes selected in all rows, or null if this data is not ready yet. + */ + @Nullable + public List getSelectedChanges(@NotNull List selectedRows) { + List changes = new ArrayList(); + for (int row : selectedRows) { + VcsFullCommitDetails commitData = getFullCommitDetails(row); + if (commitData == null || commitData instanceof LoadingDetails) { + return null; + } + changes.addAll(commitData.getChanges()); + } + return changes; + } + + @Override + public Class getColumnClass(int column) { + switch (column) { + case ROOT_COLUMN: + return VirtualFile.class; + case COMMIT_COLUMN: + return GraphCommitCell.class; + case AUTHOR_COLUMN: + return String.class; + case DATE_COLUMN: + return String.class; + default: + throw new IllegalArgumentException("columnIndex is " + column + " > " + (COLUMN_COUNT - 1)); + } + } + + @Override + public String getColumnName(int column) { + return COLUMN_NAMES[column]; + } } diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java index 01705232a253..2e18a39cd69a 100644 --- a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java +++ b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java @@ -174,7 +174,8 @@ public class VcsLogRefresherTest extends VcsLogPlatformTest { private VcsLogRefresherImpl createLoader(DataWaiter dataWaiter) { myDataHolder = new VcsLogDataHolder(myProject, myProject, myLogProviders, - ServiceManager.getService(myProject, VcsLogSettings.class), dataWaiter); + ServiceManager.getService(myProject, VcsLogSettings.class), + ServiceManager.getService(myProject, VcsLogUiProperties.class), Consumer.EMPTY_CONSUMER); return new VcsLogRefresherImpl(myProject, myDataHolder.getHashMap(), myLogProviders, myDataHolder.getUserRegistry(), myTopDetailsCache, dataWaiter, FAILING_EXCEPTION_HANDLER, RECENT_COMMITS_COUNT); }